Spaces:
Sleeping
Sleeping
File size: 4,374 Bytes
41d16b3 333dd2f 41d16b3 8354653 70d9e6c 8354653 41d16b3 70d9e6c 4595db8 333dd2f 8354653 214c544 333dd2f 214c544 333dd2f 214c544 333dd2f 214c544 8354653 333dd2f 4595db8 41d16b3 4595db8 41d16b3 995884c c9672b1 995884c 41d16b3 333dd2f 41d16b3 4595db8 333dd2f 4595db8 333dd2f 4595db8 c9672b1 41d16b3 5ae5432 99e1f27 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import os
from pathlib import Path
from typing import List
from ..database import DATA_DIR
APP_MODE_RAW = os.environ.get("APP_MODE", "").strip().lower()
_SPACE_ID = os.environ.get("SPACE_ID", "").strip().lower()
def is_hf_hosted() -> bool:
return bool(_SPACE_ID)
def _is_dda_mode() -> bool:
if APP_MODE_RAW == "legacy":
return False
if APP_MODE_RAW == "dda":
return True
# APP_MODE unset: auto-enable on satdetect-dev only (production satdetect stays legacy)
return _SPACE_ID.endswith("/satdetect-dev")
def get_public_base_url() -> str:
"""Public URL for deep links (email, share). Override with PUBLIC_BASE_URL."""
explicit = os.environ.get("PUBLIC_BASE_URL", "").strip().rstrip("/")
if explicit:
return explicit
if _SPACE_ID:
return f"https://{_SPACE_ID.replace('/', '-')}.hf.space"
return "http://localhost:7860"
IS_DDA_MODE = _is_dda_mode()
APP_MODE = APP_MODE_RAW or ("dda" if IS_DDA_MODE else "legacy")
# Project root: change_detection_webapp/
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
def get_writable_library_root() -> Path:
"""Persistent folder for uploads (HF: /home/appuser/data/library_sources)."""
return (DATA_DIR / "library_sources").resolve()
def get_storage_root() -> Path:
"""Tree library root (doc: root_directory / STORAGE_ROOT)."""
explicit = os.environ.get("STORAGE_ROOT", "").strip()
if explicit:
return Path(explicit).resolve()
if os.environ.get("LOCAL_LIBRARY_ROOT"):
return Path(os.environ["LOCAL_LIBRARY_ROOT"]).resolve()
return get_writable_library_root()
def get_library_roots() -> List[Path]:
"""Folders scanned for library images (tree storage root)."""
roots: List[Path] = []
sr = get_storage_root()
if sr not in roots:
roots.append(sr)
if os.environ.get("LOCAL_LIBRARY_ROOT"):
p = Path(os.environ["LOCAL_LIBRARY_ROOT"]).resolve()
if p not in roots:
roots.append(p)
if is_hf_hosted():
wr = get_writable_library_root()
if wr not in roots:
roots.append(wr)
for candidate in (get_writable_library_root(), PROJECT_ROOT / "library_sources"):
resolved = candidate.resolve()
if resolved not in roots:
roots.append(resolved)
return roots
# Primary root (shown in UI) — first entry from get_library_roots()
LOCAL_LIBRARY_ROOT = get_library_roots()[0]
LIBRARY_DIR = DATA_DIR / "library"
THUMBS_DIR = LIBRARY_DIR / "thumbs"
PREVIEWS_DIR = LIBRARY_DIR / "previews"
LOCAL_THUMB_CACHE = DATA_DIR / "library_cache" / "thumbs"
# Library upload limit (default 15 GB; override with MAX_GEOTIFF_MB / MAX_IMAGE_MB)
_MAX_UPLOAD_MB_DEFAULT = "15360" # 15 * 1024
MAX_GEOTIFF_BYTES = int(os.environ.get("MAX_GEOTIFF_MB", _MAX_UPLOAD_MB_DEFAULT)) * 1024 * 1024
# PNG/JPEG use the same cap unless MAX_IMAGE_MB is set separately
MAX_IMAGE_BYTES = int(os.environ.get("MAX_IMAGE_MB", _MAX_UPLOAD_MB_DEFAULT)) * 1024 * 1024
ALLOWED_EXTENSIONS = {".tif", ".tiff", ".png", ".jpg", ".jpeg"}
def ensure_library_dirs() -> None:
for root in get_library_roots():
try:
root.mkdir(parents=True, exist_ok=True)
except OSError:
pass
for d in (LIBRARY_DIR, THUMBS_DIR, PREVIEWS_DIR, LOCAL_THUMB_CACHE):
try:
d.mkdir(parents=True, exist_ok=True)
except OSError:
pass
def ensure_local_year_folders() -> None:
"""Create default year folders under each library root if missing."""
from datetime import datetime
current = datetime.now().year
for root in get_library_roots():
for year in (current - 1, current, current + 1):
try:
(root / str(year)).mkdir(parents=True, exist_ok=True)
except OSError:
pass
def max_upload_bytes_for_extension(ext: str) -> int:
if ext in (".tif", ".tiff"):
return MAX_GEOTIFF_BYTES
return MAX_IMAGE_BYTES
def geotiff_io_available() -> bool:
try:
import rasterio # noqa: F401
return True
except ImportError:
return False
def get_detection_max_side() -> int:
"""Max pixel dimension for GeoTIFF load + detection pipeline (higher = sharper, more RAM)."""
from ..detection_config import get_detection_max_side as _central
return _central()
|