Update app.py
Browse files
app.py
CHANGED
|
@@ -9,7 +9,7 @@
|
|
| 9 |
|
| 10 |
import os
|
| 11 |
from pathlib import Path
|
| 12 |
-
from typing import Optional,
|
| 13 |
|
| 14 |
# 1️⃣ Set CSP-safe environment variables BEFORE any imports (Gradio will see these)
|
| 15 |
os.environ['GRADIO_ALLOW_FLAGGING'] = 'never'
|
|
@@ -50,8 +50,7 @@ def patched_get_type(schema):
|
|
| 50 |
from processing.video.video_processor import CoreVideoProcessor, ProcessorConfig
|
| 51 |
from processing.audio.audio_processor import AudioProcessor
|
| 52 |
|
| 53 |
-
# NOTE:
|
| 54 |
-
# Here we import from your unified utils (the file you showed me earlier).
|
| 55 |
from utils import PROFESSIONAL_BACKGROUNDS, validate_video_file
|
| 56 |
|
| 57 |
# 5️⃣ CSP-safe fallback model stubs
|
|
@@ -67,7 +66,7 @@ def predict(self, point_coords=None, point_labels=None, box=None, multimask_outp
|
|
| 67 |
class CSPSafeMatAnyone:
|
| 68 |
def step(self, image_tensor, mask_tensor=None, objects=None, first_frame_pred=False, **kwargs):
|
| 69 |
import torch
|
| 70 |
-
# image_tensor
|
| 71 |
if hasattr(image_tensor, "shape"):
|
| 72 |
if len(image_tensor.shape) == 3:
|
| 73 |
_, H, W = image_tensor.shape
|
|
@@ -92,7 +91,7 @@ def __init__(self):
|
|
| 92 |
self.model_loader = ModelLoader(self.device_mgr, self.memory_mgr)
|
| 93 |
self.audio_proc = AudioProcessor()
|
| 94 |
self.models_loaded = False
|
| 95 |
-
self.core_processor = None
|
| 96 |
logger.info("VideoBackgroundApp initialized (device=%s)", self.device_mgr.get_optimal_device())
|
| 97 |
|
| 98 |
def load_models(self, progress_callback: Optional[Callable]=None) -> str:
|
|
@@ -106,8 +105,21 @@ def load_models(self, progress_callback: Optional[Callable]=None) -> str:
|
|
| 106 |
sam2_model = getattr(sam2, "model", sam2) if sam2 else CSPSafeSAM2()
|
| 107 |
matanyone_model = getattr(matanyone, "model", matanyone) if matanyone else CSPSafeMatAnyone()
|
| 108 |
|
| 109 |
-
#
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
self.core_processor.models = type('FakeModelManager', (), {
|
| 112 |
'get_sam2': lambda self_: sam2_model,
|
| 113 |
'get_matanyone': lambda self_: matanyone_model
|
|
@@ -123,20 +135,21 @@ def process_video(self, video, bg_style, custom_bg_file):
|
|
| 123 |
return None, "Models not loaded yet"
|
| 124 |
|
| 125 |
logger.info("process_video called (video=%s, bg_style=%s, custom_bg=%s)",
|
| 126 |
-
video, bg_style, getattr(custom_bg_file, "name", None))
|
| 127 |
|
| 128 |
import time
|
| 129 |
output_path = f"/tmp/output_{int(time.time())}.mp4"
|
| 130 |
|
| 131 |
-
# Background config
|
|
|
|
|
|
|
| 132 |
if custom_bg_file:
|
| 133 |
-
|
| 134 |
else:
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
cfg = PROFESSIONAL_BACKGROUNDS.get(style, PROFESSIONAL_BACKGROUNDS["office"])
|
| 138 |
|
| 139 |
-
# Validate input video (
|
| 140 |
ok = validate_video_file(video)
|
| 141 |
if not ok:
|
| 142 |
logger.warning("Invalid/unreadable video: %s", video)
|
|
@@ -146,7 +159,7 @@ def process_video(self, video, bg_style, custom_bg_file):
|
|
| 146 |
result = self.core_processor.process_video(
|
| 147 |
input_path=video,
|
| 148 |
output_path=output_path,
|
| 149 |
-
bg_config=
|
| 150 |
)
|
| 151 |
logger.info("Core processing done → %s", output_path)
|
| 152 |
|
|
@@ -180,9 +193,10 @@ def create_csp_safe_gradio():
|
|
| 180 |
video = gr.Video(label="Upload Video")
|
| 181 |
# Ensure default choice exists in PROFESSIONAL_BACKGROUNDS (use 'office')
|
| 182 |
choices = list(PROFESSIONAL_BACKGROUNDS.keys())
|
|
|
|
| 183 |
bg_style = gr.Dropdown(
|
| 184 |
choices=choices,
|
| 185 |
-
value=
|
| 186 |
label="Background Style"
|
| 187 |
)
|
| 188 |
custom_bg = gr.File(label="Custom Background (Optional)", file_types=["image"])
|
|
|
|
| 9 |
|
| 10 |
import os
|
| 11 |
from pathlib import Path
|
| 12 |
+
from typing import Optional, Dict, Any, Callable
|
| 13 |
|
| 14 |
# 1️⃣ Set CSP-safe environment variables BEFORE any imports (Gradio will see these)
|
| 15 |
os.environ['GRADIO_ALLOW_FLAGGING'] = 'never'
|
|
|
|
| 50 |
from processing.video.video_processor import CoreVideoProcessor, ProcessorConfig
|
| 51 |
from processing.audio.audio_processor import AudioProcessor
|
| 52 |
|
| 53 |
+
# NOTE: We import background presets (for the UI) and validator from utils
|
|
|
|
| 54 |
from utils import PROFESSIONAL_BACKGROUNDS, validate_video_file
|
| 55 |
|
| 56 |
# 5️⃣ CSP-safe fallback model stubs
|
|
|
|
| 66 |
class CSPSafeMatAnyone:
|
| 67 |
def step(self, image_tensor, mask_tensor=None, objects=None, first_frame_pred=False, **kwargs):
|
| 68 |
import torch
|
| 69 |
+
# image_tensor can be CHW or NCHW; our model guard normalizes it upstream
|
| 70 |
if hasattr(image_tensor, "shape"):
|
| 71 |
if len(image_tensor.shape) == 3:
|
| 72 |
_, H, W = image_tensor.shape
|
|
|
|
| 91 |
self.model_loader = ModelLoader(self.device_mgr, self.memory_mgr)
|
| 92 |
self.audio_proc = AudioProcessor()
|
| 93 |
self.models_loaded = False
|
| 94 |
+
self.core_processor: Optional[CoreVideoProcessor] = None
|
| 95 |
logger.info("VideoBackgroundApp initialized (device=%s)", self.device_mgr.get_optimal_device())
|
| 96 |
|
| 97 |
def load_models(self, progress_callback: Optional[Callable]=None) -> str:
|
|
|
|
| 105 |
sam2_model = getattr(sam2, "model", sam2) if sam2 else CSPSafeSAM2()
|
| 106 |
matanyone_model = getattr(matanyone, "model", matanyone) if matanyone else CSPSafeMatAnyone()
|
| 107 |
|
| 108 |
+
# ⬇️ NEW: fast-but-safe defaults (NVENC + model-only downscale)
|
| 109 |
+
cfg = ProcessorConfig(
|
| 110 |
+
background_preset="office", # valid preset key
|
| 111 |
+
write_fps=None, # keep source FPS
|
| 112 |
+
max_model_size=1280, # model-only downscale; output remains full-res
|
| 113 |
+
use_nvenc=True, # try GPU encoder if available
|
| 114 |
+
nvenc_codec="h264", # browser-safe preview
|
| 115 |
+
nvenc_preset="p5", # HQ preset
|
| 116 |
+
nvenc_cq=18, # lower = higher quality
|
| 117 |
+
nvenc_tune_hq=True, # high-quality tuning
|
| 118 |
+
nvenc_pix_fmt="yuv420p", # web-compatible pixel format
|
| 119 |
+
)
|
| 120 |
+
self.core_processor = CoreVideoProcessor(config=cfg, models=None)
|
| 121 |
+
|
| 122 |
+
# Minimal adapter the processor expects
|
| 123 |
self.core_processor.models = type('FakeModelManager', (), {
|
| 124 |
'get_sam2': lambda self_: sam2_model,
|
| 125 |
'get_matanyone': lambda self_: matanyone_model
|
|
|
|
| 135 |
return None, "Models not loaded yet"
|
| 136 |
|
| 137 |
logger.info("process_video called (video=%s, bg_style=%s, custom_bg=%s)",
|
| 138 |
+
video, bg_style, getattr(custom_bg_file, "name", None) if custom_bg_file else None)
|
| 139 |
|
| 140 |
import time
|
| 141 |
output_path = f"/tmp/output_{int(time.time())}.mp4"
|
| 142 |
|
| 143 |
+
# Background config passed to the processor:
|
| 144 |
+
# - custom image via {"custom_path": "..."}
|
| 145 |
+
# - preset via {"background_choice": "<key>"}
|
| 146 |
if custom_bg_file:
|
| 147 |
+
bg_cfg = {"custom_path": custom_bg_file.name}
|
| 148 |
else:
|
| 149 |
+
style = bg_style if (bg_style in PROFESSIONAL_BACKGROUNDS) else "office"
|
| 150 |
+
bg_cfg = {"background_choice": style}
|
|
|
|
| 151 |
|
| 152 |
+
# Validate input video (utils.validate_video_file returns bool)
|
| 153 |
ok = validate_video_file(video)
|
| 154 |
if not ok:
|
| 155 |
logger.warning("Invalid/unreadable video: %s", video)
|
|
|
|
| 159 |
result = self.core_processor.process_video(
|
| 160 |
input_path=video,
|
| 161 |
output_path=output_path,
|
| 162 |
+
bg_config=bg_cfg
|
| 163 |
)
|
| 164 |
logger.info("Core processing done → %s", output_path)
|
| 165 |
|
|
|
|
| 193 |
video = gr.Video(label="Upload Video")
|
| 194 |
# Ensure default choice exists in PROFESSIONAL_BACKGROUNDS (use 'office')
|
| 195 |
choices = list(PROFESSIONAL_BACKGROUNDS.keys())
|
| 196 |
+
default_choice = "office" if "office" in choices else (choices[0] if choices else "office")
|
| 197 |
bg_style = gr.Dropdown(
|
| 198 |
choices=choices,
|
| 199 |
+
value=default_choice,
|
| 200 |
label="Background Style"
|
| 201 |
)
|
| 202 |
custom_bg = gr.File(label="Custom Background (Optional)", file_types=["image"])
|