dsh-speak-plus:把 DSH 的回答连中间过程一起念出来

前言

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 核心的「快捷键」列表只列核心自己的动作,没有给插件预留注册入口,所以这个键位由插件自己监听,不会出现在那个列表里,输入框有焦点时同样生效。

行为上要明确两点,做集成或排查时容易踩:

  1. 回合内中间过程按 interimMergeMs 合并成段,段与段排队,前一段念完再念下一段;待播积压超过 interimMaxBacklog 字时丢弃最旧的。
  2. 换手规则:你发消息时不掐断当前朗读;新回合第一段内容要播时,才掐掉上一轮还在念的正文;正在念审批 / 提问时,新正文排队等待,不抢占。

另外,某些 DSH 构建里插件无法加载设置 schema,此时会直接读本 profile 的 cordis.patch.yml(按修改时间缓存,只取已知键),与运行时配置合并,运行时优先。挂载时会打一行 生效配置: … 便于排查。

适用场景与注意

适合这几类人:用 Windows SAPI 或 macOS say 做本地念读、需要靠听来确认任务进展的开发者;已经在用上游 dsh-speak、但嫌中间过程被切碎的用户;以及想给审批和提问加声音提示的团队。它不适合需要商业级 TTS 音色、或对播报时延有硬性要求的场景——它调用的是系统自带引擎。

几点限制必须写清楚:

  1. 插件以当前 DSH 进程的权限运行,安装前应先检查源码与许可证(MIT),确认 cordis.patch.yml 的内容符合自己的 profile 约定。
  2. 设置页依赖 Config schema;构建失败时设置页可能不显示,此时改 YAML 即可。
  3. 新回合内容会掐掉其他会话正在播的正文(同一套扬声器),不区分来源。
  4. 直接改 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
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜