- Drops experimental flag (continue-on-error) on macos-14 in build-omnivoice-tts.yml now that omnivoice.cpp builds cleanly with -DGGML_METAL=ON at the pinned SHA.
- Updates bin/README.md, backend/engines/omnivoice_gguf/README.md, and SPIKE-01 ADR to document verified Apple Silicon Metal acceleration.
- Corrects workflow reference in bin/README.md.
- Adds changelog credit for @martinezpl.
Closes#2105
Renames what users see. The app, the installers, the window title, the
docs and all 21 locales now say VoiceStudio, with "(previously
OmniVoice-Studio)" noted near the title of each doc surface so people
recognise it.
Deliberately NOT renamed, because renaming any of them silently breaks
an existing install — there is no legacy-path fallback anywhere in this
codebase:
- bundle identifier com.debpalash.omnivoice-studio (MSI UpgradeCode,
macOS TCC grants, managed venv, WebView localStorage, the
single-instance lock)
- data directories OmniVoice / .omnivoice and omnivoice.db
- the ~150 OMNIVOICE_* environment variables
- the X-OmniVoice-* HTTP headers (a wire protocol)
- the published Docker image paths
- the OmniVoice ENGINE, which is a model name and not this product
tests/test_identity_paths_survive_the_rename.py pins every one of those
so a future well-meaning sweep cannot orphan a user's library.
Linux .deb users install a new package name and should apt remove
omnivoice-studio; that note is in the changelog.
- validate managed binaries before exec; 0-byte GGUF placeholders fail
actionably instead of "Exec format error" (#1172)
- KittenTTS: tokenizer-measured chunking to the ONNX 512-token cap;
clear 400 for unspeakable input (#1173)
- clean SIGTERM during weight load: shutdown-aware loader, benign
cancelled-load classification, lifespan hardening, scoped log
silencers (transformers load + alembic fileConfig) (#1174)
- broken ASR deep-imports (lightning_fabric) mark the engine
unavailable with a repair hint and fall through (#1185)
- uv cache + managed Python follow the chosen install drive on
Windows (cherry-picked cross-drive class fix + spaces/D: tests) (#1186)
- adaptive silence-removal ladder for quiet clone references; localized
actionable error for truly silent clips, all 21 locales (#1188)
- CHANGELOG: consolidated Unreleased into the quiet one-liner style
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* 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>
* Phase 4 Plan 04-01: SPIKE-01 GGUF — GO + Wave 1 integration
Integrates Serveurperso/OmniVoice-GGUF as a hardware-adaptive default
voice-cloning engine, with overridable fallback to the in-process
OmniVoiceBackend. Spike confirmed GO: the model is a clean quantization
of k2-fsa/OmniVoice (Apache-2.0 + MIT runtime, `omnivoice-lm` custom
architecture so it does NOT load in vanilla llama.cpp).
Pinned SHAs:
* Serveurperso/OmniVoice-GGUF revision: 361609388ae572a820d085185bbbe2a2aac4b30e
* ServeurpersoCom/omnivoice.cpp master: 886fc079838ca7400cb2b42b36e2a65aa1daabe8
Implements GGUF-01 (hardware probe) through GGUF-05 (default-engine
resolver with graceful fallback). The four `bin/omnivoice-tts-*`
artifacts are committed as zero-byte placeholders; the new CI matrix
job builds the real binaries per platform from the pinned commit SHA
and appends a SHA-256 manifest used by `is_available()` for tampering
detection (T-04-01). The macos-14 (Apple Silicon) slot is marked
`continue-on-error: true` because omnivoice.cpp publishes no
`buildmetal.sh` (Pitfall 1 / Assumption A1) — failure feeds into Task
3's GO/NO-GO call.
Quant override is allow-listed against quant_map.json entries only
(T-04-05). Argv is composed from typed Path objects rooted in
HF_HUB_CACHE; never uses `shell=True`. HF token redaction applies to
captured stderr before logging (AUTH-05 / T-04-04).
Tests: 36 new (8 hardware-probe + 13 GGUF engine + 6 settings_store
quant override + grep gate); 428 passed in full suite vs 402+ baseline.
ADR Status stays "Proposed (research-supported)" — Task 3 (human
checkpoint) flips to Accepted after CI produces real binaries and a
reviewer signs off on the GGUF-06 cross-hardware smoke.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci: install libopenblas-dev on linux-x86_64 omnivoice-tts build
The pinned omnivoice.cpp commit (886fc079...) ships a `buildcpu.sh`
that passes `-DGGML_BLAS=ON`. ubuntu-latest has no BLAS implementation
preinstalled, so the cmake configure step fails with
`Could NOT find BLAS (missing: BLAS_LIBRARIES)` and the job exits in
13 s before producing the linux-x86_64 binary.
macOS (Accelerate, built in) and Windows (BLAS off by default in the
ggml CMakeLists for non-APPLE platforms — the build script doesn't
invoke buildcpu.sh on those slots) are unaffected and stay green.
Adds a Linux-gated apt step to install libopenblas-dev + pkg-config
before the build, restoring cross-platform parity per the
CLAUDE.md "default features must work on every platform" rule.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(gguf): constrain ref_audio to project roots — block /etc/shadow on Linux
The GGUF engine's `_build_argv` previously validated ref_audio only via
`ref_path.is_file()` — i.e. "does this path exist?" That check is
platform-dependent: `/etc/shadow` doesn't exist on macOS (rejected
naturally), but it IS a real system file on Linux, so the validation
silently accepted it. CI's ubuntu-22.04 runner exposed the gap via
`test_generate_blocks_freeform_ref_audio`, which exists precisely to
guard the "freeform ref_audio path" attack surface.
Fix: confine ref_audio to one of three allowed roots before existence
checks:
- VOICES_DIR (user-saved voice profiles)
- DUB_DIR (per-job auto-clones extracted from source video)
- tempfile.gettempdir() (browser-upload temp files; existing
`cleanup_ref` flow in generation.py)
Anything outside those roots → FileNotFoundError, matching the existing
failure-mode contract callers handle. Existence check still runs after,
so the test's mocked subprocess.run is never reached and the test
passes deterministically on all three platforms.
Cross-platform parity (per CLAUDE.md 2026-05-20 rule): identical
behaviour on macOS / Windows / Linux — the allow-list is computed from
core.config which uses platform-specific path resolution but yields the
same logical "project tree" on every OS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(gguf): mark darwin-x86_64 binary build as experimental
GitHub's macos-13 (Intel) runner pool is heavily contended — PR #100
queued for 30+ minutes waiting on darwin-x86_64 while every other
platform finished in ~1m. Intel Macs are also fading hardware (Apple's
platform momentum is entirely on Apple Silicon), and the GGUF engine's
runtime already handles a missing binary gracefully (`is_available()`
returns False on Intel Mac with a "binary not bundled for this
platform" message, same path used for first-launch before any binaries
build).
`experimental: true` mirrors what darwin-arm64 (Metal) already has —
slot still runs and uploads its binary when successful, but a failure
or runner backlog no longer blocks merges. Keeps the GGUF engine
shippable across the dominant arm64 / Linux / Windows surface without
holding the inbox on a slow-runner queue.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>