Skip to content
dsh.fish
Bundle

dsh-voice-f9

全局「按住说话」语音输入:按住 F9 说话、松手出字,任意 Windows 程序可用;本地 SenseVoice 识别,不联网、不占显卡。Hold-to-talk voice input for any Windows app, local SenseVoice via sherpa-onnx.

Source
uniwell9797
License
MIT
Updated
Updated 9 days ago

Readme

# dsh-voice-f9

全局「按住说话」语音输入,装进 DeepSeek Harness。

按住 **F9** 说话 → 松手 → 文字直接落进光标处。**任何 Windows 程序都能用** ——
微信、Word、浏览器、IDE、通达信,不限于 DSH 自己的输入框。

识别全程在本机跑(sherpa-onnx + SenseVoice int8),不联网、不占显卡、
音频不出本机;实测进程 **TCP 0 条 / UDP 0 个**。

## 它做了什么

这个插件本身不是识别引擎,而是一层**生命周期管理**:DSH 起来时把那个本地语音输入
程序拉起来,DSH 退出时收掉它,并把配置(热键、浮标、模型路径)托管好。

| 你关心的事 | 插件行为 |
| --- | --- |
| 装完就能用 | 首次激活自动把程序文件铺到 `<DSH_HOME>/voice-f9/` |
| 模型从哪来 | **不重新下载**,默认复用 DSH 自带本地语音的那一份(见下) |
| 热键 | 默认 `F9`;这台机器上 F9 是静音媒体键也能用(见「F9 是静音键」) |
| 重复启动 | 程序自带单实例保护,插件和开机自启同时拉起也只会活一个 |
| 出问题看哪 | `<DSH_HOME>/voice-f9.log`(插件)+ `<DSH_HOME>/voice-f9/语音输入日志.txt`(程序) |

## 依赖

1. **Windows**(这个程序用了 Win32 取光标位置、`winsound`、`Ctrl+V`;其他平台会跳过启动)。
2. **Python 3.10+**,并装好这几个库:

   ```powershell
   python -m pip install sherpa-onnx sounddevice numpy pyperclip keyboard uiautomation
   ```

   插件默认找 `pythonw.exe`;找不到就在配置里填 `pythonPath`。

3. **SenseVoice int8 模型**(`model.int8.onnx` 239MB + `tokens.txt`)。
   默认路径是 `<DSH_HOME>/speech-to-text/sensevoice` —— 也就是 **DSH 自带本地语音
   输入用的同一份模型**。两者是同一個文件(哈希一致),所以装两次只占一份磁盘。

   如果你还没让 DSH 下过模型,也可以把已有的模型放到别处,再用配置里的 `modelDir`
   指过去。**不建议重新下载**:`huggingface.co` 会重定向到 `us.aws.cdn.hf.co`,
   实测国内直连约 0.5 MB/s,239MB 要七八分钟,走代理更慢。

## 安装

```sh
dsh plugin --profile <你的 profile> add dsh-voice-f9
```

装完重启 DSH(或让它热加载)。之后进 **设置 → 插件 → 插件配置** 调参数。

## 配置

**本插件不声明 `Config` schema**,所以没有自动生成的设置表单 —— 这是刻意的取舍,
原因见下面「为什么没有设置表单」。配置写在 profile 的 `cordis.patch.yml` 里:

```yaml
- id: dsh-voice-f9
  name: dsh-voice-f9
  config:
    hotkey: f9            # 可写空格分隔的多个键;对讲机模式不支持组合键
    indicator: true       # 屏幕上跟着光标跑的小胶囊
    pythonPath: 'C:\Python314\pythonw.exe'
    sherpaThreads: 4
    graceMs: 3000
```

| 字段 | 默认 | 说明 |
| --- | --- | --- |
| `enabled` | `true` | 关掉就不启动,但文件还在 |
| `pythonPath` | 自动探测 | `pythonw.exe` 的绝对路径 |
| `dataRoot` | `<DSH_HOME>/voice-f9` | 程序文件放哪 |
| `modelDir` | `<DSH_HOME>/speech-to-text/sensevoice` | 模型放哪 |
| `hotkey` | `f9` | 可写空格分隔的多个键(对讲机模式只支持单键,不支持组合键) |
| `indicator` | `true` | 屏幕上跟着光标跑的小胶囊 |
| `sherpaThreads` | `4` | 推理线程数 |
| `graceMs` | `3000` | 要求子进程退出后的宽限期;`spawn` 强制要求这个字段 |

字段写错、类型不对、甚至整个 `config` 是 `null` 或字符串,都会被插件内部的
`normalizeConfig()` 兜回默认值,**不会崩、也不会拒绝加载**。

## 为什么没有设置表单

因为它需要 `import z from '@deepseek-ai/schemastery'`,而这个导入**可能解析失败**:

插件常以软链(`link:`)方式安装,Node 会按**真实路径**向上找 `node_modules`;
一旦某个组合里没有把 `@deepseek-ai/schemastery` 铺到可达位置,
整个插件就是 `failed to import` —— **所有功能全废,连"没模型"这类提示都发不出来**。

这个坑是实测踩到的,不是假想:

```
dsh: warning: 1 entry did not activate
dsh-voice-f9 (dsh-voice-f9): failed to import
```

所以本插件**零外部导入**,配置校验全部手写。代价只是没有表单,换来的是"一定能加载"。

## 用法

| 操作 | 效果 |
| --- | --- |
| 按住 `F9` 说话 | 开始录音(浮标变红) |
| 松开 | 识别(0.1~0.3 秒)→ 文字进光标处 |
| 录音时按 `Esc` | 丢弃这段 |
| 右键点浮标两次 | 退出程序 |

## 已知行为

**F9 是静音键也能用。** 有些笔记本(如 ASUS Zenbook 14)的 F9 默认是静音媒体键,
发的是 `VK_VOLUME_MUTE` 而不是 `VK_F9`。随包的程序把 `volume mute` 也绑成候选键,
且 `suppress=True` 会把这个键吞掉,所以按住 F9 是说话、**不会再静音**。

**浮标会跟着光标跑。** 走 UIA `TextPattern.GetSelection()` 拿真实光标位置,跨应用、
跨屏都跟得上(Chromium/Electron 不提供 `hwndCaret`,所以不能靠 Win32 那条路)。
想让它钉住不动,把 `indicator_pos` 改成 `top-right` 之类即可。

**和开机自启共存。** 如果你之前用安装包装过一次,注册表
`HKCU\...\CurrentVersion\Run` 里可能还有一个 `VoiceInputF9`。两边同时拉起也安全 ——
程序自带命名互斥体,第二份会自己退出并在日志里写明。想只让插件管,把那条自启删掉即可。

## 出问题了看哪

1. `<DSH_HOME>/voice-f9.log` —— 插件走到哪一步、失败原因。**先看它。**
2. `<DSH_HOME>/voice-f9/语音输入日志.txt` —— 程序自身:热键有没有绑上、模型加载用了多久。
3. 缺模型、缺 Python 这类问题**不会**把宿主拖垮:插件会记一条 warn 然后跳过启动。

## 许可

MIT。随包的程序与 SenseVoice 模型来自各自上游,请遵守其许可。

Install

dsh plugin --profile web add github:uniwell9797/dsh-voice-f9

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source