| """ |
| μ ν리μΌμ΄μ
μ€μ λͺ¨λ. |
| |
| νκ²½ λ³μ(.env)λ₯Ό pydantic-settings λ‘ λ‘λνλ©°, |
| λͺ¨λ μ€μ μ μ΄ λͺ¨λμ ``get_settings()`` ν¨μλ₯Ό ν΅ν΄ μ κ·Όν©λλ€. |
| """ |
|
|
| from __future__ import annotations |
|
|
| from functools import lru_cache |
|
|
| from pydantic import Field, field_validator |
| from pydantic_settings import BaseSettings, SettingsConfigDict |
|
|
|
|
| class Settings(BaseSettings): |
| """μ μ μ ν리μΌμ΄μ
μ€μ .""" |
|
|
| model_config = SettingsConfigDict( |
| env_file=".env", |
| env_file_encoding="utf-8", |
| case_sensitive=False, |
| extra="ignore", |
| ) |
|
|
| |
| data_go_kr_api_key: str = Field( |
| default="", |
| description="data.go.kr μλΉμ€ μΈμ¦ν€", |
| ) |
| data_go_kr_base_url: str = Field( |
| default="https://open.neis.go.kr/hub", |
| description="data.go.kr NEIS Open API κΈ°λ³Έ URL", |
| ) |
|
|
| |
| edmgr_api_key: str = Field( |
| default="", |
| description="data.edmgr.kr μλΉμ€ μΈμ¦ν€", |
| ) |
| edmgr_base_url: str = Field( |
| default="https://open.neis.go.kr/hub", |
| description="NEIS νκ΅κΈ°λ³Έμ 보 API κΈ°λ³Έ URL", |
| ) |
|
|
| |
| mois_api_key: str = Field( |
| default="", |
| description="νμλΆ μ£Όλ―Όλ±λ‘ μΈκ΅¬ν΅κ³ μλΉμ€ μΈμ¦ν€", |
| ) |
| mois_base_url: str = Field( |
| default="https://jumin.mois.go.kr/ageStatMonth.do", |
| description="νμλΆ μΈκ΅¬ν΅κ³ API URL", |
| ) |
|
|
| |
| huggingface_hub_token: str = Field( |
| default="", |
| description="Hugging Face Hub μ‘μΈμ€ ν ν°", |
| ) |
| granite_model_id: str = Field( |
| default="ibm-granite/granite-timeseries-ttm-r2", |
| description="Granite TTM λͺ¨λΈ μλ³μ", |
| ) |
|
|
| |
| app_env: str = Field(default="development") |
| log_level: str = Field(default="INFO") |
| api_host: str = Field(default="0.0.0.0") |
| api_port: int = Field(default=8000, ge=1, le=65535) |
| api_workers: int = Field(default=1, ge=1) |
|
|
| |
| redis_url: str = Field(default="") |
| cache_ttl_seconds: int = Field(default=3600, ge=0) |
|
|
| |
| ingest_page_size: int = Field(default=1000, ge=1, le=5000) |
| ingest_max_retries: int = Field(default=3, ge=0, le=10) |
| ingest_retry_delay: float = Field(default=2.0, ge=0.0) |
| http_timeout: int = Field(default=30, ge=5, le=120) |
|
|
| |
| prediction_context_length: int = Field(default=60, ge=12, le=120) |
| prediction_horizon_months: int = Field(default=60, ge=12, le=120) |
|
|
| @field_validator("log_level") |
| @classmethod |
| def _validate_log_level(cls, v: str) -> str: |
| allowed = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} |
| upper = v.upper() |
| if upper not in allowed: |
| raise ValueError(f"log_level μ {allowed} μ€ νλμ¬μΌ ν©λλ€.") |
| return upper |
|
|
| @field_validator("app_env") |
| @classmethod |
| def _validate_app_env(cls, v: str) -> str: |
| allowed = {"development", "production", "test"} |
| lower = v.lower() |
| if lower not in allowed: |
| raise ValueError(f"app_env λ {allowed} μ€ νλμ¬μΌ ν©λλ€.") |
| return lower |
|
|
|
|
| @lru_cache(maxsize=1) |
| def get_settings() -> Settings: |
| """μ€μ μ±κΈν€ λ°ν (μ΅μ΄ νΈμΆ μ .env νμΌμ μ½μ).""" |
| return Settings() |
|
|