@goodandready/dsh-voice 0.8.9 → 0.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 dsh-voice contributors
3
+ Copyright (c) 2026 GooDAnDReaDY
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,216 +1,172 @@
1
- # dsh-voice
2
-
3
- Voice input for the DeepSeek Harness Web GUI, in two modes, each with its own
4
- provider fallback chain.
5
-
6
- **Dictation** — press the mic, talk, and the text lands in the composer as you
7
- go: speech is cut into phrases on silence and each phrase is transcribed on its
8
- own. Press again to stop; sending stays in your hands.
9
-
10
- **Voice message** — press the wave button, record, press again. The transcript
11
- is inserted and sent to the agent after a short cancel window.
12
-
13
- Both modes fall back across providers, so one outage or rate limit does not
14
- lose your recording. API keys never reach the browser: audio is posted to the
15
- plugin's own route and the host talks to the providers.
16
-
17
- ## Install
18
-
19
- ```bash
20
- # From npm:
21
- dsh plugin --profile web add @goodandready/dsh-voice
22
-
23
- # Locally from a checkout:
24
- dsh plugin --profile web add file:/path/to/dsh-voice
1
+ # 📦 @goodandready/dsh-voice
2
+
3
+ <div align="center">
4
+
5
+ <h3>Zero-Latency Streaming Dictation & Multi-Provider Voice Input for DeepSeek Harness</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-voice"><img src="https://img.shields.io/npm/v/@goodandready/dsh-voice.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-10b981.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
+ <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://goodandready.app/"><img src="https://img.shields.io/badge/All_Author_Projects-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="All Author Projects"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="README.md"><b>🇬🇧 English</b></a> •
20
+ <a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
21
+ <a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
22
+ </p>
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## ⚡ Overview
29
+
30
+ **`dsh-voice`** brings voice superpowers to the **DeepSeek Harness** Web UI. Whether you need hands-free real-time streaming dictation segmented on natural breath pauses or crisp voice notes with keyboard/mouse Push-to-Talk gestures, `dsh-voice` ensures your audio is never lost thanks to **automatic multi-provider fallback chains**.
31
+
32
+ ```mermaid
33
+ graph LR
34
+ subgraph Client [Browser Web UI]
35
+ Mic[🎙️ Dictation Mic] -->|VAD Cut on Pause| Stream[Audio Chunks]
36
+ Wave[🌊 Voice Message] -->|Hold / Release| PTT[Push-to-Talk]
37
+ end
38
+
39
+ subgraph Host [DSH Host Backend]
40
+ Stream --> FFMPEG[ffmpeg 16kHz Transcoder]
41
+ PTT --> FFMPEG
42
+ FFMPEG --> Chain{Fallback Chain}
43
+
44
+ Chain -->|1st Priority| P1[Deepgram / Nova-2]
45
+ Chain -.->|On Rate Limit / 429| P2[Groq / Whisper Turbo]
46
+ Chain -.->|On Failure| P3[Local whisper.cpp / Offline]
47
+ end
48
+
49
+ subgraph Output [Target]
50
+ P1 --> Composer[💬 Web Composer / Chat]
51
+ P2 --> Composer
52
+ P3 --> Composer
53
+ end
54
+
55
+ style Client fill:#1e1e2e,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4
56
+ style Host fill:#181825,stroke:#cba6f7,stroke-width:2px,color:#cdd6f4
57
+ style Output fill:#11111b,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4
25
58
  ```
26
59
 
27
- Restart the Web UI afterwards, then hard-refresh the browser.
60
+ ---
28
61
 
29
- ## Providers
62
+ ## ✨ Key Features
30
63
 
31
- | Key | Service | Default model | Credential |
32
- |---|---|---|---|
33
- | `browser` | the browser's own speech recognition | — | none, and nothing is uploaded to the host |
34
- | `deepgram` | Deepgram | `nova-2` | `DEEPGRAM_API_KEY` |
35
- | `groq` | Groq | `whisper-large-v3-turbo` | `GROQ_API_KEY` |
36
- | `hf` | HuggingFace Inference | `openai/whisper-large-v3` | `HF_TOKEN` |
37
- | `local-whisper` | local whisper.cpp server | model given at server start | none, fully offline |
64
+ * 🎙️ **Streaming Dictation with VAD**: Speech is automatically sliced at natural pauses (`vadSilenceMs`, default 700ms) and typed into the composer in real time.
65
+ * 🌊 **Voice Notes with Cancel Window**: Record your thought and have it automatically dispatched to the agent after a safety countdown (`autoSendMs`, default 4000ms).
66
+ * 🎮 **Tactile Push-to-Talk**:
67
+ * **Mouse**: Hold the wave button releasing sends the message; dragging pointer away discards.
68
+ * **Keyboard**: Hold <kbd>Ctrl</kbd> (or custom hotkey) for hands-free speaking; press <kbd>Esc</kbd> to cancel.
69
+ * ⚡ **Zero-Latency In-Browser Captions (`browser`)**: Chrome Web Speech API recognition runs 100% locally with live floating captions as you speak.
70
+ * 🛡️ **Ironclad Multi-Provider Fallbacks**: If your primary cloud provider runs out of credits or hits a 429 rate limit, requests seamlessly fail over down the chain.
71
+ * 🧠 **Context Glossary Injection**: Automatically extracts code variables and identifiers from your composer draft to steer STT model accuracy on technical jargon.
72
+ * 🎵 **Embedded Audio Player**: Preview, scrubber, and playback of your recorded voice message directly in chat and the composer dock.
73
+ * 🔇 **Hardware Noise Suppression Toggle**: Configurable in settings to toggle browser-level noise suppression, echo cancellation, and auto gain control.
74
+ * 📊 **Provider Latency & Health Dashboard**: Live visual telemetry of provider latency (ms), success rates, and errors directly within the settings UI.
75
+ * 🔒 **Zero API Key Leakage**: Keys are resolved on the host via `ctx.credentials` (`credentialRef`) and never transmitted to browser clients.
76
+ * 🖥️ **Offline Local Whisper Server**: Automatically boots and manages [whisper.cpp](https://github.com/ggerganov/whisper.cpp) (`whisper-server`) with on-the-fly `ffmpeg` transcode.
77
+ * ⚡ **SenseVoice-ONNX / Sherpa-ONNX** *(0.8.11)*: Ultra-fast (~50–100ms) non-autoregressive local STT engine with automatic emotion/event tag stripping. Supports both Sherpa-ONNX HTTP and OpenAI-compatible endpoints.
78
+ * 🌐 **Realtime Audio Streaming** *(0.8.11)*: Low-latency WebSocket bridge (`/dsh-voice/realtime`) for OpenAI Realtime API or local Sherpa-ONNX streaming. API keys stay securely on the host.
38
79
 
39
- Keys are read through the DSH credentials service (Settings → Credentials, or
40
- `$DSH_HOME/.credentials.yaml`), falling back to the process environment. A
41
- provider without a key is skipped, not fatal.
80
+ ---
42
81
 
43
- ### Ready-made providers
82
+ ## 🎮 Four Ways to Speak
44
83
 
45
- Six providers are filled in already put the name in a chain and add the key:
46
-
47
- | Name | Model | Credential |
84
+ | Mode | Gesture / Trigger | Behavior |
48
85
  |---|---|---|
49
- | `openai` | `whisper-1` | `OPENAI_API_KEY` |
50
- | `siliconflow` | `FunAudioLLM/SenseVoiceSmall` | `SILICONFLOW_API_KEY` |
51
- | `deepinfra` | `openai/whisper-large-v3-turbo` | `DEEPINFRA_API_KEY` |
52
- | `fireworks` | `whisper-v3-turbo` | `FIREWORKS_API_KEY` |
53
- | `mistral` | `voxtral-mini-latest` | `MISTRAL_API_KEY` |
54
- | `openrouter` | `google/gemini-2.5-flash` | `OPENROUTER_API_KEY` |
55
-
56
- ```yaml
57
- - id: dsh-voice
58
- config:
59
- message:
60
- chain:
61
- - provider: openai
62
- - provider: local-whisper
63
- ```
64
-
65
- Every endpoint was probed without a key before being written down: all six answered `401`, the answer of a path that exists and wants credentials. The model ids are starting points — override `model` in a chain row to change one.
86
+ | **Dictation** | Click <kbd>🎙️ Mic</kbd> | Speech is sliced on pauses (`vadSilenceMs`) and typed live into composer |
87
+ | **Voice Message** | Click <kbd>🌊 Wave</kbd> | Records until stopped, then sends after cancel window (`autoSendMs`) |
88
+ | **Mouse PTT** | Hold <kbd>🌊 Wave</kbd> | Records while held; release sends message, drag off button to discard |
89
+ | **Keyboard PTT** | Hold <kbd>Ctrl</kbd> | Hands-free recording; release sends message, press <kbd>Esc</kbd> to discard |
66
90
 
67
- A preset is the same form as a custom provider with the fields filled in, so a `customProviders` entry under the same name replaces it outright.
91
+ > [!TIP]
92
+ > You can customize the keyboard modifier in settings (`hotkey`: `Control`, `Alt`, `Shift`, or any `KeyboardEvent.code`).
68
93
 
69
- ### Your own providers
94
+ ---
70
95
 
71
- Any OpenAI-compatible API can be added as a provider and used in the chains
72
- next to the built-in ones. Two templates, because those APIs disagree on how
73
- audio is sent:
96
+ ## 🛠️ Supported Providers Matrix
74
97
 
75
- | Template | Endpoint | Request | Transcript read from |
76
- |---|---|---|---|
77
- | `openai-transcriptions` | `{baseURL}/audio/transcriptions` | multipart: file, model, language | `text` |
78
- | `openai-chat-audio` | `{baseURL}/chat/completions` | JSON with `input_audio`: base64 and format | `choices[0].message.content` |
98
+ | Provider Key | Service Backend | Default Model | Credential Ref | Features & Notes |
99
+ |---|---|---|---|---|
100
+ | `browser` | Web Speech API | Native Browser | *None* | Zero latency, floating live captions in Chrome |
101
+ | `deepgram` | Deepgram API | `nova-2` | `DEEPGRAM_API_KEY` | Ultra-fast cloud transcription |
102
+ | `groq` | Groq Whisper | `whisper-large-v3-turbo` | `GROQ_API_KEY` | Near-instant inference speed |
103
+ | `hf` | HuggingFace Inference | `openai/whisper-large-v3` | `HF_TOKEN` | High-accuracy open Whisper |
104
+ | `local-whisper` | Local whisper.cpp | Server defined | *None* | 100% private, offline, no internet needed |
105
+ | `sensevoice` | SenseVoice-ONNX / Sherpa-ONNX | `SenseVoiceSmall` | *None* | Ultra-fast (~50ms) local non-autoregressive STT |
79
106
 
80
- OpenRouter has no `/audio/transcriptions` endpoint at all — use the chat
81
- template there:
107
+ ### 🚀 Ready-Made Presets (Plug & Play)
82
108
 
83
- ```yaml
84
- - id: dsh-voice
85
- config:
86
- customProviders:
87
- - key: openrouter
88
- template: openai-chat-audio
89
- baseURL: https://openrouter.ai/api/v1
90
- model: google/gemini-2.5-flash
91
- keyEnv: OPENROUTER_API_KEY
92
- message:
93
- chain:
94
- - provider: openrouter
95
- - provider: local-whisper
96
- ```
109
+ Just specify the name in your fallback chain and add the corresponding API key:
110
+ * `openai` (`whisper-1`) `OPENAI_API_KEY`
111
+ * `siliconflow` (`SenseVoiceSmall`) → `SILICONFLOW_API_KEY`
112
+ * `mistral` (`voxtral-mini-latest`) → `MISTRAL_API_KEY`
113
+ * `openrouter` (`google/gemini-2.5-flash`) `OPENROUTER_API_KEY`
114
+ * `deepinfra` (`whisper-large-v3-turbo`) → `DEEPINFRA_API_KEY`
115
+ * `fireworks` (`whisper-v3-turbo`) → `FIREWORKS_API_KEY`
97
116
 
98
- Fields: `key` is the name the chains refer to (it cannot shadow a built-in
99
- one), `keyEnv` names the credential holding the API key (empty means no
100
- authorization header), and `prompt` overrides the instruction sent with the
101
- audio in the chat template. A row in a chain may still override `model`.
117
+ ---
102
118
 
103
- The chat template accepts WAV and MP3 only, while the browser records
104
- webm/opus — the plugin converts with ffmpeg, the same way the local whisper
105
- provider does, so **ffmpeg is required for `openai-chat-audio`**.
119
+ ## 📦 Quick Installation
106
120
 
107
- ## Three ways to speak
121
+ ```bash
122
+ dsh plugin --profile web add @goodandready/dsh-voice
123
+ ```
108
124
 
109
- | Gesture | What happens |
110
- |---|---|
111
- | Click the microphone | dictation: speech is cut on pauses and each phrase is appended to the composer |
112
- | Click the wave | a voice message: recording runs until you stop it, then the text is sent after a cancel window |
113
- | **Hold the wave** | records only while held; release sends it, moving the pointer off the button discards |
114
- | **Hold `Ctrl`** | the same without reaching for the mouse; `Escape` discards |
125
+ > [!IMPORTANT]
126
+ > Restart DSH Web UI after installation (`systemctl --user restart dsh-web`) and refresh your browser tab.
115
127
 
116
- The hotkey is `hotkey` in the settings — a modifier name (`Control`, `Alt`, `Shift`) or a `KeyboardEvent` code. Empty turns it off.
128
+ ---
117
129
 
118
- ## Recognition in the browser
130
+ ## ⚙️ Configuration
119
131
 
120
- Put `browser` first in a chain and speech is recognised by the browser itself: no key, no upload to this host, and the text appears **while you are still speaking** — an interim caption in the recording bar, with each finished phrase going into the composer.
132
+ Open **Settings Plugins Plugin settings Voice** in the Web UI:
121
133
 
122
134
  ```yaml
123
135
  - id: dsh-voice
124
136
  config:
125
137
  dictation:
138
+ language: ru
139
+ vadSilenceMs: 700
126
140
  chain:
127
- - provider: browser
128
- - provider: local-whisper # если браузер не умеет — обычный путь
129
- ```
130
-
131
- Two things to know before choosing it:
132
-
133
- - **Chrome sends the audio to Google.** Firefox has no such API at all. Everything else in this plugin keeps audio between your browser and your own host, so this provider is the one exception — it is never used unless you put it in a chain yourself.
134
- - It needs a secure context (HTTPS or localhost), like the microphone itself.
135
-
136
- Put a normal provider after it: if the browser cannot do it, recording falls back to the chain as usual.
137
-
138
- ## Configure (Web GUI)
139
-
140
- Settings → **Plugins → Plugin settings → Voice** — the plugin's own
141
- collapsible card in the plugins tab; the sidebar keeps no separate row for it.
142
- The card has four blocks:
143
-
144
- - **Dictation** — fallback chain (provider + optional model per row, order is
145
- the order of attempts), language, and the silence threshold that ends a
146
- phrase (`vadSilenceMs`, default 700 ms).
147
- - **Voice message** — its own independent chain, language, and the cancel
148
- window before the message is sent (`autoSendMs`, default 4000 ms).
149
- - **Your own providers** — an OpenAI-compatible API per card: name, template,
150
- base URL, model, credential name. The name becomes selectable in both chains
151
- as soon as it is filled in.
152
- - **General** — local whisper endpoint, binary, model, autostart, beep, localOnly,
153
- microphone, custom vocabulary, offline polish endpoint (`polishBaseUrl`/`polishModel`/`polishKeyEnv`).
154
- - **Voice message** also has `polishSend` (polish the whole draft before sending) and
155
- `sessionCommands` ("send", "cancel", "stop", "continue" act on the session instead of text).
156
- - **Dictation** also has a wake word: browser recognition starts recording when speech
157
- begins with that phrase (empty disables it).
158
-
159
- Speed matters for dictation and accuracy for messages, which is why the chains
160
- are separate: a sensible pair is Deepgram → Groq → local for dictation and
161
- Groq → HuggingFace → local for messages.
162
-
163
- ## Local whisper.cpp
164
-
165
- The local provider needs a running [whisper.cpp](https://github.com/ggerganov/whisper.cpp)
166
- server:
167
-
168
- ```bash
169
- whisper-server -m /path/to/ggml-medium-q8_0.bin --host 127.0.0.1 --port 8001
141
+ - provider: deepgram
142
+ - provider: groq
143
+ - provider: local-whisper
144
+ message:
145
+ language: ru
146
+ autoSendMs: 4000
147
+ chain:
148
+ - provider: openai
149
+ - provider: local-whisper
150
+ hotkey: Control
151
+ autoStart: true
152
+ whisperModel: /models/ggml-medium-q8_0.bin
170
153
  ```
171
154
 
172
- Set `whisperModel` (and `whisperBin` if it is not in `PATH`) and the plugin
173
- launches the server itself when `autoStart` is on. While `whisperModel` is
174
- empty, autostart stays off.
175
-
176
- **ffmpeg is required for this provider.** whisper.cpp accepts WAV only and
177
- rejects the webm/opus the browser records, so the host converts each recording
178
- to 16 kHz mono WAV before forwarding it. Point `ffmpegBin` at your binary if it
179
- is not in `PATH`.
180
-
181
- ## Tool
155
+ ---
182
156
 
183
- The plugin also registers `transcribe_audio(file_path, language?)` for the
184
- agent, using the voice-message chain. Useful for recordings and interviews that
185
- are already files on disk.
186
-
187
- ## Routes
188
-
189
- | Route | Purpose |
190
- |---|---|
191
- | `POST /dsh-voice/transcribe` | `{dataBase64, mimeType, mode}` → `{ok, text, provider, tookMs}` |
192
- | `GET /dsh-voice/status` | whisper server state and the effective chains |
193
-
194
- ## Structure
195
-
196
- ```
197
- lib/index.js host: config, routes, transcribe_audio, whisper autostart
198
- lib/providers.js the four providers, pure functions (network injected)
199
- lib/chain.js fallback walk over a chain
200
- lib/wav.js webm/opus → WAV 16 kHz mono via ffmpeg
201
- lib/client.js browser: composer buttons, recording, settings page
202
- test/ node --test units for the chain and the providers
203
- ```
157
+ ## 🤖 Agent Tool & HTTP API
204
158
 
205
- Run the tests with `npm test` (no dependencies, Node's built-in runner).
159
+ ### Agent Tool (`transcribe_audio`)
160
+ Registers `transcribe_audio(file_path, language?)` in `ctx.tools`, allowing agents to analyze audio files, interview recordings, and voice notes directly from disk.
206
161
 
207
- ## Requirements
162
+ ### Internal HTTP Endpoints
163
+ * `POST /dsh-voice/transcribe` — `{ dataBase64, mimeType, mode }` → `{ ok, text, provider, tookMs }`
164
+ * `POST /dsh-voice/polish` — `{ text }` → `{ ok, text }`
165
+ * `GET /dsh-voice/status` — Returns daemon status, active chains, SenseVoice and realtime config.
166
+ * `GET /dsh-voice/realtime` — **WebSocket upgrade** for low-latency audio streaming (OpenAI Realtime API / Sherpa-ONNX). Accepts binary audio chunks, returns JSON text deltas.
208
167
 
209
- - DeepSeek Harness with the Web GUI
210
- - Node 20+
211
- - ffmpeg, for the local whisper provider
212
- - a microphone reachable from the browser (HTTPS or localhost)
168
+ ---
213
169
 
214
- ## License
170
+ ## 📄 License
215
171
 
216
- MIT
172
+ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
package/README.ru.md ADDED
@@ -0,0 +1,172 @@
1
+ # 📦 @goodandready/dsh-voice
2
+
3
+ <div align="center">
4
+
5
+ <h3>Потоковая диктовка без задержек и мультиязычный голосовой ввод для DeepSeek Harness</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-voice"><img src="https://img.shields.io/npm/v/@goodandready/dsh-voice.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-10b981.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
+ <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://goodandready.app/"><img src="https://img.shields.io/badge/Все_проекты_автора-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="Все проекты автора"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="README.md"><b>🇬🇧 English</b></a> •
20
+ <a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
21
+ <a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
22
+ </p>
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## ⚡ Обзор
29
+
30
+ **`dsh-voice`** добавляет полноценные голосовые возможности в веб-интерфейс **DeepSeek Harness**. Будь то непрерывная диктовка с нарезкой фраз по естественным паузам или голосовые сообщения с удобными жестами Push-to-Talk (мышь и клавиатура) — `dsh-voice` гарантирует сохранность каждой записи благодаря **автоматическим цепочкам отказоустойчивости**.
31
+
32
+ ```mermaid
33
+ graph LR
34
+ subgraph Client [Браузер Web UI]
35
+ Mic[🎙️ Микрофон диктовки] -->|Нарезка фраз VAD| Stream[Аудио-чанки]
36
+ Wave[🌊 Голосовое сообщение] -->|Зажатие / Отпускание| PTT[Push-to-Talk]
37
+ end
38
+
39
+ subgraph Host [Бэкенд DSH Host]
40
+ Stream --> FFMPEG[Транскодер ffmpeg 16кГц]
41
+ PTT --> FFMPEG
42
+ FFMPEG --> Chain{Цепочка фолбеков}
43
+
44
+ Chain -->|1-й приоритет| P1[Deepgram / Nova-2]
45
+ Chain -.->|При лимитах / 429| P2[Groq / Whisper Turbo]
46
+ Chain -.->|При сбое| P3[Локальный whisper.cpp]
47
+ end
48
+
49
+ subgraph Output [Результат]
50
+ P1 --> Composer[💬 Строка ввода чата]
51
+ P2 --> Composer
52
+ P3 --> Composer
53
+ end
54
+
55
+ style Client fill:#1e1e2e,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4
56
+ style Host fill:#181825,stroke:#cba6f7,stroke-width:2px,color:#cdd6f4
57
+ style Output fill:#11111b,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4
58
+ ```
59
+
60
+ ---
61
+
62
+ ## ✨ Ключевые возможности
63
+
64
+ * 🎙️ **Потоковая диктовка с VAD**: аудиопоток режется по естественным паузам речи (`vadSilenceMs`, по умолчанию 700 мс) и мгновенно печатается в поле ввода.
65
+ * 🌊 **Голосовые заметки с окном отмены**: запишите законченную мысль — сообщение автоматически уйдёт агенту по истечении таймера (`autoSendMs`, по умолчанию 4000 мс).
66
+ * 🎮 **Тактильный Push-to-Talk**:
67
+ * **Мышь**: зажмите кнопку волны — запись идёт пока кнопка зажата; отпускание отправляет, увод курсора отменяет запись.
68
+ * **Клавиатура**: зажмите <kbd>Ctrl</kbd> для записи без мыши; нажмите <kbd>Esc</kbd> для отмены.
69
+ * ⚡ **Субтитры браузера в реальном времени (`browser`)**: локальное распознавание Chrome Web Speech API без отправки звука на сервер с плавающими субтитрами.
70
+ * 🛡️ **Надёжные цепочки фолбеков**: при исчерпании квоты или ошибке 429 плагин мгновенно обращается к следующему провайдеру в списке.
71
+ * 🧠 **Контекстный словарь (Context Glossary)**: автоматическое извлечение переменных и технических терминов из черновика композера для точного распознавания редких слов и кода.
72
+ * 🎵 **Встроенный аудиоплеер**: предпросмотр и воспроизведение записанного голосового сообщения в чате и доке перед отправкой или для переслушивания.
73
+ * 🔇 **Аппаратное шумоподавление**: переключатель в настройках для включения/выключения браузерного шумоподавления, эхоподавления и АРУ.
74
+ * 📊 **Дашборд задержки и здоровья провайдеров**: мониторинг скорости ответа (мс), процента успешных транскрипций и ошибок в реальном времени.
75
+ * 🔒 **Безопасность API-ключей**: ключи читаются на сервере через `ctx.credentials` и никогда не попадают в браузер клиента.
76
+ * 🖥️ **Автозапуск локального whisper.cpp**: управление жизненным циклом `whisper-server` с авто-конвертацией через `ffmpeg`.
77
+ * ⚡ **SenseVoice-ONNX / Sherpa-ONNX** *(0.8.11)*: сверхбыстрый (~50–100мс) неавторегрессивный локальный STT с автоматической очисткой тегов эмоций/событий. Поддержка Sherpa-ONNX HTTP и OpenAI-совместимых эндпоинтов.
78
+ * 🌐 **Потоковое аудио в реальном времени** *(0.8.11)*: низколатентный WebSocket-мост (`/dsh-voice/realtime`) для OpenAI Realtime API или локального Sherpa-ONNX. API-ключи остаются на хосте.
79
+
80
+ ---
81
+
82
+ ## 🎮 4 способа голосового ввода
83
+
84
+ | Режим | Жест / Активация | Поведение |
85
+ |---|---|---|
86
+ | **Диктовка** | Клик <kbd>🎙️ Микрофон</kbd> | Речь режется по паузам (`vadSilenceMs`) и вставляется прямо в строку ввода |
87
+ | **Голосовое сообщение** | Клик <kbd>🌊 Волна</kbd> | Запись до нажатия стоп, затем отправка с окном отмены (`autoSendMs`) |
88
+ | **PTT Мышью** | Зажатие <kbd>🌊 Волна</kbd> | Запись пока зажата кнопка; отпускание отправляет, увод мыши сбрасывает |
89
+ | **PTT Клавиатурой** | Зажатие <kbd>Ctrl</kbd> | Запись без мыши; отпускание отправляет, нажатие <kbd>Esc</kbd> отменяет |
90
+
91
+ > [!TIP]
92
+ > Клавиатурную клавишу можно легко переопределить в настройках (`hotkey`: `Control`, `Alt`, `Shift` или любой код клавиши).
93
+
94
+ ---
95
+
96
+ ## 🛠️ Матрица поддерживаемых провайдеров
97
+
98
+ | Ключ | Сервис | Модель по умолчанию | Переменная секрета | Особенности |
99
+ |---|---|---|---|---|
100
+ | `browser` | Web Speech API | Нативная в браузере | *Не требуется* | Нулевая задержка, живые субтитры в Chrome |
101
+ | `deepgram` | Deepgram API | `nova-2` | `DEEPGRAM_API_KEY` | Сверхбыстрая облачная транскрипция |
102
+ | `groq` | Groq Whisper | `whisper-large-v3-turbo` | `GROQ_API_KEY` | Мгновенная скорость генерации |
103
+ | `hf` | HuggingFace Inference | `openai/whisper-large-v3` | `HF_TOKEN` | Высокоточный облачный Whisper |
104
+ | `local-whisper` | Локальный whisper.cpp | из параметров сервера | *Не требуется* | 100% приватность, оффлайн, без интернета |
105
+ | `sensevoice` | SenseVoice-ONNX / Sherpa-ONNX | `SenseVoiceSmall` | *Не требуется* | Сверхбыстрый (~50мс) локальный неавторегрессивный STT |
106
+
107
+ ### 🚀 Готовые пресеты (Plug & Play)
108
+
109
+ Достаточно указать имя в цепочке и добавить API-ключ:
110
+ * `openai` (`whisper-1`) → `OPENAI_API_KEY`
111
+ * `siliconflow` (`SenseVoiceSmall`) → `SILICONFLOW_API_KEY`
112
+ * `mistral` (`voxtral-mini-latest`) → `MISTRAL_API_KEY`
113
+ * `openrouter` (`google/gemini-2.5-flash`) → `OPENROUTER_API_KEY`
114
+ * `deepinfra` (`whisper-large-v3-turbo`) → `DEEPINFRA_API_KEY`
115
+ * `fireworks` (`whisper-v3-turbo`) → `FIREWORKS_API_KEY`
116
+
117
+ ---
118
+
119
+ ## 📦 Быстрая установка
120
+
121
+ ```bash
122
+ dsh plugin --profile web add @goodandready/dsh-voice
123
+ ```
124
+
125
+ > [!IMPORTANT]
126
+ > Перезапустите Web UI после установки (`systemctl --user restart dsh-web`) и обновите страницу в браузере.
127
+
128
+ ---
129
+
130
+ ## ⚙️ Настройка конфигурации
131
+
132
+ Откройте **Настройки → Плагины → Настройки плагинов → Голос** в Web UI:
133
+
134
+ ```yaml
135
+ - id: dsh-voice
136
+ config:
137
+ dictation:
138
+ language: ru
139
+ vadSilenceMs: 700
140
+ chain:
141
+ - provider: deepgram
142
+ - provider: groq
143
+ - provider: local-whisper
144
+ message:
145
+ language: ru
146
+ autoSendMs: 4000
147
+ chain:
148
+ - provider: openai
149
+ - provider: local-whisper
150
+ hotkey: Control
151
+ autoStart: true
152
+ whisperModel: /models/ggml-medium-q8_0.bin
153
+ ```
154
+
155
+ ---
156
+
157
+ ## 🤖 Инструмент агента и HTTP API
158
+
159
+ ### Инструмент агента (`transcribe_audio`)
160
+ Регистрирует `transcribe_audio(file_path, language?)` в `ctx.tools`, позволяя агентам распознавать аудиофайлы, интервью и записи с диска.
161
+
162
+ ### Внутренние HTTP эндпоинты
163
+ * `POST /dsh-voice/transcribe` — `{ dataBase64, mimeType, mode }` → `{ ok, text, provider, tookMs }`
164
+ * `POST /dsh-voice/polish` — `{ text }` → `{ ok, text }`
165
+ * `GET /dsh-voice/status` — состояние демонов, цепочки, конфигурация SenseVoice и реалтайма.
166
+ * `GET /dsh-voice/realtime` — **WebSocket upgrade** для низколатентного аудио-стриминга (OpenAI Realtime API / Sherpa-ONNX). Принимает бинарные аудио-чанки, возвращает JSON-дельты текста.
167
+
168
+ ---
169
+
170
+ ## 📄 Лицензия
171
+
172
+ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)