164 lines
7.5 KiB
Markdown
164 lines
7.5 KiB
Markdown
# 语音助手会话方案 v1(服务端 + 机端对齐)
|
||
|
||
本文档描述 **「唤醒 → 问候 → 滴声开录 → 断句上云 → 提示音 → 云端理解与 TTS → 分支循环/待机」** 的端到端方案,供 **服务端(voicellmcloud)** 与 **机端(本仓库 voice_drone_assistant)** 分工落地。
|
||
|
||
**v1 明确不做**:播报中途 **抢话 / 打断 TTS(barge-in)**;播放 TTS 时机端 **关麦或不处理用户语音**。
|
||
|
||
**关联协议**:
|
||
|
||
- 音频上行与 Fun-ASR:[CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md](./CLOUD_VOICE_PROTOCOL_pcm_asr_uplink_v1.md)
|
||
- 未唤醒不上云:由服务端/产品文档 `CLOUD_VOICE_CLIENT_WAKE_GATE_v1` 约定(机端须本地门禁后再建联上云)
|
||
- 总接口:以 voicellmcloud 仓库 `API_SPECIFICATION` 为准
|
||
- 飞控确认窗:[CLOUD_VOICE_FLIGHT_CONFIRM_v1.md](./CLOUD_VOICE_FLIGHT_CONFIRM_v1.md)
|
||
|
||
---
|
||
|
||
## 1. 产品流程(用户视角)
|
||
|
||
1. 用户说唤醒词(如「无人机」,由机端配置),**仅本地处理,不上云 ASR**。
|
||
2. 机端播放问候语(如「你好,有什么事儿吗」)— 可用本地 TTS 或 `tts.synthesize`。
|
||
3. 机端 **滴一声**,表示 **开始收音**;同时启动 **5 秒静默超时** 计时(见 §4)。
|
||
4. 用户说话;机端 **VAD/端点检测** 得到 **一整句** 后:
|
||
- 播放 **极短断句提示音**(表示「已截句、将上云」);
|
||
- **提示音播放期间闭麦或做回声隔离**,提示音结束后 **短消抖**(建议 **150~300 ms**)再恢复采集逻辑,避免把提示音当成用户语音。
|
||
5. 将该句 **PCM** 以 `turn.audio.*` 发云端;云端 **Fun-ASR → LLM → `dialog_result` → TTS**;机端播完 **全部** `tts_audio_chunk` 及收到 **`turn.complete`** 后,视为本轮播报结束(见 §3 服务端)。
|
||
6. **分支**:
|
||
- **`routing === flight_intent`**:进入 **飞控子状态机**(口头确认/取消/超时),**不使用** §4 的「闲聊滴声后 5s」规则覆盖确认窗;超时以 **`dialog_result.confirm.timeout_sec`** 及 [CLOUD_VOICE_FLIGHT_CONFIRM_v1.md](./CLOUD_VOICE_FLIGHT_CONFIRM_v1.md) 为准。
|
||
- **`routing === chitchat`**:本轮结束后 **再滴一声**,进入下一轮 **步骤 4**(同一 WebSocket 会话内 **新 `turn_id`** 再起一轮 `turn.audio.*`)。
|
||
7. 若在 **步骤 3 的滴声之后** 连续 **5 s** 内未检测到有效语音(见 §4),机端播 **超时提示音**,**不再收音**,回到 **待机**(仅唤醒)。
|
||
|
||
---
|
||
|
||
## 2. 机端状态机(规范性)
|
||
|
||
| 状态 | 含义 | 开麦 | 上云 ASR | 备注 |
|
||
|------|------|------|----------|------|
|
||
| `STANDBY` | 仅监听唤醒 | 按现网 VAD | **禁止** `turn.audio.*` | 本地 STT + 唤醒词 |
|
||
| `GREETING` | 播问候 | 可关麦或忽略输入 | 否 | 避免问候进识别 |
|
||
| `PROMPT_LISTEN` | 已滴「开始录」,等用户一句 | 开 | 否 | **5s 超时**在此状态监控 |
|
||
| `SEGMENT_END` | 已断句,播短提示音 | **闭麦/屏蔽** | 否 | 消抖后再转 `UPLOADING` |
|
||
| `UPLOADING` | 发送 `turn.audio.*` | 否 | **是** | 一轮一个 `turn_id` |
|
||
| `PLAYING_CLOUD_TTS` | 播云端 TTS | **关麦**(v1 无抢话) | 否 | 至 `turn.complete` + PCM 播完 |
|
||
| `FLIGHT_CONFIRM` | 飞控确认窗 | 按飞控文档 | **可** `turn.text` 或按产品另定 | **独立超时**,不共用 5s |
|
||
| `CHITCHAT_TAIL` | 闲聊结束,将再滴一声 | — | 否 | 回到 `PROMPT_LISTEN` |
|
||
|
||
**并发**:同一时刻仅允许 **一路** `turn.audio.start`~`end`;须等 `turn.complete` 后再开下一轮(与现有 `pipeline_lock` 一致)。
|
||
|
||
**唤醒前**:须满足未唤醒不上云的产品/协议约定。
|
||
|
||
---
|
||
|
||
## 3. 服务端(voicellmcloud)职责 — v1 **无新消息类型**
|
||
|
||
### 3.1 单轮行为(不变)
|
||
|
||
对每个完整 `turn.audio.*` 或 `turn.text`:
|
||
|
||
1. Fun-ASR(仅 `pcm_asr_uplink` + 音频轮)→ 文本
|
||
2. LLM 流式 → `dialog_result`(`routing` / `flight_intent` / `chat_reply` 等)
|
||
3. `tts_audio_chunk*` → `turn.complete`
|
||
|
||
服务端 **不** 下发「请再滴一声」「进入待机」类机端 UX 信令;这些由机端根据 **`routing` + `turn.complete`** **固定规则** 驱动。
|
||
|
||
### 3.2 机端判定「播报完成」
|
||
|
||
须同时满足:
|
||
|
||
- 收到该轮 **`turn.complete`**
|
||
- 已按序播完该轮关联的 **binary PCM**(`tts_audio_chunk` 与现实现一致)
|
||
|
||
然后机端再执行 §1 步骤 6 的分支。
|
||
|
||
### 3.3 可选下行
|
||
|
||
- **`asr.partial`**:机端 **不得** 用于驱动状态跳转;仅可 UI 展示。
|
||
- **错误**:`error` / `ASR_FAILED` 等 → 机端播简短失败提示后,建议 **回 `STANDBY` 或回到 `PROMPT_LISTEN`**(产品定)。
|
||
|
||
---
|
||
|
||
## 4. 5 秒静默超时(闲聊路径)
|
||
|
||
| 项 | 约定 |
|
||
|----|------|
|
||
| **起算点** | 「**开始收音**」的 **滴声播放结束** 时刻(或滴声后固定 **50~100 ms** 偏移,避免与滴声能量重叠)。 |
|
||
| **「无说话」** | 麦克 **RMS / VAD** 低于阈值,持续累计 ≥ **5 s**(建议可配置,默认 5)。 |
|
||
| **期间若开始说话** | 清零超时;**断句上云**后本超时在下一轮「滴声」后重新起算。 |
|
||
| **触发动作** | 播 **超时提示音** → 进入 **`STANDBY`**(不再滴声、不上云)。 |
|
||
| **不适用** | **`FLIGHT_CONFIRM`** 整段;确认窗用 **服务端给的 `timeout_sec`**。 |
|
||
|
||
**机端配置**(`system.yaml` `cloud_voice`):`listen_silence_timeout_sec`、`post_cue_mic_mute_ms`、`segment_cue_duration_ms`;环境变量见 `main_app.py` 头部说明。
|
||
|
||
---
|
||
|
||
## 5. 断句后提示音(工程)
|
||
|
||
| 项 | 约定 |
|
||
|----|------|
|
||
| 目的 | 用户感知「已截句,可等待播报」 |
|
||
| 实现 | 机端本地短 WAV / 蜂鸣;时长建议 **≤ 200 ms** |
|
||
| 回声 | **SEGMENT_END** 阶段闭麦或硬件 AEC;结束后 **≥ 150 ms** 再进入 `UPLOADING` |
|
||
| 与云端 | **无需** 上传该提示音 |
|
||
|
||
---
|
||
|
||
## 6. 时序简图(闲聊多轮)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户
|
||
participant D as 机端
|
||
participant S as 服务端
|
||
|
||
U->>D: 唤醒词(本地)
|
||
D->>D: GREETING 播问候
|
||
D->>D: 滴声 → PROMPT_LISTEN(起 5s 定时)
|
||
U->>D: 一句语音
|
||
D->>D: VAD 断句 → 短提示音 → UPLOADING
|
||
D->>S: turn.audio.start/chunk/end
|
||
S->>D: asr.partial(可选)
|
||
S->>D: dialog_result + TTS + turn.complete
|
||
D->>D: PLAYING_CLOUD_TTS(关麦)
|
||
alt chitchat
|
||
D->>D: 再滴声 → PROMPT_LISTEN
|
||
else flight_intent
|
||
D->>D: FLIGHT_CONFIRM(独立超时)
|
||
end
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 配置建议(机端)
|
||
|
||
| 键 | 默认值 | 说明 |
|
||
|----|--------|------|
|
||
| `listen_silence_timeout_sec` | `5` | 滴声后起算 |
|
||
| `post_cue_mic_mute_ms` | `150`~`300` | 断句提示音后再采集 |
|
||
| `cue_tone_duration_ms` / `segment_cue_duration_ms` | `≤200` | 断句提示 |
|
||
| `flight_confirm_handling` | 遵循飞控文档 | 禁用闲聊 5s 覆盖 |
|
||
|
||
---
|
||
|
||
## 8. 机端开发自检
|
||
|
||
- [ ] `STANDBY` 下无 `turn.audio.start`。
|
||
- [ ] `PLAYING_CLOUD_TTS` 与 `SEGMENT_END` 提示音阶段 **不开麦**(v1)。
|
||
- [ ] 每轮新 `turn_id`;不并行两轮音频上行。
|
||
- [ ] `flight_intent` 后进入 `FLIGHT_CONFIRM`,**不**误用 5s 闲聊超时。
|
||
- [ ] `chitchat` 在 TTS 完成后 **再滴** 再 `PROMPT_LISTEN`。
|
||
|
||
---
|
||
|
||
## 9. 非目标(v1)
|
||
|
||
- 播报中抢话、打断 TTS、实时 re-prompt。
|
||
- 服务端驱动「滴声/待机」(均由机端规则实现)。
|
||
- 连续免唤醒「直接说指令」跨多轮(若需另开 v2)。
|
||
|
||
---
|
||
|
||
## 10. 修订记录
|
||
|
||
| 版本 | 日期 | 说明 |
|
||
|------|------|------|
|
||
| v1 | 2026-04-07 | 首版:小爱类会话 + 双端分工;不含 barge-in |
|