Files
2026-04-08 14:38:04 +08:00

169 lines
6.2 KiB
Markdown
Raw Permalink 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.
# 3D 数字人语音聊天系统
这个项目提供一个浏览器侧渲染的 3D 数字人语音交互原型:
- 浏览器通过 WebSocket 上传麦克风 PCM 音频,并接收服务端回传的 AI 语音片段。
- 浏览器通过 WebSocket 订阅字幕和口型/头部控制数据。
- 服务端执行 VAD -> ASR -> DeepSeek LLM -> TTS,并把音频特征转换为驱动 3D 数字人的控制帧。
当前形态更接近单机演示和研发验证环境,不是已经拆分完毕的生产化架构。
当前运行约束:
- 服务端按“单客户端接管”模式工作。新的浏览器页面连上后,会主动断开旧页面的音频、字幕、动画 WebSocket。
- 浏览器刷新后,语音通道可能仍受浏览器媒体安全策略限制,需要一次页面点击或点“连接语音通道”来恢复麦克风与播放上下文。
- 前端目前默认保留随机眨眼;更激进的 idle body motion 已回退,避免部分 VRM 模型进入 T pose。
## 当前架构
语音链路:
```text
Browser Mic
-> /ws/audio
-> FastAPI / websocket audio
-> VAD
-> ASR
-> LLM
-> TTS
-> /ws/audio
-> browser audio playback
```
控制链路:
```text
LLM reply text / TTS audio
-> AvatarService
-> /ws/animation
-> browser animation buffer
-> VRM or GLTF morph targets / head bones
```
字幕链路:
```text
ASR text / LLM segmented reply
-> /ws/subtitles
-> browser message panel
```
## 关键目录
- [main.py](main.py): FastAPI 入口,聚合音频 WebSocket、字幕/动画 WebSocket、健康状态和文本对话接口。
- [core/pipeline.py](core/pipeline.py): 语音/文本对话流水线,负责 ASR、LLM、TTS 编排。
- [core/state_machine.py](core/state_machine.py): 简单会话状态机,处理用户说话、思考、数字人说话之间的切换。
- [services/asr.py](services/asr.py): ASR 封装,优先使用 FunASR,失败时进入降级模式。
- [services/llm.py](services/llm.py): 在线 LLM 封装,默认兼容 DeepSeek OpenAI-style API。
- [services/tts.py](services/tts.py): TTS 封装,优先使用 Kokoro,失败时返回静音兜底。
- [services/vad.py](services/vad.py): VAD 封装,基于 silero-vad。
- [services/avatar.py](services/avatar.py): 把音频转换成 blendshape 和头部控制帧。
- [web/app.js](web/app.js): 浏览器端 3D 舞台、音频 WebSocket、字幕和动画消费逻辑。
- [scripts](scripts): 启动、证书生成、巡检和服务管理脚本。
## 快速启动
安装依赖:
```bash
pip install -r requirements.txt
```
准备环境变量,至少包括:
```bash
export LLM_API_KEY="..."
export LLM_BASE_URL="https://api.deepseek.com/v1"
export LLM_MODEL="deepseek-chat"
```
复制 [.env.example](.env.example) 为 `.env`,填入有效的 `LLM_API_KEY`
**本地权重(除 LLM 外全部在仓库内 `models/`**:首次可用联网环境执行 `python scripts/vendor_hf_models.py`;其中 VAD 的 `silero_vad.jit` 会从已安装的 `silero-vad` 包复制到 `models/vad/`。ASR 使用 `models/asr/SenseVoiceSmall/`TTS 使用 `models/tts/Kokoro-82M/`
完整部署步骤(新机器、模型打包、HTTPS、防火墙、排错)见 **[docs/deployment.md](docs/deployment.md)**。
语音如果偏快、偏硬,可以优先调这几个参数:
- `LLM_SYSTEM_PROMPT`:先把回答风格约束成口语化、非书面化,并明确禁止客服套话,再去调 TTS,收益更大。
- `LLM_TEMPERATURE`:默认 `0.55`,能减少奇怪人设和跑偏表达。
- `TTS_SPEED`:默认 `0.90`,比 `1.0` 更像真人正常说话速度。
- `TTS_SENTENCE_MAX_LEN`:默认 `64`,避免回复被切得太碎。
- `TTS_SEGMENT_PAUSE_MS`:默认 `90`,给分段之间留一点停顿,但不要太拖。
- `TTS_FADE_MS`:默认 `12`,减轻段间拼接的突兀感。
部署到任意机器时:在项目根目录运行(保证 `models/``web/``certs/` 等相对路径有效)。证书可在 `.env` 里写相对路径(例如 `certs/dev-cert.pem`),会按项目根目录解析。也可用环境变量 `VISUAL_CHAT_PYTHON` 指定解释器。
本地启动:
```bash
python main.py
```
或使用脚本:
```bash
bash scripts/start-test.sh auto
```
如果你明确要固定走当前 shell/虚拟环境里的 Python,也可以用:
```bash
bash scripts/start-public.sh
```
基础自检:
```bash
python scripts/model_probe.py
python scripts/qa_check.py --base-url http://127.0.0.1:8080 --rounds 3
python scripts/smoke_test.py --text "你好,请做一个简短自我介绍。"
```
启动后访问:
- `http://127.0.0.1:8080/`
- `http://127.0.0.1:8080/health`
如果 `.env` 里已经配置了 `HTTP_PORT=8018``SSL_CERTFILE` / `SSL_KEYFILE`,实际访问地址通常会变成:
- `https://<server-ip>:8018/`
- `https://<server-ip>:8018/health`
如果浏览器与服务端跨机器访问,麦克风采集通常需要 HTTPS。可以先生成自签证书:
```bash
bash scripts/gen-self-signed-cert.sh
```
再在环境变量或 `.env` 中配置 `SSL_CERTFILE``SSL_KEYFILE`
监听规则:
- 服务监听地址固定按 `0.0.0.0` 规则执行。
- 即使把 `HTTP_HOST` 写成 `127.0.0.1``localhost``::1`,启动时也会自动归一化成 `0.0.0.0`,避免局域网访问被误伤。
## 核心接口
- `GET /`: 前端页面。
- `POST /chat/text`: 文本输入链路,跳过 ASR/VAD。
- `POST /chat/reset`: 清空上下文和运行时状态。
- `GET /health`: 返回后端运行指标和组件健康状态。
- `GET /meta`: 返回 HTTPS、监听端口和动画协议配置。
- `GET /events`: Server-Sent Events 运行状态流。
- `WS /ws/audio`: 双向语音通道,上传麦克风 PCM 并接收回复语音。
- `WS /ws/subtitles`: 字幕流。
- `WS /ws/animation`: 数字人控制流。
- `GET /avatar/schema`: 当前控制协议 schema。
说明:三个 WebSocket 通道当前都只保留一个活动客户端。新页面接入后,旧页面会收到 `1012 replaced` 并停止接收数据。
## 后续开发建议
优先阅读 [docs/development-guide.md](docs/development-guide.md)。这个文档说明了:
- 语音与文本两条链路的完整时序。
- 前后端之间的协议约定。
- 当前实现的边界和适合继续扩展的位置。
- 已知的工程化约束。