"""应用配置:从 .env / 环境变量读取,集中管理所有开关。""" from __future__ import annotations from functools import lru_cache from pathlib import Path 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", ) # ===== 通用 ===== tz: str = "Asia/Hong_Kong" log_level: str = "INFO" # ===== 数据库 ===== postgres_user: str postgres_password: str postgres_db: str postgres_host: str = "postgres" postgres_port: int = 5432 @property def database_url(self) -> str: # asyncpg return ( f"postgresql+asyncpg://{self.postgres_user}:{self.postgres_password}" f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}" ) @property def sync_database_url(self) -> str: # alembic 用的同步 URL return ( f"postgresql+psycopg2://{self.postgres_user}:{self.postgres_password}" f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}" ) # ===== Redis ===== redis_host: str = "redis" redis_port: int = 6379 redis_password: str redis_db: int = 0 @property def redis_url(self) -> str: return ( f"redis://:{self.redis_password}@{self.redis_host}:{self.redis_port}/{self.redis_db}" ) # ===== JWT ===== jwt_secret: str jwt_algorithm: str = "HS256" access_token_ttl_min: int = 60 refresh_token_ttl_day: int = 14 # ===== 腾讯云 TMT ===== tencentcloud_secret_id: str = "" tencentcloud_secret_key: str = "" tencentcloud_region: str = "ap-hongkong" tencent_tmt_endpoint: str = "tmt.tencentcloudapi.com" tencent_tmt_quota_month: int = 5_000_000 tencent_tmt_quota_buffer: float = 0.05 tencent_tmt_max_chars_per_req: int = 4500 @field_validator("tencent_tmt_quota_buffer") @classmethod def _check_buffer(cls, v: float) -> float: if not 0.0 <= v <= 0.5: raise ValueError("buffer 必须在 0~0.5") return v # ===== 本地翻译 ===== local_translate_enabled: bool = False local_translate_model: str = "nllb-200-distilled-600M" local_translate_device: str = "cpu" # ===== 抓取 ===== fetch_global_qps: int = 4 fetch_timeout: int = 20 fetch_fail_pause_threshold: int = 3 fetch_max_retries: int = 2 # ===== Caddy / 域名 ===== domain: str = "" acme_email: str = "" # ===== Agnes LLM(智能增强)===== # 留空 = 不启用 LLM 增强(翻译后只走默认排版,提示词也不读) agnes_api_key: str = "" agnes_base_url: str = "https://apihub.agnes-ai.com/v1" agnes_chat_model: str = "agnes-2.0-flash" agnes_image_model: str = "agnes-image-2.1-flash" # 全局 LLM 调用间隔(秒),避免被限流 llm_interval_sec: float = 2.0 # ===== 内部路径(部署后可调) ===== project_root: Path = Path(__file__).resolve().parents[2] @lru_cache def get_settings() -> Settings: return Settings() # type: ignore[call-arg] settings = get_settings()