""" Global configuration for Core Code API All configuration is loaded from environment variables or .env file. See .env.example for available settings. """ import tomllib from pathlib import Path from pydantic_settings import BaseSettings from functools import lru_cache def _get_version_from_pyproject() -> str: """Load version from pyproject.toml""" pyproject_path = Path(__file__).parent.parent / "pyproject.toml" try: with open(pyproject_path, "rb") as f: data = tomllib.load(f) return data.get("project", {}).get("version", "0.0.0") except FileNotFoundError: return "0.0.0" __version__ = _get_version_from_pyproject() class Settings(BaseSettings): """Global application settings""" # Application app_name: str = "Core Code API" app_version: str = __version__ debug: bool = False # Server host: str = "0.0.0.0" port: int = 8083 # CORS cors_origins: list[str] = ["*"] cors_credentials: bool = True cors_methods: list[str] = ["*"] cors_headers: list[str] = ["*"] # Logging log_level: str = "DEBUG" # Ollama Configuration (for AI orchestration) ollama_base_url: str = "http://ollama:11434" ollama_timeout: int = 300 # 5 minutes # Model Configuration default_model: str = "mistral-tools:7b" agent_model: str = "gemma2:9b-instruct-q5_K_M" # Must support tool calling with ADK (~4GB VRAM) lightweight_models: str = "gemma3-tools:1b,phi3:mini" heavy_models: str = "mistral:7b,gemma2:9b,gemma3:12b,mixtral:8x7b" code_models: str = "codestral:latest,codegemma:latest" # Previous config (gemma3:12b used ~10GB VRAM) # default_model: str = "gemma3:12b" # agent_model: str = "gemma3:12b" # System Prompt Variant (for A/B testing) # Options: v1_verbose, v2_concise, v3_imperative, v4_minimal, v4_gemini_suggestion, v5_adk_optimized, v7_adk_best_practice, v8_holistic system_prompt_variant: str = "v8_holistic" # Agent Configuration agent_fallback_enabled: bool = True # Model Aliases (OpenAI → Local) alias_gpt35: str = "gemma:7b" alias_gpt4: str = "mistral:7b" alias_gpt4_turbo: str = "mixtral:8x7b" alias_gpt4_code: str = "codestral:latest" # Memory Configuration memory_tier1_max_turns: int = 10 memory_consolidation_threshold: int = 10 # Qdrant Configuration qdrant_host: str = "qdrant" qdrant_port: int = 6333 qdrant_collection_conversations: str = "core_api_conversations" qdrant_collection_documents: str = "core_api_documents" qdrant_collection_user_facts: str = "core_api_user_facts" # Embeddings (using Ollama - no local models needed) embedding_model: str = "nomic-embed-text" # Ollama embedding model embedding_dimension: int = 768 # nomic-embed-text dimension embedding_batch_size: int = 32 # Search Configuration search_provider: str = "searxng" searxng_url: str = "http://searxng:8080" # Infrastructure Management (Portainer) portainer_url: str = "http://portainer:9000" portainer_api_key: str = "" # Infrastructure Management (Nginx Proxy Manager) npm_url: str = "http://npm:81" npm_email: str = "" npm_password: str = "" # Home Assistant Configuration homeassistant_url: str = "http://homeassistant:8123" homeassistant_token: str = "" homeassistant_timeout: int = 30 # Core-AI Service (AI performance metrics) core_ai_base_url: str = "http://core-ai:8086" # OIDC Authentication (Authentik) oidc_enabled: bool = False # Set to True to require authentication oidc_issuer: str = "https://auth.schweitz.net/application/o/core-api/" oidc_audience: str = "core-api" @property def model_aliases(self) -> dict: """Computed property for model aliases""" return { "gpt-3.5-turbo": self.alias_gpt35, "gpt-4": self.alias_gpt4, "gpt-4-turbo": self.alias_gpt4_turbo, "gpt-4-code": self.alias_gpt4_code, } def get_lightweight_models(self) -> list[str]: """Parse comma-separated lightweight models""" return [m.strip().strip('"').strip("'") for m in self.lightweight_models.split(",") if m.strip()] def get_heavy_models(self) -> list[str]: """Parse comma-separated heavy models""" return [m.strip().strip('"').strip("'") for m in self.heavy_models.split(",") if m.strip()] def get_code_models(self) -> list[str]: """Parse comma-separated code models""" return [m.strip().strip('"').strip("'") for m in self.code_models.split(",") if m.strip()] class Config: env_file = ".env" case_sensitive = False extra = "ignore" # Ignore extra env vars not defined in Settings @lru_cache() def get_settings() -> Settings: """Cached settings instance""" return Settings()