Spaces:
Sleeping
Sleeping
| from typing import Literal, Optional | |
| from pydantic_settings import BaseSettings, SettingsConfigDict | |
| class Settings(BaseSettings): | |
| model_config = SettingsConfigDict( | |
| env_file=".env", | |
| env_file_encoding="utf-8", | |
| extra="ignore", | |
| ) | |
| # App mode β "demo" (seeded showcase) or "personal" (real financial data) | |
| app_mode: Literal["demo", "personal"] = "personal" | |
| # Database β auto-reads DB_HOST, DB_PORT, etc. from .env | |
| db_host: str = "localhost" | |
| db_port: int = 5432 | |
| db_name: str = "financial_db" # fallback; overridden by resolved_db_name | |
| db_name_demo: str = "cashy_demo" | |
| db_name_personal: str = "financial_db" | |
| db_user: str = "financial_advisor" | |
| db_password: str = "" | |
| db_sslmode: str = "" # "require" for Neon; empty for local | |
| # LLM provider β set explicitly or auto-detected from API keys | |
| llm_provider: Optional[Literal["openai", "anthropic", "google", "huggingface", "free-tier", ""]] = None | |
| # Per-provider API keys (only one needed) | |
| openai_api_key: str = "" | |
| anthropic_api_key: str = "" | |
| google_api_key: str = "" | |
| hf_token: str = "" | |
| # Model configuration | |
| model_name: str = "" # Optional override; defaults per provider | |
| model_max_tokens: int = 512 | |
| model_temperature: float = 0.1 | |
| # HuggingFace-specific | |
| hf_inference_provider: str = "together" | |
| # LangSmith β auto-reads LANGSMITH_* from .env | |
| langsmith_tracing: str = "true" | |
| langsmith_api_key: str = "" | |
| langsmith_project: str = "cashy-financial-advisor" | |
| # App | |
| environment: str = "development" | |
| debug: bool = True | |
| def resolved_db_name(self) -> str: | |
| """Return the database name based on app_mode.""" | |
| if self.app_mode == "demo": | |
| return self.db_name_demo | |
| return self.db_name_personal | |
| def database_url(self) -> str: | |
| """Build DATABASE_URL from individual DB components.""" | |
| url = ( | |
| f"postgresql://{self.db_user}:{self.db_password}" | |
| f"@{self.db_host}:{self.db_port}/{self.resolved_db_name}" | |
| ) | |
| if self.db_sslmode: | |
| url += f"?sslmode={self.db_sslmode}" | |
| return url | |
| def database_url_safe(self) -> str: | |
| """Database URL with password redacted for logging.""" | |
| return self.database_url.replace(f":{self.db_password}@", ":***@") | |
| def resolved_provider(self) -> Optional[str]: | |
| """Return the active LLM provider: explicit setting, auto-detected from keys, or None.""" | |
| if self.llm_provider and self.llm_provider != "": | |
| return self.llm_provider | |
| # Auto-detect from populated API keys (priority order) | |
| if self.openai_api_key and self.openai_api_key != "sk-...": | |
| return "openai" | |
| if self.anthropic_api_key and self.anthropic_api_key != "sk-ant-...": | |
| return "anthropic" | |
| if self.google_api_key and self.google_api_key != "AI...": | |
| return "google" | |
| if self.hf_token and self.hf_token != "hf_...": | |
| # In demo mode, default to free-tier (user can switch to huggingface BYOK) | |
| if self.app_mode == "demo": | |
| return "free-tier" | |
| return "huggingface" | |
| return None | |
| settings = Settings() | |