import os from dataclasses import dataclass from typing import Mapping, Optional REQUIRED = ["IMMICH_URL", "IMMICH_API_KEY"] class ConfigError(Exception): def __init__(self, missing: list): self.missing = missing super().__init__(f"Missing required environment variables: {', '.join(missing)}") @dataclass class Config: immich_url: str immich_api_key: str anthropic_api_key: str data_dir: str # Postgres DSN for read-only access to Immich's pgvector embeddings. # Optional: only the pgvector spike / M1.5 visual-similarity work needs it; # REST creds (immich_url/api_key) stay required. immich_db_url: Optional[str] = None @property def db_path(self) -> str: return os.path.join(self.data_dir, "trip-cluster.db") @property def thumbs_dir(self) -> str: return os.path.join(self.data_dir, "thumbs") def load_config(env: Optional[Mapping] = None) -> Config: env = env if env is not None else os.environ missing = [k for k in REQUIRED if not (env.get(k) or "").strip()] if missing: raise ConfigError(missing) data_dir = (env.get("DATA_DIR") or "").strip() or os.path.join(os.getcwd(), "data") immich_db_url = (env.get("IMMICH_DB_URL") or "").strip() or None return Config( immich_url=env["IMMICH_URL"].strip().rstrip("/"), immich_api_key=env["IMMICH_API_KEY"].strip(), anthropic_api_key=(env.get("ANTHROPIC_API_KEY") or "").strip(), data_dir=data_dir, immich_db_url=immich_db_url, )