🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

小艺朗读 lemonhall/dsh-tts-reader

DeepSeek Harness
lemonhall33 天前有提交已提供中文文档扫描:未发现敏感能力

边写边念助手回答,随时重读任意历史消息

29.7/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/4 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add lemonhall/dsh-tts-reader
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么[目录]—
dsh 原生插件 · ui
暂无时间戳·判据 →
装得上吗[实装验证]!
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
数据截至 2026/10/05·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]—
更新放缓:最近一次提交在 33 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

⚠︎ 实装验证未通过(unknown · 2026/10/5) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

发起外部网络请求
查看扫描证据(共 2 处,展示前 2 条)
  • 发起网络请求
    lib/client.js:219
    const response = await fetch(
  • 发起网络请求
    lib/client.js:337
    const response = await fetch(url, { headers: { accept: 'application/json' }, cache: 'no-store' })
扫描于 2026/11/4(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 边写边念助手回答
  • 重读历史回答
  • 逐句流式合成

DSH 插件:用小艺(Edge TTS)边写边念助手的回答,并可重读任意一条历史回答。零依赖直连、逐句流式合成、Web Audio 无缝连播。

README

由 DeepSeek 最新模型翻译生成
dsh-tts-reader 把助手的回答默认用小艺(zh-CN-XiaoyiNeural)的声音念出来。 它替换掉 SKILL multilingual-tts-audio 那条路子:那个 SKILL 每次都要 uv run --with edge-tts python …(解析依赖 + 起 Python + 等整个 MP3 写完),而且要我 主动去调它。这个插件常驻进程内、逐句流式合成,而且边写边念。 两个入口 | 位置 | 作用 | | 输入框右侧的喇叭 | 整个会话的实时朗读开关(默认开),状态存在 localStorage | | 每条回答下方的喇叭 | 在「显示 / 复制 / 点赞 / 用量 / 时间」那一行,重读这一条;再点一下停 | 两者是独立的两条队列:点「重读某条」会临时接管扬声器(否则两边抢着说话),读完自动把实时朗读接回——从下一句开始,不补播期间错过的内容。 实时朗读不受影响:它的队列和游标始终是分开的。 它是怎么工作的 agent/assistant-stream GET /dsh-tts/tail?session=…&since=…
展开完整文档(README 剩余 1 节)
dsh-tts-reader

把助手的回答默认用小艺(zh-CN-XiaoyiNeural)的声音念出来。

它替换掉 SKILL multilingual-tts-audio 那条路子:那个 SKILL 每次都要 uv run --with edge-tts python …(解析依赖 + 起 Python + 等整个 MP3 写完),而且要我 主动去调它。这个插件常驻进程内、逐句流式合成,而且边写边念。

两个入口

| 位置 | 作用 |
| 输入框右侧的喇叭 | 整个会话的实时朗读开关(默认开),状态存在 localStorage |
| 每条回答下方的喇叭 | 在「显示 / 复制 / 点赞 / 用量 / 时间」那一行,重读这一条;再点一下停 |

两者是独立的两条队列:点「重读某条」会临时接管扬声器(否则两边抢着说话),读完自动把实时朗读接回——从下一句开始,不补播期间错过的内容。
实时朗读不受影响:它的队列和游标始终是分开的。

它是怎么工作的

agent/assistant-stream GET /dsh-tts/tail?session=…&since=…
(模型正在写的原文) (base64 MP3,按句游标拉取) │ ▲ ▼ │ lib/index.js ──► lib/feed.js ──► lib/edge-tts.js 宿主半边 逐句队列 零依赖 Edge TTS 客户端 │
Session.snapshotEvents() ────────────────┤
(某条历史回答的正文) GET /dsh-tts/message?session=…&id=…&since=…
│ │
└──────────────► lib/feed.js ─────────┤
│
lib/client.js ──┘
页面半边:Web Audio 无缝连播 + 两个开关

- 为什么在宿主侧合成:Edge 的朗读服务只在请求带浏览器 User-Agent 时才 101 升级,而浏览器的 WebSocket 无法自定义请求头;Node 可以,所以合成放在宿主侧。
- 为什么监听 agent/assistant-stream:这是模型输出的原始流,比 DOM 早。
一句话在屏幕上还没排完,声音已经出来了。
- 「重读某条」的正文从哪来:ctx.sessions.get(id).snapshotEvents() 里那条 assistant/message 事件带的 stream 正是可见正文(不含推理和工具调用)。
被查看的会话一定是活的,所以整个可见历史都能读,不受插件安装时间限制。
- 为什么是"拉"而不是"推":页面每 400 ms 用游标拉一次。没人拉就不合成,没有听众的会话不花任何代价。

改代码之后怎么生效

| 改了哪半边 | 生效方式 |
| lib/client.js | 刷新页面即可(Ctrl+F5 / CDP reload)——客户端 bundle 按 URL 现取 |
| lib/index.js / lib/feed.js / lib/edge-tts.js | 必须重启应用。宿主模块被 Node 的 ESM 缓存按 URL 锁住,plugin_manager 关掉再打开条目没有用(实测:路由依旧 404) |

⚠️ 实测警告:往 profile patch 的 hmr 条目里加 root 目录(见下)并没有让宿主半边热重载——配完之后改文件,/dsh-tts/message 依旧 404。该配置先留着,重启后再验证一次是否生效;在那之前,改宿主半边一律按"要重启"来预期。

另外:别用 plugin_manager set_plugin 去关/开这个插件。实测这会留下半死状态——路由还在,但 agent/assistant-stream 监听被停掉,于是不再产生新句子、实时朗读静默失效,而条目看起来是 enabled。要停就用输入框那个喇叭按钮。

配置

改 $DSH_HOME/profiles/desktop/cordis.patch.yml 里 dsh-tts-reader 那条的 config (本插件没有导出 Config schema,Cordis 会把整块 config 原样交给 apply):

| 键 | 默认 | 说明 |
| enabled | true | 宿主侧总开关 |
| voice | zh-CN-XiaoyiNeural | Edge TTS 短名,启动时向官方声音目录核对 |
| rate / volume / pitch | +0% / +0% / +0Hz | 合成参数 |
| maxPerRequest | 3 | 每次拉取最多返回几句 |

朗读内容会怎么处理

念的是给人听的版本,不是屏幕上的 Markdown:

- 围栏代码块 → 整块丢掉(念代码没有意义)
- 行内代码 → 保留里面的字
- 表格 → 单元格用「,」连起来,分隔行丢掉
- 链接 → 只念文字,裸 URL 变成「链接」
- 标题 #、加粗 **、引用 >、列表符号 → 去掉
- 推理过程和工具调用参数永远不念

三个协议坑(都实测过,别再踩)

1. 准入的门槛是 User-Agent,不是签名。 服务端拒绝升级时只回一个裸的 403,不说哪个头不对。把请求头逐个变量做对照实验后确认:
- User-Agent: …Chrome/143…Edg/143 → 101
- User-Agent: …Chrome/130…Edg/130(过旧)→ 403
- Sec-MS-GEC-Version 写个瞎编的 1-99.0.0.0 照样 101

lib/edge-tts.js 保留当前版本号只是为了不至于过期,它从来不是开关。

2. SSML 里必须写语音全名。 zh-CN-XiaoyiNeural 是短名,服务端只认 Microsoft Server Speech Text to Speech Voice (zh-CN, XiaoyiNeural)。
写短名不会报错 —— 服务端接受 101 升级,然后静默 reset 连接。
插件启动时拉一次官方声音目录做映射,离线兜底按 locale-Name 推导。

3. 二进制音频帧没有空行分隔。 帧结构是 [2 字节大端头长度][ASCII 头][MP3],音频从 headerLength + 2 开始。
不要去找 \r\n\r\n —— 找不到,会得到 0 字节「成功」。

一个被证伪的怀疑,记下来免得后人再查

Sec-MS-GEC 是时间戳乘 1e9/100 再哈希。这个乘积约 1.3e17,看着像超出了 float64 的精确整数范围,所以一度以为「必须用浮点、精确整数会算出另一个哈希」。

这个说法是错的。 实测对比了前后三年、332,640 个五分钟时间片,零处不一致。
原因是 ticks 被下取整到 300 的倍数,而 300 × 1e7 = 3e9 本身是 16 的倍数,乘积恰好落在 float64 能精确表示的范围内。代码里保留浮点写法只是为了跟参考实现一致。

自测

cd E:\development\dsh-tts-reader
node test/feed.mjs # 逐句队列:游标、预热、失败、剪枝(纯离线)
node test/client-load.mjs # 客户端半边:模块封装、槽位注册、渲染(纯离线)
node test/host-e2e.mjs # 宿主半边端到端:假事件 → 真路由 → 真 MP3(需联网)
node test/smoke.mjs # 语音目录 + 合成 + 文本清洗(需联网)

调试时 $env:DSH_TTS_DEBUG=1 会打印 WebSocket 帧级日志。
预览分享卡片长什么样 ↓lemonhall/dsh-tts-reader
分享 · DeepSeek Harness Hub
lemonhall/dsh-tts-reader

边写边念助手回答,随时重读任意历史消息

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部