""" Centralized path management for persistent model storage. HF Spaces mounts persistent storage at /data. Local development falls back to ~/.cache/ocr-demo so model downloads survive app restarts. """ from __future__ import annotations import os from pathlib import Path _IS_HF_SPACE = os.path.isdir("/data") or os.environ.get("SPACE_ID") is not None if _IS_HF_SPACE: _BASE = Path("/data") else: _BASE = Path(os.getenv("OCR_DEMO_CACHE_DIR", Path.home() / ".cache" / "ocr-demo")) PATHS = { "hf_home": _BASE / "huggingface", "tmp": Path("/tmp") / "ocr-demo", } def ensure_dirs() -> None: for path in PATHS.values(): path.mkdir(parents=True, exist_ok=True) def get_env_overrides() -> dict[str, str]: hf_home = PATHS["hf_home"] return { "HF_HOME": str(hf_home), "HUGGINGFACE_HUB_CACHE": str(hf_home / "hub"), "TRANSFORMERS_CACHE": str(hf_home / "hub"), "HF_XET_HIGH_PERFORMANCE": os.getenv("HF_XET_HIGH_PERFORMANCE", "1"), "CUDA_VISIBLE_DEVICES": os.getenv("CUDA_VISIBLE_DEVICES", ""), "PYTHONUNBUFFERED": "1", } def is_model_cached(model_id: str) -> bool: repo_dir = f"models--{model_id.replace('/', '--')}" snapshots = PATHS["hf_home"] / "hub" / repo_dir / "snapshots" if not snapshots.exists(): return False weight_patterns = ( "model*.safetensors", "*.safetensors", "pytorch_model*.bin", "model*.bin", "*.gguf", ) for snapshot in snapshots.iterdir(): if not snapshot.is_dir(): continue for pattern in weight_patterns: if any(snapshot.glob(pattern)): return True return False def storage_info() -> dict: import shutil info = { "environment": "HuggingFace Spaces" if _IS_HF_SPACE else "Local Dev", "base_path": str(_BASE), "paths": {k: str(v) for k, v in PATHS.items()}, } if _BASE.exists(): total, used, free = shutil.disk_usage(str(_BASE)) info["disk"] = { "total_gb": round(total / 1e9, 2), "used_gb": round(used / 1e9, 2), "free_gb": round(free / 1e9, 2), } return info