agentleFS
28672032962867203296/hermes-agent/skills/hermes/voice-full-restore/SKILL.md

voice-full-restore

Skill0 starsChanged 3 months agoMITView on GitHub

Windows 语音全链路修复:TTS播放+STT转录+whisper模型+barge_in+唤醒词。Hermes 更新后一键恢复。

The file

Files
SKILL.md

Windows 语音全链路修复

Hermes 更新后语音功能可能丢失,此技能包含全部四个修复点(TUI+CLI 双路径)。

⚠️ 关键区分:CLI vs TUI TTS 自动播放

这是最常见的困惑点。

模式启动命令TTS 自动播放全语音闭环
CLIhermes/voice on 后可用/voice on + Ctrl+B
TUIhermes tui✅ 生成+自动播放✅
  • CLI 模式 text_to_speech 工具只产出文件不播放;但敲 /voice on 后 Ctrl+B 说话会走完整语音闭环(STT→Agent→TTS→扬声器)
  • TUI 模式原生支持全自动语音,进入后 /voice on 即可

🔧 TTS "又炸了" 快速诊断(30秒)

用户说"TTS又炸了"时,按此顺序排查,不要直接修代码:

# 1. 引擎层:TTS 能生成文件吗?
D:/Hermes/hermes-agent/.venv/Scripts/python.exe -c "
from text_to_speech import text_to_speech
text_to_speech(text='诊断测试', output_path='D:/Hermes/cache/audio/diag.mp3')
print('生成成功')
"

# 2. 播放层:ffplay 能用吗?
ffplay -version 2>&1 | head -1 || echo "ffplay 不可用"

# 3. 如果都正常 → 问题在模式(CLI不自动播放 vs TUI自动播放),非引擎故障
# 4. 如果引擎报错 → 检查 Edge TTS 网络连通性

常见误判:CLI 模式下助手调 text_to_speech 生成文件但不播放 → 用户以为 TTS 炸了。这不是 bug,是 CLI 模式设计行为。切 /voice on 或 hermes tui。

🔧 STT "转文字失败" 快速诊断(30秒)

用户说"说话没反应"/"转文字崩了"时,先区分 TTS 还是 STT:

  • 能听到播报但说话没反应 → STT 问题(本节)
  • 听不到播报 → TTS 问题(上一节)
# 1. 查 STT 配置
D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config get stt

# 2. 关键字段:provider 和 local.model 路径
#    如果 provider=local → 检查本地 whisper 模型是否存在
#    如果 provider=openai → 检查 API key

# 3. 检查本地模型文件(最常见的 STT 故障原因)
ls "D:/sofeware/cache/modelscope/models/Systran/faster-whisper-medium/" 2>/dev/null || echo "模型文件丢失!"

# 4. 查日志确认根因
grep -i "transcri\|whisper\|stt" "D:/Hermes/logs/errors.log" | tail -10

常见 STT 故障根因:

  • HFValidationError: Repo id must be in the form 'namespace/repo_name' + 模型目录为空 → 本地模型文件丢失,faster-whisper 试图把路径当 repo ID 去 HF 下载但格式不合法
  • HFValidationError 但模型文件齐全(ls 显示 5 个文件)→ Windows 路径间歇性被 faster-whisper 误判,需 patch 代码。详见 references/stt-hfvalidation-with-files-present.md
  • 模型目录为空 → 文件被清理/迁移后残留空目录
  • "No speech detected 3 times, continuous mode stopped" → 见下方专项诊断

🔧 "No speech detected" / 转录返回空 — 专项诊断 ⚠️ 高频坑

症状:录音正常(WAV 文件有峰值>2000),但 STT 返回空,日志显示 Filtered Whisper hallucination: '' 或连续 3 次空转录后自动停止。

根因优先级(按概率排序):

  1. Silero VAD 过滤真实语音(最常见!)— faster-whisper 内置 VAD 把用户语音判为静音,whisper 根本没收到音频
  2. 幻觉过滤器过激 — _join_confident_segments 把正常段当幻觉丢弃
  3. CUDA 加载失败 — cublas64_12.dll 缺失导致首次 transcribe 崩溃

诊断步骤(5 分钟):

# 1. 拿真实录音直接测 STT(跳过 Hermes 管线)
D:/Hermes/hermes-agent/.venv/Scripts/python.exe -c "
from faster_whisper import WhisperModel
m = WhisperModel('D:/sofeware/cache/modelscope/models/Systran/faster-whisper-medium', device='cpu', compute_type='int8')
# 关 VAD 测
segs, info = m.transcribe('D:/sofeware/cache/Temp/hermes_voice/recording_XXXX.wav', beam_size=5, language='zh', vad_filter=False, condition_on_previous_text=False)
for s in segs: print(f'[{s.text.strip()}] no_sp={s.no_speech_prob:.2f} logp={s.avg_logprob:.2f}')
# 开 VAD 测(对比)
segs2, _ = m.transcribe('<same_file>', beam_size=5, language='zh', vad_filter=True, condition_on_previous_text=False)
print('VAD结果:', ' '.join(s.text.strip() for s in segs2))
"

# 2. 如果关 VAD 有结果但开 VAD 为空 → Silero VAD 是凶手,立即关掉
# 3. 如果关 VAD 也无结果 → 录音本身可能是噪音/静音

修复(按推荐度):

# P0: 关 Silero VAD(90% 的情况这是根因)
D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set stt.local.vad false

# P1: 强制 CPU 绕开 CUDA 崩溃
D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set stt.local.device cpu
D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set stt.local.compute_type int8

# P2: 放宽幻觉过滤阈值
D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set stt.local.no_speech_prob_threshold 0.9
D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set stt.local.logprob_threshold -3.0

配置最终状态:

stt:
  local:
    model: D:/sofeware/cache/modelscope/models/Systran/faster-whisper-medium
    language: zh
    device: cpu          # 强制 CPU,跳过 CUDA 探测
    compute_type: int8
    vad: false           # 关 Silero VAD
    no_speech_prob_threshold: 0.9   # 放宽(默认 0.6)
    logprob_threshold: -3.0         # 放宽(默认 -1.0)

注意:录音采样率 44100Hz 不是问题,faster-whisper 内部会重采样处理,已验证 44100Hz WAV 转录正常工作。

🔧 语音启动即卡死 / Hermes 冻住(三重条件)⚠️ 高频坑

症状:Hermes 启动后卡死,或 /voice on 后直接冻住,无任何响应。

三重致死条件(三个同时满足 = 必卡死):

  1. voice.auto_enable: true + voice.continuous_mode: true → 启动自动进连续监听
  2. 唤醒词补丁丢失(server.py 中无 _voice_wake_active)→ 无法过滤噪音,所有声音都提交
  3. STT 底层报错(HFValidationError / cublas 缺失)→ 引擎崩溃卡住主线程

快速修复(30秒):

D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set voice.auto_enable false
D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set voice.continuous_mode false

然后 /reload。之后语音不会自动启动,需要时手动 /voice on。

验证补丁状态:

grep -c '_voice_wake_active' D:/Hermes/hermes-agent/tui_gateway/server.py
# 0 = 补丁丢失 → 必须关闭 auto_enable,或重新打补丁

根因链:auto_enable 启动连续监听 → 无唤醒词过滤 → 环境噪音被 STT 处理 → STT 模型加载失败(HFValidationError/cublas)→ 错误处理卡住主循环 → Hermes 整体冻住。

勿混淆:这不是 TTS 或 STT 单独的问题,是三重条件叠加的结果。单独修复任一个都能解除卡死,但关闭 auto_enable 最快。

修复 5:重新下载 whisper 模型

# 使用 HF 镜像下载(约 1.5GB,1-2分钟)
mkdir -p "D:/sofeware/cache/modelscope/models/Systran/faster-whisper-medium"
HF_ENDPOINT=https://hf-mirror.com D:/Hermes/hermes-agent/.venv/Scripts/python.exe -c "
from huggingface_hub import snapshot_download
snapshot_download('Systran/faster-whisper-medium', 
    local_dir='D:/sofeware/cache/modelscope/models/Systran/faster-whisper-medium')
print('下载完成')
"

# 验证:5个文件(config.json, model.bin, README.md, tokenizer.json, vocabulary.txt)
ls "D:/sofeware/cache/modelscope/models/Systran/faster-whisper-medium/"

下载完成后 STT 立即恢复,无需 /reload。

⚠️ 如果下载完模型、文件齐全,但 STT 仍报 HFValidationError — 这是 faster-whisper 在 Windows 上间歇性不识别本地路径,并非模型问题。 需要 patch _load_local_whisper_model 函数, 详见 references/stt-hfvalidation-with-files-present.md。

详细错误特征见 references/stt-whisper-model-missing-error.md。

前置检查

# 确认 Hermes 版本
hermes --version

# 确认 ffplay 状态
python -c "import subprocess; subprocess.run(['ffplay','-version'],capture_output=True)"
# 如果报 WinError 4551 → ffplay 被 WDAC 阻止

修复 1:TTS 播放(ffplay 回退)

文件:tools/voice_mode.py,play_audio_file() 函数,ffplay 失败后、logger.warning("No audio player") 之前。

插入 Windows 两级回退:

if system == "Windows":
    try:
        subprocess.run(["cmd","/c","start","",file_path],
            stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=30)
        return True
    except: pass
    try:
        subprocess.run(["powershell","-Command",
            f"Add-Type -AssemblyName PresentationCore;"
            f"$p=New-Object System.Windows.Media.MediaPlayer;"
            f"$p.Open('{file_path}');$p.Play();Start-Sleep -Seconds 10"],
            stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=35)
        return True
    except: pass

修复 2:TTS 自打断

D:/Hermes/hermes-agent/.venv/Scripts/hermes.exe config set voice.barge_in false

原因:扬声器声音被麦克风捕获 → barge_in 误判用户说话 → 切断 TTS。

修复 3:TUI 路径唤醒词(嘿/Jarvis/拜/结束)

文件:tui_gateway/server.py,三处补丁。TUI 模式下有 beep 反馈。

补丁 A:插入状态机(~50行)

在 def _voice_mode_enabled() 之前插入:

  • _voice_wake_active、_WAKE_WORDS、_END_WORDS 全局变量
  • _reset_voice_wake_state() — 重置
  • _voice_check_wake_word(transcript) — 核心过滤(含 880Hz/440Hz beep)
  • _voice_handle_transcript(transcript) — 回调桥接
_voice_wake_active = False
_WAKE_WORDS = ["嘿","嗨","喂","hey","hi","jarvis","贾维斯"]
_END_WORDS = ["拜","掰","bye","拜拜","再见","goodbye","结束"]

补丁 B:voice.toggle off 时重置

在 if not enabled: 块内、stop_continuous() 之前插入 _reset_voice_wake_state()。

补丁 C:voice.record start 接入

  1. start_continuous() 前插入 _reset_voice_wake_state()
  2. on_transcript 改为 lambda t: _voice_handle_transcript(t)

修复 4:CLI 路径唤醒词(cli.py)

⚠️ server.py 唤醒词补丁对 CLI 模式无效!CLI 走 cli.py → voice.py 直连路径。

文件:cli.py,四处修改。CLI 无 beep,改为打印 "Standby..."。

4a. 类变量(~line 4205)

self._voice_wake_active = False

4b. 过滤方法(~line 11237)

_WAKE_WORDS = ["嘿","嗨","喂","hey","hi","jarvis","贾维斯"]
_END_WORDS = ["拜","掰","bye","拜拜","再见","goodbye","结束"]

def _voice_check_wake_word(self, transcript):
    text = transcript.strip().lower()
    for word in self._WAKE_WORDS:
        if word in text:
            self._voice_wake_active = True
            idx = text.index(word) + len(word)
            remainder = transcript[idx:].strip()
            return (bool(remainder), remainder)
    if not self._voice_wake_active:
        return (False, "")
    for word in self._END_WORDS:
        if word in text:
            self._voice_wake_active = False
            return (False, "")
    return (True, transcript)

4c. 转录门控(_voice_stop_and_transcribe,~line 11187)

if self._voice_continuous:
    should_submit, filtered = self._voice_check_wake_word(transcript)
    if not should_submit:
        return  # 待机:静默丢弃
    transcript = filtered or transcript

4d. 状态重置

  • _enable_voice_mode:self._voice_wake_active = False
  • _disable_voice_mode:self._voice_wake_active = False

验证

# server.py(TUI 路径)
grep -c '_voice_wake_active' tui_gateway/server.py        # ≥7
grep -c '_WAKE_WORDS' tui_gateway/server.py               # ≥2
grep -c '_voice_handle_transcript' tui_gateway/server.py  # ≥2

# cli.py(CLI 路径)
grep -c '_voice_wake_active' cli.py                       # ≥5
grep -c '_voice_check_wake_word' cli.py                   # ≥2

# 语法检查
python -c "import ast; ast.parse(open('tui_gateway/server.py').read()); print('OK')"
python -c "import ast; ast.parse(open('cli.py').read()); print('OK')"

生效

全部修复需 /reload 重启 Hermes。

行为

  • 待机 → 说 "Jarvis"/"嘿" → TUI:880Hz beep / CLI:无,激活,剩余文本提交给 Agent
  • 激活 → 说 "结束"/"拜" → TUI:440Hz beep / CLI:无,回到待机(语音丢弃)
  • 待机状态所有语音静默丢弃
  • /voice off 或 Ctrl+B 重新录音会重置为待机
  • Agent 回复自动 TTS 播报,不会被自己声音打断

配置参考

voice:
  auto_enable: true
  continuous_mode: true
  auto_tts: true
  barge_in: false
  silence_duration: 3.0

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.