dsh-voice-mode 0.7.12 → 0.7.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![License: MIT](https://img.shields.io/github/license/qishuilalala/dsh-voice-mode?style=flat-square&color=blue)](../../LICENSE)
4
4
  [![Latest Release](https://img.shields.io/github/v/release/qishuilalala/dsh-voice-mode?style=flat-square&color=brightgreen&include_prereleases)](https://github.com/qishuilalala/dsh-voice-mode/releases)
5
5
  [![npm version](https://img.shields.io/npm/v/dsh-voice-mode?style=flat-square&color=orange)](https://www.npmjs.com/package/dsh-voice-mode)
6
- [![Tests: 325 passing](https://img.shields.io/badge/tests-325%20%E2%9C%93-2ea043?style=flat-square)](../../docs/rules/STATE.md)
6
+ [![Tests: 380 passing](https://img.shields.io/badge/tests-380%20%E2%9C%93-2ea043?style=flat-square)](../../docs/rules/STATE.md)
7
7
 
8
8
  Full-duplex voice conversation mode for DeepSeek Harness (dsh): speak, get a
9
9
  spoken answer. Streamed zipformer2 ASR → editable draft → auto send → the
@@ -16,7 +16,7 @@ interrupts playback and the running turn. No API key.
16
16
 
17
17
  ![Real recording: streaming transcription → auto-send → sentence-by-sentence read-aloud with live captions](https://raw.githubusercontent.com/qishuilalala/dsh-voice-mode/HEAD/plugin/dsh-voice-mode/assets/demo-voice-flow.gif)
18
18
 
19
- > **Version note (v0.7.10, 2026-09-18)**: **Silent-audio causes in the output pipeline fixed** — ① a sentence whose cloud-TTS synthesis fails after 3 retries is no longer dropped silently (the status bar now says one sentence failed and was skipped; previously this showed up as "the reply is occasionally not read" with no way to tell why); ② audio playback no longer goes silent after the browser suspends the AudioContext (background tab / long idle) — the context is resumed on every enqueue and on any click/keypress; ③ dropped incomplete sentences (SSE frame loss) now leave a diagnostic trace. Otherwise as v0.7.9: **Wake-word pipeline overhaul** (Issue #10 + real-machine retest) — a harness driving the real engine pinpointed and fixed five flow defects: ① TTS echo polluting the standby segment while the agent reads (could not wake); ② only above-threshold frames uploaded, so trailing characters never flushed (wake word truncated); ③ discarding the whole segment on a wake hit (saying "wake word + command" in one breath sent only the tail); ④ the command hanging when the hit arrived after you stopped speaking; ⑤ pausing after the wake word closed the command window (command lost). **The wake word may now be said together with your command — it is stripped and never sent**, standby live-shows what it heard, and "wake word … pause … command" works. Otherwise as v0.7.7: Edge cloud TTS by default, local TTS (VITS / Kokoro) optional; silence split defaults to 1500 ms.
19
+ > **Version note (as of v0.7.12, 2026-09-19)**: v0.7.12 / v0.7.11 are **asset, documentation and search-metadata updates** (zero runtime change; v0.7.11 includes the five-version compatibility run). The following are the **runtime** changes since v0.7.10: **Silent-audio causes in the output pipeline fixed** — ① a sentence whose cloud-TTS synthesis fails after 3 retries is no longer dropped silently (the status bar now says one sentence failed and was skipped; previously this showed up as "the reply is occasionally not read" with no way to tell why); ② audio playback no longer goes silent after the browser suspends the AudioContext (background tab / long idle) — the context is resumed on every enqueue and on any click/keypress; ③ dropped incomplete sentences (SSE frame loss) now leave a diagnostic trace. Otherwise as v0.7.9: **Wake-word pipeline overhaul** (Issue #10 + real-machine retest) — a harness driving the real engine pinpointed and fixed five flow defects: ① TTS echo polluting the standby segment while the agent reads (could not wake); ② only above-threshold frames uploaded, so trailing characters never flushed (wake word truncated); ③ discarding the whole segment on a wake hit (saying "wake word + command" in one breath sent only the tail); ④ the command hanging when the hit arrived after you stopped speaking; ⑤ pausing after the wake word closed the command window (command lost). **The wake word may now be said together with your command — it is stripped and never sent**, standby live-shows what it heard, and "wake word … pause … command" works. Otherwise as v0.7.7: Edge cloud TTS by default, local TTS (VITS / Kokoro) optional; silence split defaults to 1500 ms.
20
20
 
21
21
  ---
22
22
 
@@ -211,7 +211,7 @@ You can also edit the `voice-mode:` section of `~/.dsh/settings.yaml` directly (
211
211
  | `POST /voice-mode/asr` | Raw f32 LE 16k PCM payload → `{text}` (streaming zipformer2); returns `202 {loading}` until the model is ready; `?reset=1` discards the in-flight segment (used on wake-word hit) |
212
212
  | `POST /voice-mode/cancel` | `{sessionId}` invalidates the TTS queue and drops the in-flight ASR segment |
213
213
  | `POST /voice-mode/preview` | `{voice, rate?}` one-shot synthesis preview → `audio/mpeg` (400 missing voice / voice too long; 502 synthesis failure, e.g. invalid ShortName; 403 when the plugin's `enabled=false`). Does not require voice mode to be active; uses an isolated synthesis connection and does not affect the reading queue |
214
- | `GET /voice-mode/config` | Client bootstrap parameters (silence threshold / sensitivity / voice and rate, etc.) — includes 4 new ASR fields: `senseITN` / `senseVoice` / `captionFontSize` / `captionMaxWidth` / `backchannelYield` |
214
+ | `GET /voice-mode/config` | Client bootstrap parameters (silence threshold / sensitivity / voice and rate, etc.) — includes the ASR-side fields `senseITN` / `senseVoice` / `captionFontSize` / `captionMaxWidth` / `backchannelYield` |
215
215
  | `GET /voice-mode` | Health check `{ok, name, enabled, active}` |
216
216
 
217
217
  ---
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![License: MIT](https://img.shields.io/github/license/qishuilalala/dsh-voice-mode?style=flat-square&color=blue)](LICENSE)
4
4
  [![Latest Release](https://img.shields.io/github/v/release/qishuilalala/dsh-voice-mode?style=flat-square&color=brightgreen&include_prereleases)](https://github.com/qishuilalala/dsh-voice-mode/releases)
5
5
  [![npm version](https://img.shields.io/npm/v/dsh-voice-mode?style=flat-square&color=orange)](https://www.npmjs.com/package/dsh-voice-mode)
6
- [![Tests: 325 passing](https://img.shields.io/badge/tests-325%20%E2%9C%93-2ea043?style=flat-square)](../../docs/rules/STATE.md)
6
+ [![Tests: 380 passing](https://img.shields.io/badge/tests-380%20%E2%9C%93-2ea043?style=flat-square)](../../docs/rules/STATE.md)
7
7
 
8
8
  DeepSeek Harness 语音双工对话模式:会话内一键进入 → 边说边出字的流式识别 → 停顿自动发送 → 最终答复按句流式朗读 + 实时字幕,开口即可打断(真 barge-in)。无需 API Key,识别模型在本地宿主端推理。
9
9
 
@@ -15,7 +15,7 @@ DeepSeek Harness 语音双工对话模式:会话内一键进入 → 边说边
15
15
 
16
16
  ![全双工对话闭环:声音 → 文字 → 声音](https://raw.githubusercontent.com/qishuilalala/dsh-voice-mode/HEAD/plugin/dsh-voice-mode/assets/duplex-banner.png)
17
17
 
18
- > **版本说明(v0.7.10,2026-09-18)**:**输出链路静默丢音根治**——① 云端 TTS 单句重试耗尽后不再静默跳句(现在状态条提示「有一句朗读失败,已跳过」,此前表现为「AI 回复偶尔不朗读」且无从判断);② 浏览器挂起 AudioContext 后的「无声播放」(UI 显示朗读中、字幕照走)现在每次入队 + 任意点击/按键自动恢复;③ SSE 丢帧导致的坏句丢弃留诊断痕迹。其余同 v0.7.9:**唤醒词链路全面修复**(Issue #10 + 真机复测)——台架驱动真引擎逐项定位并修掉五处流程缺陷:① 朗读期 TTS 回声污染待机段(喊不醒);② 只上传超门限帧导致尾字不 flush(唤醒词只剩半截);③ 唤醒命中丢整段(连说「唤醒词+命令」只发出去尾部几个字);④ 命中晚于停口时命令悬挂不定稿;⑤ 只喊唤醒词后停顿会关掉命令窗口(命令丢失)。**现在唤醒词可与命令连说、词头自动剥离不进消息**,待机态实时显示「它听到了什么」,支持「唤醒词…停顿…命令」。其余同 v0.7.7:朗读默认 Edge 云端,本地 TTS(VITS / Kokoro)可选;静音断句默认 1500 毫秒。
18
+ > **版本说明(截至 v0.7.12,2026-09-19)**:v0.7.12 / v0.7.11 为**素材、文档与检索元数据更新**(运行时零改动;v0.7.11 含五版本兼容实测)。以下为 v0.7.10 起的**运行时**变更:**输出链路静默丢音根治**——① 云端 TTS 单句重试耗尽后不再静默跳句(现在状态条提示「有一句朗读失败,已跳过」,此前表现为「AI 回复偶尔不朗读」且无从判断);② 浏览器挂起 AudioContext 后的「无声播放」(UI 显示朗读中、字幕照走)现在每次入队 + 任意点击/按键自动恢复;③ SSE 丢帧导致的坏句丢弃留诊断痕迹。其余同 v0.7.9:**唤醒词链路全面修复**(Issue #10 + 真机复测)——台架驱动真引擎逐项定位并修掉五处流程缺陷:① 朗读期 TTS 回声污染待机段(喊不醒);② 只上传超门限帧导致尾字不 flush(唤醒词只剩半截);③ 唤醒命中丢整段(连说「唤醒词+命令」只发出去尾部几个字);④ 命中晚于停口时命令悬挂不定稿;⑤ 只喊唤醒词后停顿会关掉命令窗口(命令丢失)。**现在唤醒词可与命令连说、词头自动剥离不进消息**,待机态实时显示「它听到了什么」,支持「唤醒词…停顿…命令」。其余同 v0.7.7:朗读默认 Edge 云端,本地 TTS(VITS / Kokoro)可选;静音断句默认 1500 毫秒。
19
19
 
20
20
  ---
21
21
 
@@ -98,17 +98,24 @@ bundle 插件安装后需重启 dsh 生效(Linux:`systemctl restart dsh`;
98
98
  | `voice` | 按引擎 | 音色:VITS 五说话人;Kokoro 103 个(下拉+◀▶,62 深沉/68 浑厚/75 清亮/76 磁性置顶);Edge 进入时自动加载全量 322 个。行内「试听」可即时预览 |
99
99
  | `rate` | `1.1` | 朗读语速倍率(0.5 慢速 ~ 2.0 快速),**即时生效**(批 J 1.0→1.1) |
100
100
  | `interruptLevel` | `0` | 发声打断灵敏度(服务端 VAD 帧级检测 + 回声门控):0 高门槛(3 帧)/ 1 中(2 帧)/ 2 低(1 帧) |
101
+ | `bargeInMode` | `detect` | 打断方式:`detect` 自动探测本机原生回声消除状态(默认;未生效时切为长按打断)/ `auto` 强制开口即打断(耳机、安静环境推荐)/ `manual` 长按打断(外放推荐)。批 7O 默认,I10 豁免(ADR-0006) |
102
+ | `echoGateDb` | `6` | 回声门控阈值(dB):自动打断要求残差高于回声地板此值。**原生 AEC 生效时此门控闲置**(Safari / 耳机等无原生 AEC 环境才兜底生效);打不断降 3-4,噪音误打断升 8-10。**不要为「打不断」调它**(详见 ADR-0006) |
101
103
  | `silenceMs` | `1500` | 说完整一句的静音停顿毫秒数 |
102
104
  | `idleTimeoutMinutes` | `5` | 无活动自动退出语音模式的分钟数(朗读计为活动;批 J 10→5) |
103
105
  | `modelHost` | 默认源 | 模型下载源(国内网络填 `https://hf-mirror.com`) |
104
106
  | `autoSend` | `true` | 静音到点自动发送(连续多段拼成一条消息);关闭则只进草稿(按住 `Ctrl` / hold 松手仍会发送) |
107
+ | `autoResume` | `false` | 切回上次语音会话时自动恢复语音模式(默认关)。开启后:下次进入语音会话即自动进入语音模式 + 恢复上次会话;关闭则需手动按 `Ctrl+Shift+V` 重新进入 |
105
108
  | `mode` | `toggle` | 交互模式:`toggle` 持续聆听 + 1500ms 静音断句;`hold` 按住说话、松手发送(短按退出) |
109
+ | `shortcut` | `Ctrl+Shift+V` | 进入 / 退出语音模式的快捷键(修饰键 Ctrl/Shift/Alt/Meta + 一个字母键);**留空 = 禁用快捷键**,改用麦克风按钮 |
106
110
  | `wakeWord` | 空(关) | 唤醒词(如「你好小D」):进入后先说唤醒词激活,避免误触;空 = 关闭。**可与命令连说**,词头自动剥掉不进消息;匹配带容错(编辑距离 ≤1 + 前 3 字符前导窗口,吸收同音字/语气词);**建议 3-4 字**——单字词无容错、2 字词的容错会连带吸收所有同首字的 2 字词(如「小莫」也会唤醒「小张」),介意误唤醒用 3 字以上;每句断句或打断后回待机需重说;**仅 toggle 模式生效**(hold / 手动打断下不生效);朗读期说唤醒词不触发 |
111
+ | `toolBeep` | `false` | 工具调用提示音(默认关):开启后 AI 调用工具时「滴」一声;关闭则全程静默 |
107
112
  | `spokenFormat` | `true` | 语音会话注入口语化提示词:开启后**仅当前语音会话**的回复被注入「口语化短句、不用 Markdown 排版符号」提示词(朗读更顺),**即时生效** |
108
113
  | `senseITN` | `true` | 批 2 P0:SenseVoice 逆文本归一化(数字/日期/货币规范化;默认开) |
114
+ | `senseVoice` | `true` | 定稿是否用 SenseVoice 重译(带标点 + 数字归一化,更准;默认开)。**关闭可省 ~228MB 模型**,只走流式识别(更快、精度下降) |
109
115
  | `captionFontSize` | `0` | 批 3 P0:字幕字号档位 0=12px / 1=14px / 2=18px / 3=24px(默认 0 与现状字节等价) |
110
116
  | `captionMaxWidth` | `1` | 批 3 P0:字幕宽度档位 0=50vw / 1=70vw / 2=90vw(视口 <686px 接近 480px,>686px 宽于 480px) |
111
117
  | `backchannelYield` | `true` | 批 5 P1:让位语义(ADR-0008);朗读期说「嗯/对」自动让位 1.5s + 真要说走硬打断。I10 豁免(默认开是产品决策);关 = 行为等同改造前 |
118
+ | `yieldMs` | `1500` | 让位窗口时长(ms,500-3000):`backchannelYield` 命中后 TTS 丢帧持续时长;窗口内用户真要说则由原 `hardBreak` 接管,窗口到点自动恢复播放 |
112
119
 
113
120
  生效范围:`voice`/`rate`/`ttsEngine`/`kokoroModel`/`spokenFormat` **立即生效**;其余设置下次进入语音模式时生效。设置项默认值由插件配置(`base` 层)提供。
114
121
 
@@ -132,9 +139,56 @@ bundle 插件安装后需重启 dsh 生效(Linux:`systemctl restart dsh`;
132
139
  | `zh-TW-HsiaoYuNeural` | 小雨 · 台湾腔 · 女声 |
133
140
  | `en-US-AriaNeural` | Aria · English · 女声 |
134
141
 
135
- ### 配置(bundle config / settings.yaml)
142
+ ---
143
+
144
+ ## 🔧 配置(bundle patch / settings.yaml)
145
+
146
+ 也可以直接编辑 `~/.dsh/settings.yaml` 的 `voice-mode:` 段(设置面板与 RPC 写的是同一份文档层):
147
+
148
+ ```yaml
149
+ - id: voice-mode
150
+ name: dsh-voice-mode
151
+ config:
152
+ enabled: true # false = 完全禁用语音模式(toggle 会被拒)
153
+ cacheDir: ~/.cache/dsh-voice-mode/models # 可覆盖;否则用平台默认
154
+ # 以下为设置项播种的默认值(设置面板优先级更高,面板是权威源):
155
+ voice: zh-CN-XiaoxiaoNeural
156
+ rate: 1.1 # 批 J 1.0→1.1
157
+ interruptLevel: 0
158
+ silenceMs: 1500
159
+ idleTimeoutMinutes: 5 # 批 J 10→5
160
+ modelHost: https://huggingface.co
161
+ ```
162
+
163
+ > 注意:`voice` / `rate` / `interruptLevel` / `silenceMs` / `idleTimeoutMinutes` / `modelHost` / `autoSend`
164
+ > 的**生效值来自设置面板**;bundle 配置只负责为这些键播种默认值
165
+ > (`enabled` / `cacheDir` 则仅由 bundle 配置决定)。
166
+ > 插件 HTTP 命名空间固定为 `/voice-mode`(与客户端打包契约一致,不可配置)。
167
+
168
+ ---
169
+
170
+ ## 🌐 API
171
+
172
+ | 路由 | 说明 |
173
+ | --- | --- |
174
+ | `GET /voice-mode/stream` | SSE:`event: audio`(`{sessionId, seq, text, audio(base64 MP3)}`)、`event: mode`(全局单活归属)、`event: tool`(提示音)、`event: asr-progress / asr-ready / asr-error / tts-error` |
175
+ | `POST /voice-mode/toggle` | `{sessionId, on}` 进入 / 退出语音模式(全局单活) |
176
+ | `POST /voice-mode/asr` | 裸 f32 LE 16k PCM → `{text}`(流式 zipformer2);模型未就绪返回 `202 {loading}`;`?reset=1` 丢弃在途段(唤醒词命中时使用) |
177
+ | `POST /voice-mode/cancel` | `{sessionId}` 作废 TTS 队列并丢弃在途 ASR 段 |
178
+ | `POST /voice-mode/preview` | `{voice, rate?}` 一次性合成试听 → `audio/mpeg`(400 缺 voice / voice 过长;502 合成失败,如无效 ShortName;403 插件 `enabled=false`)。不要求语音模式处于激活态;使用独立合成连接,不影响朗读队列 |
179
+ | `GET /voice-mode/config` | 客户端启动参数(静音阈值 / 灵敏度 / 音色与语速等)——含 ASR 侧字段 `senseITN` / `senseVoice` / `captionFontSize` / `captionMaxWidth` / `backchannelYield` |
180
+ | `GET /voice-mode` | 健康检查 `{ok, name, enabled, active}` |
181
+
182
+ ---
183
+
184
+ ## 💾 模型与缓存
136
185
 
137
- `voice-mode` 命名空间配置可直接写入 `~/.dsh/settings.yaml`;插件总开关 `enabled`(默认 `true`)、模型缓存目录 `cacheDir`、在安装配置中设置。
186
+ - 识别模型:`csukuangfj/sherpa-onnx-streaming-zipformer-zh-int8-2025-06-30`(encoder ≈154 MB / decoder / joiner / tokens,合计约 160 MB),宿主端经 sherpa-onnx(Node WASM,Apache-2.0,原生跨平台)运行
187
+ - 缓存目录的平台默认:
188
+ - **Windows**:`%LOCALAPPDATA%\dsh-voice-mode\models`
189
+ - **macOS / Linux**:`~/.cache/dsh-voice-mode/models`
190
+ - 两者都可用 `cacheDir` 覆盖
191
+ - 下载用 `.part` 断点续传;`huggingface.co` 失败时回退 `hf-mirror.com`(可用 `modelHost` 配置)
138
192
 
139
193
  ---
140
194
 
@@ -188,13 +242,13 @@ flowchart LR
188
242
  | 维度 | dsh 内置 | dsh-voice-mode(本插件) |
189
243
  | --- | --- | --- |
190
244
  | 识别模型 | 云端 API(需 key) | **本地 zipformer2 + SenseVoice**(零 key) |
191
- | 多语种 | 英文为主 | **SenseVoice 自动识别(auto)+ ITN** |
245
+ | 多语种 | 英文为主 | **SenseVoice 自动识别(zh/en/ja/ko/yue)+ ITN** |
192
246
  | 朗读引擎 | 云端 TTS | **Edge 云端 + 本地 VITS/Kokoro** 三选一 |
193
247
  | 打断检测 | 基础 VAD | **三档灵敏度 + 回声门控 + 让位语义** |
194
248
  | 热词偏置 | 无 | 无(已移除,详见 v0.7.7 文档说明) |
195
249
  | 字幕 a11y | 无 | **4 档字号 + 3 档宽度 + 主题跟随** |
196
250
  | 唤醒词 | 无 | **轻量流式匹配 + 前缀语气词白名单** |
197
- | 兼容 dsh | — | **0.1.1-rc.2 → 0.1.5-rc.2 全版本** |
251
+ | 兼容 dsh | — | **0.1.1-rc.2 → 0.1.5-rc.2 全版本(+ 0.1.6-alpha.2 预览)** |
198
252
 
199
253
  ---
200
254
 
package/lib/client.js CHANGED
@@ -2825,7 +2825,7 @@ var TELEMETRY_VIEW = [
2825
2825
  { stage: "first-tts-chunk", key: "telFirstChunk" },
2826
2826
  { stage: "first-audio-played", key: "telFirstPlayed" }
2827
2827
  ];
2828
- var BUILD_TAG = "6e27638";
2828
+ var BUILD_TAG = "928a72b";
2829
2829
  var TELEMETRY_FLAG = "dsh-voice-mode.telemetry";
2830
2830
  var telemetryEnabled = typeof localStorage !== "undefined" && localStorage.getItem(TELEMETRY_FLAG) === "1";
2831
2831
  console.log("[dsh-voice] build=" + BUILD_TAG);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-voice-mode",
3
3
  "description": "Full-duplex voice plugin for DeepSeek Harness: local zipformer2 streaming ASR (no API key) → editable draft; Edge TTS or local VITS / Kokoro read-aloud with live captions; true barge-in; hardened HTTP surface + model SHA256 pinning; compatible with all dsh releases since 0.1.1-rc.2 (verified 0.1.1-rc.2 → 0.1.5-rc.2, plus 0.1.6-alpha.2 preview). · DSH 语音双工插件:流式识别入草稿、按句朗读+实时字幕、开口即打断;免 API Key、安全加固、全版本兼容(0.1.1-rc.2 起,含 0.1.5-rc.2 端到端验证 + 0.1.6-alpha.2 预览核验)。",
4
- "version": "0.7.12",
4
+ "version": "0.7.13",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "repository": {