MogensR commited on
Commit
dd1ef11
·
1 Parent(s): 2143de4

Create ui_components.py

Browse files
Files changed (1) hide show
  1. ui_components.py +318 -0
ui_components.py ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ UI Components for Video Background Replacement
4
+ Contains all Gradio interface components separated from core processing
5
+ """
6
+
7
+ import gradio as gr
8
+ import tempfile
9
+ import cv2
10
+ import os
11
+ import time
12
+ import logging
13
+ from typing import Optional
14
+
15
+ # Import core processing functions
16
+ from app import load_models_fast, process_video_core, get_cache_status
17
+ from utilities import PROFESSIONAL_BACKGROUNDS, create_procedural_background
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # ============================================================================ #
22
+ # GRADIO MONKEY PATCH (BUG FIX for gradio>=4.44.0)
23
+ # ============================================================================ #
24
+ try:
25
+ import gradio_client.utils as gc_utils
26
+ original_get_type = gc_utils.get_type
27
+ def patched_get_type(schema):
28
+ if not isinstance(schema, dict):
29
+ if isinstance(schema, bool):
30
+ return "boolean"
31
+ return "string"
32
+ return original_get_type(schema)
33
+ gc_utils.get_type = patched_get_type
34
+ logger.info("Applied Gradio schema validation monkey patch.")
35
+ except (ImportError, AttributeError) as e:
36
+ logger.warning(f"Could not apply Gradio monkey patch: {e}")
37
+
38
+ # ============================================================================ #
39
+ # UI HELPER FUNCTIONS
40
+ # ============================================================================ #
41
+ def generate_ai_background(prompt, style):
42
+ """Generate AI background from prompt"""
43
+ if not prompt or not prompt.strip():
44
+ return None, "Please enter a prompt"
45
+ try:
46
+ bg_image = create_procedural_background(prompt, style, 1920, 1080)
47
+ if bg_image is not None:
48
+ with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
49
+ cv2.imwrite(tmp.name, bg_image)
50
+ return tmp.name, f"Background generated: {prompt[:50]}..."
51
+ return None, "Generation failed, try different prompt"
52
+ except Exception as e:
53
+ logger.error(f"AI generation error: {e}")
54
+ return None, f"Generation error: {str(e)}"
55
+
56
+ def switch_background_method(method):
57
+ """Switch between background method UI groups"""
58
+ return (
59
+ gr.update(visible=(method == "upload")),
60
+ gr.update(visible=(method == "professional")),
61
+ gr.update(visible=(method == "colors")),
62
+ gr.update(visible=(method == "ai"))
63
+ )
64
+
65
+ def update_cache_status():
66
+ """Update cache status display"""
67
+ status = get_cache_status()
68
+ sam2_status = "✅ Cached" if status["sam2_cached"] else "❌ Not cached"
69
+ matanyone_status = "✅ Cached" if status["matanyone_cached"] else "❌ Not cached"
70
+ return f"SAM2: {sam2_status}\nMatAnyone: {matanyone_status}"
71
+
72
+ # ============================================================================ #
73
+ # PROGRESS WRAPPER
74
+ # ============================================================================ #
75
+ def gradio_progress_wrapper(progress_obj, pct, desc):
76
+ """Wrapper to safely call Gradio progress"""
77
+ try:
78
+ if progress_obj is not None:
79
+ progress_obj(pct, desc=desc)
80
+ except Exception:
81
+ pass
82
+
83
+ # ============================================================================ #
84
+ # MAIN PROCESSING FUNCTION FOR UI
85
+ # ============================================================================ #
86
+ def process_video_enhanced(
87
+ video_path, bg_method, custom_img, prof_choice, grad_type,
88
+ color1, color2, color3, use_third, ai_prompt, ai_style, ai_img,
89
+ progress: Optional[gr.Progress] = None
90
+ ):
91
+ """Enhanced video processing function that handles all UI inputs"""
92
+ if not video_path:
93
+ return None, "No video file provided."
94
+
95
+ def progress_callback(pct, desc):
96
+ gradio_progress_wrapper(progress, pct, desc)
97
+
98
+ try:
99
+ if bg_method == "upload":
100
+ if custom_img and os.path.exists(custom_img):
101
+ return process_video_core(video_path, "custom", custom_img, progress_callback)
102
+ return None, "No image uploaded. Please upload a background image."
103
+
104
+ elif bg_method == "professional":
105
+ if prof_choice and prof_choice in PROFESSIONAL_BACKGROUNDS:
106
+ return process_video_core(video_path, prof_choice, None, progress_callback)
107
+ return None, f"Invalid professional background: {prof_choice}"
108
+
109
+ elif bg_method == "colors":
110
+ try:
111
+ colors = [color1 or "#3498db", color2 or "#2ecc71"]
112
+ if use_third and color3:
113
+ colors.append(color3)
114
+
115
+ from utilities import create_professional_background
116
+ bg_config = {
117
+ "type": "gradient" if grad_type != "solid" else "color",
118
+ "colors": colors if grad_type != "solid" else [colors[0]],
119
+ "direction": grad_type if grad_type != "solid" else "vertical"
120
+ }
121
+ gradient_bg = create_professional_background(bg_config, 1920, 1080)
122
+ temp_path = f"/tmp/gradient_{int(time.time())}.png"
123
+ cv2.imwrite(temp_path, gradient_bg)
124
+ return process_video_core(video_path, "custom", temp_path, progress_callback)
125
+ except Exception as e:
126
+ return None, f"Error creating gradient: {str(e)}"
127
+
128
+ elif bg_method == "ai":
129
+ if ai_img and os.path.exists(ai_img):
130
+ return process_video_core(video_path, "custom", ai_img, progress_callback)
131
+ return None, "No AI background generated. Click 'Generate Background' first."
132
+
133
+ else:
134
+ return None, f"Unknown background method: {bg_method}"
135
+
136
+ except Exception as e:
137
+ logger.error(f"Enhanced processing error: {e}")
138
+ return None, f"Processing error: {str(e)}"
139
+
140
+ def load_models_with_progress(progress: Optional[gr.Progress] = None):
141
+ """Load models with Gradio progress updates"""
142
+ def progress_callback(pct, desc):
143
+ gradio_progress_wrapper(progress, pct, desc)
144
+
145
+ return load_models_fast(progress_callback)
146
+
147
+ # ============================================================================ #
148
+ # MAIN INTERFACE CREATION
149
+ # ============================================================================ #
150
+ def create_interface():
151
+ """Create the complete Gradio interface"""
152
+
153
+ with gr.Blocks(
154
+ title="ENHANCED High-Quality Video Background Replacement - Fast Restart",
155
+ theme=gr.themes.Soft(),
156
+ css="""
157
+ .gradio-container { max-width: 1200px !important; }
158
+ .progress-bar { background: linear-gradient(90deg, #3498db, #2ecc71) !important; }
159
+ """
160
+ ) as demo:
161
+ gr.Markdown("# Cinema-Quality Video Background Replacement")
162
+ gr.Markdown("**Upload a video → Choose a background → Get professional results with AI**")
163
+ gr.Markdown("*Powered by SAM2 + MatAnyone with fast restart caching (2-4 min restarts instead of 10+)*")
164
+ gr.Markdown("---")
165
+
166
+ with gr.Row():
167
+ with gr.Column(scale=1):
168
+ gr.Markdown("### Step 1: Upload Your Video")
169
+ gr.Markdown("*Supports MP4, MOV, AVI, and other common formats*")
170
+ video_input = gr.Video(label="Drop your video here", height=300)
171
+
172
+ gr.Markdown("### Step 2: Choose Background Method")
173
+ gr.Markdown("*Select your preferred background creation method*")
174
+ background_method = gr.Radio(
175
+ choices=["upload", "professional", "colors", "ai"],
176
+ value="professional",
177
+ label="Background Method"
178
+ )
179
+ gr.Markdown(
180
+ "- **upload** = Upload Image \n"
181
+ "- **professional** = Professional Presets \n"
182
+ "- **colors** = Colors/Gradients \n"
183
+ "- **ai** = AI Generated"
184
+ )
185
+
186
+ with gr.Group(visible=False) as upload_group:
187
+ gr.Markdown("**Upload Your Background Image**")
188
+ custom_background = gr.Image(label="Drop your background image here", type="filepath")
189
+
190
+ with gr.Group(visible=True) as professional_group:
191
+ gr.Markdown("**Professional Background Presets**")
192
+ professional_choice = gr.Dropdown(
193
+ choices=list(PROFESSIONAL_BACKGROUNDS.keys()),
194
+ value="office_modern",
195
+ label="Select Professional Background"
196
+ )
197
+
198
+ with gr.Group(visible=False) as colors_group:
199
+ gr.Markdown("**Custom Colors & Gradients**")
200
+ gradient_type = gr.Dropdown(
201
+ choices=["solid", "vertical", "horizontal", "diagonal", "radial", "soft_radial"],
202
+ value="vertical",
203
+ label="Gradient Type"
204
+ )
205
+ with gr.Row():
206
+ color1 = gr.ColorPicker(label="Color 1", value="#3498db")
207
+ color2 = gr.ColorPicker(label="Color 2", value="#2ecc71")
208
+ with gr.Row():
209
+ color3 = gr.ColorPicker(label="Color 3", value="#e74c3c")
210
+ use_third_color = gr.Checkbox(label="Use 3rd color", value=False)
211
+
212
+ with gr.Group(visible=False) as ai_group:
213
+ gr.Markdown("**AI Generated Background**")
214
+ ai_prompt = gr.Textbox(
215
+ label="Describe your background",
216
+ placeholder="e.g., 'modern office with plants', 'sunset over mountains', 'abstract tech pattern'",
217
+ lines=2
218
+ )
219
+ ai_style = gr.Dropdown(
220
+ choices=["photorealistic", "artistic", "abstract", "minimalist", "corporate", "nature"],
221
+ value="photorealistic",
222
+ label="Style"
223
+ )
224
+ with gr.Row():
225
+ generate_ai_btn = gr.Button("Generate Background", variant="secondary")
226
+ ai_generated_image = gr.Image(label="Generated Background", type="filepath", visible=False)
227
+
228
+ # Wire up background method switching
229
+ background_method.change(
230
+ fn=switch_background_method,
231
+ inputs=background_method,
232
+ outputs=[upload_group, professional_group, colors_group, ai_group]
233
+ )
234
+
235
+ gr.Markdown("### Processing Controls")
236
+ gr.Markdown("*First load the AI models, then process your video*")
237
+ with gr.Row():
238
+ load_models_btn = gr.Button("Step 1: Load AI Models (Fast)", variant="secondary")
239
+ process_btn = gr.Button("Step 2: Process Video", variant="primary")
240
+
241
+ status_text = gr.Textbox(
242
+ label="System Status",
243
+ value="Ready - click 'Load AI Models' to start",
244
+ interactive=False,
245
+ lines=3
246
+ )
247
+
248
+ # Cache status indicator
249
+ cache_status = gr.Textbox(
250
+ label="Fast Restart Cache Status",
251
+ value=update_cache_status(),
252
+ interactive=False,
253
+ lines=2
254
+ )
255
+
256
+ with gr.Column(scale=1):
257
+ gr.Markdown("### Your Results")
258
+ gr.Markdown("*Processed video will appear here after Step 2*")
259
+ video_output = gr.Video(label="Your Processed Video", height=400)
260
+ result_text = gr.Textbox(
261
+ label="Processing Results",
262
+ interactive=False,
263
+ lines=6,
264
+ placeholder="Processing status and results will appear here..."
265
+ )
266
+
267
+ gr.Markdown("### Professional Backgrounds Available")
268
+ bg_preview_html = """
269
+ <div style='display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; padding: 10px; max-height: 400px; overflow-y: auto; border: 1px solid #ddd; border-radius: 8px;'>
270
+ """
271
+ for key, config in PROFESSIONAL_BACKGROUNDS.items():
272
+ colors = config["colors"]
273
+ gradient = f"linear-gradient(45deg, {colors[0]}, {colors[-1]})" if len(colors) >= 2 else colors[0]
274
+ bg_preview_html += f"""
275
+ <div style='padding: 12px 8px; border: 1px solid #ddd; border-radius: 6px; text-align: center; background: {gradient};
276
+ min-height: 60px; display: flex; align-items: center; justify-content: center;'>
277
+ <div>
278
+ <strong style='color: white; text-shadow: 1px 1px 2px rgba(0,0,0,0.8); font-size: 12px; display: block;'>{config["name"]}</strong>
279
+ <small style='color: rgba(255,255,255,0.9); text-shadow: 1px 1px 1px rgba(0,0,0,0.6); font-size: 10px;'>{config.get("description", "")[:30]}...</small>
280
+ </div>
281
+ </div>
282
+ """
283
+ bg_preview_html += "</div>"
284
+ gr.HTML(bg_preview_html)
285
+
286
+ # Event handlers
287
+ load_models_btn.click(
288
+ fn=load_models_with_progress,
289
+ outputs=status_text
290
+ )
291
+
292
+ generate_ai_btn.click(
293
+ fn=generate_ai_background,
294
+ inputs=[ai_prompt, ai_style],
295
+ outputs=[ai_generated_image, status_text]
296
+ )
297
+
298
+ process_btn.click(
299
+ fn=process_video_enhanced,
300
+ inputs=[video_input, background_method, custom_background, professional_choice,
301
+ gradient_type, color1, color2, color3, use_third_color,
302
+ ai_prompt, ai_style, ai_generated_image],
303
+ outputs=[video_output, result_text]
304
+ )
305
+
306
+ with gr.Accordion("ENHANCED Quality & Features", open=False):
307
+ gr.Markdown("""
308
+ ### SINGLE-STAGE Cinema-Quality Features:
309
+ **Processing**: Original → Final Background (SAM2 + MatAnyone)
310
+ **Quality**: Edge feathering, gamma correction, mask cleanup, H.264 CRF 18, AAC 192kbps.
311
+ **Fast Restart**: Persistent model caching reduces restart time from 10+ minutes to 2-4 minutes.
312
+ **Architecture**: Separated UI components for faster startup and better maintainability.
313
+ """)
314
+
315
+ gr.Markdown("---")
316
+ gr.Markdown("*Cinema-Quality Video Background Replacement — SINGLE-STAGE pipeline with Fast Restart*")
317
+
318
+ return demo