File size: 3,552 Bytes
53b8def
 
0e11366
5a4439e
d51358c
53b8def
d51358c
71c1c9d
d51358c
 
53b8def
 
 
 
 
 
 
 
 
 
deb575f
53b8def
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71c1c9d
 
 
d51358c
 
 
0e11366
 
71c1c9d
 
 
 
 
 
 
 
0e11366
 
 
 
5a4439e
 
 
 
 
 
 
 
 
 
53b8def
d51358c
53b8def
 
 
d51358c
0e11366
71c1c9d
d51358c
0e11366
 
 
5a4439e
d51358c
 
 
 
 
53b8def
 
 
 
 
 
 
 
 
7d9d335
 
deb575f
53b8def
 
 
 
 
0e11366
53b8def
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
# backend/app/config/settings.py
from __future__ import annotations
from pathlib import Path
from pydantic import Field, AliasChoices
from pydantic_settings import BaseSettings, SettingsConfigDict
import os, tempfile

# Resolve repo root no matter where uvicorn is launched from
REPO_ROOT = Path(__file__).resolve().parents[3]

def _try_writable(p: Path) -> Path | None:
    try:
        p.mkdir(parents=True, exist_ok=True)
        t = p / ".write_test"
        t.write_text("ok", encoding="utf-8")
        t.unlink(missing_ok=True)
        return p.resolve()
    except Exception:
        return None

def _default_data_dir() -> Path:
    """
    HF Spaces:
      - /data is writable & persisted across restarts
      - /app is read-only (repo checkout)
    Order:
      1) DATA_DIR env (if set)
      2) /data
      3) <repo>/data
      4) temp dir
    """
    candidates: list[Path] = []
    env = os.getenv("DATA_DIR")
    if env:
        candidates.append(Path(env))
    candidates.append(Path("/data"))
    candidates.append(REPO_ROOT / "data")
    candidates.append(Path(tempfile.gettempdir()) / "pulsemaps" / "data")

    for p in candidates:
        w = _try_writable(p)
        if w:
            return w
    raise RuntimeError(f"No writable DATA_DIR found. Tried: {candidates!r}")

def _default_uploads_dir() -> Path:
    return (_default_data_dir() / "uploads").resolve()

def _default_frontend_dist() -> Path:
    return (REPO_ROOT / "web" / "dist").resolve()

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        extra="ignore",
        case_sensitive=False,
        populate_by_name=True,
    )

    # Models / API keys
    OPENAI_API_KEY: str | None = None
    OPENAI_MODEL_AGENT: str = "gpt-4o"
    OPENAI_MODEL_CLASSIFIER: str = "gpt-4o-mini"

    # ✅ Google Maps (read from multiple env names for safety)
    google_maps_api_key: str | None = Field(
        default=None,
        validation_alias=AliasChoices("VITE_GOOGLE_MAPS_API_KEY", "GOOGLE_MAPS_API_KEY"),
    )
    google_maps_map_id: str | None = Field(
        default=None,
        validation_alias=AliasChoices("VITE_GOOGLE_MAPS_MAP_ID", "VITE_GOOGLE_MAPS_MAP_IDY", "GOOGLE_MAPS_MAP_ID"),
    )

    # Paths
    DATA_DIR: Path = Field(default_factory=_default_data_dir)
    REPORTS_DB: Path | None = None
    SESSIONS_DB: Path | None = None
    UPLOADS_DIR: Path | None = None
    FRONTEND_DIST: Path = Field(default_factory=_default_frontend_dist)

    # Defaults
    DEFAULT_RADIUS_KM: float = 40.0
    DEFAULT_LIMIT: int = 10
    MAX_AGE_HOURS: int = 48

    # Optional extras
    firms_map_key: str | None = None
    gdacs_rss_url: str | None = "https://www.gdacs.org/xml/rss.xml"
    nvidia_api_key: str | None = None

    def ensure_dirs(self) -> None:
        # Fill derived paths if not explicitly provided
        if self.REPORTS_DB is None:
            self.REPORTS_DB = self.DATA_DIR / "pulsemaps_reports.db"
        if self.SESSIONS_DB is None:
            self.SESSIONS_DB = self.DATA_DIR / "pulsemap_sessions.db"
        if self.UPLOADS_DIR is None:
            self.UPLOADS_DIR = self.DATA_DIR / "uploads"

        # Create & resolve
        self.DATA_DIR.mkdir(parents=True, exist_ok=True)
        self.UPLOADS_DIR.mkdir(parents=True, exist_ok=True)

        self.DATA_DIR = self.DATA_DIR.resolve()
        self.REPORTS_DB = self.REPORTS_DB.resolve()
        self.SESSIONS_DB = self.SESSIONS_DB.resolve()
        self.UPLOADS_DIR = self.UPLOADS_DIR.resolve()

settings = Settings()
settings.ensure_dirs()