Files
life-echo/api/app/core/config.py
Kevin a3f61fcc0f feat(api+app): 对话阶段化、回忆录流水线与客户端会话体验
- DB: segments 用户输入文本(Alembic 0002)
- Chat: 阶段检测/阶段提示/回复限制,编排与访谈/画像 prompts 调整
- Memoir: 忠实度检查 agent,叙事与分类等链路更新
- Core: agent 日志、Alembic 启动、LangChain/日志/配置等
- Story: time_hints;Memory 检索与相关测试
- Expo: 助手头像、会话页与消息拆分、实时会话与文案/i18n
- Docs/scripts/tests: 迁移脚本、LLM JSON/记忆检索文档、新增单测
2026-03-26 12:13:36 +08:00

168 lines
8.2 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 单点读取。
业务代码只允许 import settings禁止散落 os.getenv() / load_dotenv()。
本地开发时由 api/development.sh 在启动前将 .env.development 同步为 .env每次启动覆盖
Docker / 服务端由镜像与 compose 注入进程环境;此处仅固定读取工作目录下的 .env 作为默认值来源。
进程环境变量(容器 environment、export覆盖 .env 同名项。
"""
import secrets
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",
)
# ── Database ──────────────────────────────────────────────
database_url: str = "postgresql://postgres:postgres@localhost:5432/life_echo"
# 启动时是否执行 Alembicmain.py lifespan测试或仅读场景可关
alembic_run_on_startup: bool = True
# True迁移失败则进程退出生产推荐。False仅打错误日志并继续本地无 DB 时)
alembic_startup_fail_fast: bool = False
alembic_startup_max_retries: int = Field(default=3, ge=1, le=10)
alembic_startup_retry_base_seconds: float = Field(default=1.0, ge=0.1, le=60.0)
# ── 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
# ── Chat 访谈短回复token 上限 + 代码截断,见 reply_limits──
chat_interview_max_tokens: int = 320
chat_interview_max_segments: int = 2
chat_interview_max_chars_per_segment: int = 220
chat_opening_max_tokens: int = 256
chat_profile_followup_max_tokens: int = 280
chat_era_context_enabled: bool = True
# 访谈:每轮用 LLM 判定用户主人生阶段并更新 MemoirState.current_stageFalse 时仅用关键词
chat_stage_detection_enabled: bool = True
chat_stage_detection_max_tokens: int = 128
# ── Memoir 叙事忠实度检查FidelityCheckAgent────────────────
memoir_fidelity_check_enabled: bool = True
memoir_fidelity_check_max_tokens: int = 512
# ── 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 / TTS共用 Secret与短信、COS 密钥独立)────────────────
tencent_secret_id: str = ""
tencent_secret_key: str = ""
# ── TTS (openai | tencent),与 ASR 独立:仅控制回复侧语音合成 ──
enable_tts: bool = True
tts_provider: str = "tencent"
openai_api_key: str = ""
tts_voice_type: int = 502001 # 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" 视为开发中不可用
# ── Logging ──────────────────────────────────────────────
# 环境变量 LOG_LEVEL控制 loguru sink 最低级别TRACE/DEBUG/INFO/…)
log_level: str = "INFO"
# LOG_AGENT_VERBOSE为 True 时额外输出 Agent 单行 INFO 摘要(耗时、规模),无需全局 DEBUG
log_agent_verbose: bool = False
# AGENT_LOG_MAX_CHARSDEBUG 下记录 prompt/响应预览时的最大字符数
agent_log_max_chars: int = Field(default=4096, ge=256, le=100_000)
# 第三方 stdlib logging空=自动LOG_LEVEL 为 DEBUG/TRACE 时 Celery→INFO、httpx/httpcore→WARNING
celery_log_level: str = ""
httpx_log_level: str = ""
@field_validator("log_agent_verbose", mode="before")
@classmethod
def _coerce_log_agent_verbose(cls, v: object) -> bool:
if isinstance(v, bool):
return v
if v is None:
return False
return str(v).strip().lower() in ("1", "true", "yes", "on")
# ── Misc ─────────────────────────────────────────────────
enable_test_subscription: int = 0
enable_test_plan: str = "" # "1" / "true" / "yes" 为 True
enable_docs: bool = True
# ── Memoir Image ─────────────────────────────────────────
memoir_image_enabled: bool = False
memoir_image_poll_interval: int = 3
memoir_image_max_attempts: int = 20
memoir_image_provider: str = "liblib"
memoir_image_style_default: str = "watercolor"
memoir_image_size_default: str = "1280x720"
memoir_image_download_hosts: str = ""
# Story 正文至少多少字才创建主图 intent / 调图0 表示不限制)
story_image_min_body_chars: int = 800
# 叙事输出相对口述过短则回退为口述原文(比例与下限)
memoir_narrative_fallback_body_ratio: float = 0.5
memoir_narrative_fallback_min_chars: int = 20
# ── 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()