MogensR commited on
Commit
3b31687
·
1 Parent(s): bb1a40e

Update core/app.py

Browse files
Files changed (1) hide show
  1. core/app.py +97 -69
core/app.py CHANGED
@@ -4,7 +4,36 @@
4
  Refactored modular architecture - orchestrates specialized components
5
  """
6
 
 
7
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  import logging
9
  import threading
10
  from pathlib import Path
@@ -21,7 +50,7 @@
21
  try:
22
  import gradio_client.utils as gc_utils
23
  original_get_type = gc_utils.get_type
24
-
25
  def patched_get_type(schema):
26
  if not isinstance(schema, dict):
27
  if isinstance(schema, bool):
@@ -32,7 +61,7 @@ def patched_get_type(schema):
32
  return "number"
33
  return "string"
34
  return original_get_type(schema)
35
-
36
  gc_utils.get_type = patched_get_type
37
  logger.info("Gradio schema patch applied successfully")
38
  except Exception as e:
@@ -74,30 +103,30 @@ class VideoProcessor:
74
  """
75
  Main video processing orchestrator - coordinates all specialized components
76
  """
77
-
78
  def __init__(self):
79
  """Initialize the video processor with all required components"""
80
  self.config = get_config() # Use singleton config
81
  self.device_manager = DeviceManager()
82
  self.memory_manager = MemoryManager(self.device_manager.get_optimal_device())
83
-
84
  # Initialize ModelLoader with DeviceManager and MemoryManager (as per actual implementation)
85
  self.model_loader = ModelLoader(self.device_manager, self.memory_manager)
86
-
87
  self.audio_processor = AudioProcessor()
88
  self.progress_tracker = None
89
-
90
  # Initialize core processor (will be set up after models load)
91
  self.core_processor = None
92
  self.two_stage_processor = None
93
-
94
  # State management
95
  self.models_loaded = False
96
  self.loading_lock = threading.Lock()
97
  self.cancel_event = threading.Event()
98
-
99
  logger.info(f"VideoProcessor initialized on device: {self.device_manager.get_optimal_device()}")
100
-
101
  def _initialize_progress_tracker(self, video_path: str, progress_callback: Optional[Callable] = None):
102
  """Initialize progress tracker with video frame count"""
103
  try:
@@ -105,29 +134,29 @@ def _initialize_progress_tracker(self, video_path: str, progress_callback: Optio
105
  cap = cv2.VideoCapture(video_path)
106
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
107
  cap.release()
108
-
109
  if total_frames <= 0:
110
  total_frames = 100 # Fallback estimate
111
-
112
  self.progress_tracker = ProgressTracker(total_frames, progress_callback)
113
  logger.info(f"Progress tracker initialized for {total_frames} frames")
114
  except Exception as e:
115
  logger.warning(f"Could not initialize progress tracker: {e}")
116
  # Fallback to basic tracker
117
  self.progress_tracker = ProgressTracker(100, progress_callback)
118
-
119
  def load_models(self, progress_callback: Optional[Callable] = None) -> str:
120
  """Load and validate all AI models"""
121
  with self.loading_lock:
122
  if self.models_loaded:
123
  return "Models already loaded and validated"
124
-
125
  try:
126
  self.cancel_event.clear()
127
-
128
  if progress_callback:
129
  progress_callback(0.0, f"Starting model loading on {self.device_manager.get_optimal_device()}")
130
-
131
  # Add detailed debugging for the IndexError
132
  try:
133
  # Load models using load_all_models which returns tuple of (LoadedModel, LoadedModel)
@@ -135,47 +164,47 @@ def load_models(self, progress_callback: Optional[Callable] = None) -> str:
135
  progress_callback=progress_callback,
136
  cancel_event=self.cancel_event
137
  )
138
-
139
  except IndexError as e:
140
  import traceback
141
  logger.error(f"IndexError in load_all_models: {e}")
142
  logger.error(f"Full traceback:\n{traceback.format_exc()}")
143
-
144
  # Get more context about where exactly the error happened
145
  tb = traceback.extract_tb(e.__traceback__)
146
  for frame in tb:
147
  logger.error(f" File: {frame.filename}, Line: {frame.lineno}, Function: {frame.name}")
148
  logger.error(f" Code: {frame.line}")
149
-
150
  # Re-raise with more context
151
  raise ModelLoadingError(f"Model loading failed with IndexError at line {tb[-1].lineno}: {e}")
152
-
153
  except Exception as e:
154
  import traceback
155
  logger.error(f"Unexpected error in load_all_models: {e}")
156
  logger.error(f"Error type: {type(e).__name__}")
157
  logger.error(f"Full traceback:\n{traceback.format_exc()}")
158
  raise
159
-
160
  if self.cancel_event.is_set():
161
  return "Model loading cancelled"
162
-
163
  # Extract actual models from LoadedModel wrappers for two-stage processor
164
  sam2_predictor = sam2_result.model if sam2_result else None
165
  matanyone_model = matanyone_result.model if matanyone_result else None
166
-
167
  # Check if at least one model loaded successfully
168
  success = sam2_predictor is not None or matanyone_model is not None
169
-
170
  if not success:
171
  return "Model loading failed - check logs for details"
172
-
173
  # Initialize core processor with the model loader (it expects a models object)
174
  self.core_processor = CoreVideoProcessor(
175
  config=self.config,
176
  models=self.model_loader # Pass the whole model_loader object
177
  )
178
-
179
  # Initialize two-stage processor if available and models loaded
180
  if TWO_STAGE_AVAILABLE:
181
  if sam2_predictor is not None or matanyone_model is not None:
@@ -195,19 +224,19 @@ def load_models(self, progress_callback: Optional[Callable] = None) -> str:
195
  logger.warning(" - SAM2 predictor is None")
196
  if matanyone_model is None:
197
  logger.warning(" - MatAnyone model is None")
198
-
199
  self.models_loaded = True
200
  message = self.model_loader.get_load_summary()
201
-
202
  # Add two-stage status to message
203
  if self.two_stage_processor is not None:
204
  message += "\n✅ Two-stage processor ready with AI models"
205
  else:
206
  message += "\n⚠️ Two-stage processor not available"
207
-
208
  logger.info(message)
209
  return message
210
-
211
  except AttributeError as e:
212
  self.models_loaded = False
213
  error_msg = f"Model loading failed - method not found: {str(e)}"
@@ -223,7 +252,7 @@ def load_models(self, progress_callback: Optional[Callable] = None) -> str:
223
  error_msg = f"Unexpected error during model loading: {str(e)}"
224
  logger.error(error_msg)
225
  return error_msg
226
-
227
  def process_video(
228
  self,
229
  video_path: str,
@@ -236,30 +265,30 @@ def process_video(
236
  preview_greenscreen: bool = False
237
  ) -> Tuple[Optional[str], str]:
238
  """Process video with the specified parameters"""
239
-
240
  if not self.models_loaded or not self.core_processor:
241
  return None, "Models not loaded. Please load models first."
242
-
243
  if self.cancel_event.is_set():
244
  return None, "Processing cancelled"
245
-
246
  # Initialize progress tracker with video frame count
247
  self._initialize_progress_tracker(video_path, progress_callback)
248
-
249
  # Validate input file
250
  is_valid, validation_msg = validate_video_file(video_path)
251
  if not is_valid:
252
  return None, f"Invalid video: {validation_msg}"
253
-
254
  try:
255
  # Route to appropriate processing method
256
  if use_two_stage:
257
  if not TWO_STAGE_AVAILABLE:
258
  return None, "Two-stage processing not available - module not found"
259
-
260
  if self.two_stage_processor is None:
261
  return None, "Two-stage processor not initialized - models may not be loaded properly"
262
-
263
  logger.info("Using two-stage processing pipeline with AI models")
264
  return self._process_two_stage(
265
  video_path, background_choice, custom_background_path,
@@ -271,14 +300,14 @@ def process_video(
271
  video_path, background_choice, custom_background_path,
272
  progress_callback, preview_mask, preview_greenscreen
273
  )
274
-
275
  except VideoProcessingError as e:
276
  logger.error(f"Video processing failed: {e}")
277
  return None, f"Processing failed: {str(e)}"
278
  except Exception as e:
279
  logger.error(f"Unexpected error during video processing: {e}")
280
  return None, f"Unexpected error: {str(e)}"
281
-
282
  def _process_single_stage(
283
  self,
284
  video_path: str,
@@ -289,24 +318,24 @@ def _process_single_stage(
289
  preview_greenscreen: bool
290
  ) -> Tuple[Optional[str], str]:
291
  """Process video using single-stage pipeline"""
292
-
293
  # Generate output path
294
  import time
295
  timestamp = int(time.time())
296
  output_dir = Path(self.config.output_dir) / "single_stage"
297
  output_dir.mkdir(parents=True, exist_ok=True)
298
  output_path = str(output_dir / f"processed_{timestamp}.mp4")
299
-
300
  # Process video using core processor
301
  result = self.core_processor.process_video(
302
  input_path=video_path,
303
  output_path=output_path,
304
  bg_config={'background_choice': background_choice, 'custom_path': custom_background_path}
305
  )
306
-
307
  if not result:
308
  return None, "Video processing failed"
309
-
310
  # Add audio if not in preview mode
311
  if not (preview_mask or preview_greenscreen):
312
  final_video_path = self.audio_processor.add_audio_to_video(
@@ -315,7 +344,7 @@ def _process_single_stage(
315
  )
316
  else:
317
  final_video_path = output_path
318
-
319
  success_msg = (
320
  f"Processing completed successfully!\n"
321
  f"Frames processed: {result.get('frames', 'unknown')}\n"
@@ -323,9 +352,9 @@ def _process_single_stage(
323
  f"Mode: Single-stage\n"
324
  f"Device: {self.device_manager.get_optimal_device()}"
325
  )
326
-
327
  return final_video_path, success_msg
328
-
329
  def _process_two_stage(
330
  self,
331
  video_path: str,
@@ -335,33 +364,33 @@ def _process_two_stage(
335
  chroma_preset: str
336
  ) -> Tuple[Optional[str], str]:
337
  """Process video using two-stage pipeline"""
338
-
339
  if self.two_stage_processor is None:
340
  return None, "Two-stage processor not available"
341
-
342
  # Get video dimensions for background preparation
343
  import cv2
344
  cap = cv2.VideoCapture(video_path)
345
  frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
346
  frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
347
  cap.release()
348
-
349
  # Prepare background using core processor
350
  background = self.core_processor.prepare_background(
351
  background_choice, custom_background_path, frame_width, frame_height
352
  )
353
  if background is None:
354
  return None, "Failed to prepare background"
355
-
356
  # Process with two-stage pipeline
357
  import time
358
  timestamp = int(time.time())
359
  output_dir = Path(self.config.output_dir) / "two_stage"
360
  output_dir.mkdir(parents=True, exist_ok=True)
361
  final_output = str(output_dir / f"final_{timestamp}.mp4")
362
-
363
  chroma_settings = CHROMA_PRESETS.get(chroma_preset, CHROMA_PRESETS['standard'])
364
-
365
  logger.info(f"Starting two-stage processing with chroma preset: {chroma_preset}")
366
  result, message = self.two_stage_processor.process_full_pipeline(
367
  video_path,
@@ -370,10 +399,10 @@ def _process_two_stage(
370
  chroma_settings=chroma_settings,
371
  progress_callback=progress_callback
372
  )
373
-
374
  if result is None:
375
  return None, message
376
-
377
  success_msg = (
378
  f"Two-stage processing completed!\n"
379
  f"Background: {background_choice}\n"
@@ -381,9 +410,9 @@ def _process_two_stage(
381
  f"Quality: Cinema-grade with AI models\n"
382
  f"Device: {self.device_manager.get_optimal_device()}"
383
  )
384
-
385
  return result, success_msg
386
-
387
  def get_status(self) -> Dict[str, Any]:
388
  """Get comprehensive status of all components"""
389
  base_status = {
@@ -393,7 +422,7 @@ def get_status(self) -> Dict[str, Any]:
393
  'memory_usage': self.memory_manager.get_memory_usage(),
394
  'config': self.config.to_dict()
395
  }
396
-
397
  # Add model-specific status if available
398
  if self.model_loader:
399
  base_status['model_loader_available'] = True
@@ -403,28 +432,28 @@ def get_status(self) -> Dict[str, Any]:
403
  except AttributeError:
404
  base_status['sam2_loaded'] = False
405
  base_status['matanyone_loaded'] = False
406
-
407
  # Add processing status if available
408
  if self.core_processor:
409
  base_status['core_processor_loaded'] = True
410
-
411
  # Add two-stage processor status
412
  if self.two_stage_processor:
413
  base_status['two_stage_processor_ready'] = True
414
  else:
415
  base_status['two_stage_processor_ready'] = False
416
-
417
  # Add progress tracking if available
418
  if self.progress_tracker:
419
  base_status['progress'] = self.progress_tracker.get_all_progress()
420
-
421
  return base_status
422
-
423
  def cancel_processing(self):
424
  """Cancel any ongoing processing"""
425
  self.cancel_event.set()
426
  logger.info("Processing cancellation requested")
427
-
428
  def cleanup_resources(self):
429
  """Clean up all resources"""
430
  self.memory_manager.cleanup_aggressive()
@@ -482,20 +511,19 @@ def main():
482
  logger.info(f"Device: {processor.device_manager.get_optimal_device()}")
483
  logger.info(f"Two-stage module available: {TWO_STAGE_AVAILABLE}")
484
  logger.info("Modular architecture loaded successfully")
485
-
486
  # Import and create UI
487
  from ui_components import create_interface
488
  demo = create_interface()
489
-
490
- # Launch application
491
  demo.queue().launch(
492
  server_name="0.0.0.0",
493
  server_port=7860,
494
- share=True,
495
  show_error=True,
496
  debug=False
497
  )
498
-
499
  except Exception as e:
500
  logger.error(f"Application startup failed: {e}")
501
  raise
@@ -505,4 +533,4 @@ def main():
505
 
506
 
507
  if __name__ == "__main__":
508
- main()
 
4
  Refactored modular architecture - orchestrates specialized components
5
  """
6
 
7
+ # 0️⃣ Early threading/OMP sanitization (prevents libgomp + interop warnings)
8
  import os
9
+ def _clean_int_env(name: str, default: str | None = None):
10
+ val = os.environ.get(name)
11
+ if val is None:
12
+ if default is not None:
13
+ os.environ[name] = str(default)
14
+ return
15
+ try:
16
+ int(str(val).strip())
17
+ except ValueError:
18
+ if default is None:
19
+ os.environ.pop(name, None)
20
+ else:
21
+ os.environ[name] = str(default)
22
+
23
+ _clean_int_env("OMP_NUM_THREADS", "2")
24
+ _clean_int_env("MKL_NUM_THREADS", "2")
25
+ _clean_int_env("OPENBLAS_NUM_THREADS", "2")
26
+ _clean_int_env("NUMEXPR_NUM_THREADS", "2")
27
+
28
+ try:
29
+ import torch # call thread setters BEFORE heavy parallel work starts
30
+ if hasattr(torch, "set_num_interop_threads"):
31
+ torch.set_num_interop_threads(2)
32
+ if hasattr(torch, "set_num_threads"):
33
+ torch.set_num_threads(2)
34
+ except Exception:
35
+ pass
36
+
37
  import logging
38
  import threading
39
  from pathlib import Path
 
50
  try:
51
  import gradio_client.utils as gc_utils
52
  original_get_type = gc_utils.get_type
53
+
54
  def patched_get_type(schema):
55
  if not isinstance(schema, dict):
56
  if isinstance(schema, bool):
 
61
  return "number"
62
  return "string"
63
  return original_get_type(schema)
64
+
65
  gc_utils.get_type = patched_get_type
66
  logger.info("Gradio schema patch applied successfully")
67
  except Exception as e:
 
103
  """
104
  Main video processing orchestrator - coordinates all specialized components
105
  """
106
+
107
  def __init__(self):
108
  """Initialize the video processor with all required components"""
109
  self.config = get_config() # Use singleton config
110
  self.device_manager = DeviceManager()
111
  self.memory_manager = MemoryManager(self.device_manager.get_optimal_device())
112
+
113
  # Initialize ModelLoader with DeviceManager and MemoryManager (as per actual implementation)
114
  self.model_loader = ModelLoader(self.device_manager, self.memory_manager)
115
+
116
  self.audio_processor = AudioProcessor()
117
  self.progress_tracker = None
118
+
119
  # Initialize core processor (will be set up after models load)
120
  self.core_processor = None
121
  self.two_stage_processor = None
122
+
123
  # State management
124
  self.models_loaded = False
125
  self.loading_lock = threading.Lock()
126
  self.cancel_event = threading.Event()
127
+
128
  logger.info(f"VideoProcessor initialized on device: {self.device_manager.get_optimal_device()}")
129
+
130
  def _initialize_progress_tracker(self, video_path: str, progress_callback: Optional[Callable] = None):
131
  """Initialize progress tracker with video frame count"""
132
  try:
 
134
  cap = cv2.VideoCapture(video_path)
135
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
136
  cap.release()
137
+
138
  if total_frames <= 0:
139
  total_frames = 100 # Fallback estimate
140
+
141
  self.progress_tracker = ProgressTracker(total_frames, progress_callback)
142
  logger.info(f"Progress tracker initialized for {total_frames} frames")
143
  except Exception as e:
144
  logger.warning(f"Could not initialize progress tracker: {e}")
145
  # Fallback to basic tracker
146
  self.progress_tracker = ProgressTracker(100, progress_callback)
147
+
148
  def load_models(self, progress_callback: Optional[Callable] = None) -> str:
149
  """Load and validate all AI models"""
150
  with self.loading_lock:
151
  if self.models_loaded:
152
  return "Models already loaded and validated"
153
+
154
  try:
155
  self.cancel_event.clear()
156
+
157
  if progress_callback:
158
  progress_callback(0.0, f"Starting model loading on {self.device_manager.get_optimal_device()}")
159
+
160
  # Add detailed debugging for the IndexError
161
  try:
162
  # Load models using load_all_models which returns tuple of (LoadedModel, LoadedModel)
 
164
  progress_callback=progress_callback,
165
  cancel_event=self.cancel_event
166
  )
167
+
168
  except IndexError as e:
169
  import traceback
170
  logger.error(f"IndexError in load_all_models: {e}")
171
  logger.error(f"Full traceback:\n{traceback.format_exc()}")
172
+
173
  # Get more context about where exactly the error happened
174
  tb = traceback.extract_tb(e.__traceback__)
175
  for frame in tb:
176
  logger.error(f" File: {frame.filename}, Line: {frame.lineno}, Function: {frame.name}")
177
  logger.error(f" Code: {frame.line}")
178
+
179
  # Re-raise with more context
180
  raise ModelLoadingError(f"Model loading failed with IndexError at line {tb[-1].lineno}: {e}")
181
+
182
  except Exception as e:
183
  import traceback
184
  logger.error(f"Unexpected error in load_all_models: {e}")
185
  logger.error(f"Error type: {type(e).__name__}")
186
  logger.error(f"Full traceback:\n{traceback.format_exc()}")
187
  raise
188
+
189
  if self.cancel_event.is_set():
190
  return "Model loading cancelled"
191
+
192
  # Extract actual models from LoadedModel wrappers for two-stage processor
193
  sam2_predictor = sam2_result.model if sam2_result else None
194
  matanyone_model = matanyone_result.model if matanyone_result else None
195
+
196
  # Check if at least one model loaded successfully
197
  success = sam2_predictor is not None or matanyone_model is not None
198
+
199
  if not success:
200
  return "Model loading failed - check logs for details"
201
+
202
  # Initialize core processor with the model loader (it expects a models object)
203
  self.core_processor = CoreVideoProcessor(
204
  config=self.config,
205
  models=self.model_loader # Pass the whole model_loader object
206
  )
207
+
208
  # Initialize two-stage processor if available and models loaded
209
  if TWO_STAGE_AVAILABLE:
210
  if sam2_predictor is not None or matanyone_model is not None:
 
224
  logger.warning(" - SAM2 predictor is None")
225
  if matanyone_model is None:
226
  logger.warning(" - MatAnyone model is None")
227
+
228
  self.models_loaded = True
229
  message = self.model_loader.get_load_summary()
230
+
231
  # Add two-stage status to message
232
  if self.two_stage_processor is not None:
233
  message += "\n✅ Two-stage processor ready with AI models"
234
  else:
235
  message += "\n⚠️ Two-stage processor not available"
236
+
237
  logger.info(message)
238
  return message
239
+
240
  except AttributeError as e:
241
  self.models_loaded = False
242
  error_msg = f"Model loading failed - method not found: {str(e)}"
 
252
  error_msg = f"Unexpected error during model loading: {str(e)}"
253
  logger.error(error_msg)
254
  return error_msg
255
+
256
  def process_video(
257
  self,
258
  video_path: str,
 
265
  preview_greenscreen: bool = False
266
  ) -> Tuple[Optional[str], str]:
267
  """Process video with the specified parameters"""
268
+
269
  if not self.models_loaded or not self.core_processor:
270
  return None, "Models not loaded. Please load models first."
271
+
272
  if self.cancel_event.is_set():
273
  return None, "Processing cancelled"
274
+
275
  # Initialize progress tracker with video frame count
276
  self._initialize_progress_tracker(video_path, progress_callback)
277
+
278
  # Validate input file
279
  is_valid, validation_msg = validate_video_file(video_path)
280
  if not is_valid:
281
  return None, f"Invalid video: {validation_msg}"
282
+
283
  try:
284
  # Route to appropriate processing method
285
  if use_two_stage:
286
  if not TWO_STAGE_AVAILABLE:
287
  return None, "Two-stage processing not available - module not found"
288
+
289
  if self.two_stage_processor is None:
290
  return None, "Two-stage processor not initialized - models may not be loaded properly"
291
+
292
  logger.info("Using two-stage processing pipeline with AI models")
293
  return self._process_two_stage(
294
  video_path, background_choice, custom_background_path,
 
300
  video_path, background_choice, custom_background_path,
301
  progress_callback, preview_mask, preview_greenscreen
302
  )
303
+
304
  except VideoProcessingError as e:
305
  logger.error(f"Video processing failed: {e}")
306
  return None, f"Processing failed: {str(e)}"
307
  except Exception as e:
308
  logger.error(f"Unexpected error during video processing: {e}")
309
  return None, f"Unexpected error: {str(e)}"
310
+
311
  def _process_single_stage(
312
  self,
313
  video_path: str,
 
318
  preview_greenscreen: bool
319
  ) -> Tuple[Optional[str], str]:
320
  """Process video using single-stage pipeline"""
321
+
322
  # Generate output path
323
  import time
324
  timestamp = int(time.time())
325
  output_dir = Path(self.config.output_dir) / "single_stage"
326
  output_dir.mkdir(parents=True, exist_ok=True)
327
  output_path = str(output_dir / f"processed_{timestamp}.mp4")
328
+
329
  # Process video using core processor
330
  result = self.core_processor.process_video(
331
  input_path=video_path,
332
  output_path=output_path,
333
  bg_config={'background_choice': background_choice, 'custom_path': custom_background_path}
334
  )
335
+
336
  if not result:
337
  return None, "Video processing failed"
338
+
339
  # Add audio if not in preview mode
340
  if not (preview_mask or preview_greenscreen):
341
  final_video_path = self.audio_processor.add_audio_to_video(
 
344
  )
345
  else:
346
  final_video_path = output_path
347
+
348
  success_msg = (
349
  f"Processing completed successfully!\n"
350
  f"Frames processed: {result.get('frames', 'unknown')}\n"
 
352
  f"Mode: Single-stage\n"
353
  f"Device: {self.device_manager.get_optimal_device()}"
354
  )
355
+
356
  return final_video_path, success_msg
357
+
358
  def _process_two_stage(
359
  self,
360
  video_path: str,
 
364
  chroma_preset: str
365
  ) -> Tuple[Optional[str], str]:
366
  """Process video using two-stage pipeline"""
367
+
368
  if self.two_stage_processor is None:
369
  return None, "Two-stage processor not available"
370
+
371
  # Get video dimensions for background preparation
372
  import cv2
373
  cap = cv2.VideoCapture(video_path)
374
  frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
375
  frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
376
  cap.release()
377
+
378
  # Prepare background using core processor
379
  background = self.core_processor.prepare_background(
380
  background_choice, custom_background_path, frame_width, frame_height
381
  )
382
  if background is None:
383
  return None, "Failed to prepare background"
384
+
385
  # Process with two-stage pipeline
386
  import time
387
  timestamp = int(time.time())
388
  output_dir = Path(self.config.output_dir) / "two_stage"
389
  output_dir.mkdir(parents=True, exist_ok=True)
390
  final_output = str(output_dir / f"final_{timestamp}.mp4")
391
+
392
  chroma_settings = CHROMA_PRESETS.get(chroma_preset, CHROMA_PRESETS['standard'])
393
+
394
  logger.info(f"Starting two-stage processing with chroma preset: {chroma_preset}")
395
  result, message = self.two_stage_processor.process_full_pipeline(
396
  video_path,
 
399
  chroma_settings=chroma_settings,
400
  progress_callback=progress_callback
401
  )
402
+
403
  if result is None:
404
  return None, message
405
+
406
  success_msg = (
407
  f"Two-stage processing completed!\n"
408
  f"Background: {background_choice}\n"
 
410
  f"Quality: Cinema-grade with AI models\n"
411
  f"Device: {self.device_manager.get_optimal_device()}"
412
  )
413
+
414
  return result, success_msg
415
+
416
  def get_status(self) -> Dict[str, Any]:
417
  """Get comprehensive status of all components"""
418
  base_status = {
 
422
  'memory_usage': self.memory_manager.get_memory_usage(),
423
  'config': self.config.to_dict()
424
  }
425
+
426
  # Add model-specific status if available
427
  if self.model_loader:
428
  base_status['model_loader_available'] = True
 
432
  except AttributeError:
433
  base_status['sam2_loaded'] = False
434
  base_status['matanyone_loaded'] = False
435
+
436
  # Add processing status if available
437
  if self.core_processor:
438
  base_status['core_processor_loaded'] = True
439
+
440
  # Add two-stage processor status
441
  if self.two_stage_processor:
442
  base_status['two_stage_processor_ready'] = True
443
  else:
444
  base_status['two_stage_processor_ready'] = False
445
+
446
  # Add progress tracking if available
447
  if self.progress_tracker:
448
  base_status['progress'] = self.progress_tracker.get_all_progress()
449
+
450
  return base_status
451
+
452
  def cancel_processing(self):
453
  """Cancel any ongoing processing"""
454
  self.cancel_event.set()
455
  logger.info("Processing cancellation requested")
456
+
457
  def cleanup_resources(self):
458
  """Clean up all resources"""
459
  self.memory_manager.cleanup_aggressive()
 
511
  logger.info(f"Device: {processor.device_manager.get_optimal_device()}")
512
  logger.info(f"Two-stage module available: {TWO_STAGE_AVAILABLE}")
513
  logger.info("Modular architecture loaded successfully")
514
+
515
  # Import and create UI
516
  from ui_components import create_interface
517
  demo = create_interface()
518
+
519
+ # Launch application (no share=True on Spaces)
520
  demo.queue().launch(
521
  server_name="0.0.0.0",
522
  server_port=7860,
 
523
  show_error=True,
524
  debug=False
525
  )
526
+
527
  except Exception as e:
528
  logger.error(f"Application startup failed: {e}")
529
  raise
 
533
 
534
 
535
  if __name__ == "__main__":
536
+ main()