from functools import lru_cache from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): database_url: str = Field(default="postgresql://miniapp:miniapp_dev_password@localhost:5433/miniapp") jwt_secret: str = Field(default="dev-only-change-me-before-production") jwt_expires_hours: int = Field(default=8) log_level: str = Field(default="info") port: int = Field(default=4000) cors_origins: str = Field(default="*") oss_access_key_id: str | None = Field(default=None) oss_access_key_secret: str | None = Field(default=None) oss_endpoint: str | None = Field(default=None) oss_bucket_name: str | None = Field(default=None) wechat_miniapp_appid: str | None = Field(default=None) wechat_miniapp_secret: str | None = Field(default=None) customer_jwt_expires_hours: int = Field(default=720) model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore") @property def sqlalchemy_url(self) -> str: parsed = urlsplit(self.database_url) query = urlencode([(key, value) for key, value in parse_qsl(parsed.query, keep_blank_values=True) if key != "schema"]) normalized = urlunsplit((parsed.scheme, parsed.netloc, parsed.path, query, parsed.fragment)) if normalized.startswith("postgresql://"): return normalized.replace("postgresql://", "postgresql+psycopg://", 1) return normalized @lru_cache def get_settings() -> Settings: return Settings()