dsh-voice-space 🎤
Hold Space to talk in DeepSeek Harness. Long-press the Space bar in the chat input to record; the transcript streams in sentence by sentence while you hold, and on release it's automatically polished (homophones fixed, filler words removed, punctuation tidied) before landing at the caret. Fully local transcription — audio never leaves your machine, no STT API key required.
English · 中文
Features
- Hold-to-talk: hold
Space (≥ 450 ms) in the composer to start recording; release to stop. A quick tap still types a normal space.
- Live streaming: sentences appear in the floating panel as you speak (silence-based segmentation, ~0.6 s after each pause).
- Auto polish on release: the full transcript is sent through DeepSeek once and cleaned up — ASR homophone errors corrected, filler words (
嗯/呃/那个/就是/然后) dropped, punctuation fixed — without changing the meaning. Falls back to the raw transcript if the API/key/network is unavailable.
- IME-safe: the Space used to confirm Chinese IME candidates is never intercepted.
- Local STT: SenseVoice (sherpa-onnx, CPU) runs inside the plugin's own host half. No
dsh-voice-local required.
- Esc to cancel; focus loss cancels cleanly.
功能
- 按住说话:输入框内长按空格(≥450ms)开始录音,松手结束;轻点空格仍是普通空格。
- 实时出字:说话时按静音断句,每个短句约 0.6 秒后实时显示在悬浮面板里。
- 松手自动校准:松开后全文交给 DeepSeek 校对一次——修同音字错别字、删填充词、补标点,不改变原意;接口/Key/网络不可用时自动退回原始转写。
- 中文输入法安全:选词用的空格不被拦截。
- 本地转写:SenseVoice(sherpa-onnx,CPU)在插件自己的宿主端运行,无需安装 dsh-voice-local。
- Esc 取消;窗口失焦自动取消。
Install
Requires DeepSeek Harness with the desktop / web profile (platform: web client). Tested on the Windows desktop app (dsh 0.2.1-rc.5).
# from the GitHub repository
dsh plugin --profile desktop add "github:he-miaoqing/dsh-voice-space"
# or from npm (once published)
dsh plugin --profile desktop add dsh-voice-space
# or from a local clone / path
dsh plugin --profile desktop add "link:<absolute path to this repo>"
Then fully quit and reopen DeepSeek Harness (a page refresh is not enough in the packaged app).
Model
The SenseVoice model (model.int8.onnx + tokens.txt, ~230 MB) is downloaded automatically on first use into ~/.dsh/voice/sensevoice/ (or $DSH_HOME/voice/sensevoice/), fetched from Hugging Face mirrors. You can also pre-place those two files there to skip the download.
DeepSeek API key (for polish)
The release-time polish uses your configured DEEPSEEK_API_KEY, resolved from the DSH credentials seam at request time — it never touches the browser or the plugin cache. Without a key, the raw transcript is inserted as-is.
Usage
- Click into the main composer.
- Hold
Space for ~0.5 s → the panel shows 正在聆听…(松开空格结束,Esc 取消).
- Speak; the transcript streams into the panel.
- Release → brief
正在校准优化… → polished text is inserted at the caret.
How it works
hold Space (client keydown)
└─ AudioWorklet records 16 kHz mono PCM (silence segmenter)
└─ POST /dsh-voice-space/v1/transcribe (per sentence)
└─ pure-JS WAV decode → sherpa-onnx SenseVoice → text
release
└─ flush tail → join sentences
└─ POST /dsh-voice-space/v1/polish (DeepSeek) → cleaned text
└─ insert into composer via inputActions.setDraft
The draft is written through the host's React-controlled channel (inputActions.setDraft via the conversation.input.left slot), so undo/history and the send gesture keep working.
Host routes (/dsh-voice-space/v1)
| Method | Path | Purpose |
|---|
| GET | /health | native module + model status |
| GET | /model/status | model files + download state |
| POST | /model/download | start background model download |
| POST | /transcribe | WAV body → { ok, text } |
| POST | /polish | { text } → { ok, text } |
| GET/POST | /diag | client lifecycle beacons (debugging) |
WAV decoding is done in pure JS on purpose: in Electron the request body arrives as an "external" ArrayBuffer and sherpa-onnx's native readWaveFromBinary (zero-copy) throws External buffers are not allowed.
Disable / debug
- Disable: in the console run
window.__dshVoiceSpace.disable() (writes dsh-voice-space:enabled=0 to localStorage); enable() to restore.
- State:
window.__dshVoiceSpace.recording, .inputReady.
Privacy
- Audio is transcribed locally and is never written to disk or sent to any STT service.
- The polish step sends only the (already local) transcript text to
api.deepseek.com.
- The API key is resolved server-side from the DSH credentials seam and never enters the browser.
License
MIT