用 dsh-voice 給 DeepSeek Harness 補上口述輸入和語音朗讀

前言

DeepSeek Harness(簡稱 dsh)的設計是「一切皆插件」:模型、工具、會話、UI 都可以往運行時上掛。終端裏的智能體默認還是打字進出——離開鍵盤時沒法口述一條指令,長任務跑完也只能回來盯一屏日誌。社區裏已經出現了不少視覺、瀏覽器類插件,語音這一側仍然要單獨裝。

dsh-voice 衝着這兩個日常缺口來:把口述音頻轉成用戶消息,再讓智能體把回覆讀出來。它不自己做一套音頻管線,而是疊在 dsh 已有的 ctx.shellctx.jobsctx.settingsctx.attachmentsctx.conversationEvents 上面。本文按社區目錄頁、GitHub 倉庫 README / README.zh.md、package.jsoncordis.patch.yml 交叉覈對後整理。需要先說明兩點:社區插件目錄是獨立站點,與 DeepSeek / 幻方沒有官方從屬關係;Harness 本身仍處於 developer preview,後續可能出現不兼容變更。GitHub 上還有其他同名 dsh-voice 倉庫,能力邊界並不相同,本文只寫 Jesse-njx 維護的這一份。

這是什麼

dsh-voice 是一款「工具與能力」類 DSH 插件,由 Jesse-njx 維護,許可證 MIT,主要語言 TypeScript。倉庫 package.json 中的包名是 @dsh-voice/bundle,版本號 0.1.0,要求 Node.js >=20。2026-08-18 覈實時,目錄頁與 GitHub API 均顯示 1 星;倉庫創建於 2026-08-13,社區目錄收錄日期 2026-08-14;topic 包括 deepseek-harnessdsh-pluginsttttsvoice

一句話定位:語音筆記進去、朗讀答案出來。口述音頻會變成用戶消息(轉寫),智能體也可以把回覆讀出聲(合成);長任務、無界面運行還可以留下一句旁白。音頻默認是 ~/.dsh/voice/ 下的普通文件,會話日誌只保存引用和轉寫文本。

它解決的不是「對着麥克風即時聊天」。README 把 v0.1 的非目標寫得很清楚:不做即時流式對話、不做外呼語音電話、不做喚醒詞或常駐監聽,也不把原始音頻寫進會話日誌。錄音和播放都要等模型顯式調用工具,默認不會自己響。

核心功能

插件包註冊兩套工具、一個持久化事件、一個會話開關。Web 客戶端再補上音頻卡片。cordis.patch.yml 裏的插件 id 是 dsh-voice,name 爲 @dsh-voice/bundle

transcribe:口述變成用戶消息

transcribe({ source, to? }) 做語音轉文字。source 必須二選一,不能兩個一起傳:

  • { file: }:轉寫已經存在的音頻文件。
  • { record: { seconds? } }:從麥克風錄一段,默認 5 秒。錄音路徑要可用:ffmpeg,或 macOS 上捆綁的 swift shim。

轉寫結果插入爲用戶消息,不是工具輸出。會話裏會記一條 voice/note 事件,Web 端渲染成帶播放/暫停、時長、後端徽標和轉寫字幕的音頻卡片。工具本身返回緊湊句柄 { transcript, audioRef, backend, durationMs },方便 Code Mode 拿到結構化數據。

如果同時裝了 dsh-crosstalk,還可以帶 to:,把這條語音便籤作爲帶標籤的 peer 消息投到另一路本地會話,並附上音頻路徑。未安裝 crosstalk 時,這個參數不會出現。

speak:後臺朗讀,不阻塞當前回合

speak({ text, voice?, rate? }) 做文字轉語音。合成和播放走 ctx.jobs 上的後臺任務,kind 爲 voice-speak。工具立刻返回 { jobId, audioRef },不卡住當前回合;播放是異步的,失敗會注入一條通知,而不是把錯誤拋進這一輪對話。

每個後端都會先在 audioDir 寫下持久化文件,再盡力播放。因爲只是 ctx.jobs 上的普通工具,routines 和無界面(headless)運行也可以調用。README 把它同時當作長任務旁白:例如構建結束時報一句「構建完成,0 失敗」。旁白並不是另一套 API,就是在 job 上下文裏調用 speak

/voice 與 readReplies

會話級開關,用來自動朗讀智能體的回覆。配置項 readReplies 默認 false;會話裏可以用命令即時改:

/voice on
/voice off
/voice status
/voice speak <text>

各條含義如下:

  • on:開始朗讀助手回覆。
  • off:停止。
  • status:查看當前開關、後端和 audioDir
  • speak <text>:直接從輸入框朗讀一行,不必等模型調工具。

開關是當前會話生效,改完不用重裝插件。readReplies 只朗讀已有回覆,不會去錄音。

後端怎麼選

語音轉文字由 dsh-voice-backends 模塊負責選擇:

  • whisper-local:PATH 上的 whisper.cpp 二進制(也可在配置裏指定),經 ctx.shell 調用,完全離線。
  • openai:走標準憑據通道訪問 OpenAI 兼容的 whisper-1 端點,密鑰環境變量是 OPENAI_API_KEY。這是唯一會把音頻送出本機的 STT 路徑,而且只有顯式配置纔會啓用。
  • macos:經捆綁的 swift shim 調用系統 SFSpeechRecognizer,同樣走 ctx.shell。不額外裝軟件,也不需要網絡配置。
  • fake:文本到文本的測試夾具。文件內容是 {"transcript": "…"},或文件名形如 fixture-.m4a 時,轉寫結果就是那段文本。給 CI 跑通整條工具鏈,不碰麥克風、不碰網絡。

文字轉語音:

  • say(默認):macOS 的 say -o --file-format=m4af --data-format=aac,再用 afplay 播放。零安裝,寫出 Chrome / Safari 能播的 m4a。
  • piper:本地 Piper 二進制,離線神經 TTS。
  • edge-tts:雲端;只有寫進配置纔會用。
  • fake:寫入固定 JSON,讓 speak 的產物能再走一遍 fake STT。

選擇規則是純函數,倉庫裏有單測:配置了哪個後端就用哪個;沒配則按離線回退,STT 是 whisper-local → macos,TTS 是 say → piper雲端後端永遠不會被自動選中。本機既沒有 whisper.cpp / macOS 語音識別,也沒有 say / Piper 時,會給出明確報錯,告訴你該配什麼,而不是悄悄改走 OpenAI 或 edge-tts。

本地優先:文件在磁盤,日誌只留引用

設計中心是本地優先:

  • 除非顯式設置 stt.backend: openaitts.backend: edge-tts,音頻不出本機。
  • 每個產物都是 audioDir(默認 ~/.dsh/voice/)下可直接查看、可 rm 的文件。
  • 會話日誌只保存一條 voice/notenoteId、回合座標、audioRef(路徑 + mime + durationMs)、transcriptdirection: 'in' | 'out'backend。v0.1 沒有更新事件。
  • 音頻文件缺了或被刪掉時,Web 卡片降級成只顯示轉寫文字。回放不需要再讀一遍音頻文件。

Web 客戶端把入站便籤(STT)畫成用戶回合,把出站 speak 畫成智能體側卡片。客戶端 bundle 由 scripts/build-client.mjs 打成 lazy-CJS,安裝到 web profile 後經 /plugins/@dsh-voice/bundle/client.js 提供。

安裝與啓用

社區目錄頁給出的安裝命令如下,在 DeepSeek Harness 終端中運行即可:

dsh plugin add github:Jesse-njx/dsh-voice

需要可復現安裝時,按目錄頁說明把 commit 哈希釘上:

dsh plugin add github:Jesse-njx/dsh-voice#<commit>

<commit> 換成倉庫裏實際的 commit SHA。

倉庫 README 另外寫了按 npm 包名、並指定 web profile 的安裝方式:

dsh plugin --profile web add @dsh-voice/bundle

截至 2026-08-18,npm registry 上查不到 @dsh-voice/bundle(返回 404),不要把這條當成當前可用的安裝方式。安裝仍以目錄頁的 GitHub 命令爲準。README 帶 --profile web,是因爲網頁音頻卡片要裝進 web 客戶端;目錄頁命令本身不帶 profile。裝完如果對話裏看不到音頻卡片,需要確認當前用的是帶 Web UI 的 profile,而不是隻裝了 host 工具。

目錄頁的安全提示仍然適用:插件以當前 dsh 進程的權限運行,安裝時可能執行代碼。裝之前請自己看源碼和許可證。package.jsonprepare / prepublishOnly 會執行 pnpm build。裝完可用插件列表確認是否出現 dsh-voice;有的環境需要重啓 Harness 後才生效。在模型調用工具之前,錄音和播放都不會自己開始。

配置

所有字段都可選,寫在 profile patch 或 cordis.patch.yml 裏。README 給出的完整形狀如下:

plugins:
  dsh-voice:
    stt:
      backend: whisper-local | openai | macos | fake
      model: whisper-1
      whisperLocal: { bin: whisper-cli, model: tiny }
      openai: { baseUrl: https://api.openai.com/v1, apiKeyEnv: OPENAI_API_KEY }
    tts:
      backend: say | piper | edge-tts | fake
      voice: Samantha
      rate: 180
      piper: { bin: piper, model: /path/to/model.onnx }
      edgeTts: { voice: en-US-GuyNeural }
    readReplies: false
    audioDir: ~/.dsh/voice

缺省行爲:STT 自動選離線後端(whisper-local → macos),TTS 默認 say(自動回退時是 say → piper),readReplies 爲 false,音頻目錄是 ~/.dsh/voiceopenai 的密鑰走標準憑據通道 OPENAI_API_KEY,並回退到啓動環境變量。倉庫自帶的 cordis.patch.yml 只插入空的 stt / ttsreadReplies: false 和默認 audioDir,具體後端留給使用者自己覆蓋。

典型用法

倉庫沒有編造對話腳本,可復現的入口就是工具參數和 /voice 命令。

轉寫已有文件時,source 只帶 file;從麥克風錄幾秒則只帶 record

{ "source": { "file": "/path/to/note.m4a" } }
{ "source": { "record": { "seconds": 5 } } }

讓智能體朗讀一段文本:

{ "text": "build finished, 0 failures" }

voicerate 可選,不傳就用配置裏的默認音色和語速。

會話裏要自動讀回覆,直接輸入:

/voice on

看當前後端和目錄:

/voice status

推薦順序是:先確認本機有可用的離線後端(whisper.cpp 或 macOS 語音識別,以及 say 或 Piper),再用 /voice status 覈對,最後才讓模型調 transcribe / speak。不要一上來就把 stt.backend 設成 openai,除非你明確接受音頻離開本機。

適用場景與注意事項

比較適合這些情況:

  • 暫時離開鍵盤,想口述一條指令,讓轉寫結果作爲普通用戶消息進入對話。
  • 長構建、無界面任務跑完後,用 speak 留一句旁白,不必盯着終端。
  • 希望回覆被讀出來,但默認仍然是安靜的:用 /voice on 按會話打開。
  • 在意音頻落在哪:文件都在 ~/.dsh/voice/,日誌裏只有引用和轉寫。

使用前建議把下面幾條當作硬限制,而不是「以後可能會好」:

  1. 權限與供應鏈。插件以當前 dsh 進程權限運行,能調 shell、能讀寫 audioDir、在配置了雲端後端時還能把音頻送出本機。安裝前檢查 https://github.com/Jesse-njx/dsh-voice 源碼和 MIT 許可證;需要可復現環境時固定 commit。
  2. 不是即時語音對話。v0.1 明確不做流式對講、喚醒詞、常駐監聽、說話人分離、外呼電話,也不把原始音頻寫入會話日誌。
  3. 默認後端偏 macOS。TTS 默認是系統 say;STT 自動回退鏈裏有 macos。Linux 上通常要自己準備 whisper.cpp 和 Piper,否則會得到「該配什麼」的錯誤,而不會自動改走雲端。
  4. 錄音有前置條件{ record } 依賴 ffmpeg,或 macOS 上的捆綁 swift shim。沒有錄音路徑時,這條分支不可用,但仍可用 { file } 轉寫已有音頻。
  5. 雲端是顯式選擇openaiedge-tts 只有寫進配置纔會啓用。裝完插件不等於已經把語音送到了第三方。
  6. 網頁卡片依賴 web profile。host 側工具和 /voice 命令與 Web 音頻卡片不是同一半區。只在無 UI 的 profile 裏裝,看不到卡片是符合 README 描述的。
  7. 項目很新。倉庫 2026-08-13 才創建,版本 0.1.0,星標很少。README 寫測試套件有 46 個用例,覆蓋參數 schema、後端選擇、fake 端到端和卡片降級,但不要把它當成生產級語音套件。

小結

dsh-voice 給 DeepSeek Harness 補上了一層很薄的語音進出:transcribe 把口述變成用戶消息,speak 在後臺朗讀且不阻塞回合,/voice 按會話決定要不要自動讀回覆。音頻是磁盤上的普通文件,日誌只留引用;雲端後端不會被自動選中。它不是即時對講機器人,也不是微信語音方案;邊界寫在 README 的非目標列表裏,用的時候按「工具調用纔出聲、本地文件可刪除」來預期,會比較穩。

  • 目錄頁:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-voice/
  • GitHub:https://github.com/Jesse-njx/dsh-voice
  • DeepSeek Harness:https://github.com/deepseek-ai/deepseek-harness
羽毛球分组比赛记分
小程序二维码

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

小夜