Back to marketplace

dsh-voice

Multimodal

zhuiyueya/dsh-voice

Voice plugin for DeepSeek Harness adding speech-to-text input and read-aloud TTS for text-only DeepSeek, with zero API key for web UI.

  • ai-agents
  • deepseek
  • deepseek-harness
  • deepseek-harness-plugin
  • dsh-plugin
  • multimodal
  • speech-to-text
  • stt
  • text-to-speech
  • tts
  • voice
  • web-speech-api
  • whisper
GitHub Stars
3GitHub
Views
0DSH Plugin Hub
Forks
3GitHub
Open issues
1GitHub Issues
Manifest version
0.1.1dsh-voice
Latest push
Aug 15, 2026GitHub
License
MITJavaScript
Plugin type
Host + ClientRuns in both Host and Web Client

README

View source

DeepSeek's chat API is text-only β€” it can neither hear audio nor speak. dsh-voice bridges sound at the input/output boundary so the model never sees raw audio, yet gains a full voice loop:

🎀 speech β†’ text β†’ DeepSeek (text-only) β†’ text β†’ πŸ”Š speech

Same idea as dsh-vision-bridge β€” but for audio, the multimodal gap nobody has filled for DeepSeek Harness yet.

✨ Features

LayerWhat it does
🎀Voice input (STT) β€” Web UIA mic button in the composer tool row. Click to speak; the transcript is written straight into the input box via the browser Web Speech API.
πŸ”ŠRead-aloud (TTS) β€” Web UIA speaker button on every assistant reply. Click to read it aloud via speechSynthesis.
πŸ“„voice_transcribe toolTranscribe an attached audio file (wav/mp3/m4a/ogg/webm/flac) through any Whisper-compatible /audio/transcriptions endpoint.
πŸ—£οΈvoice_speak toolSynthesize text into an audio file through any OpenAI-compatible /audio/speech endpoint.
  • βœ… Zero API key for the Web UI β€” pure browser speech, works out of the box.
  • βœ… Zero new model β€” DeepSeek stays text-only; speech is handled at the edge.
  • βœ… Configurable backends β€” point at local whisper.cpp / Kokoro for a fully free, keyless stack.

🧭 How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         dsh Web GUI                           β”‚
β”‚                                                              β”‚
β”‚   you speak  β”€β”€πŸŽ€ SpeechRecognition──►  text  ──► input box   β”‚
β”‚                                                              β”‚
β”‚   reply text β”€β”€πŸ”Š speechSynthesis──►  you hear                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                                  β–²
         β”‚ text (STT)                       β”‚ text (TTS)
         β–Ό                                  β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              DeepSeek (text-only model)                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

attached audio ── voice_transcribe (Whisper-compatible) ──► text ──► model
model wants to speak ── voice_speak (OpenAI-compatible TTS) ──► audio file

πŸ“¦ Install

# from a local checkout
dsh plugin --profile web add "file:/path/to/dsh-voice"

# or, once published to npm
dsh plugin --profile web add dsh-voice

Activation is automatic: the package ships a bundle patch (cordis.patch.yml) and declares dsh.bundle.patch, so dsh plugin add registers it into the profile's bundles for you.

Then restart dsh web (or wait for HMR). You should see 🎀 in the composer and πŸ”Š on each reply.

βš™οΈ Configuration

The 🎀 mic button needs voice.stt.apiBase (the browser records audio and sends it to the host's Whisper-compatible backend). The πŸ”Š read-aloud needs nothing (browser speechSynthesis). To customize read-aloud language/rate/pitch, edit the constants at the top of lib/client.js (TTS_LANG, TTS_RATE, TTS_PITCH).

settings.yaml:

voice:
  stt:                        # mic button + voice_transcribe tool
    enabled: true
    apiBase: ""               # REQUIRED for the mic. Examples:
                              #   SiliconFlow: https://api.siliconflow.cn/v1
                              #   local whisper.cpp: http://127.0.0.1:8080/v1
    apiKeyEnv: VOICE_STT_API_KEY
    model: whisper-1
    language: ""              # zh / en / ... ; empty = auto-detect
  tts:                        # voice_speak tool
    enabled: true
    apiBase: ""               # empty = https://api.openai.com/v1
    apiKeyEnv: VOICE_TTS_API_KEY
    model: tts-1
    voice: alloy              # alloy/echo/fable/onyx/nova/shimmer, or a local voice id
    format: mp3

Why the mic needs a backend: Chrome's built-in SpeechRecognition uploads audio to Google, which is unreachable in some regions (you'd see θ―†εˆ«ε‡Ίι”™οΌšnetwork). dsh-voice records with MediaRecorder and transcribes through your Whisper-compatible backend instead. Two free, keyless options:

  • SiliconFlow (China-friendly, free tier) β€” apiBase: https://api.siliconflow.cn/v1, model FunAudioLLM/SenseVoiceSmall or whisper-1.
  • Local whisper.cpp β€” fully offline, apiBase: http://127.0.0.1:8080/v1 (no key).

🧰 Agent tools

ToolParametersReturns
voice_transcribepath (audio file), language?{ text, language }
voice_speaktext, outPath?, voice?{ path, bytes }

πŸ—‚ Project layout

dsh-voice/
β”œβ”€β”€ package.json          # dual-half plugin: host (main) + browser (client)
β”œβ”€β”€ cordis.patch.yml      # bundle activation layer
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ index.js          # host half: settings + voice_transcribe/voice_speak tools
β”‚   β”œβ”€β”€ client.js         # browser half: 🎀 / πŸ”Š buttons
β”‚   └── types/
β”‚       β”œβ”€β”€ index.d.ts
β”‚       └── client/index.d.ts
β”œβ”€β”€ README.md             # this file
└── README.zh-CN.md       # δΈ­ζ–‡η‰ˆ

πŸ—Ί Roadmap

  • Wire browser-UI language / rate / pitch / auto-read into the voice: settings page (currently code constants)
  • autoRead: auto read-aloud on reply completion
  • Built-in free edge-tts backend (no OpenAI key)
  • Local Whisper STT via @xenova/transformers
  • Sentence-level reading with streaming interruption

πŸ™ Credits

Inspired by these established voice solutions for other agents:

πŸ“„ License

MIT

Comments

0
Newest first