Files
immich-photo-flow/apps/trip-cluster/app/config.py
T
m038 1a6afe86fc fix(review): operator-agnostic sanity check + invariant TODOs + dedupe
Code-review follow-ups on the pgvector spike:
- self-similarity sanity check now compares to the seed's own self-distance
  (0 for cosine/L2, ~-1 for inner product <#>) instead of a hardcoded ~0, so it
  no longer misfires if Immich ever uses a vector_ip_ops index (correctness P3).
- mark the deliberate raw-SQLite read in the probe as a spike-only exception and
  add an M1.5 TODO that the real pgvector reader belongs in shared/photoflow/immich
  and SQLite access in shared/photoflow/core (project-standards P2 x2).
- document join_and_coverage's return shape; extract a _pct() helper to dedupe the
  coverage-percentage formatting (maintainability P3 x2).
Findings doc refreshed from the latest live run (coverage now ~46%, re-run ongoing).
2026-06-27 20:50:06 +02:00

50 lines
1.7 KiB
Python

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.
# M1.5 TODO: the actual pgvector reader belongs in shared/photoflow/immich
# (the only Immich client, per CLAUDE.md) — this field only carries the DSN.
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,
)