| """Centralized configuration loaded from environment variables.""" |
| from __future__ import annotations |
|
|
| import os |
| from functools import lru_cache |
|
|
| from dotenv import load_dotenv |
| from pydantic import BaseModel, Field |
|
|
| load_dotenv() |
|
|
|
|
| class Settings(BaseModel): |
| """Application settings β loaded once at startup.""" |
|
|
| |
| openai_api_key: str = Field(default_factory=lambda: os.getenv("OPENAI_API_KEY", "")) |
| openai_model: str = Field(default_factory=lambda: os.getenv("OPENAI_MODEL", "gpt-5-nano")) |
| openai_vision_model: str = Field( |
| default_factory=lambda: os.getenv("OPENAI_VISION_MODEL", "gpt-5-nano") |
| ) |
| openai_max_retries: int = Field( |
| default_factory=lambda: int(os.getenv("OPENAI_MAX_RETRIES", "3")) |
| ) |
| openai_request_timeout: int = Field( |
| default_factory=lambda: int(os.getenv("OPENAI_REQUEST_TIMEOUT", "60")) |
| ) |
|
|
| |
| app_env: str = Field(default_factory=lambda: os.getenv("APP_ENV", "development")) |
| log_level: str = Field(default_factory=lambda: os.getenv("LOG_LEVEL", "INFO")) |
| api_host: str = Field(default_factory=lambda: os.getenv("API_HOST", "0.0.0.0")) |
| api_port: int = Field(default_factory=lambda: int(os.getenv("API_PORT", "8000"))) |
| streamlit_port: int = Field( |
| default_factory=lambda: int(os.getenv("STREAMLIT_PORT", "8501")) |
| ) |
|
|
| |
| cost_per_1k_input: float = Field( |
| default_factory=lambda: float(os.getenv("COST_PER_1K_INPUT_TOKENS", "0.00005")) |
| ) |
| cost_per_1k_output: float = Field( |
| default_factory=lambda: float(os.getenv("COST_PER_1K_OUTPUT_TOKENS", "0.00040")) |
| ) |
|
|
| |
| sec_user_agent: str = Field( |
| default_factory=lambda: os.getenv( |
| "SEC_USER_AGENT", "ASP Research adityapatel1801@gmail.com" |
| ) |
| ) |
|
|
| def validate_ready(self) -> None: |
| """Raise if the app isn't ready to run β call at startup.""" |
| if not self.openai_api_key or self.openai_api_key.startswith("sk-your-key"): |
| raise RuntimeError( |
| "OPENAI_API_KEY is not set. Copy .env.example to .env and paste your key." |
| ) |
|
|
|
|
| @lru_cache(maxsize=1) |
| def get_settings() -> Settings: |
| """Cached singleton β call this everywhere instead of instantiating Settings.""" |
| return Settings() |
|
|