[本地语音降噪]:完成本地语音链路和噪音过滤,包含降噪模型、本地ASR和实时字幕稳定策略

This commit is contained in:
mkbk
2026-06-17 22:55:33 +08:00
parent a77a172412
commit 8c75fc5baf
22 changed files with 803 additions and 64 deletions
+17 -10
View File
@@ -2,7 +2,7 @@
这是一个 Python 语音桌宠运行程序。当前第一版先提供无 GUI 的真实实时语音循环:
`小杰小杰` 唤醒 -> 本地应答“我在” -> 主说话人端点采集问题 -> ASR 转文字 -> 携带本次进程内临时历史调用 LLM -> TTS 生成语音 -> 本机扬声器播放 -> 回到待机继续监听。
`小杰小杰` 本地唤醒 -> 本地应答“我在” -> 本地降噪 -> 主说话人端点采集问题 -> 本地 STT/实时字幕 -> 携带本次进程内临时历史调用云端 LLM -> 本地 TTS -> 本机扬声器播放 -> 回到待机继续监听。
## 当前能力
@@ -10,10 +10,10 @@
- `owner_voice_pet run-live --once`:只跑一轮,便于验收。
- `.env` 直接读取配置,不要求导出 shell 环境变量。
- 唤醒词检测使用本地 `sherpa-onnx` KWS 模型,不走云端 ASR。
- `OWNER_SPEECH_PROVIDER=cloud|local`选择云端语音模型或本地语音模型
- 默认云端语音模型:`mimo-v2.5-asr``mimo-v2.5-tts`
- `OWNER_SPEECH_PROVIDER=local`默认除 LLM 外全用本地语音链路;`cloud` 仅作为显式兼容选项
- 本地语音默认:wake/VAD/STT/实时字幕/TTS/降噪全部在本机执行,LLM 继续走 `.env` 中的云端配置
- 本地设备:`sounddevice` 读取麦克风,扬声器或 `afplay` 播放。
- 本地模型:`models/` 存放 `sherpa-onnx` wake/VAD/STT 模型,目录不提交 Git。
- 本地模型:`models/` 存放 `sherpa-onnx` wake/VAD/STT/denoiser 模型,目录不提交 Git。
- Pipeline`run-live` 使用 stage 化 `VoiceAssistantPipeline`,通过事件总线输出终端状态。
- 主说话人端点:默认 `OWNER_ENDPOINT_MODE=primary_speaker`,本轮音色消失后结束录音,避免背景噪声拖慢 STT。
- 临时上下文:同一次 `run-live` 进程内携带最近 user/assistant 历史,退出即清空。
@@ -43,6 +43,9 @@ OWNER_WAKE_ACK_TEXT=我在
OWNER_POST_PLAYBACK_DRAIN_MS=0
OWNER_PIPELINE_MODE=live_turn_based
OWNER_ENDPOINT_MODE=primary_speaker
OWNER_NOISE_FILTER_ENABLED=1
OWNER_NOISE_FILTER_PROVIDER=sherpa_onnx_gtcrn
OWNER_WAKE_DENOISE_ENABLED=0
OWNER_SPEAKER_PROFILE_MS=600
OWNER_SPEAKER_PROFILE_MIN_MS=120
OWNER_SPEAKER_ABSENT_MS=300
@@ -54,20 +57,22 @@ OWNER_VAD_MIN_DURATION_MS=250
OWNER_VAD_END_SILENCE_MS=350
OWNER_VAD_NO_SPEECH_TIMEOUT_MS=5000
OWNER_VAD_MAX_RECORDING_MS=12000
OWNER_SPEECH_PROVIDER=cloud
OWNER_SPEECH_PROVIDER=local
OWNER_ASR_MODEL=mimo-v2.5-asr
OWNER_TTS_MODEL=mimo-v2.5-tts
OWNER_TTS_VOICE=mimo_default
OWNER_CONTEXT_MODE=session_memory
```
`OWNER_WAKE_PROVIDER=local_kws` 表示唤醒词“小杰小杰”由本地模型检测。唤醒命中后会先本地播报 `OWNER_WAKE_ACK_TEXT=我在`,再开始听取问题。`OWNER_SPEECH_PROVIDER=cloud` 只影响唤醒后的正式问题 ASR/TTS:它会把 VAD 切出来的用户问题片段发送到云端 ASR,不会上传连续麦克风流,也不会用云端判断唤醒。改成 `local` 时使用项目 `models/` 下的本地语音模型路径
`OWNER_WAKE_PROVIDER=local_kws` 表示唤醒词“小杰小杰”由本地模型检测。唤醒命中后会先本地播报 `OWNER_WAKE_ACK_TEXT=我在`,再开始听取问题。`OWNER_SPEECH_PROVIDER=local` 表示正式问题 STT、实时字幕和 TTS 都走本地模型或 macOS 本地能力;云端只接收 final 文本和本次会话历史用于 LLM 回复
`OWNER_REALTIME_TRANSCRIPT_ENABLED=1` 表示录音期间会使用本地 streaming STT 实时显示中间转写,终端会输出 `实时转写:...`;最终发送给 LLM 的内容仍以 `转写结果:...` 为准。设置为 `0` 可以临时关闭实时显示
`OWNER_NOISE_FILTER_ENABLED=1` 表示唤醒后的正式问题阶段默认启用本地 GTCRN 降噪。降噪后的同一份音频会进入 VAD、实时字幕和 final STT;wake 阶段默认保持原始音频,`OWNER_WAKE_DENOISE_ENABLED=0` 可以避免降噪影响“小杰小杰”的 KWS 特征
`OWNER_REALTIME_TRANSCRIPT_ENABLED=1` 表示录音期间会使用本地 streaming STT 实时显示中间转写,终端会输出 `实时转写:...`。为了过滤噪音,实时字幕默认不会显示 `家``家确` 这类很短的瞬时误识别;最终发送给 LLM 的内容仍只以 `转写结果:...` 为准。设置为 `0` 可以临时关闭实时显示。
## 本地模型
即使默认走云端 ASR/TTS,也必须准备本地唤醒模型;同一脚本会下载 wake、VAD、STT 模型,便于切换到 `OWNER_SPEECH_PROVIDER=local`
首次运行前必须准备本地语音模型;同一脚本会下载 wake、VAD、2025 中文 CTC STT 和 GTCRN denoiser 模型
```bash
python3.11 scripts/download_speech_models.py --dir models
@@ -76,6 +81,8 @@ python3.11 scripts/download_speech_models.py --dir models
`models/` 已在 `.gitignore` 中,不会提交大模型文件。
默认本地 STT 使用 sherpa-onnx 官方 2025 中文 CTC int8 模型,manifest 里的关键文件是 `tokens.txt``model.int8.onnx`。旧 14M transducer 模型仍可通过旧 manifest 兼容,但不再作为默认实时字幕质量基线。
本地唤醒关键词文件位于 `models/wake/keywords.txt`。默认 `OWNER_WAKE_KWS_THRESHOLD=0.15` 已偏向灵敏;如果真人唤醒仍不灵敏,可以继续降到 `0.10`,若误唤醒变多再回调到 `0.20`
默认 `OWNER_ENDPOINT_MODE=primary_speaker` 会在本轮问题开头建立临时音色画像;`OWNER_SPEAKER_PROFILE_MIN_MS=120` 表示最少 120 毫秒有效语音即可让画像参与端点判断。当这个主说话人音色连续消失 `OWNER_SPEAKER_ABSENT_MS=300` 毫秒后,直接结束录音进入转写。它不保存长期声纹、不做主人注册、不跨进程记忆。
@@ -104,7 +111,7 @@ python3.11 scripts/download_speech_models.py --dir models
.venv/bin/python -m owner_voice_pet run-live
```
运行后终端状态来自 pipeline event bus,会显示待机、唤醒命中、应答中、请说出问题、录音中、检测到用户语音、实时转写、用户语音结束、转写中、转写结果、思考中、播放中、恢复待机等状态。说“小杰小杰”,听到“我在”且看到“请说出问题”后再提问;听到回复后可以再次说“小杰小杰”继续下一轮。本次进程内会携带临时历史,程序退出后不保存。
运行后终端状态来自 pipeline event bus,会显示待机、唤醒命中、应答中、请说出问题、录音中、检测到用户语音、实时转写、用户语音结束、转写中、转写结果、思考中、播放中、恢复待机等状态。说“小杰小杰”,听到“我在”且看到“请说出问题”后再提问;听到回复后可以再次说“小杰小杰”继续下一轮。本次进程内会携带临时历史,程序退出后不保存。背景噪声下如果实时字幕仍偶发短错字,先看最终 `转写结果`;最终文本才会进入 LLM。
## 验证
@@ -130,5 +137,5 @@ LLM smoke
- API key 只写入本地 `.env``.env` 不提交 Git。
- `models/``.venv/` 和临时音频文件不提交 Git。
- 默认不持久化麦克风原始音频。
- 云端 ASR 只接收 VAD 切分后的语音片段
- 默认不使用云端 ASR/TTS;云端 LLM 只接收最终用户文本和本次运行内临时历史
- `security-check` 会扫描已跟踪文本文件中的 `sk-...``tp-...` 形式密钥。