前言¶
DSH 的插件体系里,文本输出是基本能力,但「听」仍然是空白。开发者跑本地智能体时,常常需要离开屏幕去确认结果,或者边做别的事边听任务进展。dsh-speak 上游已经做了「把回答念出来」,但它默认只处理最终文本;一旦把中间过程也开起来,模型在工具调用间隙吐出的那些碎片会被一条条切开念,听感很差。
下面介绍的 m0yun/dsh-speak-plus 就是针对这个问题的增强分支。维护者 M0Yun,属于 DSH 客户端类插件,GitHub 仓库地址见文末。它定位是 dsh-speak 1.8.4 的增强分支,上游的朗读、队列、设置页、WebSocket 状态同步全部保留,另外补了中间过程合并、审批/提问插队、新内容换手、Alt + S 停止等行为。所有新增行为默认关闭或取保守值,不配置时与上游一致。
这是什么¶
一句话定位:给 DSH 加上中文语音播报,并且把中间过程按段合并后朗读,而不是逐句切碎地念。
- 仓库:https://github.com/M0Yun/dsh-speak-plus
- 目录页:https://www.skillhub.cn/plugins/M0Yun/dsh-speak-plus
- 上游:Alan2Z/dsh-speak(1.8.4)
- 许可证:MIT,继承上游 LICENSE
- 维护者:M0Yun
- 分类:客户端
它解决的核心问题是:开启 queueAllMessages 后,每条 assistant 消息立刻独立入队朗读,模型在工具调用之间往往只吐一两句话,于是听到的是「收到——」(被切)、「那就你自己重启。」(被切)、「6 个场景全过。」(被切)这样的碎片。本分支把连续到达的正文先攒成一段再念,同时规定什么时候该打断、什么时候不该。
核心功能¶
下表按 README 的对照列出,只写已核实的能力。
| 能力 | 上游 1.8.4 | 本分支 |
|---|---|---|
| 朗读最终回复 | 支持 | 支持 |
| 朗读中间过程 | 逐条、易被切碎 | 合并成段,按序读完 |
| 新内容打断当前朗读 | 不支持 | 可配(默认等新回合产出内容才换手) |
| 审批 / 提问优先 | 不支持(会被正文顶掉) | 插队并保护 |
| 停止播报快捷键 | 不支持 | Alt + S |
| 配置读取 | 依赖设置 schema | schema 不可用时回落读 profile 配置 |
| 队列 / 状态同步 / 设置页 / 手动重播 | 支持 | 全部保留 |
新增的五个能力是相对上游的增量,README 里逐项给了键名和默认值,见下方配置项一节。
安装与启用¶
插件以 DSH bundle 形式挂载,在 profile 的 cordis.patch.yml 中配置。下面这段是 README 给出的示例,路径里的 <你> 需要替换成实际用户名:
- id: dsh-speak
name: dsh-speak-plus
config:
queueAllMessages: true
interruptOnNewMessage: true
interimMode: queue
interimMergeMs: 800
interimMaxBacklog: 180
engine: 'C:\Users\<你>\.dsh\profiles\desktop\data\dsh-speak-edge\speak-edge.ps1' # 可选:自定义引擎
rate: 8
这一步在做什么:用 id: dsh-speak 声明挂载点与上游保持一致,用 name: dsh-speak-plus 指向本分支;config 里的键决定朗读行为,engine 是可选的自定义引擎脚本路径。
平台层面,Windows 用系统 SAPI 嗓音(装了 NaturalVoiceSAPIAdapter 可用自然音色),macOS 用系统 say。引擎脚本与上游一致(engine/speak.ps1、engine/speak.sh),也可以用 engine 指向自己的脚本。
配置项¶
新增(本分支)¶
| 键 | 默认 | 说明 |
|---|---|---|
interruptOnNewMessage |
false |
总开关:打开后启用本分支的打断 / 合并逻辑 |
interruptOnNewTurn |
false |
false:提交消息不打断,等新回合真的产出内容才换手;true:按下发送就掐断 |
interimMode |
queue |
queue:回合内各段排队读完、互不打断;replace:每段新内容立刻顶掉正在播的 |
interimMergeMs |
800 |
静默多久把碎片合并成一段,0 = 不合并 |
interimMaxBacklog |
180 |
待播正文最多积压多少字,超出丢弃最旧的 |
继承自上游(常用)¶
| 键 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关,关掉后完全不出声 |
automaticSpeech |
true |
自动朗读;手动重播始终可用 |
queueAllMessages |
false |
每条 assistant 消息都入队(中间过程) |
throttleMs |
1500 |
默认模式的合并延迟 |
engine |
空 | 覆盖引擎脚本路径 |
rate / volume |
0 / 50 |
Windows 为 SAPI 刻度(-10~10) |
maxChars |
安全值 | 超过则只念固定提示语 |
longTextMode / longTextMessage |
message |
超长文本的处理方式 |
announceApprovals / announceQuestions |
true |
审批 / 提问播报 |
announceTurnEnd / announceCommandDone / announceGoalChange / announceToolErrors / announceTodoWrite |
false |
可选事件播报 |
完整列表见上游文档 docs/UPSTREAM-README.zh-CN.md。
典型用法¶
先看一段可复现的最小配置。只想合并中间过程、不做打断,保留默认即可:
- id: dsh-speak
name: dsh-speak-plus
config:
queueAllMessages: true
interruptOnNewMessage: true
这一段的意思是:interruptOnNewMessage 打开,启用合并与打断逻辑;interruptOnNewMessage 不打开时,所有新增行为保持上游原样。
快捷键统一为 Alt + S:立刻停止播报,同时清空待播队列和还没播出的缓冲片段。README 特别说明,DSH 核心的「快捷键」列表只列核心自己的动作,没有给插件预留注册入口,所以这个键位由插件自己监听,不会出现在那个列表里,输入框有焦点时同样生效。
行为上要明确两点,做集成或排查时容易踩:
- 回合内中间过程按
interimMergeMs合并成段,段与段排队,前一段念完再念下一段;待播积压超过interimMaxBacklog字时丢弃最旧的。 - 换手规则:你发消息时不掐断当前朗读;新回合第一段内容要播时,才掐掉上一轮还在念的正文;正在念审批 / 提问时,新正文排队等待,不抢占。
另外,某些 DSH 构建里插件无法加载设置 schema,此时会直接读本 profile 的 cordis.patch.yml(按修改时间缓存,只取已知键),与运行时配置合并,运行时优先。挂载时会打一行 生效配置: … 便于排查。
适用场景与注意¶
适合这几类人:用 Windows SAPI 或 macOS say 做本地念读、需要靠听来确认任务进展的开发者;已经在用上游 dsh-speak、但嫌中间过程被切碎的用户;以及想给审批和提问加声音提示的团队。它不适合需要商业级 TTS 音色、或对播报时延有硬性要求的场景——它调用的是系统自带引擎。
几点限制必须写清楚:
- 插件以当前 DSH 进程的权限运行,安装前应先检查源码与许可证(MIT),确认
cordis.patch.yml的内容符合自己的 profile 约定。 - 设置页依赖
Configschema;构建失败时设置页可能不显示,此时改 YAML 即可。 - 新回合内容会掐掉其他会话正在播的正文(同一套扬声器),不区分来源。
- 直接改
node_modules里的插件文件会在重装 / 升级时被覆盖。
按目录页信息,该插件分类为客户端,属于社区生态项目。需要强调一点:社区目录是独立站点,与 DeepSeek / 幻方无官方从属关系,这只是聚合展示。
结尾¶
dsh-speak-plus 的价值在于把「中间过程认不清」这个上游遗留问题处理掉了:碎片合并成段、按序读完,审批和提问插队保护,Alt + S 一键停止,新增行为默认关闭。对已经在用 dsh-speak 的人来说,改动集中在一个 cordis.patch.yml,风险集中在配置而非代码。
- 目录页:https://www.skillhub.cn/plugins/M0Yun/dsh-speak-plus
- GitHub:https://github.com/M0Yun/dsh-speak-plus