from __future__ import annotations from functools import lru_cache from pathlib import Path from typing import Literal from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", extra="ignore", ) ai_host: str = "0.0.0.0" ai_port: int = 8001 demo_mode: Literal["demo", "real", "auto"] = "auto" yolo_weights: str = "" llm_base_url: str = "https://api.deepseek.com" llm_api_key: str = "" llm_model: str = "deepseek-chat" llm_temperature: float = 0.3 knowledge_dir: str = "./app/knowledge" vector_dir: str = "./data/vectorstore" @property def root_dir(self) -> Path: return Path(__file__).resolve().parent.parent def resolve_path(self, value: str) -> Path: p = Path(value) if p.is_absolute(): return p return (self.root_dir / p).resolve() @property def knowledge_path(self) -> Path: return self.resolve_path(self.knowledge_dir) @property def vector_path(self) -> Path: return self.resolve_path(self.vector_dir) @property def yolo_weights_path(self) -> Path | None: if not self.yolo_weights or not self.yolo_weights.strip(): return None path = self.resolve_path(self.yolo_weights.strip()) return path if path.is_file() else None @property def llm_enabled(self) -> bool: return bool(self.llm_api_key and self.llm_api_key.strip()) @lru_cache def get_settings() -> Settings: return Settings()