sutanna233
dsh-voice-input
No description
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 15, 2026
- Updated
- Aug 15, 2026
Introduction
DSH 插件:语音输入(dsh-voice-input)
在 dsh web 界面里按住快捷键说话,语音识别成文本后自动作为用户消息发送给 agent,实现不用打字操控 DeepSeek Harness。
给 Agent 的部署指南
这一节写给负责安装/维护本插件的 agent:照步骤执行即可,每步都标了文件路径、要插入的确切内容和幂等注意。
~指用户主目录(Windows 下即C:\Users\<用户>)。
前置条件
- 已能运行
npx @deepseek-ai/dsh web(dsh CLI 可用)。 - 存在 web profile 目录
~/.dsh/profiles/web/,里面有package.json和cordis.patch.yml。 - 本仓库源码。
步骤 1:放置插件源码
把仓库内容复制到 ~/.dsh/plugins/dsh-voice-input/,最终结构必须是:
~/.dsh/plugins/dsh-voice-input/
├── package.json
├── README.md
└── lib/
├── index.js # host 半(Node 侧)
└── client.js # browser 半(浏览器侧)
不要带 node_modules/、.git/,也不要复制运行时才生成的 ~/.dsh/voice-input.config.json(里面有 apiKey)。
步骤 2:注册 file: 依赖
编辑 ~/.dsh/profiles/web/package.json,在 dependencies 里加一行(已存在则跳过):
"dsh-voice-input": "file:../../plugins/dsh-voice-input"
路径是 profile 目录的相对路径(profiles/web → 上两级 → plugins/dsh-voice-input)。加完在 profile 目录跑一次安装让 symlink 生效(npm install,或由 dsh 启动时自动处理)。
步骤 3:注册 loader entry
编辑 ~/.dsh/profiles/web/cordis.patch.yml,在顶层数组里 insert: 列表中追加(同一个 id 不要重复):
- id: voice-input
name: dsh-voice-input
id 是 loader 内部标识(其它配置可用它定位),name 必须等于 package.json 的包名。config: 段可省略——它只是默认值/base 层,前端填的会覆盖。
步骤 4:重启 dsh
npx @deepseek-ai/dsh web
若报 EADDRINUSE: address already in use 127.0.0.1:3080:说明已有一个实例在跑,这不是插件问题。要么直接用它,要么先停掉旧的(Windows:netstat -ano | findstr :3080 找到 LISTENING 的 PID,再 taskkill /PID <pid> /F)。
验证(agent 可 CLI 自检,无需浏览器)
# host 半已加载:应返回 {engine, shortcut, xiaomiCloud:{...hasKey}, ...}
curl http://127.0.0.1:3080/voice-config
# browser 半已装配:应返回 JS,开头是 window.__ModuleLoader__.load
curl http://127.0.0.1:3080/plugins/dsh-voice-input/client.js
两个都 HTTP 200 即装配成功。再让人在浏览器打开 http://127.0.0.1:3080,输入框右侧应出现🎤和⚙。
配置(agent 可代填)
推荐让人在浏览器点⚙填。agent 也可直接写 ~/.dsh/voice-input.config.json(含 key,勿提交 git):
{
"engine": "xiaomi-cloud",
"shortcut": "ctrl+m",
"confirmBeforeSend": true,
"xiaomiCloud": {
"baseURL": "https://api.xiaomimimo.com/v1",
"model": "mimo-v2.5-asr",
"language": "auto",
"apiKey": "<小米云 key>"
}
}
分层优先级:该文件(前端层)> cordis.patch.yml 的 config:(base)> 内置默认。
排错速查
| 现象 | 根因 | 处理 |
|---|---|---|
启动报 EADDRINUSE ... 3080 | 已有实例占用端口 | 用现有实例,或 taskkill 掉旧的再起 |
识别报 HTTP 404 | 误把小米当 OpenAI /audio/transcriptions | 小米是 /chat/completions,确认 engine: xiaomi-cloud 且插件为最新 |
识别报 HTTP 400 base64 not valid | 上传的不是 wav/mp3 | 浏览器半会自动转 WAV;确认 client.js 已装配最新版 |
| 识别报 model 相关错误 | model 大小写 | 必须全小写 mimo-v2.5-asr |
| 浏览器没有🎤⚙按钮 | browser 半未装配 | 检查 package.json 的 exports 与 dsh.client(见下) |
改动本插件时必读(关键实现细节)
package.json必须有:
缺了"type": "module", "exports": { ".": "./lib/index.js", "./client": "./lib/client.js", "./package.json": "./package.json" }, "dsh": { "client": { "inject": ["@deepseek-ai/dsh-client-runtime", "@deepseek-ai/dsh-client-locale"], "platform": "web" } }exports/dsh.client,browser 半不会被打进__DSH_BOOT__(按钮不出现)。lib/index.js用命名导出apply/inject/name,不要 default export(否则 cordis 加载报错)。- 小米 ASR 不是 OpenAI transcriptions 端点:
POST {baseURL}/chat/completions,音频是 base64 data URI(data:audio/wav;base64,...)放messages[0].content[].input_audio.data,asr_options.language在请求顶层(auto/zh/en),识别文本取choices[0].message.content,只收 wav/mp3,model 全小写mimo-v2.5-asr。openai-compatible引擎才走标准POST {baseURL}/audio/transcriptions(multipart 表单)。 - 录音转码链:
MediaRecorder(webm) →decodeAudioData→OfflineAudioContext重采样 16kHz 单声道 → 16-bit WAV 上传(两种引擎都接受 wav)。 - 配置持久化:host 半自管,落盘
~/.dsh/voice-input.config.json;apiKey 只写不读(GET /voice-config只回hasKey),不经过浏览器。
功能
- 在 composer 工具行右端(发送按钮前)注册🎤麦克风按钮和⚙设置按钮
- 按住快捷键说话(默认
Ctrl+M),松开停止 → 自动识别;默认先填入输入框待确认再发送(⚙里可关掉,改回松开即发) - 录音反馈:录音中按钮显示已录秒数 + 实时音量条;60 秒自动停止(避免超长音频拖慢识别 / 超 20MB 上限)
- 前端降噪:录音链路加高通滤波(滤 80Hz 以下低频)+ 动态压缩自动增益,笔记本麦克风更干净
- 快捷键可自定义:点⚙里的快捷键输入框,按下组合即捕获(已避开
Ctrl+Space输入法切换、Alt+Space窗口菜单) - 点⚙在前端直接填配置(引擎 / baseURL / model / apiKey / 快捷键),可**一键「测试连接」**验证 baseURL/key/model 是否可用
- 识别引擎可切换:
xiaomi-cloud(默认)/openai-compatible/web-speech(浏览器原生,免配置) - apiKey 只留在 host 侧:前端只能写入新 key(空值=保持不变),接口读不回明文;YAML 里也支持
env:NAME从环境变量读
使用
npx @deepseek-ai/dsh web,浏览器打开 http://127.0.0.1:3080。- 点⚙填好云端配置(或选
web-speech免配置),可先点「测试连接」确认配置可用。 - 按住
Ctrl+M(或自定义快捷键)说话,松开即识别——默认把文本填入输入框待你核对,确认后按 Enter 发送;若想松开即发,在⚙里取消勾选「识别后需确认再发送」。
引擎说明
| 引擎 | 端点 / 协议 | 需要配置 |
|---|---|---|
xiaomi-cloud | POST {baseURL}/chat/completions,base64 input_audio,仅 wav/mp3 | baseURL / apiKey / model=mimo-v2.5-asr |
openai-compatible | POST {baseURL}/audio/transcriptions(multipart) | baseURL / apiKey / model |
web-speech | 浏览器 Web Speech API(Chrome/Edge),零配置、免费 | 无 |
架构
- host 半(
lib/index.js,Node 侧)注册四个 HTTP 端点:GET /voice-config—— 下发引擎、快捷键、确认发送开关与非敏感配置(apiKey 只回hasKey,不下发明文);POST /voice-config-update—— 合并前端表单并落盘~/.dsh/voice-input.config.json;POST /voice-config-test—— 用提交的临时配置(含可能新填的 key,不落盘)发一段短音验证 baseURL/key/model 链路,供「测试连接」按钮使用;POST /voice-transcribe—— 接收 WAV,按引擎分发到小米chat/completions或 OpenAIaudio/transcriptions;ASR 错误按状态码映射成友好中文(401=key 无效 / 404=baseURL 或模型不对 / 429=限流…)。
- browser 半(
lib/client.js,浏览器侧)是window.__ModuleLoader__.load的 CJS bundle,React 组件注册到conversation.input.right:🎤录音按钮(MediaRecorder→ WAV →inputActions.setDraft/submit发送)+ ⚙配置弹层(表单读写走上述 host 端点,快捷键按键捕获)。
文件清单
dsh-voice-input/
├── package.json # name/type:module/exports(. ./client ./package.json)/dsh.client
├── lib/
│ ├── index.js # host 半:配置持久化 + 三个 HTTP 端点 + 引擎分发
│ └── client.js # browser 半:🎤按钮 + ⚙配置弹层 + 录音转 WAV + 快捷键
└── README.md