DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

27Synthesis /

27Synthesis/dsh-go-local-voice

Verified

一个让 dsh-go 手机 App 原生界面用小米 MiMo / 豆包念回复的语音插件

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@41874739

dsh-go-local-voice · 鲸鲸朗读

鲸鲸朗读 · dsh-go-local-voice

English · 中文

面向 dsh-go 手机 App 原生界面的 TTS 插件(不是网页版)

给 DeepSeek Harness / dsh-go 手机 App 原生界面用的语音朗读插件: 长按任意一条回复 →「读出来」,用小米 MiMo TTS(或字节 豆包 Seed TTS)合成,直接在 App 里播放。

为什么需要它:DSH 生态里的 TTS 插件大多只跑在 Harness 网页版——它们的声音靠浏览器的 Web Audio 播, Flutter 原生界面里根本不会触发。这个插件走的是 dsh-go 桥接的 audio 能力,所以能真的出声。

功能

  • 长按回复 → 读出来;也可以「存成音频」导出到手机存储(MP3)
  • 小米 MiMo:mimo-v2.5-tts 内置 8 个音色(冰糖 / 茉莉 / 苏打 / 白桦 / Mia / Chloe / Milo / Dean),可加语音指令(语气、方言、情绪)
  • 豆包 Seed TTS:seed-tts-2.0 / 声音复刻 seed-icl-2.0(走 HTTP v3 单向流)
  • 长文一次念完:回合结束后台分段预取,点一次交出去的是一整段音频,不是"点一次念 120 字"
  • 可停止:停止 按钮真的停得住(固定的播放实例 + 稳定的 lease)
  • 实时状态:输入框上方状态条显示 正在合成语音… / 朗读中 0:12 / 1:40;面板里有进度条
  • 音频历史:导出过的文件在面板里列出来,点一下复制路径
  • Markdown 清洗:代码块、链接、表格、行内代码都不会被念出来(链接读作"链接")

安装

插件目录放在 $DSH_HOME/dsh-go/plugins/ 下(DSH_HOME 默认 ~/.dsh):

git clone https://github.com/27Synthesis/dsh-go-local-voice.git \
  "$HOME/.dsh/dsh-go/plugins/local-voice"

dsh plugin --profile web add "$HOME/.dsh/dsh-go/plugins/local-voice"

装完在 App 里重启一次引擎(设置 → 引擎 → 重启引擎),然后:

  • 长按助手消息 → 菜单里出现「读出来」「存成音频」
  • 输入框上方「插件」胶囊 →「鲸鲸朗读」

卸载:dsh plugin --profile web remove local-voice,再删目录。

配置

第一次用先在主面板里点「打开设置」,填 API Key:

项 说明
小米 Key 在 小米 MiMo 控制台 申请,形如 sk-...
豆包 Key 在豆包语音控制台申请(标准音色与 Agent Plan 都支持)
豆包音色 ID 形如 zh_female_...;用声音复刻时填复刻音色 ID
每段字数 默认 140。约 0.08 秒/字,140 字≈11 秒,稳在单次 30 秒的生产预算内
自动预取 默认开。回复一结束就在后台把整条合成好,之后点「读出来」几乎秒播

Key 只存在本机 data/settings.json(权限 0600),不会进仓库、不会出现在界面里、不会发给模型。 data/ 已在 .gitignore 中。

它是怎么做到的(给想改代码的人)

dsh-go 原生插件的桥接协议(v1.2)有三条硬约束决定了实现方式:

  1. media 路由必须在 30 秒内产出字节(CAP_LIMITS.mediaMs)——这是生产预算,不是音频时长上限。
  2. 音频本身可以很长(≤16 MiB),App 拿到整段自己播;play / stop 作用在同一个 instance 上。
  3. 插件不能主动推播放效果:onCapability 的返回值不会被执行成效果,所以"播完自动接下一段"做不到。

于是:

  • 预取:session/event 的 turn/end(completed)时,把回复按 140 字切段、并发 3 合成到 data/cache/<sha1>/sNNN.mp3,全齐后拼成 all.mp3。
  • 播放:read 只建任务并立刻返回 {type:'audio', op:'play', instance:'read', src:'media:speech', key};App 回来 GET 媒体路由,插件把缓存拼成一个整段 MP3(MP3 裸帧直拼是合法的,没有 ID3 头)。
  • 冷缓存:最多等 15 秒,先交已经合成好的前几段(约 30~60 秒语音),剩下的后台继续;10 分钟内再点一次从上次停的地方接着念。

实测(小米 MiMo v2.5 TTS,非流式 mp3,手机网络):15 字≈2.4 s,60 字≈4.7 s,120 字≈8.3 s, 240 字≈38 s(超预算),400 字≈32.6 s,800 字≈54.9 s → 这就是为什么段长取 140。

踩过的坑

  • instance 必须固定(这里用 read)。每次播放换新实例名,stop 就找不到 lease,"停止"永远按不动——不是接口不支持。
  • 面板的 select 下拉框不可靠:音色改成 list 一行一个、点一下立刻写设置 + toast + refresh。
  • 状态必须走数据绑定({"$": "data.info.status"}):视图里写死文字的话,每秒推数据界面也不会变。
  • 主面板只用 v1 组件(stack/text/callout/progress/list/keyValue/actions),需要输入框的项放「朗读设置」面板(v2)。

已知限制

  • 不能"回复结束自动开口":协议只允许用户点按触发播放。
  • 小米目前没有语速参数(豆包有 speech_rate,面板还没暴露)。
  • 暂停 / 继续:桥接的 pause 实测不可靠,已移除。
  • 单次播放音频上限 16 MiB(约 5.5 分钟语音),超长回复会在后台继续合成、下次点按接着念。
  • 豆包那一路没有 Key 实测过(按 v3 单向流接口写的),首次使用请先短句试听。

排查

  • data/debug.log:点按、媒体字节数与耗时、audio.ended/stopped/error、预取情况(不记 Key、不记正文)
  • data/settings.json:当前配置(0600)
  • 自查:node $DSH_HOME/skills/dsh-go-plugin/kit/bin/check.mjs <本目录> --load

致谢

  • 思路与小米/豆包接口细节参考了 dsh-xiaomi-tts(MIT)——它是网页版实现,播放侧用浏览器 Web Audio,本仓库是面向 dsh-go 原生界面的独立实现。
  • 插件格式与桥接能力来自 deepseek-harness 的 dsh-go 插件协议。

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 4187473981e0

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout