Munaf1987 commited on
Commit
ba043eb
·
verified ·
1 Parent(s): c775b2e

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +57 -411
main.py CHANGED
@@ -1,14 +1,4 @@
1
- ###############################################################################
2
- # 1. Environment Setup
3
- ###############################################################################
4
  import os
5
-
6
- os.environ["GRADIO_SERVER_NAME"] = "0.0.0.0"
7
- os.environ["GRADIO_SERVER_PORT"] = "7860"
8
-
9
- ###############################################################################
10
- # 2. Imports
11
- ###############################################################################
12
  import uuid
13
  import base64
14
  import numpy as np
@@ -26,29 +16,35 @@ import gradio as gr
26
  import uvicorn
27
  from datetime import datetime
28
  import huggingface_hub as hf
29
- from huggingface_hub import spaces
30
 
31
- # Import spaces directly without conditional
32
- try:
33
- from spaces import GPU
34
- print("✅ spaces.GPU imported successfully")
35
- USE_SPACES_GPU = True
36
- except ImportError:
37
- print("⚠️ spaces.GPU not available - using CPU fallback")
38
- USE_SPACES_GPU = False
39
 
40
- print("📦 main.py loaded. ZeroGPU debugging enabled.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- ###############################################################################
43
- # 3. Pydantic Models for API Documentation
44
- ###############################################################################
45
  class BackgroundRemovalRequest(BaseModel):
46
- """Request model for background removal"""
47
  image_format: Optional[str] = Field(default="PNG", description="Output image format (PNG, JPEG)")
48
  quality: Optional[int] = Field(default=95, ge=1, le=100, description="Output quality for JPEG (1-100)")
49
-
50
  class BackgroundRemovalResponse(BaseModel):
51
- """Response model for successful background removal"""
52
  status: str = Field(..., description="Status of the operation")
53
  image_code: str = Field(..., description="Base64 encoded image with data URI prefix")
54
  processing_time: float = Field(..., description="Processing time in seconds")
@@ -56,164 +52,24 @@ class BackgroundRemovalResponse(BaseModel):
56
  output_format: str = Field(..., description="Output image format")
57
 
58
  class ErrorResponse(BaseModel):
59
- """Error response model"""
60
  status: str = Field(..., description="Status of the operation")
61
  message: str = Field(..., description="Error message")
62
  error_code: Optional[str] = Field(None, description="Specific error code")
63
 
64
  class HealthResponse(BaseModel):
65
- """Health check response"""
66
  status: str = Field(..., description="Service status")
67
  timestamp: str = Field(..., description="Current timestamp")
68
  version: str = Field(..., description="API version")
69
  gpu_available: bool = Field(..., description="Whether GPU is available")
70
  model_loaded: bool = Field(..., description="Whether the model is loaded")
71
 
72
- ###############################################################################
73
- # 4. App Setup with Enhanced Documentation
74
- ###############################################################################
75
- API_KEY = os.getenv("API_KEY", "demo-key-change-in-production")
76
-
77
- app = FastAPI(
78
- title="🧠 Background Removal API",
79
- description="""
80
- # Background Removal API with Gradio Interface
81
-
82
- This API provides advanced background removal capabilities using ONNX models with optional GPU acceleration.
83
-
84
- ## Features
85
- - 🖼️ High-quality background removal
86
- - ⚡ GPU acceleration (when available)
87
- - 🎨 Multiple output formats (PNG, JPEG)
88
- - 📱 Gradio web interface
89
- - 🔒 API key authentication
90
- - 📊 Real-time processing metrics
91
-
92
- ## Usage
93
- 1. **Web Interface**: Visit the root path `/` for the interactive Gradio interface
94
- 2. **REST API**: Use `/api/remove-background` endpoint for programmatic access
95
- 3. **Documentation**: Visit `/api/docs` for this interactive documentation
96
-
97
- ## Authentication
98
- - API endpoints require an API key provided via form data or header
99
- - Set `API_KEY` environment variable for production use
100
-
101
- ## Gradio Integration
102
- According to [Gradio's documentation](https://www.gradio.app/guides/querying-gradio-apps-with-curl),
103
- the Gradio interface automatically exposes REST API endpoints that can be accessed via cURL:
104
-
105
- ```bash
106
- # Make prediction
107
- curl -X POST {your-url}/call/remove_background_gpu \\
108
- -H "Content-Type: application/json" \\
109
- -d '{"data": [{"path": "https://example.com/image.jpg"}]}'
110
-
111
- # Get result
112
- curl -N {your-url}/call/remove_background_gpu/{event_id}
113
- ```
114
- """,
115
- version="2.0.0",
116
- docs_url="/api/docs",
117
- redoc_url="/api/redoc",
118
- openapi_url="/api/openapi.json",
119
- contact={
120
- "name": "Background Removal API",
121
- "url": "https://github.com/yourusername/background-removal-api",
122
- },
123
- license_info={
124
- "name": "MIT",
125
- "url": "https://opensource.org/licenses/MIT",
126
- },
127
- )
128
-
129
- # Security
130
- security = HTTPBearer()
131
-
132
- app.add_middleware(
133
- CORSMiddleware,
134
- allow_origins=["*"],
135
- allow_credentials=True,
136
- allow_methods=["*"],
137
- allow_headers=["*"]
138
- )
139
-
140
- TMP_FOLDER = "tmp"
141
- os.makedirs(TMP_FOLDER, exist_ok=True)
142
- app.mount("/tmp", StaticFiles(directory=TMP_FOLDER), name="tmp")
143
-
144
- model_path = "BiRefNet-portrait-epoch_150.onnx"
145
- input_size = (1024, 1024)
146
-
147
- ###############################################################################
148
- # 5. Authentication Helper
149
- ###############################################################################
150
- async def verify_api_key(api_key: str = Form(...)):
151
- """Verify API key from form data"""
152
- if api_key != API_KEY:
153
- raise HTTPException(
154
- status_code=401,
155
- detail="Invalid API key",
156
- headers={"WWW-Authenticate": "Bearer"},
157
- )
158
- return api_key
159
-
160
- async def verify_api_key_header(credentials: HTTPAuthorizationCredentials = Depends(security)):
161
- """Verify API key from Authorization header"""
162
- if credentials.credentials != API_KEY:
163
- raise HTTPException(
164
- status_code=401,
165
- detail="Invalid API key",
166
- headers={"WWW-Authenticate": "Bearer"},
167
- )
168
- return credentials.credentials
169
-
170
- ###############################################################################
171
- # 6. Preprocess & Postprocess Utilities
172
- ###############################################################################
173
- def preprocess_image(image):
174
- """Handle both bytes and numpy arrays"""
175
- if isinstance(image, bytes):
176
- nparr = np.frombuffer(image, np.uint8)
177
- img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
178
- else:
179
- img = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
180
-
181
- original_img = img.copy()
182
- original_shape = img.shape[:2]
183
- rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
184
- resized = cv2.resize(rgb, input_size)
185
- normalized = resized.astype(np.float32) / 255.0
186
- normalized = (normalized - 0.5) / 0.5
187
- transposed = np.transpose(normalized, (2, 0, 1))
188
- input_tensor = np.expand_dims(transposed, axis=0).astype(np.float32)
189
- return input_tensor, original_shape, original_img
190
-
191
- def apply_mask(original_img, mask_array, original_shape):
192
- mask = np.squeeze(mask_array)
193
- mask = cv2.resize(mask, (original_shape[1], original_shape[0]))
194
- binary_mask = (mask > 0.5).astype(np.uint8)
195
- masked_img = cv2.bitwise_and(original_img, original_img, mask=binary_mask)
196
- alpha = (binary_mask * 255).astype(np.uint8)
197
- bgra = cv2.cvtColor(masked_img, cv2.COLOR_BGR2BGRA)
198
- bgra[:, :, 3] = alpha
199
- return bgra
200
-
201
- ###############################################################################
202
- # 7. Core Processing Function
203
- ###############################################################################
204
- @hf.hub.git_repo
205
  def process_image_core(image_data, use_gpu=False, output_format="PNG", quality=95):
206
- """Core image processing logic with enhanced options"""
207
- import time
208
- start_time = time.time()
209
-
210
- try:
211
- providers = ["CUDAExecutionProvider", "CPUExecutionProvider"] if use_gpu else ["CPUExecutionProvider"]
212
- session = ort.InferenceSession(model_path, providers=providers)
213
- except ort.OrtSessionException as e:
214
- print(f"⚠️ GPU session failed: {str(e)}")
215
- session = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"])
216
-
217
  input_name = session.get_inputs()[0].name
218
  input_tensor, original_shape, original_img = preprocess_image(image_data)
219
  output = session.run(None, {input_name: input_tensor})
@@ -221,246 +77,46 @@ def process_image_core(image_data, use_gpu=False, output_format="PNG", quality=9
221
  result_img = apply_mask(original_img, mask, original_shape)
222
  result_pil = Image.fromarray(cv2.cvtColor(result_img, cv2.COLOR_BGRA2RGBA))
223
 
224
- processing_time = time.time() - start_time
225
-
226
- return result_pil, processing_time, original_shape
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
- ###############################################################################
229
- # 8. GPU Gradio Function (Direct Decoration)
230
- ###############################################################################
 
 
 
231
  def gradio_processor(image_np):
232
- """Process image for Gradio interface"""
233
  # Convert numpy array to bytes
234
  success, img_encoded = cv2.imencode('.jpg', cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR))
235
  if not success:
236
  raise ValueError("Failed to encode image")
237
  image_bytes = img_encoded.tobytes()
238
 
239
- result, _, _ = process_image_core(image_bytes, use_gpu=USE_SPACES_GPU)
240
- return result
241
-
242
- # Apply GPU decorator directly
243
- if USE_SPACES_GPU:
244
- print("💻 Applying @GPU decorator directly")
245
- gradio_processor = GPU(duration=240)(gradio_processor)
246
- print("✅ @GPU decorator applied")
247
- else:
248
- print("💻 Skipping GPU decorator")
249
-
250
- print("🧠 gradio_processor has GPU metadata:", getattr(gradio_processor, "_spaces_gpu", None))
251
-
252
- ###############################################################################
253
- # 9. FastAPI Endpoints
254
- ###############################################################################
255
-
256
- @app.get("/", response_class=HTMLResponse, include_in_schema=False)
257
- async def root():
258
- """Root endpoint redirects to Gradio interface"""
259
- return """
260
- <!DOCTYPE html>
261
- <html>
262
- <head>
263
- <title>Background Removal Service</title>
264
- <meta http-equiv="refresh" content="0; url=/gradio">
265
- </head>
266
- <body>
267
- <p>Redirecting to Gradio interface...</p>
268
- <p><a href="/gradio">Click here if not redirected automatically</a></p>
269
- </body>
270
- </html>
271
- """
272
-
273
- @app.get("/api/health", response_model=HealthResponse, tags=["Health"])
274
- async def health_check():
275
- """
276
- Health check endpoint to verify service status
277
-
278
- Returns:
279
- HealthResponse: Current service status and information
280
- """
281
- try:
282
- # Test model loading
283
- session = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"])
284
- model_loaded = True
285
- except:
286
- model_loaded = False
287
-
288
- return HealthResponse(
289
- status="healthy",
290
- timestamp=datetime.now().isoformat(),
291
- version="2.0.0",
292
- gpu_available=USE_SPACES_GPU,
293
- model_loaded=model_loaded
294
- )
295
 
296
- @app.post(
297
- "/api/remove-background",
298
- response_model=BackgroundRemovalResponse,
299
- responses={
300
- 401: {"model": ErrorResponse, "description": "Invalid API key"},
301
- 400: {"model": ErrorResponse, "description": "Invalid input"},
302
- 500: {"model": ErrorResponse, "description": "Processing error"}
303
- },
304
- tags=["Background Removal"]
305
- )
306
- async def remove_background_api(
307
- image: UploadFile = File(..., description="Image file to process"),
308
- api_key: str = Depends(verify_api_key),
309
- output_format: str = Form(default="PNG", description="Output format: PNG or JPEG"),
310
- quality: int = Form(default=95, ge=1, le=100, description="JPEG quality (1-100, ignored for PNG)")
311
- ):
312
- """
313
- Remove background from uploaded image
314
-
315
- This endpoint processes an uploaded image and returns the result with background removed.
316
-
317
- **Parameters:**
318
- - **image**: Image file to process (supports common formats: JPEG, PNG, WebP, etc.)
319
- - **api_key**: Authentication key
320
- - **output_format**: Output image format (PNG recommended for transparency)
321
- - **quality**: JPEG compression quality (1-100, only used for JPEG output)
322
-
323
- **Returns:**
324
- - Base64 encoded image with transparent background
325
- - Processing time and metadata
326
-
327
- **Example Usage:**
328
- ```bash
329
- curl -X POST "http://localhost:7860/api/remove-background" \\
330
- -F "api_key=demo-key-change-in-production" \\
331
- -F "image=@your-image.jpg" \\
332
- -F "output_format=PNG"
333
- ```
334
- """
335
- try:
336
- # Validate image file
337
- if not image.content_type.startswith('image/'):
338
- raise HTTPException(
339
- status_code=400,
340
- detail=f"Invalid file type: {image.content_type}. Please upload an image file."
341
- )
342
-
343
- # Validate output format
344
- if output_format.upper() not in ["PNG", "JPEG", "JPG"]:
345
- raise HTTPException(
346
- status_code=400,
347
- detail="Invalid output format. Use 'PNG' or 'JPEG'."
348
- )
349
-
350
- # Process image
351
- image_data = await image.read()
352
- result_img, processing_time, original_shape = process_image_core(
353
- image_data,
354
- use_gpu=False, # CPU for API endpoint
355
- output_format=output_format.upper(),
356
- quality=quality
357
- )
358
-
359
- # Save result
360
- result_filename = f"{uuid.uuid4()}.{output_format.lower()}"
361
- output_path = f"{TMP_FOLDER}/{result_filename}"
362
-
363
- if output_format.upper() == "PNG":
364
- result_img.save(output_path, "PNG")
365
- else:
366
- # Convert RGBA to RGB for JPEG
367
- if result_img.mode == 'RGBA':
368
- rgb_img = Image.new('RGB', result_img.size, (255, 255, 255))
369
- rgb_img.paste(result_img, mask=result_img.split()[-1])
370
- rgb_img.save(output_path, "JPEG", quality=quality)
371
- else:
372
- result_img.save(output_path, "JPEG", quality=quality)
373
-
374
- # Encode to base64
375
- with open(output_path, "rb") as img_file:
376
- base64_image = base64.b64encode(img_file.read()).decode("utf-8")
377
-
378
- # Clean up temporary file
379
- os.remove(output_path)
380
-
381
- return BackgroundRemovalResponse(
382
- status="success",
383
- image_code=f"data:image/{output_format.lower()};base64,{base64_image}",
384
- processing_time=round(processing_time, 3),
385
- original_size=[original_shape[1], original_shape[0]], # width, height
386
- output_format=output_format.upper()
387
- )
388
-
389
- except HTTPException:
390
- raise
391
- except Exception as e:
392
- raise HTTPException(
393
- status_code=500,
394
- detail=f"Processing error: {str(e)}"
395
- )
396
-
397
- @app.post(
398
- "/api/remove-background-file",
399
- response_class=FileResponse,
400
- tags=["Background Removal"]
401
- )
402
- async def remove_background_file(
403
- image: UploadFile = File(..., description="Image file to process"),
404
- api_key: str = Depends(verify_api_key),
405
- output_format: str = Form(default="PNG", description="Output format: PNG or JPEG")
406
- ):
407
- """
408
- Remove background and return image file directly
409
-
410
- Similar to `/remove-background` but returns the processed image file directly
411
- instead of base64 encoded data.
412
- """
413
- try:
414
- if not image.content_type.startswith('image/'):
415
- raise HTTPException(status_code=400, detail="Invalid file type")
416
-
417
- image_data = await image.read()
418
- result_img, _, _ = process_image_core(image_data, use_gpu=False)
419
-
420
- result_filename = f"processed_{uuid.uuid4()}.{output_format.lower()}"
421
- output_path = f"{TMP_FOLDER}/{result_filename}"
422
-
423
- if output_format.upper() == "PNG":
424
- result_img.save(output_path, "PNG")
425
- else:
426
- if result_img.mode == 'RGBA':
427
- rgb_img = Image.new('RGB', result_img.size, (255, 255, 255))
428
- rgb_img.paste(result_img, mask=result_img.split()[-1])
429
- rgb_img.save(output_path, "JPEG", quality=95)
430
- else:
431
- result_img.save(output_path, "JPEG", quality=95)
432
-
433
- return FileResponse(
434
- output_path,
435
- media_type=f"image/{output_format.lower()}",
436
- filename=result_filename,
437
- background=lambda: os.remove(output_path) # Clean up after response
438
- )
439
-
440
- except Exception as e:
441
- raise HTTPException(status_code=500, detail=str(e))
442
-
443
- ###############################################################################
444
- # 10. Gradio Interface
445
- ###############################################################################
446
  interface = gr.Interface(
447
  fn=gradio_processor,
448
  inputs=gr.Image(type="numpy", label="Upload Image"),
449
  outputs=gr.Image(type="pil", label="Processed Image"),
450
- title="🧠 Background Removal Service",
451
- description="""
452
- ## Upload an image to remove its background
453
-
454
- - **GPU Acceleration**: Uses ZeroGPU when available
455
- - **High Quality**: ONNX model for precise background removal
456
- - **Fast Processing**: Optimized for real-time use
457
-
458
- ### API Access
459
- This interface is also available via REST API:
460
- - **Documentation**: [/api/docs](/api/docs)
461
- - **Health Check**: [/api/health](/api/health)
462
- - **Background Removal**: POST `/api/remove-background`
463
- """,
464
  examples=[
465
  # Add example images if you have them
466
  ],
@@ -468,21 +124,11 @@ interface = gr.Interface(
468
  allow_flagging="never"
469
  )
470
 
471
- interface.api_name = "remove_background_gpu"
472
-
473
- ###############################################################################
474
- # 11. Mount Gradio App
475
- ###############################################################################
476
  app = gr.mount_gradio_app(app, interface, path="/gradio", ssr_mode=False)
477
 
478
- ###############################################################################
479
- # 12. Run Local Dev Server
480
- ###############################################################################
481
  if __name__ == "__main__":
482
- print("🚀 Starting Background Removal Service")
483
- print(f"📖 API Documentation: http://localhost:7860/api/docs")
484
- print(f"🎨 Gradio Interface: http://localhost:7860/gradio")
485
- print(f"❤️ Health Check: http://localhost:7860/api/health")
486
  uvicorn.run(
487
  "main:app",
488
  host="0.0.0.0",
 
 
 
 
1
  import os
 
 
 
 
 
 
 
2
  import uuid
3
  import base64
4
  import numpy as np
 
16
  import uvicorn
17
  from datetime import datetime
18
  import huggingface_hub as hf
 
19
 
20
+ # Set up environment variables
21
+ os.environ["GRADIO_SERVER_NAME"] = "0.0.0.0"
22
+ os.environ["GRADIO_SERVER_PORT"] = "7860"
 
 
 
 
 
23
 
24
+ # Define the FastAPI app
25
+ app = FastAPI(
26
+ title="Background Removal API",
27
+ description="Background removal API with Gradio interface",
28
+ version="2.0.0",
29
+ docs_url="/api/docs",
30
+ redoc_url="/api/redoc",
31
+ openapi_url="/api/openapi.json",
32
+ contact={
33
+ "name": "Background Removal API",
34
+ "url": "https://github.com/yourusername/background-removal-api",
35
+ },
36
+ license_info={
37
+ "name": "MIT",
38
+ "url": "https://opensource.org/licenses/MIT",
39
+ },
40
+ )
41
 
42
+ # Define Pydantic models for API documentation
 
 
43
  class BackgroundRemovalRequest(BaseModel):
 
44
  image_format: Optional[str] = Field(default="PNG", description="Output image format (PNG, JPEG)")
45
  quality: Optional[int] = Field(default=95, ge=1, le=100, description="Output quality for JPEG (1-100)")
46
+
47
  class BackgroundRemovalResponse(BaseModel):
 
48
  status: str = Field(..., description="Status of the operation")
49
  image_code: str = Field(..., description="Base64 encoded image with data URI prefix")
50
  processing_time: float = Field(..., description="Processing time in seconds")
 
52
  output_format: str = Field(..., description="Output image format")
53
 
54
  class ErrorResponse(BaseModel):
 
55
  status: str = Field(..., description="Status of the operation")
56
  message: str = Field(..., description="Error message")
57
  error_code: Optional[str] = Field(None, description="Specific error code")
58
 
59
  class HealthResponse(BaseModel):
 
60
  status: str = Field(..., description="Service status")
61
  timestamp: str = Field(..., description="Current timestamp")
62
  version: str = Field(..., description="API version")
63
  gpu_available: bool = Field(..., description="Whether GPU is available")
64
  model_loaded: bool = Field(..., description="Whether the model is loaded")
65
 
66
+ # Define the core processing function
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  def process_image_core(image_data, use_gpu=False, output_format="PNG", quality=95):
68
+ # Load the model and preprocess the image
69
+ model_path = "BiRefNet-portrait-epoch_150.onnx"
70
+ input_size = (1024, 1024)
71
+ providers = ["CUDAExecutionProvider", "CPUExecutionProvider"] if use_gpu else ["CPUExecutionProvider"]
72
+ session = ort.InferenceSession(model_path, providers=providers)
 
 
 
 
 
 
73
  input_name = session.get_inputs()[0].name
74
  input_tensor, original_shape, original_img = preprocess_image(image_data)
75
  output = session.run(None, {input_name: input_tensor})
 
77
  result_img = apply_mask(original_img, mask, original_shape)
78
  result_pil = Image.fromarray(cv2.cvtColor(result_img, cv2.COLOR_BGRA2RGBA))
79
 
80
+ # Save the result
81
+ result_filename = f"{uuid.uuid4()}.{output_format.lower()}"
82
+ output_path = f"tmp/{result_filename}"
83
+ if output_format.upper() == "PNG":
84
+ result_pil.save(output_path, "PNG")
85
+ else:
86
+ if result_pil.mode == 'RGBA':
87
+ rgb_img = Image.new('RGB', result_pil.size, (255, 255, 255))
88
+ rgb_img.paste(result_pil, mask=result_pil.split()[-1])
89
+ rgb_img.save(output_path, "JPEG", quality=quality)
90
+ else:
91
+ result_pil.save(output_path, "JPEG", quality=quality)
92
+
93
+ # Encode the result to base64
94
+ with open(output_path, "rb") as img_file:
95
+ base64_image = base64.b64encode(img_file.read()).decode("utf-8")
96
 
97
+ # Clean up temporary file
98
+ os.remove(output_path)
99
+
100
+ return base64_image
101
+
102
+ # Define the Gradio interface
103
  def gradio_processor(image_np):
 
104
  # Convert numpy array to bytes
105
  success, img_encoded = cv2.imencode('.jpg', cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR))
106
  if not success:
107
  raise ValueError("Failed to encode image")
108
  image_bytes = img_encoded.tobytes()
109
 
110
+ # Process the image
111
+ result_img = process_image_core(image_bytes, use_gpu=False, output_format="PNG")
112
+ return result_img
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  interface = gr.Interface(
115
  fn=gradio_processor,
116
  inputs=gr.Image(type="numpy", label="Upload Image"),
117
  outputs=gr.Image(type="pil", label="Processed Image"),
118
+ title="Background Removal Service",
119
+ description="Upload an image to remove its background",
 
 
 
 
 
 
 
 
 
 
 
 
120
  examples=[
121
  # Add example images if you have them
122
  ],
 
124
  allow_flagging="never"
125
  )
126
 
127
+ # Mount the Gradio app
 
 
 
 
128
  app = gr.mount_gradio_app(app, interface, path="/gradio", ssr_mode=False)
129
 
130
+ # Run the local dev server
 
 
131
  if __name__ == "__main__":
 
 
 
 
132
  uvicorn.run(
133
  "main:app",
134
  host="0.0.0.0",