前言¶
DSH 生態裏的 TTS 插件大多跑在 Harness 網頁版,聲音靠瀏覽器的 Web Audio 播。如果目標是手機 App 的 Flutter 原生界面,這些插件根本不會觸發——播放能力和瀏覽器綁在一起了。
27Synthesis/dsh-go-local-voice(中文名「鯨鯨朗讀」)解決的就是這一件事:給 DeepSeek Harness / dsh-go 手機 App 原生界面加語音朗讀,用小米 MiMo TTS 或字節豆包 Seed TTS 合成回覆內容,直接在 App 裏播放。分類屬於模型推理,由 27Synthesis 維護。下面按功能、安裝、配置、用法的順序介紹。
核心能力¶
先明確它管哪些事,都是 README 裏寫明的可落地能力:
- 長按任意一條助手回覆,菜單出現「讀出來」和「存成音頻」;前者直接播放,後者導出 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 中。
典型用法¶
裝好並配好 Key 後,操作順序只有三步:
- 打開 App,發起一次對話。
- 回合結束後,插件已在後臺按 140 字切段、併發 3 合成,寫入
data/cache/<sha1>/sNNN.mp3,全齊後拼成all.mp3。 - 長按最新那條回覆,選「讀出來」開始播放,或選「存成音頻」導出。
冷緩存時插件最多等 15 秒,先交已經合成好的前幾段(約 30~60 秒語音),剩下的後臺繼續;10 分鐘內再點一次會從上次停的地方接着念。狀態條和麪板進度條會同步顯示進度。
實現要點¶
給想改代碼的人:dsh-go 原生插件的橋接協議(v1.2)有三條硬約束決定了實現方式。一是 media 路由必須在 30 秒內產出字節(CAP_LIMITS.mediaMs),這是生產預算,不是音頻時長上限;二是音頻本身可以很長(≤16 MiB),App 拿到整段自己播,play / stop 作用在同一個 instance 上;三是插件不能主動推播放效果,onCapability 的返回值不會被執行成效果,所以「播完自動接下一段」做不到。
據此,插件把工作拆成預取和播放兩段:session/event 的 turn/end(completed)時切段併發合成到緩存目錄;用戶點按後 read 只建任務並立刻返回 {type:'audio', op:'play', instance:'read', src:'media:speech', key},App 回來 GET 媒體路由時,插件把緩存拼成一個整段 MP3(MP3 裸幀直拼合法,不需要 ID3 頭)。
關於段長取 140:README 給出實測數據(小米 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。爲保證單段穩定落在 30 秒預算內,才把默認段長定爲 140 字。
已知限制¶
使用前需要知道這些邊界,都是 README「已知限制」列出的:
- 不能「回覆結束自動開口」:協議只允許用戶點按觸發播放。
- 小米目前沒有語速參數;豆包有
speech_rate,但面板還沒暴露。 - 暫停 / 繼續:橋接的
pause實測不可靠,已移除。 - 單次播放音頻上限 16 MiB(約 5.5 分鐘語音),超長回覆會在後臺繼續合成,下次點按接着念。
- 豆包那一路沒有 Key 實測過(按 v3 單向流接口寫的),首次使用請先短句試聽。
另外插件在踩坑裏提到幾處實現約束:播放的 instance 必須固定(這裏用 read),每次換實例名會讓 stop 找不到 lease;面板的 select 下拉框不可靠,音色面板改成 list 一行一個,點一下立刻寫設置並刷新;狀態必須走數據綁定({"$": "data.info.status"}),視圖裏寫死文字的話數據每秒推界面也不變;主面板只用 v1 組件,需要輸入框的項放在「朗讀設置」面板(v2)。
排查與自檢¶
出問題時從這三處入手:
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-go 手機原生界面裏給助手回覆加語音、不希望依賴瀏覽器 Web Audio 的人;不適合需要自動朗讀或暫停繼續的場景。
兩點提醒:這個插件會以當前 dsh 進程的權限運行,安裝前應先讀一遍源碼(倉庫地址見下)並確認許可證;插件格式與橋接能力來自 deepseek-harness 的 dsh-go 插件協議,思路和小米/豆包接口細節參考了網頁版項目 dsh-xiaomi-tts(MIT),本倉庫是面向 dsh-go 原生界面的獨立實現。
目錄頁:https://www.skillhub.cn/plugins/27Synthesis/dsh-go-local-voice
源碼:https://github.com/27Synthesis/dsh-go-local-voice
許可證:MIT(倉庫版本 1.0.0,engines.dsh 要求 >=0.2.1-rc.2 <0.3.0-0)。
小結¶
dsh-go-local-voice 的價值很集中:在 DSH 手機原生界面裏提供一條真正出聲的 TTS 路徑,覆蓋小米 MiMo 和豆包兩路,且把長文、停止、狀態、導出和 Markdown 清洗這些細節都處理掉了。安裝命令和配置字段都來自 README,功能邊界也在已知限制裏寫清楚了,照着做就能用。