Back to home

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.jsoncordis.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.ymlconfig:(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.jsonexportsdsh.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.dataasr_options.language 在请求顶层(auto/zh/en),识别文本取 choices[0].message.content,只收 wav/mp3,model 全小写 mimo-v2.5-asropenai-compatible 引擎才走标准 POST {baseURL}/audio/transcriptions(multipart 表单)。
  • 录音转码链MediaRecorder(webm) → decodeAudioDataOfflineAudioContext 重采样 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 从环境变量读

使用

  1. npx @deepseek-ai/dsh web,浏览器打开 http://127.0.0.1:3080。
  2. 点⚙填好云端配置(或选 web-speech 免配置),可先点「测试连接」确认配置可用。
  3. 按住 Ctrl+M(或自定义快捷键)说话,松开即识别——默认把文本填入输入框待你核对,确认后按 Enter 发送;若想松开即发,在⚙里取消勾选「识别后需确认再发送」。

引擎说明

引擎端点 / 协议需要配置
xiaomi-cloudPOST {baseURL}/chat/completions,base64 input_audio,仅 wav/mp3baseURL / apiKey / model=mimo-v2.5-asr
openai-compatiblePOST {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 或 OpenAI audio/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