""" 统一配置:所有环境变量通过此模块的 Settings 单点读取。 业务代码只允许 import settings,禁止散落 os.getenv() / load_dotenv()。 """ import secrets from pydantic import Field 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", ) # ── Database ────────────────────────────────────────────── database_url: str = "postgresql://postgres:postgres@localhost:5432/life_echo" # ── Redis ───────────────────────────────────────────────── redis_url: str = "redis://localhost:6379/0" redis_session_ttl: int = 86400 # ── Auth / JWT ──────────────────────────────────────────── secret_key: str = Field(default_factory=lambda: secrets.token_urlsafe(32)) algorithm: str = "HS256" access_token_expire_minutes: int = 120 refresh_token_expire_days: int = 30 # ── LLM / DeepSeek ─────────────────────────────────────── deepseek_api_key: str = "" deepseek_base_url: str = "https://api.deepseek.com" deepseek_model: str = "deepseek-chat" llm_api_key: str = "" llm_base_url: str = "" llm_model: str = "" llm_temperature: float = 0.7 # ── ASR ─────────────────────────────────────────────────── asr_provider: str = "whisper" asr_model_size: str = "small" asr_device: str = "auto" asr_compute_type: str = "auto" asr_model_cache_dir: str = "" # ── Tencent SMS ────────────────────────────────────────── tencent_sms_secret_id: str = "" tencent_sms_secret_key: str = "" tencent_sms_sdk_app_id: str = "" tencent_sms_sign_name: str = "" tencent_sms_template_id: str = "" tencent_sms_template_param_count: int = 2 # ── Tencent ASR ────────────────────────────────────────── tencent_secret_id: str = "" tencent_secret_key: str = "" tencent_asr_app_id: str = "" # ── TTS (openai | tencent) ─────────────────────────────── tts_provider: str = "tencent" openai_api_key: str = "" tts_voice_type: int = 603004 # Tencent 音色 ID,见 https://cloud.tencent.com/document/product/1073/92668 tts_codec: str = "mp3" # ── WeChat Pay ─────────────────────────────────────────── wechat_pay_app_id: str = "" wechat_pay_mch_id: str = "" wechat_pay_api_v3_key: str = "" wechat_pay_private_key_path: str = "certs/apiclient_key.pem" wechat_pay_private_key: str = "" # PEM 内容,与 private_key_path 二选一 wechat_pay_cert_serial_no: str = "" wechat_pay_notify_url: str = "" wechat_pay_platform_public_key: str = "" wechat_pay_platform_public_key_path: str = "" wechat_pay_platform_public_key_id: str = "" # ── Alipay ─────────────────────────────────────────────── alipay_app_id: str = "" alipay_private_key: str = "" alipay_public_key: str = "" alipay_notify_url: str = "" alipay_sign_type: str = "RSA2" alipay_under_development: str = "true" # "1"/"true"/"yes" 视为开发中不可用 # ── Misc ───────────────────────────────────────────────── enable_test_subscription: int = 0 enable_test_plan: str = "" # "1" / "true" / "yes" 为 True enable_docs: bool = True migration_database_url: str = "" # 脚本迁移用,空则用 database_url # ── Memoir Image ───────────────────────────────────────── memoir_image_enabled: bool = False memoir_image_max_per_chapter: int = 2 memoir_image_poll_interval: int = 3 memoir_image_max_attempts: int = 20 memoir_image_chars_per_extra: int = 1500 memoir_image_max_cap: int = 8 memoir_image_provider: str = "liblib" memoir_image_style_default: str = "watercolor" memoir_image_size_default: str = "1280x720" memoir_image_download_hosts: str = "" # ── Liblib ─────────────────────────────────────────────── liblib_access_key: str = "" liblib_secret_key: str = "" liblib_base_url: str = "https://openapi.liblibai.cloud" liblib_template_uuid: str = "" # ── Tencent COS ────────────────────────────────────────── tencent_cos_secret_id: str = "" tencent_cos_secret_key: str = "" tencent_cos_region: str = "ap-shanghai" tencent_cos_bucket: str = "" tencent_cos_base_url: str = "" tencent_cos_token: str = "" settings = Settings()