低配版赛博女友复盘——从一句话到数字人回应,一条链路的搭建与取舍
低配版赛博女友复盘——从一句话到数字人回应,一条链路的搭建与取舍
仓库:ydflow/cyber-girlfriend-16gb · React + Node.js + Python
一句话:让一张角色图片拥有声音、表情和与你对话的能力。

一、背景:把「一句话」变成「一次完整的回应」
数字人、虚拟陪伴这类方向很火,但大多数 demo 止步于「一段视频」或「一段对话」。这个项目的野心是把它做成一条完整的链路:
上传角色图片、设定性格,按下麦克风说话。角色听懂后给出贴合设定的回答,播放合成语音,并在本地生成带口型和表情的回应视频。
一次回应的旅程是这样的:
1 | 麦克风 → 火山引擎语音识别 → DeepSeek 生成回复 → 火山引擎语音合成 |
二、技术组成:本地运行与云端调用并存
| 部分 | 技术与职责 |
|---|---|
| 前端 | React,浏览器录音、静音检测、界面、本地会话保存 |
| 后端 | Node.js,编排服务调用、配置管理、密钥保护 |
| 对话 | DeepSeek,结合角色设定 + 记忆 + 近期上下文生成回复 |
| 语音识别/合成 | 火山引擎,ASR + TTS |
| 动画 | Python + LivePortrait(人像动作)+ MuseTalk(口型),本地生成视频 |
一个关键设计是**「本地运行 + 云端调用」并存**:网页、后端、动画服务跑在本机(隐私可控),但语音识别、对话生成、语音合成走外部 API(需要联网和凭据)。
三、几个值得记录的取舍
1. 先做「一轮回应」,不做「实时视频通话」
诚实地说,当前是一轮语音输入 → 生成回复 → 生成视频 → 播放,不是边说边生成的实时通话。首次加载模型、准备角色、生成视频都需要等待。
这个取舍很务实:先把一条链路的正确性跑通,再谈实时性。实时数字人通话是另一个量级的工程难题,值得单独立项。
2. 容错体验:动画失败就回退到纯语音
动画生成失败时,前端会尝试回退到纯语音播放。不让「视频失败」变成「整个体验失败」——这是体验设计上的降级保护。
3. 密钥保护:后端不返回真实 Key
后端保存配置时调用密钥保护函数,读取配置的接口只返回配置状态与必要的非密钥参数,不返回真实 API Key 或 Token。公开上传时也排除本地配置文件。这是安全底线。
4. 情绪与表情参数化
回复支持开心、害羞、难过、关心、生气、惊讶、中性等状态,并带强度参数。动画服务用这些参数选择和调整动作——让「表情」不是随机播放,而是被「情绪」驱动的。
四、诚实的能力边界
README 里明确写了定位和边界,这是我很看重的一点:
- 「16GB 显存」是配置方向,不是保证:尚未提供公开版在全新环境的显存峰值、耗时、帧率基准,不代表所有 16GB 显卡都能达到同样效果;
- 默认角色用通用占位图:展示图不作为可选角色安装,个人原图、私密设定、测试视频都不在仓库里;
- 没有自动总结、长期记忆、跨设备同步:记忆面板展示已有条目,但不会自动写入长期记忆。
五、几点复盘
- 「先把一条链路跑通」比「一步到位」更现实。数字人从一句话到回应视频,拆成 ASR→对话→TTS→动画四段,一段段验证,比试图一步做出实时通话更靠谱。
- 降级保护是体验的一部分。动画失败回退语音,让用户在「不完美」时依然有可用体验。
- 密钥不进仓库、不进返回是硬底线。个人项目最容易在这上面翻车。
- 诚实标注「16GB 不代表都能跑」,比吹一个「低配也能玩」的噱头更负责。
这个项目让我意识到,数字人真正的难点不在「能不能动」,而在链路每一环的可靠衔接。下一篇讲日程小程序「日序」,是一个完全不同风格的项目——本地优先、纯 TypeScript、201 个测试。








