from pydantic_settings import BaseSettings from functools import lru_cache import os from pathlib import Path # Calculate the project root (tipitaka-api folder) PROJECT_ROOT = Path(__file__).resolve().parent.parent # Detect Data Directory # 1. Environment variable DATA_DIR # 2. Docker standard path /app/data (Only if on Linux/Docker) # 3. Local project 'data' folder # Detect Data Directory if os.getenv("DATA_DIR"): DATA_DIR_DEFAULT = os.getenv("DATA_DIR") elif os.name != 'nt' and os.path.exists("/app/data"): DATA_DIR_DEFAULT = "/app/data" else: # Use 'data' folder in project root as default DATA_DIR_DEFAULT = str(PROJECT_ROOT / "data") DATA_DIR = Path(DATA_DIR_DEFAULT) class Settings(BaseSettings): """Application settings — loaded from .env file or environment variables.""" # ── LLM Provider ── LLM_API_KEY: str = "" LLM_BASE_URL: str = "https://api.deepseek.com" LLM_MODEL_FAST: str = "deepseek-chat" LLM_MODEL_REASONER: str = "deepseek-reasoner" # ── Paths ── DATA_DIR: str = str(DATA_DIR) DATABASE_PATH: str = "" QDRANT_PATH: str = "" SNAPSHOT_DIR: str = "" QDRANT_URL: str | None = None ST_EMBED_MODEL: str = "jinaai/jina-embeddings-v5-text-small-retrieval" QDRANT_COLLECTION: str = "tipitaka_chunks" def __init__(self, **values): super().__init__(**values) data_path = Path(self.DATA_DIR) rag_root = PROJECT_ROOT.parent.parent # F:\_Ai\Tipitaka-AI-Expert\RAG # Initialize paths if not explicitly provided if not self.DATABASE_PATH: # Priority: 1. data/tipitaka_mcu.db, 2. RAG_ROOT/tipitaka_mcu.db local_db = data_path / "tipitaka_mcu.db" root_db = rag_root / "tipitaka_mcu.db" if local_db.exists(): self.DATABASE_PATH = str(local_db) elif root_db.exists(): self.DATABASE_PATH = str(root_db) else: self.DATABASE_PATH = str(local_db) # Fallback if not self.QDRANT_PATH: self.QDRANT_PATH = str(data_path / "qdrant_storage") if not self.SNAPSHOT_DIR: # Priority: 1. DATA_DIR/snapshots, 2. RAG_ROOT/snapshots local_snapshots = data_path / "snapshots" root_snapshots = rag_root / "snapshots" if local_snapshots.exists(): self.SNAPSHOT_DIR = str(local_snapshots) elif root_snapshots.exists(): self.SNAPSHOT_DIR = str(root_snapshots) else: self.SNAPSHOT_DIR = str(local_snapshots) # Fallback # ── CORS ── CORS_ORIGINS: str = "*" # ── Discord Webhook (health alerts) ── DISCORD_WEBHOOK_URL: str = "" DEBUG: bool = True PORT: int = 8000 # ── Production static file serving ── SERVE_STATIC: bool = False STATIC_DIR: str = "" class Config: env_file = ".env" env_file_encoding = "utf-8" extra = "ignore" @lru_cache() def get_settings() -> Settings: return Settings()