""" 配置包:只读环境变量,组装 Settings。 本文件职责:集中声明 YTD_ENV、端口、企微与库变量名(对齐 prompt/13、09)。 禁止:在本包写业务 if/else;禁止把密钥默认值写进源码。 """ from __future__ import annotations from functools import lru_cache from pathlib import Path from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict def _find_dotenv() -> str: """自 agent 目录向上找仓库根 .env;找不到则返回空,由环境变量本身提供。""" here = Path(__file__).resolve() for parent in here.parents: candidate = parent / ".env" if candidate.is_file(): return str(candidate) return "" class Settings(BaseSettings): """ 进程级只读配置。 调用时机:HTTP / Worker 启动时通过 get_settings() 加载一次。 企微密钥必须来自环境/.env,源码中不得出现明文 Secret。 """ model_config = SettingsConfigDict( env_file=_find_dotenv() or None, env_file_encoding="utf-8", extra="ignore", ) ytd_env: str = Field(default="test", alias="YTD_ENV") agent_http_port: int = Field(default=8910, alias="AGENT_HTTP_PORT") public_base_url: str = Field(default="", alias="PUBLIC_BASE_URL") biz_api_base_url: str = Field(default="http://127.0.0.1:8180", alias="BIZ_API_BASE_URL") agent_callback_token: str = Field(default="", alias="AGENT_CALLBACK_TOKEN") # 企微询价应用(与正式同一套应用 ID;密钥只从环境读) wecom_corp_id: str = Field(default="", alias="WECOM_CORP_ID") wecom_agent_id: str = Field(default="1000010", alias="WECOM_AGENT_ID") wecom_secret: str = Field(default="", alias="WECOM_SECRET") wecom_callback_token: str = Field(default="", alias="WECOM_CALLBACK_TOKEN") wecom_encoding_aes_key: str = Field(default="", alias="WECOM_ENCODING_AES_KEY") wecom_callback_reply_text: str = Field( default="询价智能体接通成功。已收到:{content}", alias="WECOM_CALLBACK_REPLY_TEXT", ) # 本机注入开关:test 默认开;prod 默认关 dev_inject_enabled: bool = Field(default=False, alias="DEV_INJECT_ENABLED") pg_host: str = Field(default="", alias="PG_HOST") pg_port: int = Field(default=5432, alias="PG_PORT") pg_database: str = Field(default="", alias="PG_DATABASE") pg_user: str = Field(default="", alias="PG_USER") pg_password: str = Field(default="", alias="PG_PASSWORD") redis_url: str = Field(default="", alias="REDIS_URL") redis_key_prefix: str = Field(default="inquiry_robot:", alias="REDIS_KEY_PREFIX") libreoffice_slots: int = Field(default=1, alias="LIBREOFFICE_SLOTS") http_job_slots: int = Field(default=3, alias="HTTP_JOB_SLOTS") @lru_cache(maxsize=1) def get_settings() -> Settings: """返回进程内单例 Settings。副作用:首次可能读 .env。""" return Settings()