116 lines
3.4 KiB
Python
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
|