import logging import os import time from datetime import datetime, timezone from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent UPLOAD_DIR = BASE_DIR / "uploads" UPLOAD_DIR.mkdir(parents=True, exist_ok=True) VIDEO_UPLOAD_DIR = UPLOAD_DIR / "videos" VIDEO_UPLOAD_DIR.mkdir(parents=True, exist_ok=True) OUTPUT_DIR = BASE_DIR / "outputs" OUTPUT_DIR.mkdir(parents=True, exist_ok=True) VIDEO_OUTPUT_DIR = OUTPUT_DIR / "videos" VIDEO_OUTPUT_DIR.mkdir(parents=True, exist_ok=True) TEXTURE_DIR = BASE_DIR / "texturas" TEXTURE_DIR.mkdir(parents=True, exist_ok=True) LOG_DIR = BASE_DIR / "logs" LOG_DIR.mkdir(exist_ok=True) TEMPLATES_DIR = BASE_DIR / "templates" TEMPLATES_DIR.mkdir(parents=True, exist_ok=True) CLASSIC_DASHBOARD_HTML_PATH = TEMPLATES_DIR / "classic_dashboard.html" logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s", handlers=[ logging.FileHandler(LOG_DIR / "app.log", encoding="utf-8"), logging.StreamHandler(), ], ) logger = logging.getLogger("backend.segmentation") SAM2_CONFIG_PATH = os.getenv("SAM2_CONFIG_PATH", "configs/sam2.1/sam2.1_hiera_l.yaml") SAM2_MODEL_PATH = os.getenv("SAM2_MODEL_PATH") SAM2_DEFAULT_MODEL_NAMES = ( "sam2.1_hiera_large_fresh.pt", "sam2.1_hiera_large.pt", "sam2.1_hiera_large.pth", "sam2_hiera_large.pt", ) SAM2_MODEL_DIR_CANDIDATES = ("models", "modelo") SAM2_UNLOAD_AFTER_USE = str(os.getenv("SAM2_UNLOAD_AFTER_USE", "0")).strip().lower() in {"1", "true", "yes"} FRONTEND_DEBUG = str(os.getenv("FRONTEND_DEBUG", "0")).strip().lower() in {"1", "true", "yes", "on"} # URL del Space de Gradio GPU (principal). Si falla, se usa el CPU fallback. # Local: http://localhost:7860 # Producción: https://.hf.space GRADIO_SPACE_URL: str = os.getenv("GRADIO_SPACE_URL", "").rstrip("/") # URL del Space de Gradio CPU (respaldo automático si el GPU falla o agota quota). GRADIO_CPU_FALLBACK_URL: str = os.getenv("GRADIO_CPU_FALLBACK_URL", "").rstrip("/") MAX_UPLOAD_WIDTH = 1024 UPLOAD_JPEG_QUALITY = 82 SD_JOB_STALE_SECONDS = 120 UPLOAD_JOB_STALE_SECONDS = 900 UPLOAD_BASE_SECONDS = 8.0 UPLOAD_SECONDS_PER_MEGAPIXEL = 70.0 SD_QUICK_TIMEOUT_SECONDS = 15.0 SEMANTIC_MODEL_ID = "nvidia/segformer-b5-finetuned-ade-640-640" DEPTH_MODEL_ID = "Intel/dpt-hybrid-midas" def utc_now_iso() -> str: return datetime.now(timezone.utc).isoformat() def log_timing_start(step_name: str) -> float: started = time.perf_counter() logger.info(f"[{step_name}] START at {utc_now_iso()}") return started def log_timing_end(step_name: str, started: float) -> None: elapsed = time.perf_counter() - started logger.info(f"[{step_name}] DONE {elapsed:.3f}s at {utc_now_iso()}") def load_classic_dashboard_html() -> str: if not CLASSIC_DASHBOARD_HTML_PATH.exists() or not CLASSIC_DASHBOARD_HTML_PATH.is_file(): raise RuntimeError(f"Dashboard HTML template not found: {CLASSIC_DASHBOARD_HTML_PATH}") return CLASSIC_DASHBOARD_HTML_PATH.read_text(encoding="utf-8")