DeepSHPlugins
dsh-voice 專案預覽
GITHUB / COMMUNITY PROJECT

dsh-voice

工具與整合TypeScriptMIT

Web UI 全雙工語音對話:輸入框麥克風(RMS 端點檢測)配合瀏覽器本地 whisper 轉寫,回覆按句流式朗讀,開口說話即打斷播放與正在執行的回合(真 barge-in),無需 API key。

4 Starshaoku123 更新時間 2026-08-23
訪問 GitHub 倉庫
dsh-voice 專案預覽

專案介紹

中文

Web UI 全雙工語音對話:輸入框麥克風(RMS 端點檢測)配合瀏覽器本地 whisper 轉寫,回覆按句流式朗讀,開口說話即打斷播放與正在執行的回合(真 barge-in),無需 API key。

English

Full-duplex voice mode for the Web UI: a composer mic (RMS endpoint detection) transcribes speech with whisper running locally in the browser, assistant replies stream back as spoken audio sentence-by-sentence, and speaking interrupts playback and the running turn (true barge-in). No API key.

專案資訊與收錄訊號

快照 2026-09-11
作者 / 組織
haoku123
倉庫
haoku123/dsh-voice
GitHub Stars
4
Forks
5
開發語言
TypeScript
許可證
MIT
最近推送
2026-08-23
Manifest
資料中檢測到宣告

公開倉庫不自動等於可商用;許可證與當前相容性以原專案文件為準。Manifest 和資料評分不構成安裝安全認證。

資料評分

66/ 100
維護活躍
88
文件與實用資訊
85
生態關注度
40
安裝便捷訊號
75
專案宣告訊號
100

近 19 天仍在更新;README 含完整安裝與使用說明。

評分來自已有資料快照的五維模型,僅作瀏覽參考,不是實際使用評測或安全檢測結論。

安裝與使用

所有專案資料與許可均以對應 GitHub 倉庫為準。

dsh plugin --profile web add github:haoku123/dsh-voice

複製命令不會自動執行。請先閱讀倉庫文件,確認環境要求與許可證。

專案截圖

倉庫 README

GitHub 原文

已儲存的倉庫文件快照;文件抓取時間未記錄,可能與上方目錄介紹處於不同版本。安裝前請核對當前倉庫說明。

儲存庫檔案保留原文,指令與授權文字不作自動改寫。

dsh-voice

Full-duplex voice mode for DeepSeek Harness: streamed ASR → LLM → TTS with barge-in.

Status

v0.7.0 — press-to-talk with a live caption.

Speak into the composer mic: the assistant silences itself (playback stops, host synthesis queue drops), the running turn is cancelled (the stop-button route), and your speech is transcribed by the host (SenseVoice, CN-native simplified-Chinese ASR with punctuation + ITN) and submitted. The reply streams back as spoken audio with live captions.

Three ways to dictate:

gesturebehaviour
tap the miccontinuous dictation; the VAD segments on trailing silence
hold the send key (or the mic)records until release, slide up to discard
hold Ctrl (configurable asr.hotkey)same, without leaving the keyboard; Esc discards

While a hold is open the overlay shows a live caption — the interim transcript of what has been said so far — and keeps a spinner up after release until the authoritative transcript lands.

Barge-in detection is triggered by the mic's leading speech edge. The ASR engine runs an NLMS acoustic echo canceller (see src/aec.ts) using the page's own TTS playback as the echo reference, so loud assistant audio is subtracted from the mic before the VAD — the browser-level echoCancellation constraint is kept only as a fallback when no echo reference is available.

Live caption interims are incremental: each pass sends only the audio recorded since the last pass (correlated by session header), and the host decodes a bounded sliding window per session instead of re-decoding the whole hold. Preview cost therefore stops growing with hold length.

Demo

dsh-voice demo

The loop: hold the composer's send key (its arrow is covered by a mic glyph), watch the live caption fill in while you speak, release into a spinner until the final transcript lands, then the reply streams back as spoken audio sentence-by-sentence — until the user's voice interrupts playback and stops the running turn mid-line (true barge-in). Ctrl does the same without leaving the keyboard.

How it works

input:  mic ──RMS endpoint detection──▶ POST /asr (raw f32 PCM)
                                           │ text (SenseVoice)
                                           ▼
        composer draft ──submit──▶ model stream ──llm/stream tap──▶ SentenceSegmenter
                                                                     │
        browser ◀── SSE /dsh-voice-api/stream ── TtsQueue (msedge-tts) ◀──┘
                  (base64 MP3 frames + caption text)

barge-in: speech edge ──▶ engine.skip() + POST /cancel (epoch bump)
                         + session.cancel() when a turn is running
  • The llm/stream tap is lossless: every chunk is yielded unchanged, the

segmenter only observes. The model stream is never blocked by synthesis.

(Apache-2.0) running SenseVoice — the CN-native speech model that outperforms whisper on Chinese: native simplified output, punctuation, inverse text normalization (ITN) and 50+ language auto-detection. The browser only records and posts raw little-endian f32 PCM.

  • Model files stream through a cache-through proxy at

/dsh-voice-api/hf and are mirrored to disk (~/.cache/dsh-voice/models/, configurable via cacheDir), so every browser/recognizer load after the first is served from local disk. Downloads resume from partial .part files when interrupted. Use npm run prefetch to warm the cache once.

  • RMS endpoint detection: 16kHz getUserMedia, 2s trailing-silence cutoff,

max 30s segment, pre/post padding. Zero dependencies.

  • Press-to-talk bypasses the VAD entirely. Holding the key is already the

intent, so every buffer between press and release is kept — gating on loudness there only drops quiet speech, which is indistinguishable from a broken button. Only captures below 250ms are discarded (mis-taps).

  • Live caption: while a hold is open the engine re-decodes the buffer

every ~900ms and shows the interim text. SenseVoice is not a streaming model, so this is only requested while the overlay is actually on screen, and stops past 12s of audio. Interims are strictly previews: they never reach the composer draft, and an interim that lands after the release is dropped (epoch check) so it can never overwrite the final transcript.

  • Barge-in is three-layered: local playback queue cleared, host TtsQueue

epoch bumped (queued AND in-flight synthesis dropped), and the running turn cancelled when session.running is true. An aborted turn never flushes its trailing half-sentence — exactly what the user interrupted.

  • modelHost accepts any HF-compatible mirror (e.g. https://hf-mirror.com

for CN networks).

API

RoutePurpose
GET /dsh-voice-api/streamSSE; event: audio frames {sessionId, seq, text, audio(base64 MP3)}
POST /dsh-voice-api/asrraw little-endian f32 PCM body → {text} via SenseVoice
POST /dsh-voice-api/cancel{sessionId} drops queued + in-flight synthesis (epoch bump)
GET /dsh-voice-api/configASR runtime config {asr: {...}} for the mic button
GET /dsh-voice-api/hf/*cache-through HF model proxy (mirrors to cacheDir)
GET /dsh-voice-api/*ping: {ok, name, enabled}

Config (bundle patch row):

- id: voice
  name: '@haoku123/dsh-voice'
  config:
    voice: zh-CN-XiaoxiaoNeural
    cacheDir: ~/.cache/dsh-voice/models   # optional, on-disk model cache
    asr:
      model: csukuangfj/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17
      modelHost: https://huggingface.co   # or https://hf-mirror.com
      language: auto                      # auto | zh | en | ja | ko | yue
      useItn: true                        # inverse text normalization
      autoSend: false
      mode: toggle                        # toggle | hold
      hotkey: Control                     # keyboard press-to-talk; '' disables

Model files are fetched through the proxy on first use; warm the cache once with the dsh host running:

npm run prefetch          # uses http://127.0.0.1:3080 by default

Install

dsh plugin --profile web add <repo-url-or-path>
dsh --profile web

Note: needs Node ≥ 22.19 or ≥ 24 (node:zlib zstd APIs).

Tests

npm test                                # segmenter unit tests (pure, no network)
node test/host.integration.test.mjs     # llm/stream tap + real Edge TTS + SSE + /config
node test/bargein.test.mjs              # client inject face wiring (skipPlayback/cancelTurn)
node test/bargein-semantics.test.mjs    # aborted turn no-flush + cancel drops in-flight
node verify-client.mjs                  # client bundle registration/exports/slots/dynamic-import

使用前核對

安裝步驟、相容版本與授權範圍以原專案當前文件為準。Stars 和評分是快照中的導航訊號。

安裝與排錯 · 專案問題反饋

同類專案