Files
fund-tracer/backend/app/config.py

95 lines
2.7 KiB
Python
Raw Normal View History

2026-03-09 14:46:56 +08:00
"""Application configuration from environment + runtime overrides."""
from functools import lru_cache
from pathlib import Path
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
"""App settings loaded from env."""
app_name: str = "Fund Tracer API"
debug: bool = False
# Database
database_url: str = "sqlite+aiosqlite:///./fund_tracer.db"
# Uploads
upload_dir: Path = Path("./uploads")
max_upload_size_mb: int = 20
allowed_extensions: set[str] = {"png", "jpg", "jpeg", "webp"}
# LLM
llm_provider: str = "openai" # openai | anthropic | deepseek | custom_openai
openai_api_key: str | None = None
anthropic_api_key: str | None = None
deepseek_api_key: str | None = None
custom_openai_api_key: str | None = None
custom_openai_base_url: str | None = None
openai_model: str = "gpt-4o"
anthropic_model: str = "claude-3-5-sonnet-20241022"
deepseek_model: str = "deepseek-chat"
custom_openai_model: str = "gpt-4o-mini"
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
extra = "ignore"
_runtime_overrides: dict[str, str | None] = {}
def _apply_overrides(settings: Settings) -> Settings:
for key, value in _runtime_overrides.items():
if hasattr(settings, key):
setattr(settings, key, value)
return settings
@lru_cache
def get_settings() -> Settings:
return _apply_overrides(Settings())
def update_runtime_settings(payload: dict[str, str | None]) -> Settings:
"""Update runtime settings and refresh cached Settings object."""
allowed = {
"llm_provider",
"openai_api_key",
"anthropic_api_key",
"deepseek_api_key",
"custom_openai_api_key",
"custom_openai_base_url",
"custom_openai_model",
}
for key, value in payload.items():
if key in allowed:
_runtime_overrides[key] = value
get_settings.cache_clear()
return get_settings()
def public_settings() -> dict:
s = get_settings()
return {
"llm_provider": s.llm_provider,
"providers": ["openai", "anthropic", "deepseek", "custom_openai"],
"models": {
"openai": s.openai_model,
"anthropic": s.anthropic_model,
"deepseek": s.deepseek_model,
"custom_openai": s.custom_openai_model,
},
"base_urls": {
"custom_openai": s.custom_openai_base_url or "",
},
"has_keys": {
"openai": bool(s.openai_api_key),
"anthropic": bool(s.anthropic_api_key),
"deepseek": bool(s.deepseek_api_key),
"custom_openai": bool(s.custom_openai_api_key),
},
}