feat(mcp): Rust-owned speaking pill with self-contained audio playback

The pill window now surfaces for agent-initiated speech without main-window
involvement. Rust subscribes to /events/speak via a tokio task + reqwest
streaming body (speak_monitor.rs), shows the pill, and forwards events to
the dictate webview over Tauri's event bus. The pill plays audio via a
plain HTMLAudioElement and emits dictate:hide when playback ends. The
pill stays hidden through the ~1 s generation wait and only surfaces when
audio actually starts, with the counter armed at that moment.

Fixes a shared-dict mutation in mcp_server/events.publish() that caused
the second subscriber (Rust speak_monitor) to receive `event: message`
instead of named speak-start/speak-end frames. Also teaches the speak_monitor
parser to handle CRLF framing (sse-starlette default). Main-window
AudioPlayer now skips autoplay for source in {mcp, rest} to avoid
double-play when both windows are alive.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
James Pine
2026-04-23 01:46:17 -07:00
co-authored by Claude Opus 4.7
parent 0cef2c9fe1
commit 6b75e097e1
14 changed files with 387 additions and 192 deletions
+7 -6
View File
@@ -147,15 +147,16 @@ export function DictationHero() {
);
}
// ─── Card: Multi-Engine STT ─────────────────────────────────────────────────
// ─── Card: Whisper, sized for every machine ────────────────────────────────
type EngineRow = { name: string; size: string; langs: string };
const STT_ENGINES: EngineRow[] = [
{ name: 'Whisper', size: '1.5B', langs: '99 langs' },
{ name: 'Whisper Base', size: '74M', langs: '99 langs' },
{ name: 'Whisper Small', size: '244M', langs: '99 langs' },
{ name: 'Whisper Medium', size: '769M', langs: '99 langs' },
{ name: 'Whisper Large', size: '1.5B', langs: '99 langs' },
{ name: 'Whisper Turbo', size: '809M', langs: '99 langs' },
{ name: 'Parakeet v3', size: '600M', langs: '25 langs' },
{ name: 'Qwen3-ASR', size: '600M', langs: '50+ langs' },
];
function MultiEngineSTTAnimation() {
@@ -400,9 +401,9 @@ function AgentVoiceAnimation() {
const CAPTURE_FEATURES = [
{
title: 'Multi-Engine STT',
title: 'Whisper, sized for every machine',
description:
'Whisper, Whisper Turbo, Parakeet v3, Qwen3-ASR. Pick the model that fits your accent, language, or speed — all running on your hardware.',
'Base, Small, Medium, Large, and Turbo. Pick the size that fits your hardware and quality bar — 99 languages across every tier, all running locally.',
icon: Mic2,
animation: MultiEngineSTTAnimation,
},
+3 -3
View File
@@ -157,16 +157,16 @@ const CAPTURES: Capture[] = [
ago: '22 min ago',
createdAtLabel: 'Apr 22, 3:29 PM',
source: 'dictation',
sttModel: 'parakeet-v3',
sttModel: 'turbo',
language: 'en',
},
{
id: 'c3',
seed: 37,
transcriptRaw:
"tech overview for the readme seven TTS engines qwen3 kokoro chatterbox luxtts customvoice tada and chatterbox turbo four STT whisper whisper turbo parakeet v3 qwen3 ASR one local LLM qwen 3.5 shared runtime across all of them one model directory one GPU story no fragmented caches pick the right model per job speed on CPU laptops quality on an M series mac all switchable per generation",
"tech overview for the readme seven TTS engines qwen3 kokoro chatterbox luxtts customvoice tada and chatterbox turbo whisper for STT in five sizes from base up to large and a turbo variant one local LLM qwen 3.5 shared runtime across all of them one model directory one GPU story no fragmented caches pick the right model per job speed on CPU laptops quality on an M series mac all switchable per generation",
transcriptRefined:
"Tech overview for the README: seven TTS engines — Qwen3, Kokoro, Chatterbox, LuxTTS, CustomVoice, TADA, and Chatterbox Turbo. Four STT — Whisper, Whisper Turbo, Parakeet v3, Qwen3-ASR. One local LLM, Qwen 3.5, with a shared runtime across all of them. One model directory, one GPU story, no fragmented caches. Pick the right model per job — speed on CPU laptops, quality on an M-series Mac, switchable per-generation.",
"Tech overview for the README: seven TTS engines — Qwen3, Kokoro, Chatterbox, LuxTTS, CustomVoice, TADA, and Chatterbox Turbo. Whisper for STT, in five sizes from Base up to Large, plus a Turbo variant. One local LLM, Qwen 3.5, with a shared runtime across all of them. One model directory, one GPU story, no fragmented caches. Pick the right model per job — speed on CPU laptops, quality on an M-series Mac, switchable per-generation.",
durationMs: 34000,
ago: '1 hr ago',
createdAtLabel: 'Apr 22, 2:51 PM',
@@ -131,25 +131,6 @@ const MODEL_GROUPS: ModelGroup[] = [
{ icon: Zap, label: '8x faster' },
],
},
{
name: 'Parakeet v3',
author: 'NVIDIA',
sizes: ['600M'],
description:
'Current quality leader for non-English local STT. Very fast, with strong accuracy on European and Asian languages.',
tags: [
{ icon: Languages, label: '25 langs' },
{ icon: Zap, label: 'Fast' },
],
},
{
name: 'Qwen3-ASR',
author: 'Alibaba',
sizes: ['600M'],
description:
'int8 quantized for cross-platform use. Highest multilingual coverage of any engine — 50+ languages with strong accuracy.',
tags: [{ icon: Languages, label: '50+ langs' }],
},
],
},
{