Spaces:
Running
Running
feat: implement Search Architecture V3 (Hybrid search with Qwen query transformation, batch embeddings, batch Qdrant searches, and optimized CPU reranking)
c6f014f | 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" | |
| def get_settings() -> Settings: | |
| return Settings() | |