助手本体:会话引擎、LLM 路由、记忆、身份、语音适配

从 Obsidian 笔记库剥离为独立仓库。规划文档与 P0 报告留在笔记库,
代码(助手本体、TTS 服务、P0 基准脚本、ESP32 固件)在此。

架构:服务器是助手,本地是客户端
- 助手本体跑在 cadadmin-server,N5095 只做 USB 外设桥与网络桥接
- 起因:实测 N5095 无 AVX2,跑不动可用的语音模型

当前技术栈
- LLM:DeepSeek deepseek-flash(云端,必须关思考)
- TTS:Qwen3-TTS 1.7B(服务器 3090,独立 HTTP 服务)
- STT:Zipformer 中英双语 int8(CPU,中文识别率未测)

实测:端到端 16/16 通过,首音延迟 1545ms
(对比:本地 LLM + vits-zh-ll 是 179ms,但音色不满意——音质与延迟
在此硬件上此消彼长)

设计要点
- MemoryStore 接口按"可能远程"设计(全 async、可超时、可失败)
- user_id / session_id / track_id 三者分开,人脸只作候选不自动切身份
- 记忆查询强制带 owner_user_id,无按 id 单独取的口子
- 自动抽取的记忆是"候选",默认不参与检索
- 异步写记忆绑定创建时的身份,不读"当前用户"
- 引擎与传输解耦,只用文件音频即可端到端测试

模型与音频产物不进版本管理(1.1GB),由 download_models.sh 恢复
This commit is contained in:
ylhan
2026-09-15 11:05:09 +08:00
commit 35e107c290
46 changed files with 5976 additions and 0 deletions
+158
View File
@@ -0,0 +1,158 @@
{
"1": {
"短句": {
"first_ms": 3512.398196000049,
"total_ms": 3512.4536819998866,
"dur_s": 0.5618125,
"rtf": 6.252003438869528,
"text": "好的,我记住了。"
},
"中句": {
"first_ms": 6728.828355000132,
"total_ms": 6728.931756000293,
"dur_s": 1.7795,
"rtf": 3.781360919359535,
"text": "今天北京晴转多云,气温十八到二十六度,出门记得带件外套。"
},
"长段": {
"first_ms": 4259.075834999749,
"total_ms": 4259.120488000008,
"dur_s": 0.942875,
"rtf": 4.517163450086181,
"text": "我查了一下,明天上午十点有个会议,地点在三号会议室。另外提醒你,后天是妈妈的生日,要不要我提前帮你订一束花?还有,你上周说要买的那本书,现在有货了,价格是四十九块八。"
},
"数字": {
"first_ms": 7015.1300140000785,
"total_ms": 7015.235308999763,
"dur_s": 1.735875,
"rtf": 4.041325158205379,
"text": "订单编号是七三九一,金额一千二百五十元六角。"
},
"日期": {
"first_ms": 10958.226222000121,
"total_ms": 10958.3969360001,
"dur_s": 3.165375,
"rtf": 3.4619585154997745,
"text": "会议定在二零二六年九月十四日下午三点半。"
},
"中英混读": {
"first_ms": 8337.178994000169,
"total_ms": 8337.248050000198,
"dur_s": 2.2680625,
"rtf": 3.6759339965279607,
"text": "这个 API 的 response time 大概在 200 毫秒左右。"
},
"_分句接续": {
"max_gap_s": 3.4393423310002254,
"total_audio_s": 2.6743125,
"timeline": [
{
"i": 0,
"text": "我查了一下,明天上午十点有个会议,地",
"dur_s": 1.04,
"gen_ms": 3355.619835000198,
"first_ms": 3355.5726700001287,
"gap_s": 0.0,
"late": 0.0
},
{
"i": 1,
"text": "另外提醒你,后天是妈妈的生日,要不要",
"dur_s": 1.1223125,
"gen_ms": 4479.338345000087,
"first_ms": 4479.295166000156,
"gap_s": 3.4393423310002254,
"late": 0.0
},
{
"i": 2,
"text": "还有,你上周说要买的那本书,现在有货",
"dur_s": 0.512,
"gen_ms": 1627.3659610001232,
"first_ms": 1627.323898999748,
"gap_s": 0.5050545779996796,
"late": 0.0
}
],
"total_gen_ms": 9462.324141000408
}
},
"2": {
"短句": {
"first_ms": 1833.8097639998523,
"total_ms": 1833.856194999953,
"dur_s": 0.5618125,
"rtf": 3.2641783424184276,
"text": "好的,我记住了。"
},
"中句": {
"first_ms": 3504.9386239998057,
"total_ms": 3504.9927340000977,
"dur_s": 1.7795,
"rtf": 1.9696503141332382,
"text": "今天北京晴转多云,气温十八到二十六度,出门记得带件外套。"
},
"长段": {
"first_ms": 2213.8197690001107,
"total_ms": 2213.8693260003492,
"dur_s": 0.942875,
"rtf": 2.347998754872437,
"text": "我查了一下,明天上午十点有个会议,地点在三号会议室。另外提醒你,后天是妈妈的生日,要不要我提前帮你订一束花?还有,你上周说要买的那本书,现在有货了,价格是四十九块八。"
},
"数字": {
"first_ms": 3649.676482999894,
"total_ms": 3649.726979999741,
"dur_s": 1.735875,
"rtf": 2.1025286843809265,
"text": "订单编号是七三九一,金额一千二百五十元六角。"
},
"日期": {
"first_ms": 5695.0202110001555,
"total_ms": 5695.0819460003,
"dur_s": 3.165375,
"rtf": 1.7991808066975636,
"text": "会议定在二零二六年九月十四日下午三点半。"
},
"中英混读": {
"first_ms": 4329.835705000278,
"total_ms": 4329.891841000062,
"dur_s": 2.2680625,
"rtf": 1.9090707778114855,
"text": "这个 API 的 response time 大概在 200 毫秒左右。"
},
"_分句接续": {
"max_gap_s": 1.2875714189999234,
"total_audio_s": 2.6743125,
"timeline": [
{
"i": 0,
"text": "我查了一下,明天上午十点有个会议,地",
"dur_s": 1.04,
"gen_ms": 1753.6386409997249,
"first_ms": 1753.5868829995707,
"gap_s": 0.0,
"late": 0.0
},
{
"i": 1,
"text": "另外提醒你,后天是妈妈的生日,要不要",
"dur_s": 1.1223125,
"gen_ms": 2327.566012999796,
"first_ms": 2327.5196609997693,
"gap_s": 1.2875714189999234,
"late": 0.0
},
{
"i": 2,
"text": "还有,你上周说要买的那本书,现在有货",
"dur_s": 0.512,
"gen_ms": 848.2465030001549,
"first_ms": 848.2053440002346,
"gap_s": 0.0,
"late": 0.2740608039997383
}
],
"total_gen_ms": 4929.451156999676
}
}
}