chore: checkpoint 第一版
ci / verify (push) Canceled after 0s

This commit is contained in:
Codex Local
2026-09-06 17:04:11 +08:00
parent a8cdec98d1
commit 0c2151ace9
659 changed files with 185855 additions and 554 deletions
+97 -26
View File
@@ -1,8 +1,45 @@
# Windows 语音终端模拟器
# Windows 硬件对话智能体测试程序
该程序使用Electron和火山引擎Web RTC SDK模拟一台真实语音终端。它采集Windows麦克风、加入平台分配的RTC房间、发布本地音频、订阅并播放豆包智能体音频,并通过设备v2接口完成激活、状态等待、心跳、Token续签和结束通话。进房后还会启动RTC实时字幕,收集长者与智能体的最终话轮并通过现有`turns:batch`设备接口可靠上传;字幕未成功启动时拒绝继续激活通话,避免生成没有聊天记录的完成通话。
这是方案 1 的 Windows 端到端验收工具。默认页面不再使用平台代管的 RTC/StartVoiceChat,而是按火山“硬件对话智能体低负载标准协议”直接连接 `wss://ai-gateway.vei.volces.com/v1/realtime`。传统 RTC 模拟器仍保留在页面右上角的“传统 RTC 测试页”。
创建通话返回的隐私策略允许原录音时,模拟器同时通过RTC原始音频帧回调采集长者`near`和智能体`far`轨道。结束通话后自动封装为单声道WAV PCM16、按平台限制分片、申请短期对象地址直传,并等待后台完整性与容器校验完成。家庭工作台的通话记录会标记“可听聊天语音”,获得独立PLAY授权的账号可在详情中选择“听长者语音”或“听智能体语音”。
## 实际覆盖的流程
1. 使用平台设备 ID、时间戳、随机数、正文摘要和 HMAC-SHA256 调用设备 v2/v3 接口。
2. 调用平台 `/device/v3/hardware-agent-credentials:provision`;平台自动应用产品级Instance ID、Product Key、默认Bot、传输和最低SDK配置,并使用KMS/Secret挂载的 Product Secret 代设备调用 DynamicRegister。
3. 火山在动态注册时从产品额度中分配 License;平台只把本设备 Device Secret 下发给设备,Windows 使用 Safe Storage 加密保存后重新拉取配置版本并进入 `ACTIVE`。
4. 创建 `/device/v3/agent-sessions`,从平台取得产品默认 Bot ID、`low_load` 传输方案、本次冻结的人设、背景、最近摘要、确认记忆和授权范围。
5. 按火山规定的请求头签名建立 WebSocket,等待 `session.created`,提交本次 `session.update`,收到 `session.updated` 后才向平台回报 `session_started`并开放麦克风。
6. Windows 麦克风被转换为 PCM16、16kHz、单声道、20ms 分片,通过 `input_audio_buffer.append` 实时上行;`response.audio.delta` 按火山 low-load WebSocket SDK 的 PCM16、16kHz、单声道格式实时播放。
7. 消费服务端 VAD、用户最终识别、智能体最终字幕、Function Calling 和错误事件;双方最终话轮通过 v3 `turns:batch` 幂等上传。
8. 智能体触发 `memory_search`、`search_memory` 或 `retrieve_memory` 时,程序使用平台签发的当前会话短期令牌调用同源记忆工具,再把结果作为 `function_call_output` 返回火山。
9. 周期提交 `session_updated`。平台返回 `stop_session` 时立即关麦、补传字幕、关闭火山连接并回报 `session_ended`。
10. 页面显示 13 项验收门禁,可导出不包含任何密钥的 JSON 报告。
## 使用前配置
平台维护中心只需把测试设备配置为:
- `voice_runtime = volc_hardware_agent`
平台部署需配置并关联同一火山产品和 Bot:
- Instance ID
- Product Key
- 默认 Bot ID
- 传输方式 `low_load`
- 最低 SDK 版本不高于 `1.1.0-windows-standard-protocol`
- Product Secret(只进入平台密钥挂载,不进入Windows程序)
- Device Name 由平台按设备ID稳定生成,或使用设备绑定中预先登记的名称
- 可用的硬件对话智能体 License
Windows程序不提供 Product Secret、Device Secret 或 Bot ID 输入框。Bot ID、Instance ID、Product Key 和 Device Name 均来自平台;设备不能覆盖产品默认路由。
开始测试前还需按控制台中的 Bot 模型选择“智能体模型类型”:
- 通用 LLM:使用官方 `config.LLMConfig.SystemMessages` 注入平台冻结的人设、背景与授权上下文;
- 豆包端到端语音:使用官方 `config.S2SConfig.ProviderParams.dialog` 注入 `system_role`、`speaking_style` 和 `dialog_id`。
两种模式都使用官方 `session.object/config/agent_config/input_audio_format/output_audio_format` 报文结构。字段依据火山[初始化会话配置](https://www.volcengine.com/docs/6348/2139862?lang=zh)与[标准协议自定义接入](https://www.volcengine.com/docs/6348/1904602?lang=zh)文档。
## 构建
@@ -12,36 +49,70 @@ npm install
npm run build
```
输出:`release/voice-device-simulator-0.1.0-windows-x64.exe`。
输出文件:
连接公网测试服务器时,可以直接双击EXE,也可以使用`launch-cloud-device.ps1`启动。Electron主进程优先读取启动脚本传入的临时环境变量,否则从当前Windows用户的`%LOCALAPPDATA%\DataTerminalVoiceDevice\server-device-secret`读取设备签名密钥。密钥不写入源码、安装包或浏览器存储,也不会回传到渲染进程;输入框留空并显示“已从Windows安全凭据文件加载”即表示可直接检测。
## 自动连续性验证
本地回归时可让模拟器自动启动通话、播放一段测试音频,并把双方最终字幕写入JSON结果文件。该入口只接受本机文件和回环地址,不影响正常交互使用:
```powershell
$env:SIMULATOR_AUTO_TEST = '1'
$env:SIMULATOR_AUTOMATED_AUDIO_PATH = 'C:\path\to\question.wav'
$env:SIMULATOR_AUTO_RESULT_PATH = 'C:\path\to\result.json'
& .\release\voice-device-simulator-0.1.0-windows-x64.exe
```text
release/hardware-agent-tester-0.3.5-windows-x64.exe
```
测试会等待长者与智能体的最终字幕,结束通话后退出;结果文件包含通话ID、最终话轮和通过/失败状态。测试音频支持WAV、MP3和OGG,大小不得超过10 MB。
当前测试包未配置商业代码签名证书,Windows 可能显示“未知发布者”。交付前可用同目录 SHA-256 文件校验完整性;正式面向终端用户分发时应由甲方或发布主体使用其代码签名证书签名。
`npm run build` 会依次执行协议单测、TypeScript 检查、双页面构建和 Windows x64 便携包封装。
## 本地完整自动回归
先启动仓库根目录的 Compose 开发环境,然后运行:
```powershell
Set-Location .\device-simulator-windows
pwsh -NoProfile -File .\test\run-hardware-e2e.ps1
pwsh -NoProfile -File .\test\run-hardware-e2e.ps1 -ModelMode s2s
pwsh -NoProfile -File .\test\run-hardware-e2e.ps1 -ExecutablePath .\release\hardware-agent-tester-0.3.5-windows-x64.exe
```
第一条验证通用 LLM 报文,第二条验证端到端语音报文。回归会临时创建 `low_load` 设备绑定,启动一个校验真实火山签名和事件格式的本机 WebSocket 网关,再启动实际 Electron 窗口。测试只有在以下证据全部成立时才返回 PASS:
- 动态上下文确认后才开放麦克风;
- PCM 上行和音频下行均发生;
- 用户与智能体各产生一条最终字幕并写入 PostgreSQL;
- 平台下发停止状态,Windows 程序通过下一次 `session_updated` 收到 `stop_session`;
- 会话、硬件会话均为 `COMPLETED`;
- SaaS `conversation.started` 和 `conversation.completed` 事件均已产生;
- 页面 13 项验收门禁全部通过。
测试结束会删除临时会话、事件和设备绑定,不污染日常开发数据。
## 安全边界
- RTC AppKey、火山AK/SK和豆包Access Token只存在本地后端的受保护文件中;
- 模拟器安装包只接收平台签发的短期RTC Token;
- 设备签名密钥只驻留Electron主进程内存,不写入浏览器存储;
- 当前测试构建只允许设备API地址指向`localhost`、`127.0.0.1`或固定测试服务器`https://121.41.46.238`,避免误连其他环境;
- 关闭软件或结束通话时停止音频采集并销毁RTC引擎。
- 未取得`record_near`或`record_far`授权的轨道不会注册PCM回调;`upload_allowed=false`时不会采集或上传任何原录音。
- Product Secret 只存在于平台KMS/Secret挂载和注册调用内存,不到达设备,不写入数据库明文、日志或报告。
- 平台返回的本设备Device Secret使用 Electron `safeStorage` 加密后保存在当前 Windows 用户目录,不进入源码和安装包;License由火山产品侧分配,不下发Windows程序。
- 平台设备密钥只驻留 Electron 主进程,渲染页面不能读取已加载的明文。
- 记忆工具地址必须与配置的平台 API 同源,防止短期令牌被发送给第三方地址。
- 默认只允许连接火山官方硬件网关;本机 `ws://127.0.0.1` 仅供自动回归。
- 平台确认 `session.updated` 前不会启动麦克风;收到 `stop_session` 后不会继续发送音频。
- 导出的报告包含设备标识、Bot、配置摘要、事件和字幕,但不包含 Product Secret、Device Secret、平台签名密钥或记忆工具令牌。
- 自动回归通过仅在`SIMULATOR_AUTO_TEST=1`时生效的进程环境注入mock一机一密,不写入正式Windows凭据缓存。
## 实时字幕前提
## 真实验收与本地模拟的区别
测试所用RTC AppID必须在火山RTC控制台开启“实时字幕”和“流式语音识别”。流式语音识别凭据来自豆包语音控制台创建的“流式语音识别”应用,包括APP ID、Access Token和Cluster ID;“音视频字幕生成”类型不能替代该应用。未开通时程序会显示`ServiceAccessDenied`并清理本次未激活通话。
### 0.3.5 播放速度修复
最终字幕会在程序的“实时字幕与上传”区域显示。每条最终字幕使用通话内稳定键和严格递增序号上传;网络失败时留在内存队列,并在心跳及结束通话前重试。存在未上传字幕时,程序不会结束并丢弃当前通话。
- 根据火山 low-load WebSocket SDK 示例,将智能体下行 PCM 的源采样率从错误的 24kHz 修正为 16kHz,避免 1.5 倍速和音调升高。
- Windows 输出设备不是 16kHz 时,由 AudioWorklet 按实际系统输出采样率连续重采样,不改变语速和音高。
完整本地启动顺序见[本地真实RTC联调说明](../deploy/local-rtc/README.md)。
### 0.3.4 连续音频播放修复
- 火山返回的 `pcm_s16le/16kHz/mono` 音频进入常驻 AudioWorklet 环形缓冲,不再按 WebSocket 分片创建独立播放器。
- 默认预缓冲 120ms,网络瞬时抖动时自动重新缓冲,减少断音、金属音和语速漂移。
- 连续处理跨分片的奇数字节,并在开始、结束和断流时做短淡入淡出以避免爆音。
- 测试报告新增播放分片数、采样数和欠载次数。
### 0.3.3 失败会话修复
- 火山 `error` 事件与连接 Promise 的异常共用一个失败清理任务,同一轮仅提交一次 `session_failed`,保留首次错误。
- 失败清理期间禁止发送文字或重复结束;延迟到达的事件不再恢复“通话中”。失败后重新检测即可开始新一轮。
- 新通话清空上一轮验收结果、错误和计时;失败清理的关闭不再标为正常关闭。
- `npm test` 包含执行实际渲染器代码的并发失败回归测试,不会连接线上平台或消耗火山额度。
- 此修复不代表火山 `internal_error: StartVoiceChat failed` 的上游原因已解决。
本地自动回归证明 Windows 程序、平台控制面、数据库、PCM 管道和协议状态机完整可执行。最终真实火山验收仍必须使用实际 Instance/Product/Device/Bot/License 凭据,确认火山返回真实 ASR、LLM、TTS 音频;程序不会把本机模拟网关的 PASS 冒充真实供应商验收。