dsh-record:給 DSH 輸入框加一個錄音按鈕,錄完直接掛到 prompt 上

前言

給 DSH / 智能體客戶端做語音輸入時,常見做法是外掛一個錄音工具,錄完導出文件再手動傳上去,中途要切窗口、找路徑、等接口。dsh-record 把這條鏈路收進輸入框:在 composer 里加一個麥克風按鈕,點擊開始錄、再點一次停止,錄音會作爲對話附件直接掛在當前 prompt 上,跟着正常上傳隊列一起發出去。輸出格式在插件設置頁選,支持 MP3(默認)、WAV、WebM。

下面介紹這個插件。它由 most-silence 維護,開源協議 MIT,倉庫 https://github.com/most-silence/dsh-record ,社區目錄頁是 https://www.skillhub.cn/plugins/most-silence/dsh-record 。

能做什麼

一句話定位:一個客戶端插件,給 DSH 的 composer 加錄音按鈕,錄完把音頻文件作爲 conversation 附件附到當前 prompt 上。它只負責錄製、轉碼、掛載這三步,不寫磁盤文件、不做語音識別——需要轉文字的話要另配一個 speech-to-text 插件(README 建議 dsh-stt)。

已經覈實的能力:

  • 按鈕註冊在 conversation.input.right 槽位、提交動作之前,沒有懸浮窗,可以和其他 composer 控件共存。
  • 輸出格式 mp3 / wav / webm,默認 mp3,在 Settings → Plugins → dsh-record 裏選。
  • 懸停提示跟隨界面語言:中文顯示「錄音」,英文顯示「Record」。按鈕向宿主 locale 服務註冊了 zh / en 字典,切換語言後提示、aria-label、狀態通知會跟着更新。
  • 錄音走瀏覽器 MediaRecorder,優先 webm/opus,按能力回退;錄音中有計時器和文件名預覽(rec-YYYYMMDD-HHMMSS-<n>s.mp3)。
  • 三個格式都在瀏覽器內完成:MP3 由 lamejs 編碼(128 kbps CBR),WAV 是 16-bit PCM 無損重封裝,WebM 就是瀏覽器原生 Opus 容器不轉碼。
  • 掛載走宿主 draft-attachment 通道(conversation.createDrafts + inputActions.addAttachments),輸入框裏顯示爲文件卡片並帶上傳進度。
  • 轉碼失敗時(比如 OfflineAudioContext 不可用)直接掛原始 WebM,保證錄音不丟。

安裝與啓用

README 給的安裝命令是本地構建後按文件路徑添加,不是從 registry 拉包:

git clone https://github.com/most-silence/dsh-record
cd dsh-record && npm install && npm run build
dsh plugin --profile <your-profile> add file:$PWD

安裝完重啓 dsh 宿主,再刷新網頁。可以用 npm run build 重新構建(tsdown 產出 lib/index.js 和 lib/client.js),npm test 跑 14 個 node:test 用例(客戶端工廠契約 9 個、編碼器 5 個),測試在 Node 24 上跑,不需要瀏覽器。

配置

配置只有一個字段,在 Settings → Plugins → dsh-record 裏改:

字段 取值 含義
format mp3(默認)· wav · webm 輸出容器。MP3 / WAV 在停止錄音後於瀏覽器內轉碼,WebM 原樣掛載。改動在下次頁面加載時生效,因爲瀏覽器那半邊只在啓動時讀一次配置。

瀏覽器端啓動時通過 GET /dsh-record/config 讀取這個配置,路由不可達就回退到 mp3。

架構與兩個坑

插件是典型的前端 + 宿主兩段式:

browser half (lib/client.js)               host half (lib/index.js)
├─ mic button @ conversation.input.right   ├─ Config schema { format: mp3 | wav | webm }
├─ zh/en dictionaries → locale service     └─ GET /dsh-record/config → serves resolved config
├─ MediaRecorder → webm/opus                  (same-origin guarded)
├─ decode → lamejs (mp3) / PCM wrap (wav)
└─ attach via createDrafts + addAttachments

README 裏特別記了兩條從真實崩潰裏學到的加固規則,做同類插件值得抄:

  1. @breezystack/lamejs 要內聯打包。DSH 的模塊表是凍結的,裏面沒有 lamejs,如果把它當構建外置依賴,require("@breezystack/lamejs") 會查不到模塊表並導致整個 web 啓動中斷。構建工具 tsdown 用 noExternal 強制內聯。
  2. 宿主端的 Config 用 z.union([...]),不能用 z.enum([...]),並且 schemastery 保持 external。宿主自帶的 schemastery 版本沒有 enum 方法,用打包進來的私有副本構造的 schema 又和宿主校驗器不兼容,任一種都會在 import 階段拋錯,把這行插件判成 required 從而拖垮整個 profile。

注意點

  • 這個插件以當前 dsh 進程的權限運行,安裝第三方插件前建議先讀一遍源碼,也注意它的開源協議(本項目是 MIT)。
  • 附件通道依賴宿主客戶端契約,README 驗證版本是 dsh 0.2.1-rc.2(conversation.input.right 槽位、createDrafts / addAttachments)。上游接口變動後可能退化爲行內錯誤提示。
  • 轉碼發生在停止錄音之後,不是邊錄邊轉,所以很長的錄音會有一小段編碼等待。
  • 錄音需要瀏覽器麥克風授權,頁面必須走 HTTPS 或 localhost。
  • 輸出格式放在宿主 profile 配置裏而不是瀏覽器裏,所以每次改完要刷新頁面才生效。

小結

dsh-record 解決的是一個很具體的鏈路問題:輸入框裏錄音 → 瀏覽器內轉碼 → 作爲 prompt 附件上傳,不碰磁盤、不做識別。如果你已經在用 DSH 做客戶端語音輸入,可以先在測試 profile 裏裝上試一輪,確認附件通道和格式符合預期,再考慮接到正式流程裏。

  • 目錄頁:https://www.skillhub.cn/plugins/most-silence/dsh-record
  • 代碼倉庫:https://github.com/most-silence/dsh-record
羽毛球分组比赛记分
小程序二维码

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

小夜