MogensR's picture
Update app.py
89d63a7 verified
#!/usr/bin/env python3
"""
Hugging Face Spaces Entry Point
This file must remain in root for HF Spaces compatibility
Imports and runs the main application from core/app.py
"""
# --- BEGIN ABSOLUTE-IMPORT & ENV HOTFIX (Hugging Face) ---
import os, re, io, sys
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) # /home/user/app
# Ensure top-level packages are importable (utils, core, models, processing)
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)
# Quiet invalid OMP_NUM_THREADS warnings (libgomp)
val = os.environ.get("OMP_NUM_THREADS")
if val is not None and not str(val).strip().isdigit():
# Either unset or set to a safe default; we set to 1
os.environ["OMP_NUM_THREADS"] = "1"
def _patch_relative_imports(project_root: str):
"""
Rewrite 'from ..X.y' -> 'from X.y' for top-level packages.
Runs once at startup; safe/no-op if already fixed.
"""
skip_dirs = {"venv", ".git", "__pycache__"}
rx_from = re.compile(r"(?m)^from\s+\.+(utils|core|models|processing)\.")
touched = []
for root, dirs, files in os.walk(project_root):
# prune
dirs[:] = [d for d in dirs if d not in skip_dirs]
for fn in files:
if not fn.endswith(".py"):
continue
path = os.path.join(root, fn)
try:
with io.open(path, "r", encoding="utf-8") as f:
src = f.read()
new = rx_from.sub(r"from \1.", src)
if new != src:
with io.open(path, "w", encoding="utf-8") as f:
f.write(new)
touched.append(os.path.relpath(path, project_root))
except Exception:
# Don't block startup if a file can't be read/written
pass
if touched:
print(f"✅ Fixed relative imports in {len(touched)} file(s):")
for p in touched:
print(" -", p)
_patch_relative_imports(PROJECT_ROOT)
# --- END ABSOLUTE-IMPORT & ENV HOTFIX ---
# --- BEGIN robust compatibility: ensure 'utilities' references the real utils package ----------
# Some legacy modules import `utilities`. We will ensure sys.modules['utilities'] points
# to the same module object as 'utils' by:
# 1) Attempting a normal import of utils; if that works, alias it.
# 2) If normal import fails or would recurse, fall back to loading utils/__init__.py
# directly via importlib.util.spec_from_file_location, placing the module object
# into sys.modules BEFORE executing the module to avoid circular lazy-swaps.
import importlib
import importlib.util
from types import ModuleType
def _ensure_utilities_alias(project_root: str):
# If utilities already exists and isn't obviously broken, leave it alone.
if "utilities" in sys.modules and getattr(sys.modules["utilities"], "__name__", "").startswith("utils"):
return
# Try normal import first (fast path)
try:
_utils = importlib.import_module("utils")
sys.modules["utilities"] = _utils
return
except Exception:
# proceed to robust file-loader fallback below
pass
# Fallback: load utils package explicitly from filesystem using its __init__.py
utils_init = os.path.join(project_root, "utils", "__init__.py")
if not os.path.exists(utils_init):
# nothing we can do here — leave to normal import to raise error later
return
spec = importlib.util.spec_from_file_location("utils", utils_init)
if spec is None or spec.loader is None:
return
# Create the module object and put it in sys.modules BEFORE execution.
# This ensures imports within utils that examine sys.modules won't re-enter a cycle.
utils_mod = importlib.util.module_from_spec(spec)
sys.modules["utils"] = utils_mod
# Also alias utilities -> utils_mod so imports of utilities see the same module object.
sys.modules["utilities"] = utils_mod
# Execute the module (this will run utils/__init__.py)
try:
spec.loader.exec_module(utils_mod) # type: ignore[attr-defined]
except Exception:
# If execution fails, remove the partially-initialized entries so Python's import machinery can surface a clean error.
sys.modules.pop("utils", None)
sys.modules.pop("utilities", None)
raise
# Ensure alias early, before importing core
_ensure_utilities_alias(PROJECT_ROOT)
# --- END robust compatibility ------------------------------------------------
# Import the main application from core
from core.app import (
VideoProcessor,
processor,
load_models_with_validation,
process_video_fixed,
get_model_status,
get_cache_status,
PROCESS_CANCELLED,
main,
)
# Re-export for backward compatibility
__all__ = [
"VideoProcessor",
"processor",
"load_models_with_validation",
"process_video_fixed",
"get_model_status",
"get_cache_status",
"PROCESS_CANCELLED",
"main",
]
# Entry point for Hugging Face Spaces
if __name__ == "__main__":
main()