| from __future__ import annotations |
|
|
| import os |
| from dataclasses import dataclass |
| from pathlib import Path |
|
|
| from dotenv import load_dotenv |
|
|
|
|
| PROJECT_ROOT = Path(__file__).resolve().parents[1] |
| DATA_DIR = PROJECT_ROOT / "data" |
| IMAGE_DIR = DATA_DIR / "images" |
| FAVORITES_DIR = DATA_DIR / "favorites" |
| METADATA_CSV = DATA_DIR / "metadata.csv" |
| DEFAULT_NAMESPACE = "image-retrieval-lab3" |
| DEFAULT_MODEL_NAME = "sentence-transformers/clip-ViT-B-32" |
| ALL_CATEGORIES_LABEL = "All" |
| FAVORITES_ZIP_PATH = FAVORITES_DIR / "favorites.zip" |
|
|
|
|
| class ConfigurationError(RuntimeError): |
| """Raised when required runtime configuration is missing or invalid.""" |
|
|
|
|
| @dataclass(frozen=True) |
| class Settings: |
| project_root: Path |
| image_dir: Path |
| favorites_dir: Path |
| metadata_csv: Path |
| clip_model_name: str |
| upstash_url: str | None |
| upstash_token: str | None |
| upstash_namespace: str |
|
|
| def require_upstash(self) -> None: |
| missing = [] |
| if not self.upstash_url: |
| missing.append("UPSTASH_VECTOR_REST_URL") |
| if not self.upstash_token: |
| missing.append("UPSTASH_VECTOR_REST_TOKEN") |
| if missing: |
| joined = ", ".join(missing) |
| raise ConfigurationError( |
| f"Missing Upstash Vector configuration: {joined}. " |
| "Copy .env.example to .env and fill in your Upstash REST URL and token." |
| ) |
|
|
|
|
| def load_settings() -> Settings: |
| load_dotenv(PROJECT_ROOT / ".env") |
| return Settings( |
| project_root=PROJECT_ROOT, |
| image_dir=IMAGE_DIR, |
| favorites_dir=FAVORITES_DIR, |
| metadata_csv=METADATA_CSV, |
| clip_model_name=os.getenv("CLIP_MODEL_NAME", DEFAULT_MODEL_NAME), |
| upstash_url=os.getenv("UPSTASH_VECTOR_REST_URL"), |
| upstash_token=os.getenv("UPSTASH_VECTOR_REST_TOKEN"), |
| upstash_namespace=os.getenv("UPSTASH_VECTOR_NAMESPACE", DEFAULT_NAMESPACE), |
| ) |
|
|
|
|