fix: TTS hot-swap actually works + GUI max-width + Python builder discoverable
Some checks are pending
Rust CI / cargo test (jarvis-core) (push) Waiting to run
Rust CI / cargo clippy (push) Waiting to run
Rust CI / cargo check (workspace) (push) Waiting to run

ROOT CAUSE ANALYSIS

User reported: (a) TTS dropdown doesn't apply, (b) GUI feels stretched,
(c) no link to command builder, (d) Python doesn't even start.

Issues (a), (b), (c) addressed here. (d) addressed in python repo.

=== Fix A: TTS hot-swap (was completely broken) ===

Two distinct bugs:
1. `tts::init_backend()` only read JARVIS_TTS env var, NEVER consulted
   `Settings.tts_backend` in the DB. So saving "Silero" in the GUI
   dropdown changed nothing — not even on restart.
2. `BACKEND: OnceCell<...>` couldn't be replaced at runtime, so even
   if init had picked the right backend, the dropdown was useless
   mid-session.

Fixed:
- `tts::BACKEND` is now `Lazy<RwLock<Option<Arc<dyn TtsBackend>>>>`.
- `choose_backend_name()` resolves from DB → env → auto-detect.
- New `swap_to(name)` replaces the live backend atomically.
- IPC: new `IpcAction::SwitchTts { backend }`. jarvis-app reacts to
  it the same way it reacts to SwitchLlm.
- GUI's `set_tts_backend` now persists + hot-swaps GUI's TTS + Svelte
  page also fires `switchDaemonTts()` over WS so the running daemon
  installs the new backend.
- Removed "Применится при следующем запуске" hint — now applies
  immediately. RU + EN locale strings updated.

=== Fix B: GUI max-width ===

main + #header had no max-width, so on a 1920px monitor the labels
sprawled across 1860px of space, which felt stretched. Added
max-width: 1280px + margin: 0 auto + box-sizing: border-box. Smaller
windows are unaffected.

Also added the same cap on .app-container.assist-page so the home
screen arc reactor centres properly.

=== Fix C: Command builder discoverable ===

The Python fork ships a separate yaml-editing tool at
`python/tools/command_builder/` (pywebview GUI). No way to find it
from the main Rust GUI. Fixed:

- New tauri command `open_command_builder` (crates/jarvis-gui/src/
  tauri_commands/builder.rs). Locates the Python fork via
  $JARVIS_PYTHON_DIR → sibling python/ → C:\Jarvis\python, prefers
  the project's .venv, spawns `python -m tools.command_builder`.
- New blue "Конструктор команд (Python)" button on /settings page
  near the Save / Back buttons.

Tests: 140 rust + 104 python all pass. Release builds of jarvis-app
and jarvis-gui both green.
This commit is contained in:
Bossiara13 2026-05-24 22:12:04 +03:00
parent 05b75feee4
commit 6729e53be6
12 changed files with 206 additions and 29 deletions

View file

@ -7,7 +7,7 @@
import { showInExplorer } from "@/functions"
import {
appInfo, assistantVoice, translations, translate,
switchDaemonLlm, reloadDaemonLlm,
switchDaemonLlm, reloadDaemonLlm, switchDaemonTts,
} from "@/stores"
import HDivider from "@/components/elements/HDivider.svelte"
@ -140,7 +140,10 @@
async function applyTtsBackend(target: string) {
try {
// 1. GUI Tauri command — persists to DB + hot-swaps GUI's TTS.
await invoke<string>("set_tts_backend", { name: target })
// 2. Tell the running daemon (separate process) to switch too.
switchDaemonTts(target || "auto")
} catch (err) {
backendSwapError = String(err)
}
@ -426,7 +429,7 @@
{ label: 'Silero (PyTorch helper)', value: "silero" },
]}
label={t('settings-tts-backend') || 'TTS движок'}
description={t('settings-tts-backend-desc') || 'Применится при следующем запуске jarvis-app.'}
description={t('settings-tts-backend-desc') || 'Применяется сразу — без перезапуска.'}
variant="filled"
bind:value={selectedTtsBackend}
on:change={() => applyTtsBackend(selectedTtsBackend)}
@ -672,6 +675,26 @@
<Space h="sm" />
<Button
color="blue"
radius="md"
size="sm"
uppercase
fullSize
on:click={async () => {
try {
const msg = await invoke<string>("open_command_builder")
backendSwapError = "Конструктор команд: " + msg
} catch (e) {
backendSwapError = "Не удалось запустить конструктор: " + String(e)
}
}}
>
Конструктор команд (Python)
</Button>
<Space h="sm" />
<Button
color="gray"
radius="md"