* feat(engines): real synthesis "Self-test" + copy-paste setup snippet for opt-in engines Builds on #905's Engines-settings fixes (verified still green: license dialog mounts, matrix reloads on select, cpu_fallback routing toast, cpu-native → cpu_only). Two enhancements, no #905 behavior touched. Real "Self-test" for in-process TTS engines ------------------------------------------- The existing /engines/{id}/health probe only imports the package and reports "deps OK" for in-process engines — it never proves the engine can emit audio. New POST /engines/{id}/selftest runs a *tiny real synthesis* from a fixed short ASCII phrase and reports ok + duration + sample-rate + sample count, proving the engine actually produces audio. Guardrails keep it cross-platform-identical and CPU-cheap: TTS + available + in-process only, bounded wall-clock timeout (OMNIVOICE_SELFTEST_TIMEOUT_S, default 90s) that returns ok=false/timed_out instead of hanging the panel, a process-wide lock so a click-storm can't stack model loads, loopback-gated, and only ever on user click (never on load). The Compat Matrix gains a "Self-test" button (with cooldown) that renders "0.82s @ 24 kHz in 820 ms". HF tokens in a synth error are redacted like the health route. Verified end-to-end: kittentts synthesized 89,200 samples @ 24 kHz. Copy-paste setup snippet for path-gated opt-in engines ------------------------------------------------------ IndexTTS / MOSS-v1.5 / dots.tts / Confucius4 gate on an OMNIVOICE_*_DIR env var. list_backends() now emits a single-sourced `setup_snippet` (the exact `export VAR=/path/...` line) surfaced with a Copy button inside the matrix's "Why unavailable?" disclosure, so users don't reconstruct it from the docs. Also tightened the incomplete SelectEngineResponse TS type to include the routing echo (routing_status/effective_device/routing_reason) the post-select toast already reads at runtime. Tests: backend selftest success/subprocess-reject/unavailable/unknown/loopback/ exception-capture/timeout/HF-redaction + setup_snippet shape; frontend self-test render, timeout marker, subprocess+ASR gating, setup-snippet render. New route added to the API route snapshot. Full vitest (808) + backend engine/routing/asr/ route-inventory/no-CJK green; lint 0 errors; format + typecheck:ci clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): allow setup_snippet key in list_backends shape assertion The engine self-test PR added setup_snippet to each backend entry but only updated the route-shape test; test_list_backends_shape strict-asserts the key set. Add setup_snippet there too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: mergetest <test@local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Bundled binaries
This directory holds platform-specific binaries that ship inside the OmniVoice Studio installer. Today:
| File | Built from | Purpose |
|---|---|---|
omnivoice-tts-darwin-arm64 |
ServeurpersoCom/omnivoice.cpp @ pinned SHA |
GGUF inference runtime — Apple Silicon |
omnivoice-tts-darwin-x86_64 |
same | Intel Mac |
omnivoice-tts-linux-x86_64 |
same | Linux |
omnivoice-tts-windows-x86_64.exe |
same | Windows |
checksums.sha256 |
computed by scripts/build-omnivoice-tts.sh |
SHA-256 manifest — verified by OmniVoiceGGUFBackend.is_available() |
The pinned commit SHA for omnivoice.cpp lives in
backend/engines/omnivoice_gguf/quant_map.json _meta.runtime_commit_sha.
Building locally
scripts/build-omnivoice-tts.sh --platform <slug> --commit-sha <40hex>
See .github/workflows/ci.yml build-omnivoice-tts job for the CI
matrix that produces these artifacts on every PR. The Apple Silicon
slot (macos-14) is marked continue-on-error: true because the
upstream omnivoice.cpp README does not publish a buildmetal.sh
(Pitfall 1 in 04-RESEARCH.md); a failed Metal build is documented
and the macOS Apple Silicon cloning default falls back to the
in-process OmniVoiceBackend.
Placeholder note
Until the CI matrix produces real binaries, this directory may contain
zero-byte placeholders. OmniVoiceGGUFBackend.is_available() returns
(False, "...binary missing...") in that case so the engine reports
honestly through the Engine Compatibility Matrix and the default
selection falls back to the in-process OmniVoiceBackend.