Files
inquiry_robot/inquiry-agent/agent/config/__init__.py
T

148 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
配置包:只读环境变量,组装 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/jeecgboot", alias="BIZ_API_BASE_URL")
biz_api_token: str = Field(default="", alias="BIZ_API_TOKEN")
biz_api_username: str = Field(default="", alias="BIZ_API_USERNAME")
biz_api_password: str = Field(default="", alias="BIZ_API_PASSWORD")
biz_api_timeout_seconds: float = Field(default=10.0, alias="BIZ_API_TIMEOUT_SECONDS")
agent_callback_token: str = Field(default="", alias="AGENT_CALLBACK_TOKEN")
# 兼容现网变量名
inquiry_agent_callback_token: str = Field(default="", alias="INQUIRY_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")
pg_sslmode: str = Field(default="prefer", alias="PG_SSLMODE")
# 可直接给完整 DSN;为空则由 host/port/user 等拼装
pg_dsn: str = Field(default="", alias="PG_DSN")
# postgres | memory;正式必须 postgres;memory 仅本地骨架冒烟
checkpoint_backend: str = Field(default="postgres", alias="CHECKPOINT_BACKEND")
redis_url: str = Field(default="", alias="REDIS_URL")
redis_key_prefix: str = Field(default="inquiry_robot:", alias="REDIS_KEY_PREFIX")
# redis | memory;正式必须 redis + URL 指向逻辑库 /1(与现网 /0 隔离)
redis_backend: str = Field(default="redis", alias="REDIS_BACKEND")
redis_required: bool = Field(default=False, alias="REDIS_REQUIRED")
# auto | memory | postgres;auto=有 PG_DSN 则尝试 PG
message_store_backend: str = Field(default="auto", alias="MESSAGE_STORE_BACKEND")
wecom_aibot_bridge_token: str = Field(default="", alias="WECOM_AIBOT_BRIDGE_TOKEN")
wecom_aibot_ingress_url: str = Field(
default="http://127.0.0.1:8910/internal/aibot/inbound",
alias="WECOM_AIBOT_INGRESS_URL",
)
deepseek_api_key: str = Field(default="", alias="DEEPSEEK_API_KEY")
deepseek_base_url: str = Field(default="https://api.deepseek.com", alias="DEEPSEEK_BASE_URL")
deepseek_model: str = Field(default="", alias="DEEPSEEK_MODEL")
qwen_api_key: str = Field(default="", alias="QWEN_API_KEY")
qwen_base_url: str = Field(default="", alias="QWEN_BASE_URL")
qwen_text_model: str = Field(default="", alias="QWEN_TEXT_MODEL")
qwen_vl_model: str = Field(default="", alias="QWEN_VL_MODEL")
# prompt/04:未确认不得打真实模型(出站 HTTP 客户端强制检查)
llm_data_usage_confirmed: bool = Field(default=False, alias="LLM_DATA_USAGE_CONFIRMED")
# Worker 槽是否允许对 ordered_actions 走真网(仍受上一开关约束)
llm_allow_network: bool = Field(default=False, alias="LLM_ALLOW_NETWORK")
# LibreOffice:默认 Windows 安装路径;Linux 可改 /usr/bin/libreoffice
libreoffice_path: str = Field(
default=r"C:\Program Files\LibreOffice\program\soffice.exe",
alias="LIBREOFFICE_PATH",
)
libreoffice_timeout_seconds: float = Field(
default=120.0, alias="LIBREOFFICE_TIMEOUT_SECONDS"
)
object_storage_endpoint_url: str = Field(default="", alias="OBJECT_STORAGE_ENDPOINT_URL")
object_storage_bucket: str = Field(default="inquiry-robot", alias="OBJECT_STORAGE_BUCKET")
object_storage_access_key: str = Field(default="", alias="OBJECT_STORAGE_ACCESS_KEY")
object_storage_secret_key: str = Field(default="", alias="OBJECT_STORAGE_SECRET_KEY")
object_storage_path_style: bool = Field(default=True, alias="OBJECT_STORAGE_PATH_STYLE")
libreoffice_slots: int = Field(default=1, alias="LIBREOFFICE_SLOTS")
http_job_slots: int = Field(default=3, alias="HTTP_JOB_SLOTS")
def resolve_pg_dsn(self) -> str:
"""
解析 PostgreSQL 连接串(运行账 / Graph checkpoint)。
返回值:PG_DSN 或由分量拼出的 URI;缺关键字段时返回空串。
禁止:连现网 ytd_runtime(由部署/环境保证库名,代码不写死切换)。
"""
raw = (self.pg_dsn or "").strip()
if raw:
return raw
if not (self.pg_host and self.pg_database and self.pg_user):
return ""
# 密码可为空(本机信任);sslmode 走环境
from urllib.parse import quote_plus
user = quote_plus(self.pg_user)
password = quote_plus(self.pg_password or "")
auth = f"{user}:{password}@" if self.pg_password else f"{user}@"
return (
f"postgresql://{auth}{self.pg_host}:{self.pg_port}/"
f"{self.pg_database}?sslmode={self.pg_sslmode or 'prefer'}"
)
@lru_cache(maxsize=1)
def get_settings() -> Settings:
"""返回进程内单例 Settings。副作用:首次可能读 .env。"""
return Settings()