feat(i18n): persist language preference and thread through chat, memoir, TTS

- Add users.language_preference (Alembic 0018, default zh); capture at signup/SMS
  only; expose on auth and profile APIs
- Lite English prompts for chat and memoir; localized stage labels and agent
  names (Life Echo / 岁月知己)
- Tencent TTS: language-aware synthesis, ModelType=1 for 501004, English chunking
- WebSocket pipeline: emit all AGENT_RESPONSE segments when TTS cancels; INFO logs
  for tts_this_turn and TTS decisions; on-demand TTS logging
- Expo: device language on auth, i18n tiers/agent name, [SPLIT] streaming UX fixes
- Tests for migration, prompts, pipeline, router tts_this_turn, reply segments

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin
2026-05-11 16:16:49 +08:00
parent 5ce29aad64
commit ccdc4e4277
64 changed files with 3233 additions and 208 deletions

View File

@@ -1,11 +1,23 @@
"""
访谈 Agent 可配置性格Persona仅影响语气不替代事实边界与槽位约束。
同时提供品牌名称(中英)的单一来源,便于跨 prompt / UI 文案一致。
"""
from __future__ import annotations
from typing import Final
# Brand / interviewer name — keep aligned with frontend i18n `conversation.agentName`,
# OpenAPI title, README, and project metadata. zh = 「岁月知己」en = Life Echo.
AGENT_NAME_ZH: Final[str] = "岁月知己"
AGENT_NAME_EN: Final[str] = "Life Echo"
def agent_name(language: str = "zh") -> str:
"""Return the interviewer brand name for the requested language."""
return AGENT_NAME_EN if (language or "zh").strip().lower() == "en" else AGENT_NAME_ZH
# 与 settings.chat_interview_persona 及文档保持一致
VALID_INTERVIEW_PERSONAS: Final[frozenset[str]] = frozenset(
{"default", "warm_listener", "curious_guide"}