feat(tts): Phase 4 — Read Page Aloud with OS-native voices
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled

Platform-dispatched TTS (spd-say + espeak-ng fallback on Linux, say on
macOS, PowerShell System.Speech on Windows) with a shared SpeakerButton
component. Tap to speak, tap again to stop; only one button speaks at
a time so two surfaces don't talk over each other. Text always travels
via argv (or a PowerShell here-string delivered through -EncodedCommand
on Windows) so user content never enters a shell string.

Mount points: DictationPage transcript footer, transcript viewer header,
per-step in MicroSteps. Settings gains a "Read aloud" accordion with
voice picker (lazy-loaded from the OS synth), rate slider 0.5-2.0x,
and a British-English test utterance.

Rust tests cover rate mapping, NaN handling, and Windows here-string
terminator safety. No pause/resume, no SSML, no cloud voices — that
stays out of scope per the Layer-1 roadmap.
This commit is contained in:
2026-04-24 16:01:47 +01:00
parent b344e8a580
commit 9f53702c7e
12 changed files with 699 additions and 7 deletions

View File

@@ -218,6 +218,7 @@ pub fn run() {
app.manage(commands::hotkey::HotkeyState::new());
app.manage(commands::audio::NativeCaptureState::new());
app.manage(commands::live::LiveTranscriptionState::default());
app.manage(commands::tts::TtsState::new());
app.manage(AppState {
whisper_engine: Arc::new(LocalEngine::new(EngineName::new("whisper"))),
@@ -292,6 +293,10 @@ pub fn run() {
// HITL feedback (Phase 2 roadmap)
commands::feedback::record_feedback,
commands::feedback::list_feedback_examples_cmd,
// Read aloud (Phase 4 roadmap)
commands::tts::tts_speak,
commands::tts::tts_stop,
commands::tts::tts_list_voices,
// Profiles + profile terms (canonical SQLite-backed profile CRUD) — Task 12
commands::profiles::list_profiles_cmd,
commands::profiles::get_profile_cmd,