Agent Skills › peters/horizon › horizon-speech

horizon-speech

GitHub

诊断语音听写异常(乱码、无响应),通过检查音频捕获层而非模型,排查麦克风配置、设备匹配及信号问题。

assets/plugins/codex/skills/horizon-speech/SKILL.md peters/horizon

触发场景

听写出错或无关文本 听写无输出 疑似麦克风故障

安装

npx skills add peters/horizon --skill horizon-speech -g -y
更多选项

非标准路径

npx skills add https://github.com/peters/horizon/tree/main/assets/plugins/codex/skills/horizon-speech -g -y

不安装直接使用

npx skills use peters/horizon@horizon-speech

指定 Agent (Claude Code)

npx skills add peters/horizon --skill horizon-speech -a claude-code -g -y

安装 repo 全部 skill

npx skills add peters/horizon --all -g -y

预览 repo 内 skill

npx skills add peters/horizon --list

SKILL.md

Frontmatter
{
    "name": "horizon-speech",
    "description": "Check that a microphone is usable for Horizon dictation and report which layer is at fault — no signal, bad level, or a genuine model\/accent limit. Use when dictation produces wrong, unrelated, or empty text."
}

Horizon speech input check

This skill uses local audio diagnostics. Horizon has no speech MCP tool. Do not treat dictation as an MCP-controlled capability.

Run this when a user says dictation "types the wrong thing", produces text they never said, or produces nothing.

Read this first

Whisper-family models hallucinate fluent, plausible text when fed silence. Given a digitally silent recording, NB-Whisper will confidently emit something like Esther Smith, forfatter — grammatical, idiomatic, and completely unrelated to the user. The output looks like a model, accent, or dialect problem. It is almost always a capture problem.

So: measure the capture level before touching models, languages, or config. Never conclude "the model is bad at your accent" until step 3 shows real signal.

A user cannot tell these apart from the transcript alone. That is the whole reason this skill exists.

1. Compare configured device against reality

Horizon keeps its settings in settings.sqlite, and a YAML file is an export that Horizon never reads back. Do not read config.yaml to find a setting: it may be absent, because the first start of a build with a store moves it to config.yaml.imported-<time>, or it may be a stale export.

Find the settings path, then export it:

  • With HORIZON_HOME set and not empty, Horizon uses only that folder and ignores every location below.
  • Otherwise it uses $HOME/.horizon/, then $XDG_CONFIG_HOME/horizon/, then a relative horizon.yaml/horizon.yml in the working directory. Resolution keys off HOME; USERPROFILE is never consulted.

The store sits beside that path and has the same name with the extension replaced by .settings.sqlite (config.settings.sqlite, or horizon.settings.sqlite). Read the settings with:

horizon --export-config /tmp/horizon-settings.yaml   # --config <path> for another path

That command fails when the store does not exist yet, which means Horizon has not saved a setting on this computer.

Read features.speech from the export:

  • input_device: "" means the system default input is used.
  • A non-empty name is matched case-insensitively: exact, then substring, then a normalized identity key.

If the configured name matches no present device, Horizon falls back to the system default and only logs a warning. The user never sees it. A config naming a microphone that is no longer plugged in therefore looks like it works. Check the name against the live device list before anything else.

List input devices:

  • Linux (PipeWire/PulseAudio): wpctl status, or pactl list short sources
  • Linux (ALSA only): arecord -l
  • macOS: system_profiler SPAudioDataType, or ffmpeg -f avfoundation -list_devices true -i ""

Also confirm the device is not a Bluetooth headset in HSP/HFP mode. That profile is narrowband and heavily compressed; it degrades accuracy badly. Prefer a wired or USB microphone, or force the A2DP-era high-quality input if the stack offers one.

2. Record a short sample

Ask the user to speak normally for about six seconds. Record mono at 16 kHz — that is what the models consume.

Record from the device step 1 matched, never the system default. When input_device names a non-default microphone, sampling the default measures a different device than Horizon uses and can yield the exact opposite diagnosis — a silent default while the real microphone works, or the reverse.

  • Linux (ALSA): arecord -D <device> -f S16_LE -r 16000 -c 1 -d 6 sample.wav, where <device> is a name from arecord -L
  • Linux (PipeWire): pw-record --target <node-name-or-id> --rate 16000 --channels 1 sample.wav
  • macOS: ffmpeg -f avfoundation -i ":<device-index>" -ar 16000 -ac 1 -t 6 sample.wav

Only fall back to the default device when input_device is empty, since that is what Horizon itself then uses.

Tell the user when recording starts. If you launch the recorder as a background task, add a visible countdown first — otherwise the window elapses while they are still reading your message, and you will measure an empty room and misdiagnose it as a dead microphone.

3. Measure the level

level.py sits next to this SKILL.md. Invoke it by its full path — the working directory is normally the user's workspace, not the installed skill directory, so a bare level.py will not be found:

python3 <dir containing this SKILL.md>/level.py sample.wav

It needs only the Python 3 standard library, and reports peak, RMS and clipped samples, each as a percentage of full scale so the numbers mean the same thing at every sample width:

Reading Meaning Fix
peak below 0.6% No signal — capture muted, or no device Unmute capture; confirm the right device is selected and present
clipped samples > 20 Too hot — distortion Lower gain; turn microphone boost off first
rms above 25% Hotter than necessary Reduce gain slightly
rms 5–25% Ideal for ASR Nothing to do
rms 2–5% Usable A little more gain would help
rms below 2% Too quiet Raise gain, or move closer

4. Transcribe the same file

Run the profile's model against sample.wav and compare with what the user actually said. Horizon's models are transcribe.cpp GGUFs; if a transcribe-cli build is available:

transcribe-cli -m <model>.gguf -l <lang> sample.wav

Otherwise have the user dictate the same sentence in Horizon and compare.

5. Verdict

Combine steps 3 and 4 — this is the part the user cannot do alone:

  • No signal + fluent unrelated text → capture is dead. The text is hallucinated. Fix the microphone; the model is fine.
  • Good level + empty transcript → real audio, no speech detected. Usually room noise only, or the user did not speak inside the window.
  • Clipping + roughly correct text → working but distorted. Reduce gain; accuracy will improve, especially on consonants.
  • Good level + mostly correct text with wrong proper nouns or English technical terms → this is the model's genuine limit, not the microphone. Suggest an initial prompt to bias vocabulary, or a profile whose model suits the language better. Only at this point is accent or dialect worth discussing.

Report which of these it is explicitly. "Your microphone is fine, the model mis-heard a term" and "your microphone captured nothing" are opposite fixes and look identical in the transcript.

Adjusting gain

Turn microphone boost off before raising capture volume — boost amplifies the microphone's own noise floor as much as the voice.

  • Linux (PipeWire): wpctl set-volume <source-id> <0.0-1.0>. This maps onto the ALSA hardware control. Boost lives in amixer -c <card>, e.g. amixer -c <card> sset 'Mic Boost' 0.
  • macOS: System Settings → Sound → Input → Input volume.

Re-run steps 2–3 after each change. Gain that sounds fine to a human can still be clipping.

版本历史

  • 0a2fd78 当前 2026-11-02 22:03

    移除Windows支持,更新配置读取逻辑为仅从SQLite store读取,不再直接读取YAML文件。

  • 8cf6ee9 2026-10-19 05:07

    新增 HORIZON_HOME 环境变量对配置路径的覆盖逻辑说明,明确其优先于默认路径的行为。

  • fb94995 2026-09-22 10:25

同 Skill 集合

assets/plugins/claude-code/skills/horizon-app-testing/SKILL.md
assets/plugins/claude-code/skills/horizon-browser/SKILL.md
assets/plugins/claude-code/skills/horizon-cast/SKILL.md
assets/plugins/claude-code/skills/horizon-cloud/SKILL.md
assets/plugins/claude-code/skills/horizon-device/SKILL.md
assets/plugins/claude-code/skills/horizon-notify/SKILL.md
assets/plugins/claude-code/skills/horizon-speech/SKILL.md
assets/plugins/codex/skills/horizon-app-testing/SKILL.md
assets/plugins/codex/skills/horizon-browser/SKILL.md
assets/plugins/codex/skills/horizon-cast/SKILL.md
assets/plugins/codex/skills/horizon-cloud/SKILL.md
assets/plugins/codex/skills/horizon-device/SKILL.md
assets/plugins/codex/skills/horizon-notify/SKILL.md
crates/horizon-device/skills/horizon-device/SKILL.md

元信息

文件数
0
版本
0a2fd78
Hash
525fc15a
收录时间
2026-09-22 10:25

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-11-03 12:02
浙ICP备14020137号-1