pi-voicekit 0.1.3 → 0.1.4
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/README.md +82 -35
- package/extensions/voice/config.ts +2 -2
- package/extensions/voice/onboarding.ts +2 -2
- package/extensions/voice/settings-panel.ts +2 -2
- package/extensions/voice/tts-local-models.ts +1 -1
- package/extensions/voice/tts-onboarding-overlay.ts +7 -3
- package/extensions/voice/tts-playback.ts +2 -2
- package/extensions/voice/ui-aura.ts +1 -1
- package/extensions/voice/ui-help-overlay.ts +2 -2
- package/extensions/voice/ui-locale-labels.ts +1 -1
- package/extensions/voice/ui-width.ts +1 -1
- package/extensions/voice.ts +10 -10
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -6,32 +6,30 @@
|
|
|
6
6
|
> Not affiliated with the original author. Old name: `pi-listen`.
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
|
-
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/banner.png" alt="pi-
|
|
9
|
+
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/brand/banner-en.png" alt="pi-voicekit — Voice input and output for the Pi coding agent" width="100%" />
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
**
|
|
12
|
+
**Voice in and voice out for [Pi](https://github.com/earendil-works/pi-coding-agent).**
|
|
13
|
+
Hold-to-talk STT — Deepgram streaming (cloud) or 21 offline models — plus TTS that
|
|
14
|
+
speaks the agent's replies (Kitten, Kokoro, Piper, or Deepgram Aura).
|
|
13
15
|
|
|
14
16
|
[](https://www.npmjs.com/package/pi-voicekit)
|
|
15
17
|
[](https://github.com/CyFeng16/pi-voicekit/blob/main/LICENSE)
|
|
16
18
|
[](https://x.com/baanditeagle)
|
|
17
19
|
|
|
18
|
-
> **
|
|
19
|
-
>
|
|
20
|
-
>
|
|
21
|
-
>
|
|
22
|
-
>
|
|
23
|
-
> rate limiting. Diagnostic command `/voice-speak-info` shows everything.
|
|
24
|
-
> Resume-on-interrupt downloads. Plus all v6 features (14 local models from
|
|
25
|
-
> 25 MB Kitten Nano up, Deepgram Aura cloud, region-strict language matching,
|
|
26
|
-
> sentence-aware chunking). [Full changelog →](CHANGELOG.md)
|
|
20
|
+
> **v0.1.3 — current release** — audio capture prefers `ffmpeg` when
|
|
21
|
+
> `PULSE_SERVER` is set (SSH audio tunnel / remote PulseAudio), so remote
|
|
22
|
+
> microphones record reliably. Voice in **and** voice out: 21 offline STT models,
|
|
23
|
+
> 20 local TTS voices plus Deepgram Aura, driven by one `/voice-settings` panel
|
|
24
|
+
> with 5 tabs. The 0.1.x line is documented in the [changelog](CHANGELOG.md).
|
|
27
25
|
|
|
28
26
|
---
|
|
29
27
|
|
|
30
28
|
## See How It Works
|
|
31
29
|
|
|
32
30
|
<p align="center">
|
|
33
|
-
<a href="https://github.com/CyFeng16/pi-voicekit/blob/main/assets/pi-
|
|
34
|
-
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/banner.png" alt="Watch demo video" width="600" />
|
|
31
|
+
<a href="https://github.com/CyFeng16/pi-voicekit/blob/main/assets/demo/pi-voicekit-demo.mp4">
|
|
32
|
+
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/brand/banner-en.png" alt="Watch demo video" width="600" />
|
|
35
33
|
</a>
|
|
36
34
|
<br>
|
|
37
35
|
<em>Click to watch the demo video</em>
|
|
@@ -50,7 +48,7 @@ pi install npm:pi-voicekit
|
|
|
50
48
|
|
|
51
49
|
### 2. Choose your backend
|
|
52
50
|
|
|
53
|
-
pi-
|
|
51
|
+
pi-voicekit supports two transcription backends:
|
|
54
52
|
|
|
55
53
|
| | Deepgram (cloud) | Local models (offline) |
|
|
56
54
|
| ---------------- | -------------------------------------------------------- | --------------------------------------------------- |
|
|
@@ -79,7 +77,7 @@ No setup needed — run `/voice-settings`, switch backend to Local, and select a
|
|
|
79
77
|
|
|
80
78
|
### 3. Open Pi
|
|
81
79
|
|
|
82
|
-
On first launch, pi-
|
|
80
|
+
On first launch, pi-voicekit checks your setup and tells you what's ready:
|
|
83
81
|
|
|
84
82
|
- Backend configured (Deepgram key or local model)
|
|
85
83
|
- Audio capture tool detected (sox, ffmpeg, or arecord)
|
|
@@ -87,7 +85,7 @@ On first launch, pi-listen checks your setup and tells you what's ready:
|
|
|
87
85
|
|
|
88
86
|
### Audio capture
|
|
89
87
|
|
|
90
|
-
pi-
|
|
88
|
+
pi-voicekit auto-detects your audio tool. No manual install needed if you already have sox or ffmpeg.
|
|
91
89
|
|
|
92
90
|
| Priority | Tool | Platforms | Install |
|
|
93
91
|
| -------- | --------------- | --------------------- | ------------------------------------------------------------ |
|
|
@@ -95,33 +93,42 @@ pi-listen auto-detects your audio tool. No manual install needed if you already
|
|
|
95
93
|
| 2 | **ffmpeg** | macOS, Linux, Windows | `brew install ffmpeg` / `apt install ffmpeg` |
|
|
96
94
|
| 3 | **arecord** | Linux only | Pre-installed (ALSA) |
|
|
97
95
|
|
|
96
|
+
> When `PULSE_SERVER` is set (SSH audio tunnel or remote PulseAudio) the order
|
|
97
|
+
> becomes **ffmpeg → sox → arecord** — network Pulse sources need ffmpeg.
|
|
98
|
+
|
|
98
99
|
---
|
|
99
100
|
|
|
100
101
|
## Settings Panel
|
|
101
102
|
|
|
102
|
-
All configuration lives in one place: `/voice-settings`.
|
|
103
|
+
All configuration lives in one place: `/voice-settings`. Five tabs cover everything you need.
|
|
103
104
|
|
|
104
105
|
### General — backend, language, scope
|
|
105
106
|
|
|
106
|
-
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/settings-general.png" alt="General settings — backend, model, language, scope, voice toggle" width="600" />
|
|
107
|
+
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/screenshots/settings-general.png" alt="General settings — backend, model, language, scope, voice toggle" width="600" />
|
|
107
108
|
|
|
108
109
|
Toggle between Deepgram (cloud, live streaming) and Local (offline, batch mode). Change language, scope, and enable/disable voice — all with keyboard shortcuts.
|
|
109
110
|
|
|
110
111
|
### Models — browse, search, install
|
|
111
112
|
|
|
112
|
-
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/settings-models.png" alt="Models tab — browse 21 models with accuracy/speed ratings" width="600" />
|
|
113
|
+
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/screenshots/settings-models.png" alt="Models tab — browse 21 models with accuracy/speed ratings" width="600" />
|
|
113
114
|
|
|
114
115
|
Browse 21 models from Parakeet, Whisper, Moonshine, SenseVoice, GigaAM, Paraformer, and Qwen3. Each model shows accuracy and speed ratings (●●●●○/●●●●○), fitness badges, and download status. Fuzzy search to find models fast. Press Enter to activate and download.
|
|
115
116
|
|
|
116
117
|
### Downloaded — manage installed models
|
|
117
118
|
|
|
118
|
-
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/settings-downloaded.png" alt="Downloaded tab — manage installed models, activate or delete" width="600" />
|
|
119
|
+
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/screenshots/settings-downloaded.png" alt="Downloaded tab — manage installed models, activate or delete" width="600" />
|
|
119
120
|
|
|
120
121
|
See what's installed, total disk usage, and which model is active. Press Enter to activate, `x` to delete. Models from [Handy](https://github.com/cjpais/handy) are auto-detected and can be imported without re-downloading.
|
|
121
122
|
|
|
123
|
+
### Speak — TTS models and voices
|
|
124
|
+
|
|
125
|
+
Pick a TTS backend (local sherpa-onnx or Deepgram Aura), browse 20 local voices
|
|
126
|
+
from ~13 MB, download on selection, and choose a voice per backend. Auto-speak of
|
|
127
|
+
agent replies is toggled here.
|
|
128
|
+
|
|
122
129
|
### Device — hardware profile and dependencies
|
|
123
130
|
|
|
124
|
-
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/settings-device.png" alt="Device tab — hardware profile, dependencies, disk space" width="600" />
|
|
131
|
+
<img src="https://raw.githubusercontent.com/CyFeng16/pi-voicekit/main/assets/screenshots/settings-device.png" alt="Device tab — hardware profile, dependencies, disk space" width="600" />
|
|
125
132
|
|
|
126
133
|
See your hardware profile (RAM, CPU, GPU), dependency status (sherpa-onnx runtime), available disk space, and total downloaded models. Model recommendations are based on this profile.
|
|
127
134
|
|
|
@@ -133,7 +140,7 @@ See your hardware profile (RAM, CPU, GPU), dependency status (sherpa-onnx runtim
|
|
|
133
140
|
|
|
134
141
|
| Action | Key | Notes |
|
|
135
142
|
| -------------------- | -------------------- | ----------------------------------------------------------------------- |
|
|
136
|
-
| **Record to editor** | Hold `SPACE` (≥
|
|
143
|
+
| **Record to editor** | Hold `SPACE` (≥0.7s) | Release to finalize. Pre-records during warmup so you don't miss words. |
|
|
137
144
|
| **Toggle recording** | `Ctrl+Shift+V` | Works in all terminals — press to start, press again to stop. |
|
|
138
145
|
| **Clear editor** | `Escape` × 2 | Double-tap within 500ms to clear all text. |
|
|
139
146
|
|
|
@@ -150,10 +157,15 @@ See your hardware profile (RAM, CPU, GPU), dependency status (sherpa-onnx runtim
|
|
|
150
157
|
| ------------------------ | --------------------------------------------------------- |
|
|
151
158
|
| `/voice-settings` | Settings panel — backend, models, language, scope, device |
|
|
152
159
|
| `/voice-models` | Settings panel (Models tab) |
|
|
160
|
+
| `/voice-setup` | Run the first-run setup wizard |
|
|
161
|
+
| `/voice-language` | Open the settings panel to change language |
|
|
153
162
|
| `/voice-speak <text>` | Speak text out loud (TTS) |
|
|
154
163
|
| `/voice-speak-test` | Speak a sample sentence |
|
|
155
164
|
| `/voice-speak-toggle` | Enable / disable TTS |
|
|
156
|
-
| `/voice-
|
|
165
|
+
| `/voice-stream` | Toggle Deepgram streaming TTS (cloud) |
|
|
166
|
+
| `/voice-speak-stop` | Stop in-flight TTS playback |
|
|
167
|
+
| `/voice-autosubmit` | Toggle: STT text auto-sent to the agent (`on`/`off`) |
|
|
168
|
+
| `/voice-hold-delay` | Set hold-to-talk delay (200-3000 ms, default 700) |
|
|
157
169
|
| `/voice-speak-models` | Browse / install TTS voice models |
|
|
158
170
|
| `/voice-speak-info` | Diagnose TTS state |
|
|
159
171
|
| `/voice-help` | Keyboard + command reference (or press `F1`) |
|
|
@@ -245,10 +257,10 @@ Models from [Handy](https://github.com/cjpais/handy) (`~/Library/Application Sup
|
|
|
245
257
|
| **Device-aware recommendations** | Scores models against your hardware. Only best-in-class models get [recommended]. |
|
|
246
258
|
| **Enterprise download pipeline** | Pre-checks (disk, network, permissions), live progress with speed/ETA, post-verification |
|
|
247
259
|
| **Handy integration** | Auto-detects models from Handy app, imports via symlink |
|
|
248
|
-
| **Audio fallback chain** | Tries sox
|
|
260
|
+
| **Audio fallback chain** | Tries sox → ffmpeg → arecord in order — ffmpeg first when `PULSE_SERVER` is set |
|
|
249
261
|
| **Pre-recording** | Audio capture starts during warmup — you never miss the first word |
|
|
250
262
|
| **Tail recording** | Keeps recording 1.5s after release so your last word isn't clipped |
|
|
251
|
-
| **Live streaming** | Deepgram Nova 3 WebSocket — interim transcripts
|
|
263
|
+
| **Live streaming** | Deepgram Nova 3 WebSocket (Nova 2 for Chinese locales) — live interim transcripts |
|
|
252
264
|
| **56+ languages** | Deepgram: 56+ with live streaming. Local: up to 57 depending on model. |
|
|
253
265
|
| **Continuous dictation** | `/voice dictate` for long-form input without holding keys |
|
|
254
266
|
| **Typing cooldown** | Space holds within 400ms of typing are ignored |
|
|
@@ -260,15 +272,47 @@ Models from [Handy](https://github.com/cjpais/handy) (`~/Library/Application Sup
|
|
|
260
272
|
## Architecture
|
|
261
273
|
|
|
262
274
|
```
|
|
263
|
-
|
|
264
|
-
extensions/voice
|
|
265
|
-
extensions/voice/
|
|
266
|
-
extensions/voice/
|
|
267
|
-
extensions/voice/
|
|
268
|
-
extensions/voice/
|
|
269
|
-
extensions/voice/
|
|
270
|
-
|
|
271
|
-
|
|
275
|
+
# core
|
|
276
|
+
extensions/voice.ts Main extension — state machine, recording, UI, command surface
|
|
277
|
+
extensions/voice/config.ts Config loading, saving, migration
|
|
278
|
+
extensions/voice/onboarding.ts First-run wizard, language picker
|
|
279
|
+
extensions/voice/audio-tool.ts Capture tool detection (sox / ffmpeg / arecord)
|
|
280
|
+
extensions/voice/hold-to-talk.ts Hold detection, Kitty and non-Kitty terminals
|
|
281
|
+
extensions/voice/release-controller.ts Recording lifecycle, release handling
|
|
282
|
+
|
|
283
|
+
# speech-to-text
|
|
284
|
+
extensions/voice/deepgram.ts Deepgram URL builder, API key resolver
|
|
285
|
+
extensions/voice/local.ts Model catalog (21 models), in-process transcription
|
|
286
|
+
extensions/voice/sherpa-engine.ts sherpa-onnx bindings — recognizer lifecycle, inference
|
|
287
|
+
extensions/voice/sherpa-loader.ts Lazy native module loading
|
|
288
|
+
extensions/voice/model-download.ts Download manager — resume, progress, verification, Handy import
|
|
289
|
+
extensions/voice/device.ts Device profiling — RAM, GPU, CPU, container detection
|
|
290
|
+
|
|
291
|
+
# text-to-speech
|
|
292
|
+
extensions/voice/speak.ts Speak entry point, auto-speak wiring
|
|
293
|
+
extensions/voice/tts-engine.ts sherpa-onnx TTS synthesis
|
|
294
|
+
extensions/voice/tts-deepgram.ts Deepgram Aura voices (cloud)
|
|
295
|
+
extensions/voice/tts-local-models.ts Local TTS catalog — 20 voices (Kitten, Kokoro, Piper)
|
|
296
|
+
extensions/voice/tts-playback.ts Playback, buffering, player detection
|
|
297
|
+
extensions/voice/tts-text-filter.ts Code-block stripping, sentence prep
|
|
298
|
+
extensions/voice/tts-onboarding.ts TTS onboarding flow
|
|
299
|
+
extensions/voice/tts-onboarding-overlay.ts TTS onboarding overlay
|
|
300
|
+
extensions/voice/tts-install-progress.ts Model install progress widget
|
|
301
|
+
extensions/voice/tts-playback-indicator.ts Speaking indicator widget
|
|
302
|
+
|
|
303
|
+
# settings and UI
|
|
304
|
+
extensions/voice/settings-panel.ts Settings panel — overlay, 5 tabs
|
|
305
|
+
extensions/voice/ui-picker.ts Generic list picker
|
|
306
|
+
extensions/voice/ui-help-overlay.ts Keyboard and command reference
|
|
307
|
+
extensions/voice/ui-aura.ts Visual primitives (Liquid Braille, Aurora)
|
|
308
|
+
extensions/voice/ui-widget-base.ts Widget registry and base class
|
|
309
|
+
extensions/voice/ui-render-ticker.ts Shared render ticker
|
|
310
|
+
extensions/voice/ui-icons.ts Glyph and icon set
|
|
311
|
+
extensions/voice/ui-width.ts CJK-aware visual width helpers
|
|
312
|
+
extensions/voice/ui-locale-labels.ts Native language and voice labels
|
|
313
|
+
|
|
314
|
+
# types
|
|
315
|
+
extensions/voice/sherpa-onnx-node.d.ts Type declarations for the optional native module
|
|
272
316
|
```
|
|
273
317
|
|
|
274
318
|
---
|
|
@@ -300,6 +344,8 @@ Settings stored in Pi's settings files under the `voice` key:
|
|
|
300
344
|
into `~/.pi/agent/settings.json`. If you paste a key during onboarding, that is
|
|
301
345
|
an explicit save and it still goes to `~/.env.secrets` or `~/.zshrc`.
|
|
302
346
|
|
|
347
|
+
Hold-to-talk delay defaults to **700 ms** (`/voice-hold-delay` accepts 200–3000 ms).
|
|
348
|
+
|
|
303
349
|
---
|
|
304
350
|
|
|
305
351
|
## Troubleshooting
|
|
@@ -310,6 +356,7 @@ Run `/voice test` inside Pi for full diagnostics.
|
|
|
310
356
|
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
311
357
|
| "DEEPGRAM_API_KEY not set" | [Get a key](https://dpgr.am/pi-voice) → `export DEEPGRAM_API_KEY="..."` in `~/.zshrc` |
|
|
312
358
|
| "No audio capture tool found" | `brew install sox` or `brew install ffmpeg` |
|
|
359
|
+
| Remote microphone records silence | Audio over PulseAudio/SSH — install ffmpeg on the Pi side (capture then prefers ffmpeg) |
|
|
313
360
|
| Space doesn't activate voice | Run `/voice-settings` — voice may be disabled |
|
|
314
361
|
| Local model not transcribing | Check `/voice-settings` → Device tab for sherpa-onnx status |
|
|
315
362
|
| Download failed | Partial downloads auto-resume on retry. Check disk space in Device tab. |
|
|
@@ -321,7 +368,7 @@ Run `/voice test` inside Pi for full diagnostics.
|
|
|
321
368
|
|
|
322
369
|
- **Cloud STT** — audio is sent to Deepgram for transcription (Deepgram backend only)
|
|
323
370
|
- **Local STT** — audio never leaves your machine (local backend)
|
|
324
|
-
- **No telemetry** — pi-
|
|
371
|
+
- **No telemetry** — pi-voicekit does not collect or transmit usage data
|
|
325
372
|
- **API key** — stored in env var or Pi settings, never logged
|
|
326
373
|
|
|
327
374
|
See [SECURITY.md](SECURITY.md) for vulnerability reporting.
|
|
@@ -150,7 +150,7 @@ export function readJsonFile(filePath: string): Record<string, unknown> {
|
|
|
150
150
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
151
151
|
} catch (err) {
|
|
152
152
|
process.stderr.write(
|
|
153
|
-
`[pi-
|
|
153
|
+
`[pi-voicekit] Warning: failed to read ${filePath}: ${err instanceof Error ? err.message : err}\n`
|
|
154
154
|
);
|
|
155
155
|
return {};
|
|
156
156
|
}
|
|
@@ -303,7 +303,7 @@ export function loadGlobalToggleShortcut(options: ConfigPathOptions = {}): strin
|
|
|
303
303
|
const candidate = (globalVoice as any).toggleShortcut;
|
|
304
304
|
if (isValidShortcut(candidate)) return candidate;
|
|
305
305
|
process.stderr.write(
|
|
306
|
-
`[pi-
|
|
306
|
+
`[pi-voicekit] Warning: invalid toggleShortcut "${candidate}" in settings, using default "${fallback}"\n`
|
|
307
307
|
);
|
|
308
308
|
}
|
|
309
309
|
} catch {
|
|
@@ -314,7 +314,7 @@ export function finalizeOnboardingConfig(
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
export async function promptFirstRunOnboarding(ctx: VoiceUiContext): Promise<FirstRunDecision> {
|
|
317
|
-
const choice = await ctx.ui.select("Set up pi-
|
|
317
|
+
const choice = await ctx.ui.select("Set up pi-voicekit now?", ["Start voice setup", "Remind me later"]);
|
|
318
318
|
|
|
319
319
|
return { action: choice === "Start voice setup" ? "start" : "later" };
|
|
320
320
|
}
|
|
@@ -665,7 +665,7 @@ export async function runVoiceOnboarding(
|
|
|
665
665
|
}
|
|
666
666
|
|
|
667
667
|
// ─── Choose scope ────────────────────────────────────────
|
|
668
|
-
const scopeChoice = await ctx.ui.select("Where should pi-
|
|
668
|
+
const scopeChoice = await ctx.ui.select("Where should pi-voicekit settings be saved?", [
|
|
669
669
|
"Global (all projects)",
|
|
670
670
|
"Project only (this repo)",
|
|
671
671
|
]);
|
|
@@ -193,7 +193,7 @@ export class VoiceSettingsPanel {
|
|
|
193
193
|
// commands remain available (panel-less).
|
|
194
194
|
if (isPanelTooNarrow(width)) {
|
|
195
195
|
return [
|
|
196
|
-
` ${this.bold("pi-
|
|
196
|
+
` ${this.bold("pi-voicekit")}`,
|
|
197
197
|
` ${this.warning(`Terminal too narrow ${ICON.middot} resize to ${ICON.arrowRight} 60 cols`)}`,
|
|
198
198
|
` ${this.dim("Slash commands still work: /voice-speak, /voice-models, /voice-settings")}`,
|
|
199
199
|
];
|
|
@@ -212,7 +212,7 @@ export class VoiceSettingsPanel {
|
|
|
212
212
|
// backend/model/voice + active language. Width-tier aware:
|
|
213
213
|
// at "mid" (60-79) the row is trimmed; at "wide" (≥80) it
|
|
214
214
|
// shows the full picture.
|
|
215
|
-
lines.push(t(` ${this.bold("pi-
|
|
215
|
+
lines.push(t(` ${this.bold("pi-voicekit")} ${this.dim(this.p.formatDeviceSummary(device))}`));
|
|
216
216
|
lines.push(t(" " + this.renderStatusRow(widthTier(width) === "mid")));
|
|
217
217
|
lines.push(t(this.dim(" " + "─".repeat(Math.min(iw, 60)))));
|
|
218
218
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* Visual design (no emoji per v7.1 hard constraint):
|
|
19
19
|
*
|
|
20
|
-
* ┌─ pi-
|
|
20
|
+
* ┌─ pi-voicekit TTS ─────────────────────────────────────────────┐
|
|
21
21
|
* │ │
|
|
22
22
|
* │ Voice output ready. │
|
|
23
23
|
* │ │
|
|
@@ -90,7 +90,11 @@ export class TtsOnboardingOverlay {
|
|
|
90
90
|
// v7.2: rounded corners for modal feel. Title sits inline on the
|
|
91
91
|
// top edge with thin spacing so the box reads as a "sheet"
|
|
92
92
|
// rather than a hard frame (HIG modal aesthetic).
|
|
93
|
-
|
|
93
|
+
// Title sits inline on the top edge; the pad is derived from the title's
|
|
94
|
+
// *visual* width so the frame stays exactly as wide as the body/bottom
|
|
95
|
+
// rows (brand length is data, not a magic constant).
|
|
96
|
+
const title = "pi-voicekit TTS";
|
|
97
|
+
const top = `${ICON.boxRoundedTL}${ICON.boxH.repeat(2)} ${bold(title)} ${ICON.boxH.repeat(Math.max(0, innerW - visualWidth(title) - 4))}${ICON.boxRoundedTR}`;
|
|
94
98
|
const bottom = `${ICON.boxRoundedBL}${ICON.boxH.repeat(innerW)}${ICON.boxRoundedBR}`;
|
|
95
99
|
const hr = `${ICON.boxV}${" ".repeat(innerW)}${ICON.boxV}`;
|
|
96
100
|
const row = (s: string): string => {
|
|
@@ -147,7 +151,7 @@ export class TtsOnboardingOverlay {
|
|
|
147
151
|
const dim = (s: string) => (t ? t.fg("dim", s) : s);
|
|
148
152
|
const accent = (s: string) => (t ? t.fg("accent", s) : s);
|
|
149
153
|
return [
|
|
150
|
-
` ${accent("pi-
|
|
154
|
+
` ${accent("pi-voicekit TTS")}`,
|
|
151
155
|
` ${dim("Voice output ready. Resize to ≥60 cols for the full hint.")}`,
|
|
152
156
|
` ${accent("[↵]")} ${dim("test")} ${accent("[m]")} ${dim("pick")} ${accent("[esc]")} ${dim("skip")}`,
|
|
153
157
|
];
|
|
@@ -210,7 +210,7 @@ export interface OpenPlaybackStreamOpts {
|
|
|
210
210
|
* Open a streaming playback sink. Returns `null` when no streaming-capable
|
|
211
211
|
* player is found on PATH — the caller should fall back to the file-based
|
|
212
212
|
* `play()` path. Player priority: `sox` (preferred — works on macOS via
|
|
213
|
-
* homebrew, Linux via apt/yum, ships with most pi-
|
|
213
|
+
* homebrew, Linux via apt/yum, ships with most pi-voicekit STT installs) →
|
|
214
214
|
* `paplay` (Linux PulseAudio) → null.
|
|
215
215
|
*
|
|
216
216
|
* Windows is intentionally unsupported here — PowerShell SoundPlayer
|
|
@@ -464,7 +464,7 @@ function pickStreamingPlayer(sampleRate: number): StreamingPlayerSpec | null {
|
|
|
464
464
|
if (process.platform === "linux" && binaryAvailable("paplay")) {
|
|
465
465
|
return {
|
|
466
466
|
cmd: "paplay",
|
|
467
|
-
args: ["--raw", `--rate=${sampleRate}`, "--format=s16le", "--channels=1", "--client-name=pi-
|
|
467
|
+
args: ["--raw", `--rate=${sampleRate}`, "--format=s16le", "--channels=1", "--client-name=pi-voicekit"],
|
|
468
468
|
};
|
|
469
469
|
}
|
|
470
470
|
// sox last-resort: cross-platform but has the macOS CoreAudio
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* "Auroral" visual language — v7.2 world-class polish.
|
|
3
3
|
*
|
|
4
|
-
* Three primitives that elevate pi-
|
|
4
|
+
* Three primitives that elevate pi-voicekit's visual identity from
|
|
5
5
|
* "minimal CLI" to "premium application":
|
|
6
6
|
*
|
|
7
7
|
* 1. Liquid Braille waveform — sub-cell vertical bars at 4-level
|
|
@@ -103,7 +103,7 @@ export class HelpOverlay {
|
|
|
103
103
|
const w = Math.max(60, Math.min(width - 2, 90));
|
|
104
104
|
const lines: string[] = [];
|
|
105
105
|
lines.push(
|
|
106
|
-
` ${bold("pi-
|
|
106
|
+
` ${bold("pi-voicekit")} ${dim(ICON.middot)} ${bold("Help")} ${dim(`${ICON.middot} press [esc] to close`)}`
|
|
107
107
|
);
|
|
108
108
|
lines.push(` ${dim(ICON.boxH.repeat(Math.min(w, 60)))}`);
|
|
109
109
|
for (const sec of HELP_SECTIONS) {
|
|
@@ -127,7 +127,7 @@ export class HelpOverlay {
|
|
|
127
127
|
const dim = (s: string) => (t ? t.fg("dim", s) : s);
|
|
128
128
|
const accent = (s: string) => (t ? t.fg("accent", s) : s);
|
|
129
129
|
const lines: string[] = [];
|
|
130
|
-
lines.push(` ${accent("pi-
|
|
130
|
+
lines.push(` ${accent("pi-voicekit Help")}`);
|
|
131
131
|
for (const sec of HELP_SECTIONS) {
|
|
132
132
|
lines.push("");
|
|
133
133
|
lines.push(` ${accent(sec.heading)}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Native-script + gender labels for the Voice picker (§8 of v7.1 plan).
|
|
3
3
|
*
|
|
4
|
-
* Hand-curated for the languages pi-
|
|
4
|
+
* Hand-curated for the languages pi-voicekit ships voices for, using the
|
|
5
5
|
* BCP-47 base-language tag (not script/region) as the lookup key. Three
|
|
6
6
|
* intentional omissions:
|
|
7
7
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* two halves of nothing.
|
|
9
9
|
*
|
|
10
10
|
* Hand-curated EAW Wide/Fullwidth ranges from Unicode 15.1 EastAsianWidth.txt
|
|
11
|
-
* — only the blocks pi-
|
|
11
|
+
* — only the blocks pi-voicekit actually ships labels for (CJK, Hangul,
|
|
12
12
|
* Hiragana/Katakana, fullwidth ASCII). Hindi/Devanagari and Arabic
|
|
13
13
|
* intentionally NOT covered: per the v7.1 plan their voices are rendered
|
|
14
14
|
* with romanized labels, so a precise width here is unnecessary and a
|
package/extensions/voice.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* pi-
|
|
2
|
+
* pi-voicekit — Enterprise-grade voice STT for Pi CLI.
|
|
3
3
|
*
|
|
4
4
|
* Architecture (modeled after Claude Code's voice pipeline):
|
|
5
5
|
*
|
|
@@ -2279,7 +2279,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2279
2279
|
// actually loaded after a `pi install .` (path-installed
|
|
2280
2280
|
// extensions cache modules across `pi install` reinstalls — only
|
|
2281
2281
|
// a fresh `pi` process picks up source changes).
|
|
2282
|
-
voiceDebug("pi-
|
|
2282
|
+
voiceDebug("pi-voicekit loaded", { reason });
|
|
2283
2283
|
|
|
2284
2284
|
// Migration / setup runs on EVERY session_start, regardless of reason.
|
|
2285
2285
|
// Only the first-run notification is gated on isStartup.
|
|
@@ -2323,7 +2323,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2323
2323
|
? `Local model: ${LOCAL_MODELS.find((m) => m.id === config.localModel)?.name || config.localModel} (offline, batch mode)`
|
|
2324
2324
|
: "Deepgram Nova-3 (cloud, live streaming)";
|
|
2325
2325
|
const lines = [
|
|
2326
|
-
"pi-
|
|
2326
|
+
"pi-voicekit ready!",
|
|
2327
2327
|
"",
|
|
2328
2328
|
" Hold SPACE to record → release to transcribe",
|
|
2329
2329
|
` ${toggleShortcutLabel} to toggle recording`,
|
|
@@ -2339,7 +2339,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2339
2339
|
// No backend configured — show install hint only on actual startup.
|
|
2340
2340
|
if (!isStartup) return;
|
|
2341
2341
|
const lines = [
|
|
2342
|
-
"pi-
|
|
2342
|
+
"pi-voicekit installed — voice input for Pi",
|
|
2343
2343
|
"",
|
|
2344
2344
|
" Two backends available:",
|
|
2345
2345
|
" • Deepgram — cloud, live streaming, $200 free credit (6–12 months of use)",
|
|
@@ -2955,27 +2955,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
2955
2955
|
// ─── /voice-setup → redirects to settings panel ─────────────────────────
|
|
2956
2956
|
|
|
2957
2957
|
pi.registerCommand("voice-setup", {
|
|
2958
|
-
description: "Open pi-
|
|
2958
|
+
description: "Open pi-voicekit settings panel",
|
|
2959
2959
|
handler: async (_args, cmdCtx) => openSettingsPanel(cmdCtx),
|
|
2960
2960
|
});
|
|
2961
2961
|
|
|
2962
2962
|
// ─── /voice-language → redirects to settings panel ───────────────────────
|
|
2963
2963
|
|
|
2964
2964
|
pi.registerCommand("voice-language", {
|
|
2965
|
-
description: "Open pi-
|
|
2965
|
+
description: "Open pi-voicekit settings to change language",
|
|
2966
2966
|
handler: async (_args, cmdCtx) => openSettingsPanel(cmdCtx),
|
|
2967
2967
|
});
|
|
2968
2968
|
|
|
2969
2969
|
// ─── /voice-help → v7.1 §11 keyboard / command reference ────────────────
|
|
2970
2970
|
|
|
2971
2971
|
pi.registerCommand("voice-help", {
|
|
2972
|
-
description: "Show pi-
|
|
2972
|
+
description: "Show pi-voicekit keyboard + command reference",
|
|
2973
2973
|
handler: async (_args, cmdCtx) => openHelpOverlay(cmdCtx),
|
|
2974
2974
|
});
|
|
2975
2975
|
|
|
2976
2976
|
async function openHelpOverlay(cmdCtx: ExtensionCommandContext): Promise<void> {
|
|
2977
2977
|
if (!cmdCtx.hasUI) {
|
|
2978
|
-
cmdCtx.ui.notify("pi-
|
|
2978
|
+
cmdCtx.ui.notify("pi-voicekit: hold space=record · /voice-speak <text> · /voice-settings · /voice-help", "info");
|
|
2979
2979
|
return;
|
|
2980
2980
|
}
|
|
2981
2981
|
const { HelpOverlay } = await import("./voice/ui-help-overlay");
|
|
@@ -3637,10 +3637,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
3637
3637
|
handler: async (_args, cmdCtx) => openSettingsPanel(cmdCtx, 3),
|
|
3638
3638
|
});
|
|
3639
3639
|
|
|
3640
|
-
// ─── /voice-settings — unified pi-
|
|
3640
|
+
// ─── /voice-settings — unified pi-voicekit settings panel ─────────────
|
|
3641
3641
|
|
|
3642
3642
|
pi.registerCommand("voice-settings", {
|
|
3643
|
-
description: "Open pi-
|
|
3643
|
+
description: "Open pi-voicekit settings — backend, models, language, device",
|
|
3644
3644
|
handler: async (_args, cmdCtx) => openSettingsPanel(cmdCtx),
|
|
3645
3645
|
});
|
|
3646
3646
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-voicekit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Voice in + voice out for Pi CLI — hold-to-talk STT (Deepgram streaming or 21 offline models) plus TTS (Kitten Nano, Piper, Kokoro, or Deepgram Aura)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -46,10 +46,9 @@
|
|
|
46
46
|
"typecheck": "bunx tsc -p tsconfig.json",
|
|
47
47
|
"test": "bun test",
|
|
48
48
|
"check": "bun run typecheck && bun run test",
|
|
49
|
-
"format": "
|
|
50
|
-
"format:check": "
|
|
51
|
-
"release:dry": "bun run check && bun publish --dry-run"
|
|
52
|
-
"release": "bun run check && bun publish --access public"
|
|
49
|
+
"format": "prettier --write \"**/*.{ts,json,yml,yaml}\"",
|
|
50
|
+
"format:check": "prettier --check \"**/*.{ts,json,yml,yaml}\"",
|
|
51
|
+
"release:dry": "bun run check && bun publish --dry-run"
|
|
53
52
|
},
|
|
54
53
|
"peerDependencies": {
|
|
55
54
|
"@earendil-works/pi-coding-agent": "*",
|
|
@@ -58,7 +57,8 @@
|
|
|
58
57
|
"devDependencies": {
|
|
59
58
|
"@earendil-works/pi-coding-agent": "^0.85.0",
|
|
60
59
|
"@earendil-works/pi-tui": "^0.85.0",
|
|
61
|
-
"@types/ws": "^8"
|
|
60
|
+
"@types/ws": "^8",
|
|
61
|
+
"prettier": "3.3.3"
|
|
62
62
|
},
|
|
63
63
|
"pi": {
|
|
64
64
|
"extensions": [
|