"""Runtime configuration loaded from environment variables / .env. Portable across self-host setups: defaults to a local SQLite file so the app runs with zero external services, and switches to PostgreSQL automatically when DATABASE_URL points at postgres (e.g. inside docker-compose). """ from __future__ import annotations import os from functools import lru_cache from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def _load_dotenv(path: Path = ROOT / ".env") -> None: if not path.exists(): return for raw in path.read_text(encoding="utf-8").splitlines(): line = raw.strip() if not line or line.startswith("#") or "=" not in line: continue key, value = line.split("=", 1) key = key.strip() value = value.strip().strip('"').strip("'") if key and key not in os.environ: os.environ[key] = value _load_dotenv() class Settings: """Plain settings container (no extra dependency).""" def __init__(self) -> None: # Storage. Default = local SQLite (zero-config). Docker sets postgres URL. default_db = f"sqlite+aiosqlite:///{ROOT / 'data' / 'lograg.db'}" self.database_url: str = os.getenv("DATABASE_URL", default_db) # Optional LLM (RAG answer). System works fully offline without these. self.openrouter_api_key: str = os.getenv("OPENROUTER_API_KEY", "") self.openrouter_model: str = os.getenv("OPENROUTER_MODEL", "openrouter/free") self.openrouter_embed_model: str = os.getenv( "OPENROUTER_EMBED_MODEL", "nvidia/llama-nemotron-embed-vl-1b-v2:free" ) # Server self.host: str = os.getenv("HOST", "0.0.0.0") self.port: int = int(os.getenv("PORT", "8000")) # Realtime mock stream guardrails self.max_mock_burst: int = int(os.getenv("MAX_MOCK_BURST", "500")) self.max_csv_rows: int = int(os.getenv("MAX_CSV_ROWS", "50000")) @property def llm_ready(self) -> bool: return bool(self.openrouter_api_key) @property def is_postgres(self) -> bool: return self.database_url.startswith("postgres") @lru_cache(maxsize=1) def get_settings() -> Settings: settings = Settings() # Ensure local sqlite directory exists. if settings.database_url.startswith("sqlite"): (ROOT / "data").mkdir(parents=True, exist_ok=True) return settings