# Ziin PC 端语音接入说明 v1

这份说明解决一个很具体的问题：

- 为什么有的系统里已经有“业务助手 / 使用助手”，但 PC 端没有语音
- PC 端语音到底要接哪些前后端环节
- 接到什么程度，才算不是“文字助手”，而是真正可用的语音助手

## 1. 先说结论

如果某个系统的 PC 端没有语音，通常不是因为 Ziin 后端不支持，也不是因为产品定义里没有语音。

更常见的真实原因是：

- 只接了文字问答入口
- 没接录音按钮
- 没接浏览器麦克风权限申请
- 没接语音文件上传
- 没接 ASR 任务创建与轮询
- 没把转写结果回填到 query

所以“PC 端没语音”本质上一般是前端接入不完整，不是能力不存在。

## 2. 当前仓库里已经有的 PC 语音链路

当前官网版本已经实现过一条完整的 PC 浏览器录音链路，参考：

- `components/floating-ziin-assistant.tsx`

关键点：

- 浏览器权限：`navigator.mediaDevices.getUserMedia({ audio: true })`
- 浏览器录音：`MediaRecorder`
- 录音文件上传：`POST /api/site-demo/media/upload-token` + `POST /api/site-demo/media/upload-complete`
- 创建 ASR 任务：`POST /api/site-demo/media/asr/transcribe`
- 查询任务结果：`GET /api/site-demo/media/tasks/:taskId`
- 识别完成后，再发起正式 `query`

这说明：

- PC 浏览器端语音是可做的
- 当前 Ziin 站点也已经这样做了
- 其他系统如果没有语音，通常只是没有把这段接入复制过去

## 3. PC 端最小接入链路

### 前端最小步骤

1. 页面上提供录音入口
2. 点击或按住后申请麦克风权限
3. 用 `MediaRecorder` 录音
4. 停止录音后得到 `Blob`
5. 上传原始音频文件
6. 调用 ASR 接口创建任务
7. 轮询任务状态直到 `success`
8. 取回 transcript
9. 把 transcript 作为问题继续提交给 `query`

### 后端最小步骤

1. 接收上传凭证申请
2. 完成文件上传确认
3. 创建 `asr.voice` 任务
4. 调度真实 ASR provider
5. 存储任务结果
6. 提供任务查询接口
7. 把 transcript 接回标准问答链路

## 4. PC 端必须具备的浏览器能力

不是所有嵌入环境都天然支持浏览器录音。

最少需要：

- `navigator.mediaDevices.getUserMedia`
- `MediaRecorder`
- HTTPS 环境
- 用户允许麦克风权限

如果缺任一项：

- 不能直接用浏览器录音
- 就只能退回文字输入
- 或改成宿主客户端原生录音后再上传

## 5. 为什么有些 PC 系统看起来“只有文字助手”

因为很多系统第一版接入时只做了下面这些：

- 一个悬浮入口
- 一个文本输入框
- 一个调用 `query` 的接口

这在演示时已经能看起来“像助手”。

但语音真正多出来的是另一整条链路：

- 麦克风权限
- 录音状态管理
- 文件上传
- 异步转写
- 任务轮询
- 失败处理
- 转写结果回填

所以实际项目里经常出现：

- 产品上说支持多模态
- 后端上也确实有 ASR
- 但某个嵌入系统里只有文字版助手

这并不矛盾，只是接入没做完整。

## 6. 推荐的前端交互形态

PC 端不建议只放一个小麦克风图标然后什么反馈都没有。

至少要有：

- 录音开始态
- 录音中态
- 上传中态
- 转写中态
- 转写失败态
- 自动回填后的提问态

用户必须明确知道当前是在：

- 录音
- 上传
- 识别
- 生成答案

否则 PC 端体验会很像“点了没反应”。

## 7. 标准接口顺序

推荐顺序如下：

1. `POST /media/upload-token`
2. `POST /media/upload-complete`
3. `POST /media/asr/transcribe`
4. `GET /media/tasks/:taskId`
5. `POST /api/ziin/query`

如果是站内 demo 通道，对应就是：

1. `POST /api/site-demo/session`
2. `POST /api/site-demo/media/upload-token`
3. `POST /api/site-demo/media/upload-complete`
4. `POST /api/site-demo/media/asr/transcribe`
5. `GET /api/site-demo/media/tasks/:taskId`
6. `POST /api/site-demo/query`

## 8. 推荐的数据回填方式

语音识别完成后，不要只把 transcript 当普通字符串扔进输入框。

更稳的做法是：

- 把 transcript 作为 `question`
- 同时把原始音频作为一类输入信号记录
- 把多模态入口 payload 一并传给 `query`

这样做的好处是：

- 审计可追踪
- 学习闭环知道这次是语音输入
- 后续能区分“文字提问”和“语音提问”

## 9. 失败时该怎么降级

PC 端语音不是必须 100% 成功，但失败时要有明确降级：

- 浏览器不支持录音：退文字输入
- 用户拒绝麦克风权限：退文字输入
- 上传失败：允许重试
- ASR 失败：提示转写失败并允许改为文字
- transcript 为空：提示未识别到有效语音

正确姿势不是“失败后没反应”，而是“失败后明确切回文字模式”。

## 10. 对接入方最重要的一句话

如果你的 PC 端现在只有“业务助手 / 使用助手”的文字问答，那不是 Ziin 不支持语音，而是你的 PC 前端还没把语音入口和转写链路接进去。

真正要补的是接入，不是换产品方向。
