File size: 8,275 Bytes
87be849
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c005998
 
87be849
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d2ccaa1
 
 
 
 
87be849
d2ccaa1
 
 
 
 
 
 
87be849
d2ccaa1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
import os
import numpy as np
import requests
from flask import Flask, request, jsonify, send_file
from werkzeug.utils import secure_filename
import onnxruntime
from PIL import Image
import io
import base64
import logging

# ุฅุนุฏุงุฏ ุงู„ุชุณุฌูŠู„
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max file size

# ุชุญุฏูŠุซ ุงู„ู…ุณุงุฑุงุช ู„ู„ุนู…ู„ ููŠ Codespaces
# MODEL_URL = "https://huggingface.co/skytnt/anime-seg/resolve/main/isnetis.onnx"
MODEL_URL = "https://huggingface.co/briaai/RMBG-1.4/resolve/main/onnx/model_fp16.onnx?download=true"
MODEL_PATH = "isnetis.onnx"
UPLOAD_FOLDER = "uploads"
RESULT_FOLDER = "results"

# ุฅู†ุดุงุก ุงู„ู…ุฌู„ุฏุงุช
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(RESULT_FOLDER, exist_ok=True)

class BackgroundRemover:
    def __init__(self):
        self.session = None
        self.input_name = None
        self.output_name = None
        
    def download_model(self):
        if os.path.exists(MODEL_PATH):
            logger.info("โœ… Model already exists, skipping download")
            return True
            
        try:
            logger.info("๐Ÿ“ฅ Downloading model from HuggingFace...")
            response = requests.get(MODEL_URL, stream=True)
            response.raise_for_status()
            
            total_size = int(response.headers.get('content-length', 0))
            downloaded = 0
            
            with open(MODEL_PATH, 'wb') as f:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        f.write(chunk)
                        downloaded += len(chunk)
                        if total_size > 0:
                            progress = (downloaded / total_size) * 100
                            print(f"\r๐Ÿ“ฅ Downloading: {progress:.1f}%", end="", flush=True)
            
            print()  # ุณุทุฑ ุฌุฏูŠุฏ
            logger.info("โœ… Model downloaded successfully")
            return True
        except Exception as e:
            logger.error(f"โŒ Failed to download model: {e}")
            return False
    
    def load_model(self):
        try:
            logger.info("๐Ÿ”„ Loading ONNX model...")
            providers = ['CPUExecutionProvider']
            
            # ุงู„ุชุญู‚ู‚ ู…ู† ุฏุนู… GPU (ุงุฎุชูŠุงุฑูŠ)
            try:
                available_providers = onnxruntime.get_available_providers()
                if 'CUDAExecutionProvider' in available_providers:
                    providers.insert(0, 'CUDAExecutionProvider')
                    logger.info("๐Ÿš€ CUDA provider available")
                else:
                    logger.info("๐Ÿ’ป Using CPU provider")
            except:
                logger.info("๐Ÿ’ป Using CPU provider")
            
            self.session = onnxruntime.InferenceSession(MODEL_PATH, providers=providers)
            self.input_name = self.session.get_inputs()[0].name
            self.output_name = self.session.get_outputs()[0].name
            
            logger.info(f"โœ… Model loaded successfully")
            logger.info(f"๐Ÿ“Š Input: {self.input_name}, Output: {self.output_name}")
            return True
        except Exception as e:
            logger.error(f"โŒ Failed to load model: {e}")
            return False
    
    def preprocess_image(self, image):
        original_size = image.size
        image = image.convert('RGB')
        image = image.resize((1024, 1024), Image.LANCZOS)
        image_array = np.array(image).astype(np.float32)
        image_array = image_array / 255.0
        image_array = np.transpose(image_array, (2, 0, 1))
        image_array = np.expand_dims(image_array, axis=0)
        return image_array, original_size
    
    def postprocess_mask(self, mask, original_size):
        mask = mask.squeeze()
        mask = (mask * 255).astype(np.uint8)
        mask = Image.fromarray(mask, mode='L')
        mask = mask.resize(original_size, Image.LANCZOS)
        return mask
    
    def remove_background(self, image_path):
        try:
            logger.info(f"๐Ÿ–ผ๏ธ Processing image: {image_path}")
            image = Image.open(image_path)
            preprocessed, original_size = self.preprocess_image(image)
            
            logger.info("๐Ÿค– Running AI inference...")
            mask = self.session.run([self.output_name], {self.input_name: preprocessed})[0]
            mask = self.postprocess_mask(mask, original_size)
            
            logger.info("โœ‚๏ธ Applying mask to remove background...")
            image = image.convert('RGBA')
            image.putalpha(mask)
            
            logger.info("โœ… Background removed successfully")
            return image
        except Exception as e:
            logger.error(f"โŒ Failed to remove background: {e}")
            return None

# ุฅู†ุดุงุก ูƒุงุฆู† ุฅุฒุงู„ุฉ ุงู„ุฎู„ููŠุฉ
background_remover = BackgroundRemover()

@app.route('/', methods=['GET'])
def health_check():
    """ูุญุต ุตุญุฉ ุงู„ุณูŠุฑูุฑ"""
    return jsonify({
        'status': 'โœ… Server is running',
        'model_loaded': background_remover.session is not None,
        'endpoints': {
            'health_check': '/ (GET)',
            'remove_background': '/remove-background (POST)'
        },
        'info': 'Background Remover API - Ready to use!'
    })

@app.route('/remove-background', methods=['POST'])
def remove_background_endpoint():
    """ุฅุฒุงู„ุฉ ุฎู„ููŠุฉ ุงู„ุตูˆุฑุฉ"""
    try:
        # ุงู„ุชุญู‚ู‚ ู…ู† ูˆุฌูˆุฏ ุงู„ู…ู„ู
        if 'file' not in request.files:
            return jsonify({'error': 'No file uploaded'}), 400
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({'error': 'No file selected'}), 400
        
        # ุงู„ุชุญู‚ู‚ ู…ู† ู†ูˆุน ุงู„ู…ู„ู
        if not file.content_type.startswith('image/'):
            return jsonify({'error': 'File must be an image'}), 400
        
        # ุญูุธ ุงู„ู…ู„ู
        filename = secure_filename(file.filename)
        filepath = os.path.join(UPLOAD_FOLDER, filename)
        file.save(filepath)
        
        logger.info(f"๐Ÿ“‚ File saved: {filepath}")
        
        # ู…ุนุงู„ุฌุฉ ุงู„ุตูˆุฑุฉ
        result = background_remover.remove_background(filepath)
        
        if result is None:
            os.remove(filepath)  # ุญุฐู ุงู„ู…ู„ู ููŠ ุญุงู„ุฉ ุงู„ูุดู„
            return jsonify({'error': 'Failed to process image'}), 500
        
        # ุญูุธ ุงู„ู†ุชูŠุฌุฉ
        result_filename = f"result_{filename.rsplit('.', 1)[0]}.png"
        result_path = os.path.join(RESULT_FOLDER, result_filename)
        result.save(result_path, 'PNG')
        
        # ุญุฐู ุงู„ู…ู„ู ุงู„ุฃุตู„ูŠ
        os.remove(filepath)
        
        logger.info(f"โœ… Result saved: {result_path}")
        
        return send_file(result_path, mimetype='image/png', as_attachment=False)
        
    except Exception as e:
        logger.error(f"โŒ Error in remove_background_endpoint: {e}")
        return jsonify({'error': 'Internal server error'}), 500

if __name__ == '__main__':
    print("=" * 60)
    print("๐ŸŽฏ Background Remover API Server")
    print("=" * 60)
    
    logger.info("๐Ÿš€ Starting Background Remover Server...")
    
    # ุชุญู…ูŠู„ ูˆุชุดุบูŠู„ ุงู„ู†ู…ูˆุฐุฌ
    if not background_remover.download_model():
        logger.error("โŒ Failed to download model. Exiting...")
        exit(1)
    
    if not background_remover.load_model():
        logger.error("โŒ Failed to load model. Exiting...")
        exit(1)
    
    # ุฅุนุฏุงุฏ ุงู„ู…ู†ูุฐ
if __name__ == '__main__':
    if not background_remover.download_model():
        exit(1)
    if not background_remover.load_model():
        exit(1)
    
    # Hugging Face Spaces ูŠุณุชุฎุฏู… ุงู„ู…ู†ูุฐ 7860
    port = int(os.environ.get('PORT', 7860))
    print(f'๐Ÿ“ก Running on port: {port}')
    print(f'๐ŸŒ Local URL: http://localhost:{port}')
    print(f'๐Ÿ” Health check: http://localhost:{port}/')
    print(f'๐Ÿ“ฑ API endpoint: http://localhost:{port}/remove-background')
    print('=' * 60)
    
    app.run(host='0.0.0.0', port=port, debug=False)