"""Application settings. Every setting can be overridden with an environment variable prefixed ``BOR_`` (or a local gitignored ``.env`` file — see ``.env.example``). """ from __future__ import annotations import os from functools import lru_cache from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", env_prefix="BOR_", extra="ignore", ) # --- App --- app_name: str = "Brain of Reese" app_version: str = "0.1.0" environment: str = "development" log_level: str = "INFO" static_dir: str = "frontend" # --- Database (PostgreSQL 17 + pgvector) --- database_url: str = "postgresql+psycopg://reese:reese@localhost:5432/brain_of_reese" # --- LLM (self-hosted, OpenAI-compatible "aipi" endpoint) --- llm_base_url: str = "https://aipi.reeseapps.com/v1" llm_api_key: str = "" llm_chat_model: str = "turbo" llm_embed_model: str = "embed" # --- RAG tuning --- embedding_dim: int = 768 # verified against aipi /v1 (embed model) top_k_chunks: int = 4 top_n_docs: int = 2 relevance_threshold: float = 0.30 max_context_chars: int = 24_000 chunk_target_chars: int = 2_000 chunk_overlap_chars: int = 200 embed_batch_size: int = 16 # Suggested questions (onboarding + empty state). suggestions: list[str] = [ "How is my Kubernetes cluster set up?", "What's my backup strategy?", "How do I deploy a new service?", "What's currently running in the homelab?", ] @property def effective_api_key(self) -> str: """API key for aipi: explicit setting, then $AIPI_KEY, then a placeholder.""" return self.llm_api_key or os.environ.get("AIPI_KEY", "") or "not-needed" @lru_cache def get_settings() -> Settings: return Settings()