"""Runtime paths and shared execution controls for the Space.""" import os import tempfile import threading import warnings from pathlib import Path APP_ROOT = Path(__file__).resolve().parent def _usable_root(path: Path, *, warn: bool = False) -> Path | None: try: path.mkdir(parents=True, exist_ok=True) probe = path / ".write_probe" probe.write_text("ok", encoding="utf-8") probe.unlink(missing_ok=True) return path except OSError as exc: if warn: warnings.warn(f"Runtime storage path is not writable: {path} ({exc})") return None def _select_storage_root() -> Path: configured = ( os.environ.get("MOMSVOICE_STORAGE_DIR") or os.environ.get("SPACE_STORAGE_DIR") ) candidates: list[tuple[Path, bool]] = [] if configured: candidates.append((Path(configured).expanduser(), True)) candidates.extend([ (Path("/data") / "momsvoice", False), (APP_ROOT, True), (Path(tempfile.gettempdir()) / "momsvoice", True), ]) for candidate, warn in candidates: usable = _usable_root(candidate, warn=warn) if usable is not None: return usable raise RuntimeError("No writable runtime storage path is available.") STORAGE_ROOT = _select_storage_root() VOICE_PROFILE_DIR = STORAGE_ROOT / "Voice_Profile" AUDIO_CACHE_DIR = STORAGE_ROOT / "audio_cache" SAMPLE_SOUNDS_DIR = STORAGE_ROOT / "sample_sounds" for _path in (VOICE_PROFILE_DIR, AUDIO_CACHE_DIR, SAMPLE_SOUNDS_DIR): _path.mkdir(parents=True, exist_ok=True) # Serializes GPU-heavy model calls across Gradio events and background pregen # threads. This keeps the Space responsive under hackathon demo traffic. GPU_INFERENCE_LOCK = threading.RLock() def gradio_allowed_paths() -> list[str]: return [ str(APP_ROOT / "assets"), str(SAMPLE_SOUNDS_DIR), ]