from functools import lru_cache from pathlib import Path from pydantic import Field, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") app_name: str = "Fast RAG Chatbot" llm_provider: str = Field(default="openai", alias="LLM_PROVIDER") groq_api_key: str = Field(default="", alias="GROQ_API_KEY") groq_model: str = Field(default="qwen/qwen3-32b", alias="GROQ_MODEL") groq_rewrite_model: str = Field(default="llama-3.1-8b-instant", alias="GROQ_REWRITE_MODEL") fireworks_api_key: str = Field(default="", alias="FIREWORKS_API_KEY") fireworks_model: str = Field(default="accounts/fireworks/models/qwen3-30b-a3b-instruct-2507", alias="FIREWORKS_MODEL") fireworks_rewrite_model: str = Field(default="accounts/fireworks/models/qwen3-8b", alias="FIREWORKS_REWRITE_MODEL") openai_api_key: str = Field(default="", alias="OPENAI_API_KEY") openai_model: str = Field(default="gpt-4o-mini", alias="OPENAI_MODEL") openai_rewrite_model: str = Field(default="gpt-4o-mini", alias="OPENAI_REWRITE_MODEL") hf_api_key: str = Field(default="", alias="HF_API_KEY") hf_model: str = Field(default="meta-llama/Llama-3.1-8B-Instruct", alias="HF_MODEL") embedding_model: str = Field(default="BAAI/bge-small-en-v1.5", alias="EMBEDDING_MODEL") reranker_model: str = Field(default="cross-encoder/ms-marco-MiniLM-L-6-v2", alias="RERANKER_MODEL") docs_dir: Path = Field(default=Path("docs"), alias="DOCS_DIR") @model_validator(mode='after') def set_persistent_paths(self) -> 'Settings': # If we are on Hugging Face (detected by /data volume), # force use of /data for persistence regardless of other settings. if Path("/data").exists(): self.index_dir = Path("/data/index") self.sessions_dir = Path("/data/sessions") return self index_dir: Path = Field(default=Path("data/index"), alias="INDEX_DIR") sessions_dir: Path = Field(default=Path("data/sessions"), alias="SESSIONS_DIR") chunk_size_tokens: int = 350 # Reduced for TPM safety chunk_overlap_tokens: int = 80 top_k: int = Field(default=8, alias="TOP_K") # Focused retrieval — quality over quantity max_context_chunks: int = 5 # Enough for exhaustive lists, focused enough for precision request_timeout_s: float = 20.0 cors_allow_origins: str = Field(default="*", alias="CORS_ALLOW_ORIGINS") api_key: str = Field(default="", alias="API_KEY") rate_limit_requests: int = Field(default=60, alias="RATE_LIMIT_REQUESTS") rate_limit_window_seconds: int = Field(default=60, alias="RATE_LIMIT_WINDOW_SECONDS") # SMTP Settings for OTP smtp_server: str = Field(default="smtp.gmail.com", alias="SMTP_SERVER") smtp_port: int = Field(default=465, alias="SMTP_PORT") smtp_user: str = Field(default="", alias="SMTP_USER") smtp_pass: str = Field(default="", alias="SMTP_PASS") admin_email: str = Field(default="randomjoedown@gmail.com", alias="ADMIN_EMAIL") admin_user: str = Field(default="martech_admin", alias="ADMIN_USER") admin_pass: str = Field(default="martech_admin_303", alias="ADMIN_PASS") # WhatsApp API Settings (Meta Cloud API) meta_whatsapp_phone_id: str = Field(default="", alias="META_WHATSAPP_PHONE_ID") meta_whatsapp_token: str = Field(default="", alias="META_WHATSAPP_TOKEN") meta_whatsapp_admin_number: str = Field(default="", alias="META_WHATSAPP_ADMIN_NUMBER") @lru_cache def get_settings() -> Settings: return Settings()