J.A.R.V.I.S-rust/frontend
Bossiara13 8ff87f3096
Some checks failed
Rust CI / cargo test (jarvis-core) (push) Has been cancelled
Rust CI / cargo clippy (push) Has been cancelled
Rust CI / cargo check (workspace) (push) Has been cancelled
fix: serialize all audio (no overlap) + GUI shows daemon's TTS, not its own
## Issue 1: Voices were overlapping

Root cause was structural, not a single bug: every TTS backend's speak()
was fire-and-forget (`cmd.spawn()` instead of `cmd.status()`) AND cue
WAVs went through a completely SEPARATE audio path (Kira) with no
coordination. Two back-to-back calls — `voices::play_reply()` + a
`tts::speak("Готово")` + an idle banter chime — all started their
audio at the same moment.

Fix: ONE speech worker thread drains a `mpsc::Sender<Job>` channel.
Jobs are `Speak { text, opts }` or `Wav(path)`. The worker:
- forces opts.detached = false so backends BLOCK until audio finishes
- plays WAVs synchronously via PowerShell SoundPlayer
- thus implicitly serialises everything queued behind it

Both call paths now feed the same queue:
- `tts::speak()` → Job::Speak
- `tts::play_wav()` → Job::Wav  (used by Piper/Silero for their .wav output)
- `voices::play_random_from_list()` now also calls `tts::play_wav()`
  instead of `audio::play_sound()` — that re-routes cue sounds through
  the same queue. Trade-off: cue WAVs lose Kira's native low-latency
  start (~50ms slower) but gain guaranteed ordering against TTS.

Two new unit tests:
- `speech_queue_serialises_calls`: fires 5 speak() back-to-back with an
  80ms-per-call fake backend, asserts gaps between starts are ≥60ms
  (i.e. the worker IS waiting). Confirms no overlap.
- `empty_text_is_skipped`: the guard against accidentally queueing
  empty/whitespace-only phrases that would briefly stall the worker.

## Issue 2: GUI shows ITS OWN tts state, not the daemon's

User toggled TTS dropdown → "Saved!" banner → "Активный движок" chip
still showed sapi. Reason: `get_active_backends` Tauri command read
THIS process's (GUI's) `tts::backend()`. But the GUI process hardly
ever speaks — the daemon (jarvis-app, separate process) is what
actually replies to voice commands. Two processes, two TTS state
machines, GUI was showing the wrong one.

Fix: settings page now prefers `$daemonHealth` (filled via the
existing WS `query_health` event from the daemon) for the "Активный
движок" chip. Falls back to GUI's local `activeBackends` only when
the daemon is unreachable, and shows an orange "демон не отвечает —
показано из GUI" badge so the user knows the chip is stale.

Plus:
- `applyTtsBackend` / `applyLlmBackend` now call `queryDaemonHealth()`
  right after the swap so the chip updates within ~100ms instead of
  waiting up to 5s for the next footer poll.
- `switchDaemonTts` / `switchDaemonLlm` returns false when WS isn't
  connected. The page now reads that return value and SURFACES a red
  notification — previously the swap silently went nowhere if the
  daemon wasn't running, which exactly matches the user's "GUI looks
  changed but nothing happens" symptom.

## Tests

- 145 → 147 rust core tests (+2 speech queue).
- Frontend rebuilds in 6.16s; release jarvis-app + jarvis-gui green.
2026-05-24 23:35:46 +03:00
..
public Multilingual support via Fluent + Frontend improvements + Rewrite of ArcReactor 2026-01-07 05:04:04 +05:00
src fix: serialize all audio (no overlap) + GUI shows daemon's TTS, not its own 2026-05-24 23:35:46 +03:00
.gitignore project restructure with Rust workspaces 2026-01-04 05:19:47 +05:00
index.html project restructure with Rust workspaces 2026-01-04 05:19:47 +05:00
package-lock.json chore: build frontend assets so tauri context generates cleanly 2026-04-22 17:57:29 +03:00
package.json fix: toasts say 'J.A.R.V.I.S.' (was 'PowerShell') + unbreak frontend build 2026-05-24 22:22:19 +03:00
tsconfig.json frontend fixes & db rewrite with serde 2026-01-04 09:00:51 +05:00
tsconfig.node.json frontend fixes & db rewrite with serde 2026-01-04 09:00:51 +05:00
vite.config.ts frontend fixes & db rewrite with serde 2026-01-04 09:00:51 +05:00