Files
yellow-bank-soal/app/core/config.py
Dwindi Ramadhana cf193d7ea0 first commit
2026-03-21 23:32:59 +07:00

116 lines
3.4 KiB
Python

"""
Application configuration using Pydantic Settings.
Loads configuration from environment variables with validation.
"""
from typing import Literal, List, Union
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
# Database
DATABASE_URL: str = Field(
default="postgresql+asyncpg://postgres:postgres@localhost:5432/irt_bank_soal",
description="PostgreSQL database URL with asyncpg driver",
)
# FastAPI
SECRET_KEY: str = Field(
default="dev-secret-key-change-in-production",
description="Secret key for JWT token signing",
)
API_V1_STR: str = Field(default="/api/v1", description="API v1 prefix")
PROJECT_NAME: str = Field(default="IRT Bank Soal", description="Project name")
ENVIRONMENT: Literal["development", "staging", "production"] = Field(
default="development", description="Environment name"
)
# OpenRouter (AI Generation)
OPENROUTER_API_KEY: str = Field(
default="", description="OpenRouter API key for AI generation"
)
OPENROUTER_MODEL_QWEN: str = Field(
default="qwen/qwen-2.5-coder-32b-instruct",
description="Qwen model identifier",
)
OPENROUTER_MODEL_LLAMA: str = Field(
default="meta-llama/llama-3.3-70b-instruct",
description="Llama model identifier",
)
OPENROUTER_TIMEOUT: int = Field(default=30, description="OpenRouter API timeout in seconds")
# WordPress Integration
WORDPRESS_API_URL: str = Field(
default="", description="WordPress REST API base URL"
)
WORDPRESS_AUTH_TOKEN: str = Field(
default="", description="WordPress JWT authentication token"
)
# Redis (Celery)
REDIS_URL: str = Field(
default="redis://localhost:6379/0", description="Redis connection URL"
)
CELERY_BROKER_URL: str = Field(
default="redis://localhost:6379/0", description="Celery broker URL"
)
CELERY_RESULT_BACKEND: str = Field(
default="redis://localhost:6379/0", description="Celery result backend URL"
)
# CORS - stored as list, accepts comma-separated string from env
ALLOWED_ORIGINS: List[str] = Field(
default=["http://localhost:3000"],
description="List of allowed CORS origins",
)
@field_validator("ALLOWED_ORIGINS", mode="before")
@classmethod
def parse_allowed_origins(cls, v: Union[str, List[str]]) -> List[str]:
"""Parse comma-separated origins into list."""
if isinstance(v, str):
return [origin.strip() for origin in v.split(",") if origin.strip()]
return v
# Global settings instance
_settings: Union[Settings, None] = None
def get_settings() -> Settings:
"""
Get application settings instance.
Returns:
Settings: Application settings
Raises:
ValueError: If settings not initialized
"""
global _settings
if _settings is None:
_settings = Settings()
return _settings
def init_settings(settings: Settings) -> None:
"""
Initialize settings with custom instance (useful for testing).
Args:
settings: Settings instance to use
"""
global _settings
_settings = settings