dsh-voice-mode 0.7.15 → 0.7.17

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
@@ -10,7 +10,7 @@ spoken answer. Streamed zipformer2 ASR → editable draft → auto send → the
10
10
  final reply is read out sentence-by-sentence via Edge TTS, and your voice
11
11
  interrupts playback and the running turn. No API key.
12
12
 
13
- > 中文说明见 [README.md](./README.md)。
13
+ > **English** · [中文](https://github.com/qishuilalala/dsh-voice-mode/blob/HEAD/plugin/dsh-voice-mode/README.md)
14
14
 
15
15
  ![dsh-voice-mode full-duplex voice conversation](https://raw.githubusercontent.com/qishuilalala/dsh-voice-mode/HEAD/assets/hero-banner.png)
16
16
 
@@ -46,7 +46,8 @@ interrupts playback and the running turn. No API key.
46
46
  - **Barge-in**: three sensitivity levels of voice-onset detection → local mute + host synth queue invalidation (epoch) + running turn cancellation (the half-finished part is kept and naturally flows into your new message). With a wake word set, barge-in **remains speak-to-interrupt** (the gate is the VAD, not the wake word; the engine returns to standby afterwards)
47
47
  - **Lazy model download with progress**: the zipformer2 Chinese streaming model (~160 MB, `.part` resumable) is downloaded on first use with live progress in the status bar; `npm run prefetch` can pre-download it
48
48
  - **Resilience**: mic-denied red hint, visible model-download failure, TTS unreachable status hint (auto retry), failed submit keeps the text in the draft, SSE auto-reconnect
49
- - **Settings**: Settings → Plugins → voice-mode, with voice / rate / interrupt sensitivity / silence pause / idle timeout / model mirror / auto send / interaction mode / wake word / ITN / caption tiers / yield semantics; **voices are previewable** (the "试听/Preview" button synthesizes and plays the current voice at the current rate instantly, no need to enter voice mode; custom ShortNames are previewable too)
49
+ - **Settings**: location depends on your dsh version (see Settings below), with voice / rate / interrupt sensitivity / silence pause / idle timeout / model mirror / auto send / interaction mode / wake word / ITN / caption tiers / yield semantics; **voices are previewable** (the "试听/Preview" button synthesizes and plays the current voice at the current rate instantly, no need to enter voice mode; custom ShortNames are previewable too)
50
+ - **Interface language**: follows dsh's language setting (Settings → General → Language) and **switches instantly, no reload** — the settings page, voice status bar, captions, voice names/gender/accent and error messages all follow it, and the LLM spoken-style prompt is chosen in English or Chinese accordingly. Dictionaries are registered in dsh's official locale service under the `voice-mode` namespace, so community language packs can add more languages (missing ones fall back to English). The plugin's name and description in the Plugins page are localized too.
50
51
  - **Idle exit**: auto-exit and mic release after 5 minutes of inactivity (reading counts as activity; batch J 10→5)
51
52
 
52
53
  ---
@@ -104,13 +105,20 @@ npm run prefetch # run inside the plugin dir; writes to the platform ca
104
105
  3. The AI answer is read sentence-by-sentence with a caption overlay at the bottom-right; click "Skip" or just start speaking to interrupt
105
106
  4. Click "Exit" in the status bar (or press `Ctrl+Shift+V` again) to leave voice mode
106
107
 
107
- On first entry the recognition model is downloaded; the status bar shows `正在加载模型… <file> <percent>%`.
108
+ On first entry the recognition model is downloaded; the status bar shows `Loading model… <file> <percent>%`.
108
109
 
109
- If a wake word is configured, you land in standby first (the status bar prompts `说『唤醒词』开始`), and recognizing starts after you speak the wake word.
110
+ If a wake word is configured, you land in standby first (the status bar prompts `Say "<wake word>" to start`), and recognizing starts after you speak the wake word.
110
111
 
111
112
  ---
112
113
 
113
- ## ⚙️ Settings (Settings → Plugins → Plugins config → 语音模式)
114
+ ## ⚙️ Settings
115
+
116
+ **Works on every dsh version: Settings → Voice Mode** (the plugin registers its own page in the Settings dialog). Secondary entry points (same card) vary by version:
117
+
118
+ - dsh ≤ 0.1.5: Settings → Plugins → plugin config → voice mode
119
+ - dsh 0.1.6-alpha and later (incl. 0.1.7 / 0.2.0): left sidebar **Plugins** → the installed `dsh-voice-mode` → the "Voice Mode" card on its detail page
120
+ - On dsh 0.1.7+ the values are stored in the plugin's own file `~/.dsh/voice-mode.settings.json` (under `$DSH_HOME`) and take precedence over same-named keys in the profile config. The first run migrates the old `voice-mode:` block from `settings.yaml(.imported)` once. To reset, set the file's content to `{}` (do not delete it).
121
+
114
122
 
115
123
  ### 4 new settings (11 batches of comprehensive fixes)
116
124
 
@@ -304,8 +312,8 @@ flowchart LR
304
312
  | Symptom | Fix |
305
313
  | --- | --- |
306
314
  | Mic click does nothing, red hint in the status bar | The browser denied mic permission: allow it in the address bar and retry |
307
- | Status bar stuck on `正在加载模型… x%` | Check the network; the model is large (160 MB) — `npm run prefetch` first; on mainland networks set `modelHost` to `https://hf-mirror.com` |
308
- | Status bar shows `语音模型下载失败` | Both mirrors are unreachable: check network/proxy and re-enter voice mode (resumable) |
315
+ | Status bar stuck on `Loading model… x%` | Check the network; the model is large (160 MB) — `npm run prefetch` first; on mainland networks set `modelHost` to `https://hf-mirror.com` |
316
+ | Status bar shows `Model download failed (<file>)` | Both mirrors are unreachable: check network/proxy and re-enter voice mode (resumable) |
309
317
  | Caption appears (overlay) but no sound | Check system volume/output; if autoplay is blocked, click anywhere on the page and retry |
310
318
  | Status bar shows `朗读连接失败:正在重试…` | Edge TTS unreachable (overseas service), auto-retries; if it persists, check network/proxy |
311
319
  | Poor recognition | Get closer to the mic, reduce ambient noise; if echo remains, raise the interrupt sensitivity by one step |
package/README.md CHANGED
@@ -7,6 +7,8 @@
7
7
 
8
8
  DeepSeek Harness 语音双工对话模式:会话内一键进入 → 边说边出字的流式识别 → 停顿自动发送 → 最终答复按句流式朗读 + 实时字幕,开口即可打断(真 barge-in)。无需 API Key,识别模型在本地宿主端推理。
9
9
 
10
+ **中文** · [English](https://github.com/qishuilalala/dsh-voice-mode/blob/HEAD/plugin/dsh-voice-mode/README.en.md)
11
+
10
12
  > **Full-duplex voice mode for DeepSeek Harness** — streamed ASR to an editable draft, sentence-by-sentence read-aloud with live captions, and speaking interrupts playback and the running turn.
11
13
 
12
14
  ![dsh-voice-mode 全双工语音对话](https://raw.githubusercontent.com/qishuilalala/dsh-voice-mode/HEAD/assets/hero-banner.png)
@@ -50,8 +52,8 @@ DeepSeek Harness 语音双工对话模式:会话内一键进入 → 边说边
50
52
  - **输出链路**:只朗读最终答复的 `text-delta`(reasoning/工具调用不读),按句流式朗读(默认 Edge 云端;可切本地 VITS/Kokoro,中英混读选 Kokoro)+ 右下角实时字幕浮层;工具调用触发提示音;全文照常写入聊天记录;口语化提示词(设置 `spokenFormat`,默认开)让回复为自然短句、不带 Markdown 排版符号
51
53
  - **开口打断(barge-in)**:服务端 Silero VAD 帧级检测 + 回声门控(echoGateDb)三档灵敏度 → 本地静音 + host 合成队列作废 + 正在运行的回合取消(保留半截并自然续入新消息);朗读中自动切超灵敏档。开启唤醒词后打断**仍是开口即打断**(打断门控是 VAD,不是唤醒词;打断后回待机态)
52
54
  - **模型懒加载与进度**:首次使用自动下载识别/合成模型(`.part` 断点续传),状态条实时显示进度;可用 `npm run prefetch` 预下载
53
- - **设置**:设置 → Plugins → 插件配置 → 语音模式(voice-mode),可调朗读引擎/音色/语速/打断灵敏度/静音停顿/空闲超时/模型镜像/自动发送/交互模式/唤醒词/口语化提示词/字幕档位/让位语义;**音色可试听**(按当前音色+语速即时合成预览,自定义 ShortName 亦可)
54
- - **界面语言**:跟随浏览器语言(中文 / English;切换后刷新页面生效)
55
+ - **设置**:入口随 dsh 版本而不同(见下方「设置」),可调朗读引擎/音色/语速/打断灵敏度/静音停顿/空闲超时/模型镜像/自动发送/交互模式/唤醒词/口语化提示词/字幕档位/让位语义;**音色可试听**(按当前音色+语速即时合成预览,自定义 ShortName 亦可)
56
+ - **界面语言**:跟随 dsh 的语言设置(设置 → 通用 → 语言),**切换即时生效、无需刷新**——设置页、语音状态条、字幕、音色名称/性别/口音、错误提示全部随之变化;LLM 口语化提示词也按界面语言选中/英文版。插件词典注册在 dsh 官方 locale 服务的 `voice-mode` 命名空间,社区语言包可据此补充其它语言,缺失的语言回落英文。插件名称与描述在「插件」页同样按语言显示。
55
57
  - **容错**:麦克风被拒红点提示、模型下载失败可见提示、TTS 连接失败状态条提示(自动退避重试)、提交失败文字留在草稿、SSE 断线自动重连
56
58
  - **空闲退出**:5 分钟无活动自动退出并释放麦克风(**正在朗读计为活动**,长朗读不会中途下线;批 J 已微调默认 10→5)
57
59
 
@@ -88,7 +90,14 @@ bundle 插件安装后需重启 dsh 生效(Linux:`systemctl restart dsh`;
88
90
 
89
91
  ---
90
92
 
91
- ## ⚙️ 设置(设置 → Plugins → 插件配置 → 语音模式)
93
+ ## ⚙️ 设置
94
+
95
+ **所有 dsh 版本通用入口:设置(Settings)→ 语音模式(Voice Mode)**。另有按版本不同的次要入口(卡片内容一致):
96
+
97
+ - dsh ≤ 0.1.5:设置 → Plugins → 插件配置 → 语音模式
98
+ - dsh 0.1.6-alpha 及以后(含 0.1.7、0.2.0):左侧 **Plugins** → 已安装的 `dsh-voice-mode` → 详情页「语音模式」卡片
99
+ - dsh 0.1.7+ 起,设置保存在插件自有文件 `~/.dsh/voice-mode.settings.json`(`$DSH_HOME` 下),优先于 profile 配置里的同名键;首次运行会从旧 `settings.yaml(.imported)` 的 `voice-mode:` 段迁移一次;恢复默认请把该文件内容改成 `{}`(不要删除)。
100
+
92
101
 
93
102
  | 键 | 默认 | 说明 |
94
103
  | --- | --- | --- |
@@ -325,7 +334,11 @@ src/tts-queue.ts host:逐会话 TTS 队列 + epoch 打断机制
325
334
  src/segmenter.ts host:句子切分 + 文本消毒(markdown 剥离 + 噪声字符剔除)
326
335
  src/asr.ts client:音频采集、VAD 分段、增量识别、唤醒词、按住说门控
327
336
  src/client.tsx client:麦克风按钮 + 模式切换按钮 + 状态条 + 字幕浮层 + 打断
328
- src/strings.ts client:中英文案字典(navigator.language)
337
+ src/strings.ts client:中英文案词典(zh / en 两份,键一一对应;有测试守卫)
338
+ src/i18n.ts client:接入官方 locale 服务(语言即时切换、语言包扩展、无服务时回退)
339
+ src/voice-catalog.ts host+client:音色目录单一数据源;src/voice-labels.ts 按语言生成音色/镜像标签
340
+ src/errors.ts host↔client:稳定错误码(host 不发自然语言,客户端按语言翻译)
341
+ src/prompts.ts host:LLM 口语化提示词(中/英)与试听例句(按音色语种)
329
342
  ```
330
343
 
331
344
  ---
package/icon.svg ADDED
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="128" height="128" role="img" aria-label="Voice Mode">
2
+ <rect width="128" height="128" rx="28" fill="#4d6bfe"/>
3
+ <rect x="50" y="26" width="28" height="48" rx="14" fill="#ffffff"/>
4
+ <path d="M38 62v4a26 26 0 0 0 52 0v-4" fill="none" stroke="#ffffff" stroke-width="7" stroke-linecap="round"/>
5
+ <path d="M64 92v14M50 106h28" fill="none" stroke="#ffffff" stroke-width="7" stroke-linecap="round"/>
6
+ <path d="M20 58v12M108 58v12M10 63v2M118 63v2" fill="none" stroke="#ffffff" stroke-opacity=".6" stroke-width="6" stroke-linecap="round"/>
7
+ </svg>