MogensR commited on
Commit
6e16e71
·
1 Parent(s): 7f55866

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +86 -565
Dockerfile CHANGED
@@ -1,579 +1,100 @@
1
- #!/usr/bin/env python3
2
- """
3
- High-Quality Video Background Replacement
4
- Upload video → Choose professional background → Replace with cinema quality
5
- """
6
 
7
- import os
8
- import sys
9
- import tempfile
10
- import cv2
11
- import numpy as np
12
- from pathlib import Path
13
- import gradio as gr
14
- import torch
15
- import requests
16
- from PIL import Image, ImageDraw
17
- import json
18
 
19
- # Suppress warnings and optimize for quality
20
- import warnings
21
- warnings.filterwarnings("ignore")
22
- os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'max_split_size_mb:1024'
23
- os.environ['CUDA_LAUNCH_BLOCKING'] = '0'
24
 
25
- # Global variables for models
26
- sam2_predictor = None
27
- matanyone_model = None
28
- models_loaded = False
29
 
30
- # Professional background templates
31
- PROFESSIONAL_BACKGROUNDS = {
32
- "office_modern": {
33
- "name": "Modern Office",
34
- "type": "gradient",
35
- "colors": ["#f8f9fa", "#e9ecef", "#dee2e6"],
36
- "direction": "diagonal"
37
- },
38
- "office_executive": {
39
- "name": "Executive Office",
40
- "type": "gradient",
41
- "colors": ["#2c3e50", "#34495e", "#5d6d7e"],
42
- "direction": "vertical"
43
- },
44
- "studio_blue": {
45
- "name": "Professional Blue",
46
- "type": "gradient",
47
- "colors": ["#1e3c72", "#2a5298", "#3498db"],
48
- "direction": "radial"
49
- },
50
- "studio_green": {
51
- "name": "Broadcast Green",
52
- "type": "color",
53
- "colors": ["#00b894"],
54
- "chroma_key": True
55
- },
56
- "conference": {
57
- "name": "Conference Room",
58
- "type": "gradient",
59
- "colors": ["#74b9ff", "#0984e3", "#6c5ce7"],
60
- "direction": "horizontal"
61
- },
62
- "minimalist": {
63
- "name": "Minimalist White",
64
- "type": "gradient",
65
- "colors": ["#ffffff", "#f1f2f6", "#ddd"],
66
- "direction": "soft_radial"
67
- },
68
- "warm_gradient": {
69
- "name": "Warm Sunset",
70
- "type": "gradient",
71
- "colors": ["#ff7675", "#fd79a8", "#fdcb6e"],
72
- "direction": "diagonal"
73
- },
74
- "cool_gradient": {
75
- "name": "Cool Ocean",
76
- "type": "gradient",
77
- "colors": ["#74b9ff", "#0984e3", "#00cec9"],
78
- "direction": "vertical"
79
- },
80
- "corporate": {
81
- "name": "Corporate Navy",
82
- "type": "gradient",
83
- "colors": ["#2d3436", "#636e72", "#74b9ff"],
84
- "direction": "radial"
85
- },
86
- "creative": {
87
- "name": "Creative Purple",
88
- "type": "gradient",
89
- "colors": ["#6c5ce7", "#a29bfe", "#fd79a8"],
90
- "direction": "diagonal"
91
- }
92
- }
93
 
94
- def download_and_setup_models():
95
- """Download and setup SAM2 and MatAnyone models with quality optimizations"""
96
- global sam2_predictor, matanyone_model, models_loaded
97
-
98
- if models_loaded:
99
- return "✅ High-quality models already loaded"
100
-
101
- try:
102
- # Download SAM2 if needed
103
- sam2_checkpoint = "/tmp/sam2_hiera_large.pt"
104
- if not os.path.exists(sam2_checkpoint):
105
- print("📥 Downloading SAM2 large model for maximum quality...")
106
- url = "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_large.pt"
107
- response = requests.get(url, stream=True)
108
- total_size = int(response.headers.get('content-length', 0))
109
- downloaded = 0
110
-
111
- with open(sam2_checkpoint, 'wb') as f:
112
- for chunk in response.iter_content(chunk_size=8192):
113
- f.write(chunk)
114
- downloaded += len(chunk)
115
- if total_size > 0:
116
- percent = (downloaded / total_size) * 100
117
- print(f"Download progress: {percent:.1f}%")
118
-
119
- # Setup SAM2 with quality settings
120
- sys.path.append('/tmp/segment-anything-2')
121
- from sam2.build_sam import build_sam2
122
- from sam2.sam2_image_predictor import SAM2ImagePredictor
123
-
124
- device = "cuda" if torch.cuda.is_available() else "cpu"
125
- print(f"🚀 Loading SAM2 on {device} for maximum quality...")
126
-
127
- sam2_model = build_sam2("sam2_hiera_large.yaml", sam2_checkpoint, device=device)
128
- sam2_predictor = SAM2ImagePredictor(sam2_model)
129
-
130
- # Setup MatAnyone with quality optimizations
131
- sys.path.append('/tmp/MatAnyone')
132
- from inference import MatAnyoneInference
133
-
134
- print("🎨 Loading MatAnyone for cinema-quality matting...")
135
- matanyone_model = MatAnyoneInference()
136
-
137
- models_loaded = True
138
- gpu_info = f" (GPU: {torch.cuda.get_device_name(0)})" if torch.cuda.is_available() else " (CPU)"
139
- return f"✅ High-quality models loaded successfully!{gpu_info}"
140
-
141
- except Exception as e:
142
- return f"❌ Error loading models: {e}"
143
 
144
- def segment_person_hq(image):
145
- """High-quality person segmentation using SAM2"""
146
- # Set image with quality optimizations
147
- sam2_predictor.set_image(image)
148
-
149
- h, w = image.shape[:2]
150
-
151
- # Use multiple points for better segmentation
152
- points = np.array([
153
- [w//2, h//2], # Center
154
- [w//2, h//3], # Upper body
155
- [w//2, 2*h//3], # Lower body
156
- [w//3, h//2], # Left side
157
- [2*w//3, h//2], # Right side
158
- ])
159
- labels = np.array([1, 1, 1, 1, 1]) # All positive points
160
-
161
- # Predict with high quality settings
162
- masks, scores, _ = sam2_predictor.predict(
163
- point_coords=points,
164
- point_labels=labels,
165
- multimask_output=True
166
- )
167
-
168
- # Select best mask and apply smoothing
169
- best_mask = masks[np.argmax(scores)]
170
-
171
- # Smooth mask edges for better quality
172
- kernel = np.ones((3,3), np.uint8)
173
- best_mask = cv2.morphologyEx(best_mask.astype(np.uint8), cv2.MORPH_CLOSE, kernel)
174
- best_mask = cv2.GaussianBlur(best_mask.astype(np.float32), (3,3), 1.0)
175
-
176
- return (best_mask * 255).astype(np.uint8)
177
 
178
- def refine_mask_hq(image, mask):
179
- """Cinema-quality mask refinement using MatAnyone"""
180
- # Apply edge-preserving filtering before MatAnyone
181
- image_filtered = cv2.bilateralFilter(image, 9, 75, 75)
182
-
183
- # Use MatAnyone for professional matting
184
- refined_mask = matanyone_model.infer(image_filtered, mask)
185
-
186
- # Post-process for smooth edges
187
- refined_mask = cv2.medianBlur(refined_mask, 3)
188
-
189
- return refined_mask
190
 
191
- def create_professional_background(bg_config, width, height):
192
- """Create professional background based on configuration"""
193
- if bg_config["type"] == "color":
194
- # Solid color
195
- color_hex = bg_config["colors"][0].lstrip('#')
196
- color_rgb = tuple(int(color_hex[i:i+2], 16) for i in (0, 2, 4))
197
- color_bgr = color_rgb[::-1] # Convert to BGR
198
- background = np.full((height, width, 3), color_bgr, dtype=np.uint8)
199
-
200
- elif bg_config["type"] == "gradient":
201
- background = create_gradient_background(bg_config, width, height)
202
-
203
- return background
204
 
205
- def create_gradient_background(bg_config, width, height):
206
- """Create high-quality gradient backgrounds"""
207
- colors = bg_config["colors"]
208
- direction = bg_config.get("direction", "vertical")
209
-
210
- # Convert hex colors to RGB
211
- rgb_colors = []
212
- for color_hex in colors:
213
- color_hex = color_hex.lstrip('#')
214
- rgb = tuple(int(color_hex[i:i+2], 16) for i in (0, 2, 4))
215
- rgb_colors.append(rgb)
216
-
217
- # Create PIL image for high-quality gradients
218
- pil_img = Image.new('RGB', (width, height))
219
- draw = ImageDraw.Draw(pil_img)
220
-
221
- if direction == "vertical":
222
- # Vertical gradient
223
- for y in range(height):
224
- # Interpolate between colors
225
- progress = y / height
226
- if len(rgb_colors) == 2:
227
- r = int(rgb_colors[0][0] + (rgb_colors[1][0] - rgb_colors[0][0]) * progress)
228
- g = int(rgb_colors[0][1] + (rgb_colors[1][1] - rgb_colors[0][1]) * progress)
229
- b = int(rgb_colors[0][2] + (rgb_colors[1][2] - rgb_colors[0][2]) * progress)
230
- else:
231
- # Multi-color gradient
232
- segment = progress * (len(rgb_colors) - 1)
233
- idx = int(segment)
234
- local_progress = segment - idx
235
-
236
- if idx >= len(rgb_colors) - 1:
237
- r, g, b = rgb_colors[-1]
238
- else:
239
- c1, c2 = rgb_colors[idx], rgb_colors[idx + 1]
240
- r = int(c1[0] + (c2[0] - c1[0]) * local_progress)
241
- g = int(c1[1] + (c2[1] - c1[1]) * local_progress)
242
- b = int(c1[2] + (c2[2] - c1[2]) * local_progress)
243
-
244
- draw.line([(0, y), (width, y)], fill=(r, g, b))
245
-
246
- elif direction == "horizontal":
247
- # Horizontal gradient
248
- for x in range(width):
249
- progress = x / width
250
- if len(rgb_colors) == 2:
251
- r = int(rgb_colors[0][0] + (rgb_colors[1][0] - rgb_colors[0][0]) * progress)
252
- g = int(rgb_colors[0][1] + (rgb_colors[1][1] - rgb_colors[0][1]) * progress)
253
- b = int(rgb_colors[0][2] + (rgb_colors[1][2] - rgb_colors[0][2]) * progress)
254
- else:
255
- segment = progress * (len(rgb_colors) - 1)
256
- idx = int(segment)
257
- local_progress = segment - idx
258
-
259
- if idx >= len(rgb_colors) - 1:
260
- r, g, b = rgb_colors[-1]
261
- else:
262
- c1, c2 = rgb_colors[idx], rgb_colors[idx + 1]
263
- r = int(c1[0] + (c2[0] - c1[0]) * local_progress)
264
- g = int(c1[1] + (c2[1] - c1[1]) * local_progress)
265
- b = int(c1[2] + (c2[2] - c1[2]) * local_progress)
266
-
267
- draw.line([(x, 0), (x, height)], fill=(r, g, b))
268
-
269
- elif direction == "diagonal":
270
- # Diagonal gradient
271
- for y in range(height):
272
- for x in range(width):
273
- progress = (x + y) / (width + height)
274
- progress = min(1.0, progress)
275
-
276
- if len(rgb_colors) == 2:
277
- r = int(rgb_colors[0][0] + (rgb_colors[1][0] - rgb_colors[0][0]) * progress)
278
- g = int(rgb_colors[0][1] + (rgb_colors[1][1] - rgb_colors[0][1]) * progress)
279
- b = int(rgb_colors[0][2] + (rgb_colors[1][2] - rgb_colors[0][2]) * progress)
280
- else:
281
- segment = progress * (len(rgb_colors) - 1)
282
- idx = int(segment)
283
- local_progress = segment - idx
284
-
285
- if idx >= len(rgb_colors) - 1:
286
- r, g, b = rgb_colors[-1]
287
- else:
288
- c1, c2 = rgb_colors[idx], rgb_colors[idx + 1]
289
- r = int(c1[0] + (c2[0] - c1[0]) * local_progress)
290
- g = int(c1[1] + (c2[1] - c1[1]) * local_progress)
291
- b = int(c1[2] + (c2[2] - c1[2]) * local_progress)
292
-
293
- pil_img.putpixel((x, y), (r, g, b))
294
-
295
- elif direction in ["radial", "soft_radial"]:
296
- # Radial gradient
297
- center_x, center_y = width // 2, height // 2
298
- max_distance = np.sqrt(center_x**2 + center_y**2)
299
-
300
- for y in range(height):
301
- for x in range(width):
302
- distance = np.sqrt((x - center_x)**2 + (y - center_y)**2)
303
- progress = distance / max_distance
304
- progress = min(1.0, progress)
305
-
306
- if direction == "soft_radial":
307
- progress = progress**0.7 # Softer falloff
308
-
309
- if len(rgb_colors) == 2:
310
- r = int(rgb_colors[0][0] + (rgb_colors[1][0] - rgb_colors[0][0]) * progress)
311
- g = int(rgb_colors[0][1] + (rgb_colors[1][1] - rgb_colors[0][1]) * progress)
312
- b = int(rgb_colors[0][2] + (rgb_colors[1][2] - rgb_colors[0][2]) * progress)
313
- else:
314
- segment = progress * (len(rgb_colors) - 1)
315
- idx = int(segment)
316
- local_progress = segment - idx
317
-
318
- if idx >= len(rgb_colors) - 1:
319
- r, g, b = rgb_colors[-1]
320
- else:
321
- c1, c2 = rgb_colors[idx], rgb_colors[idx + 1]
322
- r = int(c1[0] + (c2[0] - c1[0]) * local_progress)
323
- g = int(c1[1] + (c2[1] - c1[1]) * local_progress)
324
- b = int(c1[2] + (c2[2] - c1[2]) * local_progress)
325
-
326
- pil_img.putpixel((x, y), (r, g, b))
327
-
328
- # Convert PIL to OpenCV format
329
- background = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
330
- return background
331
 
332
- def replace_background_hq(frame, mask, background):
333
- """High-quality background replacement with edge feathering"""
334
- # Resize background to match frame exactly
335
- background = cv2.resize(background, (frame.shape[1], frame.shape[0]), interpolation=cv2.INTER_LANCZOS4)
336
-
337
- # Apply edge feathering for smooth transitions
338
- mask_float = mask.astype(np.float32) / 255.0
339
-
340
- # Create feathered mask
341
- feather_radius = 3
342
- mask_feathered = cv2.GaussianBlur(mask_float, (feather_radius*2+1, feather_radius*2+1), feather_radius/3)
343
-
344
- # Expand mask to 3 channels
345
- mask_3channel = np.stack([mask_feathered] * 3, axis=2)
346
-
347
- # High-quality compositing with gamma correction
348
- frame_linear = np.power(frame.astype(np.float32) / 255.0, 2.2)
349
- background_linear = np.power(background.astype(np.float32) / 255.0, 2.2)
350
-
351
- # Composite in linear space
352
- result_linear = frame_linear * mask_3channel + background_linear * (1 - mask_3channel)
353
-
354
- # Convert back to sRGB
355
- result = np.power(result_linear, 1/2.2) * 255.0
356
- result = np.clip(result, 0, 255).astype(np.uint8)
357
-
358
- return result
359
 
360
- def process_video_hq(video_path, background_choice, custom_background_path, progress=gr.Progress()):
361
- """High-quality video processing with professional backgrounds"""
362
- if not models_loaded:
363
- return None, "❌ Models not loaded. Click 'Load Models' first."
364
-
365
- try:
366
- progress(0, desc="🎬 Initializing high-quality processing...")
367
-
368
- # Read video with quality settings
369
- cap = cv2.VideoCapture(video_path)
370
- fps = cap.get(cv2.CAP_PROP_FPS)
371
- total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
372
- frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
373
- frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
374
-
375
- # Prepare background
376
- if background_choice == "custom" and custom_background_path:
377
- # Use uploaded image
378
- background = cv2.imread(custom_background_path)
379
- if background is None:
380
- return None, "❌ Could not read custom background image"
381
- background_name = "Custom Image"
382
- else:
383
- # Use professional background
384
- if background_choice in PROFESSIONAL_BACKGROUNDS:
385
- bg_config = PROFESSIONAL_BACKGROUNDS[background_choice]
386
- background = create_professional_background(bg_config, frame_width, frame_height)
387
- background_name = bg_config["name"]
388
- else:
389
- return None, "❌ Invalid background selection"
390
-
391
- # Setup high-quality output video
392
- output_path = "/tmp/processed_video_hq.mp4"
393
- # Use high-quality codec
394
- fourcc = cv2.VideoWriter_fourcc(*'mp4v')
395
- out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
396
-
397
- progress(0.1, desc=f"🎨 Using {background_name} background...")
398
-
399
- # Process each frame with quality optimizations
400
- frame_count = 0
401
- while True:
402
- ret, frame = cap.read()
403
- if not ret:
404
- break
405
-
406
- # Update progress
407
- progress_pct = 0.1 + (frame_count / total_frames) * 0.8
408
- progress(progress_pct, desc=f"✨ Processing frame {frame_count + 1}/{total_frames} (High Quality)")
409
-
410
- # High-quality person segmentation
411
- mask = segment_person_hq(frame)
412
-
413
- # Cinema-quality mask refinement
414
- refined_mask = refine_mask_hq(frame, mask)
415
-
416
- # High-quality background replacement
417
- result_frame = replace_background_hq(frame, refined_mask, background)
418
-
419
- # Write frame
420
- out.write(result_frame)
421
- frame_count += 1
422
-
423
- cap.release()
424
- out.release()
425
-
426
- progress(0.9, desc="🎵 Adding high-quality audio...")
427
-
428
- # Add audio back with high quality settings
429
- final_output = "/tmp/final_output_hq.mp4"
430
- audio_cmd = f'ffmpeg -y -i {output_path} -i {video_path} -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k -map 0:v:0 -map 1:a:0? -shortest {final_output}'
431
- os.system(audio_cmd)
432
-
433
- # Save to MyAvatar/My Videos
434
- myavatar_path = "/tmp/MyAvatar/My_Videos/"
435
- os.makedirs(myavatar_path, exist_ok=True)
436
-
437
- import shutil
438
- import time
439
- saved_filename = f"hq_background_replaced_{int(time.time())}.mp4"
440
- saved_path = os.path.join(myavatar_path, saved_filename)
441
- shutil.copy2(final_output, saved_path)
442
-
443
- progress(1.0, desc="✅ High-quality processing complete!")
444
-
445
- return final_output, f"✅ High-Quality Success!\n🎬 Background: {background_name}\n📁 Saved: MyAvatar/My Videos/{saved_filename}\n🎯 Quality: Cinema-grade with SAM2 + MatAnyone"
446
-
447
- except Exception as e:
448
- return None, f"❌ Error: {str(e)}"
449
 
450
- def get_model_status():
451
- """Get current model loading status"""
452
- if models_loaded:
453
- gpu_info = f" (GPU: {torch.cuda.get_device_name(0)})" if torch.cuda.is_available() else " (CPU)"
454
- return f"✅ High-quality models loaded{gpu_info}"
455
- else:
456
- return "⏳ Models not loaded. Click 'Load Models' for cinema-quality processing."
457
 
458
- def create_interface():
459
- """Create enhanced Gradio interface with professional backgrounds"""
460
-
461
- # Create background choices
462
- bg_choices = ["custom"] + list(PROFESSIONAL_BACKGROUNDS.keys())
463
- bg_labels = ["📷 Custom Image"] + [f"🎨 {config['name']}" for config in PROFESSIONAL_BACKGROUNDS.values()]
464
- bg_dropdown_choices = list(zip(bg_labels, bg_choices))
465
-
466
- with gr.Blocks(title="High-Quality Video Background Replacement", theme=gr.themes.Soft()) as demo:
467
- gr.Markdown("# 🎬 Cinema-Quality Video Background Replacement")
468
- gr.Markdown("**Professional background replacement using SAM2 + MatAnyone AI models**")
469
-
470
- with gr.Row():
471
- with gr.Column(scale=1):
472
- gr.Markdown("### 📥 Input")
473
- video_input = gr.Video(label="🎥 Upload Video (MP4, MOV, AVI)")
474
-
475
- gr.Markdown("### 🎨 Background Selection")
476
- background_choice = gr.Dropdown(
477
- choices=bg_dropdown_choices,
478
- value="office_modern",
479
- label="Choose Background Type",
480
- info="Select professional background or upload custom image"
481
- )
482
-
483
- custom_background = gr.Image(
484
- label="📷 Custom Background Image",
485
- type="filepath",
486
- visible=False,
487
- info="Upload your own background image (will be resized to match video)"
488
- )
489
-
490
- # Show/hide custom background based on selection
491
- def toggle_custom_bg(choice):
492
- return gr.update(visible=(choice == "custom"))
493
-
494
- background_choice.change(
495
- fn=toggle_custom_bg,
496
- inputs=background_choice,
497
- outputs=custom_background
498
- )
499
-
500
- with gr.Row():
501
- load_models_btn = gr.Button("🚀 Load High-Quality Models", variant="secondary", size="lg")
502
- process_btn = gr.Button("✨ Process with Cinema Quality", variant="primary", size="lg")
503
-
504
- status_text = gr.Textbox(
505
- label="🔧 System Status",
506
- value=get_model_status(),
507
- interactive=False,
508
- lines=2
509
- )
510
-
511
- with gr.Column(scale=1):
512
- gr.Markdown("### 📤 High-Quality Output")
513
- video_output = gr.Video(label="🎬 Processed Video", height=400)
514
- result_text = gr.Textbox(
515
- label="📊 Processing Results",
516
- interactive=False,
517
- lines=4
518
- )
519
-
520
- gr.Markdown("### 🎨 Professional Backgrounds Available")
521
- bg_preview_html = "<div style='display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; padding: 10px;'>"
522
- for key, config in PROFESSIONAL_BACKGROUNDS.items():
523
- colors_display = " → ".join(config["colors"][:2])
524
- bg_preview_html += f"""
525
- <div style='padding: 8px; border: 1px solid #ddd; border-radius: 8px; text-align: center; background: linear-gradient(45deg, {config["colors"][0]}, {config["colors"][-1]});'>
526
- <strong style='color: white; text-shadow: 1px 1px 2px rgba(0,0,0,0.7);'>{config["name"]}</strong>
527
- </div>
528
- """
529
- bg_preview_html += "</div>"
530
- gr.HTML(bg_preview_html)
531
-
532
- # Event handlers
533
- load_models_btn.click(
534
- fn=download_and_setup_models,
535
- outputs=status_text
536
- )
537
-
538
- process_btn.click(
539
- fn=process_video_hq,
540
- inputs=[video_input, background_choice, custom_background],
541
- outputs=[video_output, result_text]
542
- )
543
-
544
- # Info section
545
- with gr.Accordion("ℹ️ Quality & Features", open=False):
546
- gr.Markdown("""
547
- ### 🏆 Cinema-Quality Features:
548
- - **🤖 SAM2 Large Model**: Meta's most advanced segmentation
549
- - **🎨 MatAnyone**: CVPR 2025 professional matting
550
- - **✨ Edge Feathering**: Smooth, natural transitions
551
- - **🎬 Gamma Correction**: Professional color compositing
552
- - **🎵 High-Quality Audio**: 192kbps AAC preservation
553
- - **📺 H.264 Codec**: CRF 18 for broadcast quality
554
-
555
- ### 🎨 Professional Backgrounds:
556
- - **Office Environments**: Modern, Executive styles
557
- - **Studio Backdrops**: Broadcast-quality gradients
558
- - **Creative Themes**: Artistic color combinations
559
- - **Custom Images**: Upload your own backgrounds
560
-
561
- ### 💾 Output:
562
- - Saved to: **MyAvatar/My Videos/**
563
- - Format: **MP4 (H.264)**
564
- - Quality: **Cinema-grade**
565
- """)
566
-
567
- return demo
568
 
569
- if __name__ == "__main__":
570
- print("🎬 Starting Cinema-Quality Video Background Replacement...")
571
-
572
- # Create and launch interface
573
- demo = create_interface()
574
- demo.launch(
575
- server_name="0.0.0.0",
576
- server_port=7860,
577
- share=True,
578
- show_error=True
579
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.10 base image optimized for Hugging Face Spaces
2
+ FROM python:3.10-slim
 
 
 
3
 
4
+ # Set environment variables to prevent threading issues
5
+ ENV OMP_NUM_THREADS=1
6
+ ENV MKL_NUM_THREADS=1
7
+ ENV OPENBLAS_NUM_THREADS=1
8
+ ENV NUMEXPR_NUM_THREADS=1
9
+ ENV PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:1024
10
+ ENV CUDA_LAUNCH_BLOCKING=0
 
 
 
 
11
 
12
+ # Prevent Python from writing pyc files and buffering stdout/stderr
13
+ ENV PYTHONDONTWRITEBYTECODE=1
14
+ ENV PYTHONUNBUFFERED=1
 
 
15
 
16
+ # Set working directory
17
+ WORKDIR /app
 
 
18
 
19
+ # Install system dependencies required for video processing and ML libraries
20
+ RUN apt-get update && apt-get install -y \
21
+ git \
22
+ wget \
23
+ curl \
24
+ ffmpeg \
25
+ libsm6 \
26
+ libxext6 \
27
+ libxrender-dev \
28
+ libglib2.0-0 \
29
+ libgomp1 \
30
+ libgl1-mesa-glx \
31
+ libglib2.0-0 \
32
+ libfontconfig1 \
33
+ libxrender1 \
34
+ libxtst6 \
35
+ && rm -rf /var/lib/apt/lists/* \
36
+ && apt-get clean
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ # Upgrade pip and install core Python packages
39
+ RUN pip install --upgrade pip setuptools wheel
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ # Copy requirements first for better Docker layer caching
42
+ COPY requirements.txt .
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ # Install Python dependencies
45
+ RUN pip install --no-cache-dir -r requirements.txt
 
 
 
 
 
 
 
 
 
 
46
 
47
+ # Install PyTorch (Hugging Face Spaces handles CUDA automatically)
48
+ RUN pip install torch torchvision torchaudio
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ # Install computer vision and ML dependencies
51
+ RUN pip install opencv-python-headless \
52
+ transformers \
53
+ accelerate \
54
+ huggingface-hub \
55
+ omegaconf \
56
+ hydra-core
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
+ # Install SAM2 from official repository
59
+ RUN pip install git+https://github.com/facebookresearch/segment-anything-2.git
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
+ # Install MatAnyone from official repository
62
+ RUN pip install git+https://github.com/PeiqingYang/MatAnyone.git
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
+ # Create necessary directories with proper permissions
65
+ RUN mkdir -p /app/checkpoints \
66
+ && mkdir -p /app/Configs \
67
+ && mkdir -p /tmp/MyAvatar/My_Videos \
68
+ && chmod 755 /app/checkpoints \
69
+ && chmod 755 /app/Configs \
70
+ && chmod 755 /tmp/MyAvatar/My_Videos
71
 
72
+ # Copy application files
73
+ COPY . .
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
+ # Download SAM2 configuration files if not present
76
+ RUN if [ ! -d "Configs" ] || [ -z "$(ls -A Configs)" ]; then \
77
+ echo "Downloading SAM2 configs..." && \
78
+ git clone --depth 1 https://github.com/facebookresearch/segment-anything-2.git temp_sam2 && \
79
+ cp -r temp_sam2/sam2_configs/* Configs/ 2>/dev/null || \
80
+ cp -r temp_sam2/configs/* Configs/ 2>/dev/null || \
81
+ echo "Config copy failed, will use defaults" && \
82
+ rm -rf temp_sam2; \
83
+ fi
84
+
85
+ # Ensure all Python files are executable
86
+ RUN find /app -name "*.py" -exec chmod +x {} \;
87
+
88
+ # Create a non-root user for security (optional but recommended)
89
+ RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app /tmp/MyAvatar
90
+ USER appuser
91
+
92
+ # Expose the port that Gradio will run on
93
+ EXPOSE 7860
94
+
95
+ # Health check to ensure the application is running
96
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=120s --retries=3 \
97
+ CMD curl -f http://localhost:7860/ || exit 1
98
+
99
+ # Set the default command to run the application
100
+ CMD ["python", "app.py"]