File size: 2,362 Bytes
44c2f50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
"""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
    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
    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"))
    )

    # Pricing (gpt-5-nano defaults; override in .env when swapping models)
    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 (v2)
    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()