[Wake/VAD/STT 与 Live runtime]:完成真实重复语音运行,包含云端ASR/TTS开关、run-live和临时上下文测试

This commit is contained in:
mkbk
2026-06-17 20:00:55 +08:00
parent ac97daa1e7
commit 4b7cd18a0f
20 changed files with 1043 additions and 68 deletions
@@ -4,7 +4,7 @@
`add-voice-pet-pipeline` 已归档并生成 `voice-pet-pipeline` 主规范。当前仓库已有 Python 包、CLI acceptance、`.env` 配置读取、Provider 协议、mock 测试、桌宠资产和 OpenSpec 主规范,但真实运行能力仍不完整:没有 `run-live` 常驻命令,没有真实麦克风输入和扬声器输出,没有本地模型下载/检查,没有证明同一运行进程内可以连续多轮携带历史。
本设计聚焦第一版“无 GUI 的真实实时语音版”。GUI 桌宠窗口、长期记忆、播放中打断跨设备 Transport 和云端 STT/TTS 均不在本变更范围内。
本设计聚焦第一版“无 GUI 的真实实时语音版”。GUI 桌宠窗口、长期记忆、播放中打断跨设备 Transport 不在本变更范围内ASR/TTS 由 `.env``OWNER_SPEECH_PROVIDER=cloud|local` 控制,默认先走云端以保证真实可用
## Goals
@@ -12,8 +12,8 @@
2. 提供 `--once`,便于单轮真实验收和自动化测试。
3. 使用 `.env` 作为默认配置来源,避免要求用户导出 shell 环境变量。
4. 使用 `sounddevice` 真实读取本机麦克风。
5. 使用 `sherpa-onnx` 本地 VAD/STT 模型,模型存放在项目 `models/`
6. 使用 macOS `say/afplay` 先保证本地 TTS 真实播出
5. 使用 `OWNER_SPEECH_PROVIDER=cloud|local` 明确选择语音模型路径
6. 默认 cloud 模式使用 NewAPI 的 `mimo-v2.5-asr``mimo-v2.5-tts`local 模式保留 `sherpa-onnx`本地 TTS 路径
7. 在同一个 `run-live` 进程内保留最近 user/assistant 历史,进程退出即丢弃。
8. 新增自动化测试证明两轮 runtime、临时上下文、进程隔离和错误恢复。
@@ -34,10 +34,10 @@ CLI
-> LiveVoiceRuntimeFactory
-> SoundDeviceAudioTransport
-> WakeDetector("小杰小杰")
-> SherpaOnnxVadProvider
-> SherpaOnnxSttProvider
-> Energy/Sherpa VAD provider
-> CloudAsrSttProvider or SherpaOnnxSttProvider
-> OpenAI/NewAPI LlmProvider
-> MacOsSayTtsProvider
-> CloudTtsProvider or MacOsSayTtsProvider
-> ConversationContext(empty per process)
-> TerminalRuntimeReporter
@@ -58,7 +58,7 @@ LiveVoiceRuntime.run()
1. Parse CLI args.
2. Load `.env` and merge only explicitly supported defaults.
3. Validate LLM config.
4. Validate models when live mode requires local VAD/STT.
4. Validate speech provider mode; cloud mode validates credentials and model names, local mode validates project-local VAD/STT models.
5. Validate audio devices.
6. Create one `ConversationContext` for the process.
7. Enter loop:
@@ -184,12 +184,13 @@ Test requirements:
## Wake/VAD/STT Design
First implementation can use one of two local strategies:
First implementation can use one of two strategies:
1. Preferred: sherpa-onnx VAD for endpointing plus sherpa-onnx STT for short wake windows and user utterances.
2. Future replacement: dedicated local KWS provider for “小杰小杰”.
1. Default cloud mode: local VAD cuts speech segments, `mimo-v2.5-asr` transcribes wake and user segments through NewAPI-compatible `/v1/audio/transcriptions`.
2. Local mode: sherpa-onnx VAD/STT uses project-local model assets under `models/`.
3. Future replacement: dedicated local KWS provider for “小杰小杰”.
The implementation must not send raw audio to the cloud for wake, VAD, or STT. If a dedicated wake model is unavailable, wake detection may transcribe short local segments and search for the normalized wake word.
Cloud mode sends only VAD-cut speech segments to ASR, not the continuous microphone stream. Local mode does not send wake, VAD, or STT audio to the cloud. If a dedicated wake model is unavailable, wake detection may transcribe short speech segments and search for the normalized wake word.
## Model Download Design
@@ -241,4 +242,4 @@ No persistent data migration is needed. Existing `.env` remains valid. New optio
1. Which exact sherpa-onnx Chinese STT model gives the best latency/accuracy tradeoff on this Mac.
2. Whether future wake detection should use a dedicated KWS model instead of short-window STT.
3. Whether TTS should later move from macOS `say` to sherpa-onnx TTS for consistent voice and offline packaging.
3. Whether local TTS should later move from macOS `say` to sherpa-onnx TTS for consistent voice and offline packaging.
@@ -4,7 +4,7 @@
### 完整业务价值
本变更把现有语音桌宠从“可用 mock/fixture 验收链路”升级为“可真实运行的无 GUI 实时语音程序”。完成后,用户可以在 macOS 本机启动 `owner_voice_pet run-live`,程序常驻监听本机麦克风,说出唤醒词“小杰小杰”后进入录音,完成 VAD 端点检测、STT 转写、云端 LLM 回复、本地 TTS 语音合成和扬声器播放,然后自动回到待机继续监听下一轮。
本变更把现有语音桌宠从“可用 mock/fixture 验收链路”升级为“可真实运行的无 GUI 实时语音程序”。完成后,用户可以在 macOS 本机启动 `owner_voice_pet run-live`,程序常驻监听本机麦克风,说出唤醒词“小杰小杰”后进入录音,完成 VAD 端点检测、`.env` 选择的 ASR 转写、云端 LLM 回复、按 `.env` 选择的 TTS 语音合成和扬声器播放,然后自动回到待机继续监听下一轮。
该能力的核心价值是让桌宠语音链路从工程骨架变成可反复使用的真实语音入口。用户不需要手动运行一次性 acceptance,也不需要手工提供文本输入;只要进程存活,就可以多轮唤醒、多轮提问、多轮播放,并且同一次运行进程内的第二轮、第三轮会携带前面 user/assistant 历史,从而支持“刚才那句话”“继续解释上一轮”这类连续对话。
@@ -33,8 +33,8 @@
2. CLI 增加 `run-live``model-check``device-check`README 增加 `.env`、模型下载和真实运行说明。
3. Runtime 增加常驻循环,成功或失败都返回待机;`--once` 只用于测试和单轮人工验收。
4. Audio Transport 从占位实现升级为 `sounddevice` 本机麦克风输入和本机扬声器/播放器输出。
5. VAD/STT 从占位边界升级为 `sherpa-onnx` 本地模型 Provider 或明确的本地 Provider 装载路径;模型下载到项目 `models/`,不提交 Git
6. TTS 第一版选择 macOS 本地 `say/afplay`,优先保证真实播出;后续可用 OpenSpec 新变更替换为 `sherpa-onnx` TTS
5. ASR/TTS 从占位边界升级为可配置 Provider`OWNER_SPEECH_PROVIDER=cloud` 默认使用 NewAPI `mimo-v2.5-asr``mimo-v2.5-tts``OWNER_SPEECH_PROVIDER=local` 使用本地模型/本地播放路径
6. 本地模型仍下载到项目 `models/`,不提交 Git,并通过 `model-check` 验证
7. 对话上下文策略明确为“进程内临时历史”:同一个 `run-live` 进程保留多轮 user/assistant,进程退出即丢弃,不落盘。
8. 测试套件新增重复 runtime、临时上下文、进程本地上下文隔离、模型检查、设备检查的自动化覆盖。
@@ -67,7 +67,7 @@
6. `run-live` 必须使用本机扬声器播放回复音频,TTS 第一版允许通过 macOS `say` 生成音频,再用 `afplay` 或 transport 播放。
7. 唤醒词必须固定为“小杰小杰”;第一版可通过短语音段 STT 命中唤醒词,或通过本地 KWS Provider 命中唤醒词,但检测链路必须在本机执行。
8. 唤醒命中后必须进入录音和 VAD 端点检测;录音结束后进入 STT。
9. STT 必须优先本地实现,默认候选为 `sherpa-onnx`;模型文件必须位于项目 `models/`
9. STT/ASR 必须由 `.env``OWNER_SPEECH_PROVIDER` 决定;`cloud` 使用 `OWNER_ASR_MODEL=mimo-v2.5-asr``local` 使用项目 `models/` 下的本地模型
10. LLM 必须使用 `.env` 配置的云端 NewAPI/OpenAI 兼容接口;模型名来自配置,不能写死在核心逻辑。
11. 每轮 LLM 请求必须包含 system prompt、本次进程内最近 user/assistant 历史和当前 user message。
12. LLM 回复成功后必须追加 assistant 消息到同一个进程内 `ConversationContext`
@@ -144,7 +144,10 @@
4. `OWNER_LLM_API_STYLE`:第一版保留 `chat_completions` 或现有兼容值。
5. `OWNER_CONTEXT_MAX_MESSAGES`:本次进程内历史最大消息数。
6. `OWNER_CONTEXT_MAX_CHARS`:本次进程内历史最大字符数。
7. `OWNER_SPEECH_MODELS_DIR`:可选,默认 `models/`
7. `OWNER_SPEECH_PROVIDER``cloud``local`,默认 `cloud`
8. `OWNER_ASR_MODEL`:云 ASR 模型,默认 `mimo-v2.5-asr`
9. `OWNER_TTS_MODEL`:云 TTS 模型,默认 `mimo-v2.5-tts`
10. `OWNER_SPEECH_MODELS_DIR`:本地模型目录,默认 `models/`
#### CLI 输入
@@ -185,7 +188,7 @@
1. 新增 `LiveVoiceRuntime` 或等价 runtime 编排器,管理常驻循环、一次性模式、状态输出、错误恢复和共享 `ConversationContext`
2. 扩展 `SoundDeviceAudioTransport`,真实打开 `sounddevice` 输入流,提供录音片段读取,并支持本机播放或与 macOS 播放命令协作。
3. 新增或完善 `SherpaOnnxVadProvider``SherpaOnnxSttProvider` `models/` 加载本地模型
3. 新增或完善 `CloudAsrSttProvider``CloudTtsProvider``SherpaOnnxVadProvider``SherpaOnnxSttProvider` `OWNER_SPEECH_PROVIDER` 选择云端或本地语音路径
4. 新增模型下载脚本和检查命令,把模型资产生命周期从“人工假设”变成“可诊断前置条件”。
5. 修改 README 和 `.env.example`,用 `.env` 作为默认配置路径,明确运行命令和本地依赖安装命令。
6. 新增两轮 runtime 测试,证明真实运行层不是单轮 acceptance 的包装。
@@ -1,7 +1,7 @@
## ADDED Requirements
### Requirement: Live repeat voice runtime
The system SHALL provide a `run-live` command that performs real repeated voice conversation with local microphone input, local speech processing, cloud LLM reply generation, local TTS, local speaker playback, and automatic return to standby.
The system SHALL provide a `run-live` command that performs real repeated voice conversation with local microphone input, configured speech recognition and speech synthesis providers, cloud LLM reply generation, local speaker playback, and automatic return to standby.
#### Scenario: Live runtime starts in standby
- **WHEN** the user runs `PYTHONPATH=src python3.11 -m owner_voice_pet run-live`
@@ -46,6 +46,21 @@ The system SHALL provide project-local speech model preparation and diagnostics
- **WHEN** `sherpa-onnx` is unavailable, a model file is missing, or a model cannot be loaded
- **THEN** `model-check` SHALL fail with a structured model error and SHALL NOT start live microphone listening
### Requirement: Configurable speech provider mode
The system SHALL read `OWNER_SPEECH_PROVIDER` from `.env` to choose between cloud speech providers and local speech providers for first-version live runtime.
#### Scenario: Cloud speech provider is selected
- **WHEN** `OWNER_SPEECH_PROVIDER=cloud`
- **THEN** live ASR SHALL use the configured cloud model from `OWNER_ASR_MODEL`, live TTS SHALL use the configured cloud model from `OWNER_TTS_MODEL`, and the implementation SHALL default those models to `mimo-v2.5-asr` and `mimo-v2.5-tts`
#### Scenario: Local speech provider is selected
- **WHEN** `OWNER_SPEECH_PROVIDER=local`
- **THEN** live ASR/VAD SHALL use project-local speech model assets and local TTS SHALL use a local playback-capable provider
#### Scenario: Speech provider is invalid
- **WHEN** `OWNER_SPEECH_PROVIDER` is neither `cloud` nor `local`
- **THEN** startup validation SHALL fail with a structured configuration error
### Requirement: Live audio device readiness
The system SHALL provide live audio device diagnostics and SHALL use `sounddevice` for first-version real microphone and speaker access.
@@ -123,11 +138,11 @@ The system SHALL use the local microphone as the first-version input Transport a
- **WHEN** the microphone or speaker is missing, denied, unsupported, or inaccessible through `sounddevice`
- **THEN** the system SHALL expose a recoverable Transport error with a stable error code and SHALL NOT silently fall back to fixture audio in live mode
### Requirement: Local STT transcription
The system SHALL transcribe captured user utterances through a local STT provider, with `sherpa-onnx` as the first live implementation candidate and project-local models under `models/`.
### Requirement: Configured STT transcription
The system SHALL transcribe captured user utterances through the configured STT provider; cloud mode SHALL use NewAPI-compatible ASR and local mode SHALL use project-local `sherpa-onnx` model assets under `models/`.
#### Scenario: STT succeeds
- **WHEN** local STT returns non-empty text for a captured live audio segment
- **WHEN** configured STT returns non-empty text for a captured live audio segment
- **THEN** the pipeline SHALL add the trimmed text as a user message to the current process conversation context
#### Scenario: STT returns empty text
@@ -135,11 +150,11 @@ The system SHALL transcribe captured user utterances through a local STT provide
- **THEN** the live runtime SHALL skip LLM invocation and return to standby with a recoverable status
#### Scenario: STT provider fails
- **WHEN** the STT provider raises an error or cannot load its local model
- **WHEN** the STT provider raises an error, cloud ASR fails, or local model loading fails
- **THEN** the system SHALL emit an STT or model error code and SHALL recover to a state where future wake attempts are possible if startup can continue safely
### Requirement: Local TTS synthesis and playback
The system SHALL synthesize assistant replies through a local TTS provider and SHALL play synthesized speech through the local system output path, with macOS `say/afplay` accepted as the first live implementation.
### Requirement: Configured TTS synthesis and playback
The system SHALL synthesize assistant replies through the configured TTS provider and SHALL play synthesized speech through the local system output path; cloud mode SHALL use NewAPI-compatible TTS and local mode SHALL use a local playback-capable TTS provider.
#### Scenario: Reply text is ready for speech
- **WHEN** the LLM produces a non-empty reply for a live turn
@@ -27,21 +27,21 @@
## 4. Wake/VAD/STT 与模型检查
- [ ] 4.1 实现 `model-check` CLI;前置条件:模型 manifest 和路径约定完成;验收标准:检查依赖、目录、关键文件和 Provider 可加载性;测试要点:缺模型、缺依赖、成功三类测试;优先级:P0;预计:45 分钟。
- [ ] 4.2 实现 `SherpaOnnxVadProvider` 或等价本地 VAD 适配;前置条件:模型文件可用;验收标准:可分析帧并输出 speech/silence;测试要点:fake 模型或短音频 fixture;优先级:P0;预计:60 分钟。
- [ ] 4.3 实现 `SherpaOnnxSttProvider` 真实转写;前置条件:STT 模型文件可用;验收标准:可从 AudioSegment 返回中文文本;测试要点:空音频、无模型、成功 fixture;优先级:P0;预计:60 分钟。
- [ ] 4.4 实现 live 唤醒检测策略;前置条件:STT/VAD 可用;验收标准:能从实时音频中识别“小杰小杰”并进入录音,不把唤醒词传给 LLM;测试要点:命中/未命中测试;优先级:P0;预计:60 分钟。
- [ ] 4.5 增加 VAD 端点和 STT 文本有效性测试;前置条件:4.1 至 4.4 完成;验收标准:无语音、空文本、最大录音时长均可恢复待机;测试要点:runtime 状态断言;优先级:P0;预计:45 分钟。
- [ ] 4.6 验证并提交“Wake/VAD/STT 与模型检查”模块;前置条件:4.1 至 4.5 完成;验收标准:compileall、wake/vad/stt tests、model-check、OpenSpec strict 通过后 commit;测试要点:提交信息为中文格式;优先级:P0;预计:20 分钟。
- [x] 4.1 实现 `model-check` CLI;前置条件:模型 manifest 和路径约定完成;验收标准:检查依赖、目录、关键文件和 Provider 可加载性;测试要点:缺模型、缺依赖、成功三类测试;优先级:P0;预计:45 分钟。
- [x] 4.2 实现 `SherpaOnnxVadProvider` 或等价本地 VAD 适配;前置条件:模型文件可用;验收标准:可分析帧并输出 speech/silence;测试要点:fake 模型或短音频 fixture;优先级:P0;预计:60 分钟。
- [x] 4.3 实现 `SherpaOnnxSttProvider` 真实转写;前置条件:STT 模型文件可用;验收标准:可从 AudioSegment 返回中文文本;测试要点:空音频、无模型、成功 fixture;优先级:P0;预计:60 分钟。
- [x] 4.4 实现 live 唤醒检测策略;前置条件:STT/VAD 可用;验收标准:能从实时音频中识别“小杰小杰”并进入录音,不把唤醒词传给 LLM;测试要点:命中/未命中测试;优先级:P0;预计:60 分钟。
- [x] 4.5 增加 VAD 端点和 STT 文本有效性测试;前置条件:4.1 至 4.4 完成;验收标准:无语音、空文本、最大录音时长均可恢复待机;测试要点:runtime 状态断言;优先级:P0;预计:45 分钟。
- [x] 4.6 验证并提交“Wake/VAD/STT 与模型检查”模块;前置条件:4.1 至 4.5 完成;验收标准:compileall、wake/vad/stt tests、model-check、OpenSpec strict 通过后 commit;测试要点:提交信息为中文格式;优先级:P0;预计:20 分钟。
## 5. Live runtime、LLM/TTS 与临时上下文
- [ ] 5.1 新增 `LiveVoiceRuntime` 常驻循环;前置条件:Transport、Wake/VAD/STT 可用;验收标准:默认循环、`--once` 单轮、Ctrl-C 清理;测试要点:fake runtime 两轮;优先级:P0;预计:60 分钟。
- [ ] 5.2 新增 `run-live` CLI;前置条件:LiveVoiceRuntime 可构造;验收标准:读取 `.env`、构造 Provider、输出中文状态;测试要点:CLI 参数和错误码测试;优先级:P0;预计:60 分钟。
- [ ] 5.3 接入 LLM 请求临时历史;前置条件:ConversationContext 可复用;验收标准:第二轮请求包含第一轮 user/assistant;新 runtime 上下文为空;测试要点:temporary-context 和 process-local 测试;优先级:P0;预计:60 分钟。
- [ ] 5.4 接入 macOS `say/afplay` TTS 播放;前置条件:TTS Provider 已有边界;验收标准:非空回复可生成并播放音频;测试要点:mock subprocess 成功/失败;优先级:P0;预计:45 分钟。
- [ ] 5.5 增加 live 错误恢复;前置条件:runtime 主流程完成;验收标准:STT 空文本、LLM 失败、TTS 失败、播放失败后都恢复待机;测试要点:状态序列测试;优先级:P0;预计:60 分钟。
- [ ] 5.6 验证并提交“Live runtime 与临时上下文”模块;前置条件:5.1 至 5.5 完成;验收标准:compileall、unittest、security-check、OpenSpec strict 通过后 commit;测试要点:提交信息为中文格式;优先级:P0;预计:20 分钟。
- [x] 5.1 新增 `LiveVoiceRuntime` 常驻循环;前置条件:Transport、Wake/VAD/STT 可用;验收标准:默认循环、`--once` 单轮、Ctrl-C 清理;测试要点:fake runtime 两轮;优先级:P0;预计:60 分钟。
- [x] 5.2 新增 `run-live` CLI;前置条件:LiveVoiceRuntime 可构造;验收标准:读取 `.env`、构造 Provider、输出中文状态;测试要点:CLI 参数和错误码测试;优先级:P0;预计:60 分钟。
- [x] 5.3 接入 LLM 请求临时历史;前置条件:ConversationContext 可复用;验收标准:第二轮请求包含第一轮 user/assistant;新 runtime 上下文为空;测试要点:temporary-context 和 process-local 测试;优先级:P0;预计:60 分钟。
- [x] 5.4 接入 macOS `say/afplay` TTS 播放;前置条件:TTS Provider 已有边界;验收标准:非空回复可生成并播放音频;测试要点:mock subprocess 成功/失败;优先级:P0;预计:45 分钟。
- [x] 5.5 增加 live 错误恢复;前置条件:runtime 主流程完成;验收标准:STT 空文本、LLM 失败、TTS 失败、播放失败后都恢复待机;测试要点:状态序列测试;优先级:P0;预计:60 分钟。
- [x] 5.6 验证并提交“Live runtime 与临时上下文”模块;前置条件:5.1 至 5.5 完成;验收标准:compileall、unittest、security-check、OpenSpec strict 通过后 commit;测试要点:提交信息为中文格式;优先级:P0;预计:20 分钟。
## 6. 文档、真实验收、归档