9.0 KiB
HEL-902 统一审核报告:自定义声音前后台(离线)
审核人:总工。2026-10-27/28。零真实 LLM/嵌入/ASR/TTS 调用、零共享音色写入、零部署、零依赖下载安装。
1. 实际统一 head 与整合范围
- 整合分支
hel-902-integration,merge headd167ba9(本卡推送):origin/hel-900-preserved@37b4e69(作者源码701442d直接以 HEL-899 后台ce7279e为父);- merge
origin/hel-879-assembly@be149cd(真实窗口修复:LiveKit 服务端 token 携带 SDK 对等 video grants、Twirp JSON、自签证书材料与窗口证据),无冲突,未改写任何母线/旧现场/PR#11。
- 前端保全独立复核:
docs/rework/hel900/preservation/preservation.json八文件 Git blob SHA-256 与工作树逐文件比对 8/8 一致;作者附件 ZIP 重新下载校验 SHA-25615879ce6…d74fe与保全记录一致。36 张截图全部为有效 PNG(22 张 1440×900、14 张 390×844@2x),命名与 harness 视口定义一致。
2. 实际运行(本机可离线证明的部分)
| 项 | 结果 |
|---|---|
全量后端 pytest tests -q(py3.11.16,既有审核 venv 复用,零安装) |
376/376 通过(370 基线 + 本卡新增故障注入 6) |
scripts/verify_hel899_custom_voice.py(真实统一 app + fake 面板/TTS/LiveKit 全链) |
12/12 通过(本机重跑) |
ruff check src tests scripts |
通过 |
| 需求检查 4 组(origin/main 与 ce7279e,各带/不带 handoff-HEL-900) | 4/4 通过(本机重跑) |
总工新增故障注入 tests/test_voice_review_hel902.py |
6/6 通过(见 §4) |
本机无法复跑、如实声明:前端 tsc --noEmit/eslint/vitest 137/vite build 与浏览器 83 项本运行环境没有 web 依赖(node_modules 全部被清理,npm 本地缓存不完整,npm ci --offline 因缺包失败),而本卡禁止依赖下载安装。作者的 137/83/构建/lint 记录在 docs/rework/hel900/preservation/author-logs/ 完整在库且与 handoff 声明一致(vitest 137/137、lint 0 错 1 既有警告、build 337.92kB、浏览器 83/83 PASS);本卡对这些只作证据采信 + 逐行代码静态复核(§3),不冒充复跑。前端复跑与两主题×电脑/手机浏览器实测列入补测包的可选预审项(需一次性依赖安装授权)与真机窗口项。
3. 代码复核结论(逐项对合同 §2 与用户原话 01a17de1)
前端 web/src/voice/custom.ts / VoiceSection.tsx / ManagePanel.tsx / components.css(作者原件):
- 上传=原始 WAV 字节+查询串、浏览器
OfflineAudioContext@16k真解码重采→16k mono PCM16、≥2s/静音/15MB/解不开拒绝、allow_asr仅「文字空且用户显式开开关」为 true、试听响应必须合法 WAV、canplay 后才可应用、参考原声与现场合成分开标注、每类请求独立 AbortController+代际守卫、objectURL 全回收、录音仅点击开启/只取音轨/停止取消离开即释放/20s 自动停/迟到授权即关、登记中重复点击不再发且不中止已发上传、演示入口不挂载组件零请求(real && open条件,静态核实)——与合同一致。 - CSS 新增 44 行仅用既有 token(
--accent/--dur-ui/--field…),无硬编码色(两处中性白透明度除外,双主题安全)。 - 验收措辞勘误(非缺陷):「改扩展名的非 WAV 在浏览器被拒」仅对解不开的内容成立;可解开的音频(含改名 WebM/MP3)按合同设计转成真 WAV 后上传,mock 端核验的正是产物 WAV 头。
后端 src/cybergril/voice/custom.py / router.py / session.py / app.py(ce7279e)+ livekit_wire(hel-879-assembly 修复):
- 会话开启先
_capture_voice(选择有效→选择;否则 worker 文件现值;再无效→default;从未选择不代写)写 worker 文件后才create_dispatch,worker 会话入口读一次;通话中改选最迟下一通话生效、绝不半句换人(离线链 12/12 含 pin/next-call 用例)。 - 共享注册表只经 8090:
cg-服务端生成 8 hex、撞名换新、既有 11 支与通用助手状态零写入零删除(测试断言)。 - 试听未知音色前置拦截(TTS 零调用,防静默回落 default);试听零写聊天/记忆/回执。
4. 后台重点补核(故障注入,总工新增,全部假服务)
| 场景 | 实际行为 | 判定 |
|---|---|---|
| 8090 登记成功、本地元数据落盘失败 | 面板已登记;未捕获 OSError→HTTP 500(未映射合同错误文案);但进程内记录仍在可试听可应用,重启后元数据丢、共享注册表仍在→声音仍列出可用(label=ID),可恢复、不逼重复注册 | 🟡 文案/映射建议修 |
| 上传在面板侧已生效但响应断连→重试 | 503 诚实拒绝;重试另立新 cg- ID,共享注册表留下无元数据孤儿条目(列表可见 label=ID、可正常使用;既有 11 支与通用状态零改写) | 🟡 孤儿回收走 8090 自有删除,登记失败提示可加「已登记的半条会以编号显示」说明 |
| 通话开启 worker 音色写不进 | 503「写不进」、不开房、选择不受牵连、恢复即通 | ✅ |
| worker 文件可读→其他键保留;损坏(非 JSON)→整体重写仅剩 voice | 与 docstring「保留其他键」在损坏场景不符 | 🟡 注释/极端行为说明 |
| 试听流水写不进 | 试听仍成功(流水尽力而为),应用凭据缺失→409 fail-closed,守门不放松 | ✅(方向正确) |
| 选择状态落盘失败 | 整体回滚、worker 文件不动、503 如实 | ✅ |
| ASR/试听流水与限额 | 流水仅核算(有界 5000→2000 行);硬闸只有 LLM/嵌入(think/budget.py acquire),试听/登记/开房无代码级上限 |
✅ 如实;补测包按 ops 上限申报 |
_capture_voice 写文件与 worker 实际读文件之间的窗口 |
用户恰在开房瞬间「应用」会落进本通话(worker 仍整通话单一音色,无半句换人;仅「最迟下一通话」表述在该秒级窗口内不成立) | 🟡 残余竞态,单用户设置面板实际难触发;可在 custom._lock 内串行化 capture→dispatch 根除 |
5. 集中问题清单(交有限返修/承接,不另起多轮)
🔴 必须修(视觉作者一轮内,或经授权的必要小修)
- 「外接服务」分区仍写语音识别/语音合成「尚未接通」,与同面板「她的声音」分区矛盾(HEL-878 起语音链路已在真实窗口验证)。要求按实际能力如实说明:建议随
/api/voice/status动态显示(如「语音合成:已接入她的声音 · 这会儿服务器状态 X」),不得一律改「已接通」,也不得维持「尚未接通」。位置web/src/manage/ManagePanel.tsx:190。
🟡 建议优化(同轮顺手或后续小卡)
2. 登记成功但本地元数据落盘失败→500:把 OSError 映射为 503/422 中文文案,并说明「已登记的半条会以编号出现在列表里」。custom.py register()。
3. 登记响应断连重试产生的共享孤儿 cg- 条目:在列表/文档标注「无元数据条目=未完成登记,可用或经 8090 面板删除」;补测包含回收步骤。
4. write_worker_voice docstring「保留其他键」补一句「文件读不出时整体重写」的实况。
5. 会话页显示「本次通话声音」(POST /api/voice/session 响应已含 voice 字段,前端 SessionGrant 未取):建议开房后在通话条上显示本次音色并与「下一通生效」文案区分。结论:需要,小改。
6. _capture_voice→worker 读文件的秒级窗口竞态:用 custom._lock 把 capture+dispatch 串行化即可根除(后端小改)。
承接保留(不悄删):自定义音色删除与完整备份/恢复(CG-009/R6 后续卡);R5 整体真机验收;R1–R7 完整功能;真实克隆相似度与真机(iPhone/Android/Safari)录音路径未测;演示入口零外发的浏览器复验。
6. 需求与勘误
- 需求 v1.12/60 项核对:CG-010 边界已按用户原话
01a17de1更新(自定义音色为准),原话证据sources/comment-evidence-custom-voice-20261027.json逐字一致;CG-009 备份恢复等其余条文未被触动。 - 勘误(本卡完成,属授权的非视觉小修):
docs/requirements/README.md首行基准 v1.11→v1.12(current/baseline/changes 早已 v1.12),勘误说明写入该行;基准未回退,4 组需求检查复跑通过。
7. 结论
通过(离线审核)+ 一轮有限返修:后台 376/376 与离线全链 12/12 在统一整合 head 上实际复跑通过;前端作者证据完整且经逐行静态复核与合同比对一致,1 项必须修(外接服务文案)与 5 项建议优化集中交视觉作者/后续小卡;真实试听/转写/克隆相似度/真机麦克风与前端复跑全部列入补测包(r5-followup-package.md),未获批准前真实 cap=0。不部署、不合并、不替换正式界面。