Spaces:
Sleeping
Sleeping
| """ | |
| config.py β Centralised, validated configuration using Pydantic Settings. | |
| All values are read from environment variables (or .env file). | |
| Import the singleton `settings` anywhere in the project. | |
| """ | |
| from functools import lru_cache | |
| from typing import Literal | |
| from pydantic import Field, field_validator | |
| from pydantic_settings import BaseSettings, SettingsConfigDict | |
| class Settings(BaseSettings): | |
| model_config = SettingsConfigDict( | |
| env_file=".env", | |
| env_file_encoding="utf-8", | |
| case_sensitive=False, | |
| extra="ignore", | |
| ) | |
| # ββ LLM ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| groq_api_key: str = Field(..., description="Groq API key (free tier)") | |
| llm_model: str = Field("llama-3.3-70b-versatile", description="Groq chat model") | |
| stt_model: str = Field("whisper-large-v3-turbo", description="Groq Whisper STT model") | |
| tts_voice: str = Field("en-US-JennyNeural", description="Edge-TTS voice") | |
| # ββ RAG βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| chroma_persist_dir: str = Field("./data/chroma_db") | |
| embedding_model: str = Field("all-MiniLM-L6-v2") | |
| docs_dir: str = Field("./data/sample_files") | |
| chunk_size: int = Field(500, ge=100, le=4000) | |
| chunk_overlap: int = Field(50, ge=0, le=500) | |
| # ββ MCP Server ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| mcp_server_host: str = Field("0.0.0.0") | |
| mcp_server_port: int = Field(8000, ge=1024, le=65535) | |
| mcp_transport: Literal["sse", "stdio"] = Field("sse") | |
| # ββ SQLite ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| sqlite_db_path: str = Field("./data/database.db") | |
| # ββ Audio βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| audio_sample_rate: int = Field(16000) | |
| audio_channels: int = Field(1) | |
| audio_silence_threshold: int = Field(500) | |
| audio_silence_duration_sec: float = Field(1.5) | |
| audio_min_speech_duration_sec: float = Field(0.5) | |
| # ββ App βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| app_env: Literal["development", "production"] = Field("development") | |
| log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = Field("INFO") | |
| log_format: Literal["json", "console"] = Field("console") | |
| def overlap_less_than_chunk(cls, v: int, info) -> int: | |
| chunk_size = info.data.get("chunk_size", 500) | |
| if v >= chunk_size: | |
| raise ValueError("chunk_overlap must be less than chunk_size") | |
| return v | |
| # NEW β works both locally and on HF Spaces | |
| def mcp_server_url(self) -> str: | |
| if self.is_production: | |
| return f"https://{self.mcp_server_host}/sse" | |
| return f"http://localhost:{self.mcp_server_port}/sse" | |
| def is_production(self) -> bool: | |
| return self.app_env == "production" | |
| def get_settings() -> Settings: | |
| """Return the cached Settings singleton.""" | |
| return Settings() # type: ignore[call-arg] | |
| # Convenience singleton β import this everywhere | |
| settings = get_settings() | |