27 Commits
Author SHA1 Message Date
Palash Debnath 020febe327 Merge branch 'fix/review-2066' into fix/community-integration
# Conflicts:
#	CHANGELOG.md
2026-09-17 12:38:56 +05:30
Palash Debnath fc98d07b39 fix: integrate current main and finish review requirements for #2066 2026-09-17 12:10:32 +05:30
Palash Debnath 2a3257be78 fix: integrate current main and finish review requirements for #2075 2026-09-17 12:10:15 +05:30
Palash Debnath 9ca9f74255 Merge branch 'review/gpu-2149' into fix/linux-electron-setup-sidebar 2026-09-17 01:41:08 +05:30
Palash Debnath 5af8fe6967 Make Electron the default desktop and refresh setup documentation 2026-09-16 22:11:59 +05:30
Shivendra-CoherentandClaude Opus 5 64f74e0dd2 fix: keep the backend alive on pre-Ampere NVIDIA GPUs (#2135)
On a Tesla T4 the backend exited during the first /generate with no
traceback and no HTTP response, leaving the client with
RemoteDisconnected and every later call with ConnectionRefused. Three
separate defects combined, which is why none of the reporter's
workarounds helped.

1. torch.compile(mode="reduce-overhead") captures CUDA graphs. T4
   (sm_75) passed the existing arch gate, so capture was attempted and
   aborted the process from inside the native CUDA library — below the
   interpreter, where neither the #278 eager-fallback wrapper nor any
   except clause can see it. The compile mode is now resolved per GPU:
   Ampere (sm_80) and newer keep the cudagraph mode, older cards drop to
   the non-cudagraph "default" mode and keep their compiled Inductor
   kernels. Fails open on any probe error, so no GPU that works today
   loses the optimization. OMNIVOICE_FORCE_CUDAGRAPH=1 restores it.

2. should_torch_compile() never read TORCH_COMPILE_DISABLE. main.py sets
   it on win32, build_engine_env injected it into subprocesses, and
   docs/install/windows.md tells users to export it — but the in-process
   gate ignored it, so the reporter exported the documented variable and
   still got "torch.compile applied". The gate now honours
   TORCH_COMPILE_DISABLE / TORCHDYNAMO_DISABLE / TORCHINDUCTOR_DISABLE on
   every platform, and an env opt-out on the parent propagates to engine
   subprocesses. The settings DB path is logged alongside the toggle:
   the reporter had three omnivoice.db files and edited one the backend
   never opened.

3. Settings -> Performance -> "Disable torch.compile" was rendered
   disabled outside Windows in both the Tauri and Electron UIs, so the
   one control that would have stopped this was unreachable for the
   affected Linux user. The toggle is now live on every platform, and
   build_engine_env honours it everywhere rather than only on win32.

Also arms faulthandler before torch is imported, so a fatal native
signal writes the faulting thread's Python stack to backend_err.log
instead of the process vanishing silently. This does not prevent a
crash; it makes one diagnosable. OMNIVOICE_DISABLE_FAULTHANDLER=1 skips
it.

Tests fail before / pass after, verified by stashing the source and
running the new tests against unfixed code. The crash test kills a real
child interpreter with a real SIGSEGV and requires a named Python frame
in the output. test_torch_compile_path_gate's fixture now clears the
compile-disable env vars: main.py setdefaults them on win32, so on a
Windows runner they leaked into os.environ and decided those tests.

Not verified on real hardware — no Turing GPU available. The sm_80 floor
is inferred from the crash report and from docs/hardware-notes-tesla-t4.md,
which already flagged cudagraphs on T4 as attempted by default and never
evaluated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 17:20:09 +05:30
Palash Debnath 5cde34c113 fix(ci): prepare hosted Windows policy for non-admin MSI smoke 2026-09-07 18:20:43 +05:30
Palash Debnath e1e96ae5a2 fix: preserve frontend resources during per-user MSI build 2026-09-07 16:41:20 +05:30
Palash Debnath 079be2fbe5 docs: describe automatic Windows MSI authoring validation 2026-09-07 11:52:41 +05:30
Palash Debnath 997ba9e673 fix(windows): author per-user MSI file keypaths and folder cleanup 2026-09-07 11:48:20 +05:30
Palash Debnath 0ed7d2ec22 chore(release): prepare v0.5.2 (#1761)
Synchronize VoiceStudio release metadata, lockfiles, installers, container references, documentation, and the dated v0.5.2 changelog after all planned fixes landed.
2026-09-02 10:26:14 +05:30
Palash Debnath 51bbf50ce3 Ship a supported per-user Windows installer (#1730)
Closes #1713

Adds a separately identified per-user MSI and updater channel, non-administrator install/uninstall verification, and fail-closed WebView2 handling for current-user installs.
2026-09-01 22:03:33 +05:30
Palash Debnath 9fe68ddb3f docs(installer): qualify fail-closed WebView behavior 2026-08-30 22:10:10 +05:30
Palash Debnath 2af47dbd4b fix(installer): make WebView2 download opt-in 2026-08-30 21:51:46 +05:30
Palash Debnath e1101255bd fix: make WebView2 MSI bootstrap controllable 2026-08-30 21:25:12 +05:30
Palash Debnath 7640f42dce feat(install): one-command installer URL (.sh + .ps1) + 3-OS install smoke (#1627)
* feat(install): one-command installer URL (.sh + .ps1) + 3-OS install smoke

- scripts/install.ps1: Windows source installer (winget deps, uv, bun,
  clone, uv sync, frontend build); honors OMNIVOICE_PYTHON/OMNIVOICE_REGION
- infra/install-redirect: Cloudflare Worker serving /install with
  User-Agent sniffing (curl -> sh, PowerShell -> ps1, browser -> landing
  page); proxies live from main; /install.sh + /install.ps1 aliases
- scripts/install.sh: fix stale advertised URL (main/install.sh never
  existed) and repo-root resolution so a local run no longer clones a
  duplicate repo into ~/VoiceStudio (verified on macOS arm64)
- .github/workflows/install-smoke.yml: run both installers end-to-end on
  ubuntu/macos/windows when they change
- docs-sync: install one-liners lead each platform guide; STRUCTURE.md

(#1626)

* fix(install): don't let a failed bun download pass silently

curl | sh runs an empty script and exits 0 when the download fails, so
a bun.sh hiccup surfaced much later as 'bun: command not found' (seen
on the macos-latest smoke runner). Fetch to a temp file, verify, fall
back to npm -g bun when node exists, and die with the manual command.
Same post-install verification for uv.

* fix(install): UTF-8 BOM for install.ps1 + quiet-style changelog entry

- tests/scripts/test_uninstall_ping.py requires shipped PowerShell
  scripts with non-ASCII text to carry a UTF-8 BOM (Windows PowerShell
  5.1 mis-decodes otherwise); same treatment uninstall.ps1 already gets
- test_changelog_style caps entries at ~400 chars
2026-08-21 11:47:39 +00:00
Palash Debnath 95a35b8e07 feat(indextts): add native IndexTTS 2.5 support (#1485)
* feat(indextts): add native 2.5 sidecar support

* fix(indextts): preserve legacy language metadata

* docs(indextts): state model license terms accurately

* fix: preserve IndexTTS upgrades and duration controls

* fix: complete IndexTTS upgrade safeguards
2026-08-11 01:26:25 +00:00
Palash Debnath 0c82167839 feat(firstrun): let the user choose the portable folder (#766)
Portable mode put everything in OmniVoiceStudio-Data beside the app — the only storage row on the setup screen you could look at but not change, while installed mode had a picker for all three of its directories.

The pin had a reason: portable_base() is computed from the executable's location and never read from config, which is what makes a portable install self-discovering. A user-chosen folder breaks that, because the only record of the location would live inside the folder being located.

So it is recorded somewhere findable, in order: a portable.path marker beside the app; then portableDir in the per-user config for app folders that are read-only; then the historical default, so existing portable installs resolve byte-identically.

The marker stores a RELATIVE path whenever the folder sits inside the app's own directory — the USB-stick case portable mode exists for, where app and folder move as a unit and the mount path is free to change. Anywhere else only an absolute path can be stored, and the setup screen says the install is tied to it rather than promising portability it cannot keep.

Two traps worth naming, both caught in review: the per-user fallback would recurse forever through load_config (config_path to portable_config_file to portable_base), so it reads the platform config file directly; and clear_portable_dir was reading through that same chain, silently failing to clear the machine record so the old folder kept winning after the user chose the default.

This also retires the greyed-out Portable option after a default Program Files install (#766) — you point it at a writable disk and get the machine-bound variant.

Rust 109 passed, frontend 1705 passed. All 21 locales in lockstep; docs/install/windows.md rewritten.
2026-08-07 07:52:05 +05:30
Palash Debnath 5cab8e0149 feat: rename the product to VoiceStudio (previously OmniVoice-Studio)
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.
2026-08-07 01:30:58 +05:30
Palash Debnath a23e69d014 chore: point every repo reference at github.com/debpalash/VoiceStudio (#1394)
The repository was renamed. 724 references across 59 files now point at the new URL — README badges, docs, install guides, the updater's releases API call, CONTRIBUTING, the Colab link and the probe harness. GitHub redirects the old URLs, so nothing was broken in the meantime.

Deliberately NOT renamed, because each breaks something on a user's machine: the Tauri bundle identifier (the path to every existing user's data), /usr/lib/omnivoice-studio and the compose container names, and the published Docker image paths.

The image path needed a code change to STAY still: docker.yml derived it from github.repository, so the next build would have published to ghcr.io/debpalash/voicestudio while Docker Hub, a hardcoded literal, stayed put — everyone pulling the documented GHCR path would have kept receiving the last pre-rename image forever. It is now pinned, with a test that fails if it ever derives from the repo name again.

Also makes the probe's repo-name assertion shape-based: it hardcoded the old name and failed on every PR after the rename while the code it tests worked perfectly.
2026-08-06 18:15:56 +05:30
debpalashandClaude Fable 5 933743e336 fix: resolve open issue batch — #1172 #1173 #1174 #1185 #1186 #1188
- 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>
2026-07-19 04:29:33 +05:30
1808a373a1 fix(linux): AppRun workaround detection reads the BUNDLED WebKitGTK version, not the host's (#961 follow-up) (#1024)
The launcher decided whether to export WEBKIT_DISABLE_COMPOSITING_MODE
by asking the host's pkg-config — but LD_LIBRARY_PATH makes the
BUNDLED libwebkit2gtk the one that actually runs, so on any machine
where the two diverge the detection read the wrong number. This was
the second bug identified during #961's investigation (the reporter
built from source, so their dev packages answered pkg-config with a
healthy version while the shipped bundle ran an older lib) and was
explicitly deferred in #1007 as not-safely-fixable at runtime.

The fix makes it knowable by construction instead: inject-apprun.sh
runs at bundle time ON the build host whose libwebkit2gtk gets
bundled, so it stamps that version into .bundled-webkitgtk-version
inside the AppDir. AppRun reads the stamp first and only falls back to
host pkg-config for bundles predating it. Empty/unreadable stamp fails
safe (workaround on), same philosophy as the missing-pkg-config path.

Tests: 3 new cases in AppRun.test.sh — marker-beats-host in both
directions (broken-marker/healthy-host and the #961 inversion,
healthy-marker/broken-host) plus empty-marker fail-safe. Also wires
AppRun.test.sh into pytest (tests/test_apprun_launcher.py) — it was
previously run by NO CI job, so the launcher could regress silently.

Also documents Windows install-to-another-drive behavior in
docs/install/windows.md (#938): local drives work via the wizard's
directory picker, mapped network drives are a Windows Installer
limitation, and the data directory moves independently of the app.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 03:53:46 +05:30
4aa9abe22a docs+scripts: install fixes — desktop-prod tauri resolution, Ubuntu white-screen guidance, honest GPU/prereq docs (#960 #961 #962) (#964)
* docs+scripts: install fixes — desktop-prod tauri resolution, Ubuntu white-screen guidance, honest GPU/prereq docs (#960 #961 #962)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(changelog): add the install-fixes batch under [Unreleased] (#964)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 19:34:01 +05:30
be1ec3ade0 fix(platform): declare Intel-Mac local backend unsupported — honest first-run gate + docs (#889); Windows portable-install docs (#766 follow-up) (#891)
torch >=2.3 ships no macOS x86_64 wheels (transformers 5.x needs torch >=2.6),
so `uv sync` can never resolve on an Intel Mac — per the platform-parity rule
the honest option is declaring the platform unsupported, not letting first
launch die in a raw resolver error:

- bootstrap.rs: pre-check on macOS x86_64 before any venv create / uv sync
  (first-run AND repair paths) fails fast with an actionable message
  (remote-backend escape hatch + docs link); healthy pre-torch-bump venvs are
  deliberately untouched. Unit test pins the message's load-bearing phrases.
- BootstrapSplash: routes the failure to a dedicated localized hint
  (bootstrap.hint_intel_mac, all 21 locales) and suppresses the useless
  Retry-oriented hints for it.
- README + docs/install/macos.md (+ troubleshooting #9): every Intel-Mac
  support claim now says UI-installs-but-backend-cannot-run, including the
  from-source path (also broken); remote backend documented as the only use.
- release.yml: #889 note on the macos-15-intel leg — artifact is UI-only;
  keep-or-drop is an owner call, deliberately not changed here.
- docs/install/windows.md: new "Portable install (Windows)" section promised
  in #766 — custom MSI wizard folder / msiexec INSTALLDIR=..., what lives in
  OmniVoiceStudio-Data next to the exe, and the Program-Files-greyed-out why.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 18:22:37 +05:30
Deepak VishwakarmaandClaude Opus 4.8 de3d83f14b docs: add rust as prerequisite for from-source builds (#704)
Adds Rust/Cargo as a from-source build prerequisite across the linux/macos/windows install docs. Thanks @Deepakv2104.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 03:03:23 +05:30
Palash DebnathandClaude Fable 5 ea26893bfc fix(scripts): desktop-prod works from cmd/PowerShell via cross-platform launcher (#282) (#333)
`bun run desktop-prod` (and its :run/:upgrade/:pill/:run:pill variants)
invoked `bash scripts/desktop-prod.sh` directly. On Windows, cmd and
PowerShell have no `bash` on PATH unless Git Bash happens to be there,
so the documented from-source install path died with a cryptic spawn
failure before printing anything — the exact first step in issue #282's
repro.

Add scripts/desktop-prod.mjs, a tiny launcher (runs under bun or node):

- macOS/Linux: execs the bash script unchanged — zero behavior change.
- Windows: locates Git Bash via `where.exe bash`, well-known Git for
  Windows install paths, or derived from git.exe's location; explicitly
  skips C:\Windows\System32\bash.exe (the WSL launcher, which would run
  the script inside Linux and wipe/launch the wrong paths).
- No usable bash: prints an actionable error (install Git for Windows,
  use `bun run desktop`, or use the installer) instead of a spawn error.

All flags are forwarded untouched and the child's exit code is
propagated. scripts/desktop-prod.sh itself is unchanged, and
docs/install/windows.md now lists Git for Windows as a prerequisite
for from-source installs.

Refs #282

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:15:10 +05:30
Palash DebnathandClaude Opus 4.7 715766cb04 Phase 1 Wave 2: per-OS install docs + Settings UI + error→docs deeplinks (#94)
* docs(install): per-OS install pages + drift validator + CI gate

Splits the 600-line README install section into self-contained per-OS docs
under docs/install/{macos,windows,linux,docker}.md plus a Top-10
troubleshooting index. Each OS doc is end-to-end: a user opens it and
reaches a working app following only commands inside that file.

Adds:
- docs/install/{macos,windows,linux,docker}.md  (OS-specific install paths)
- docs/install/troubleshooting.md               (top 10 install errors)
- docs/engines/cosyvoice.md                     (closes #55 docs half)
- docs/features/diarization.md                  (pyannote license flow)
- docs/setup/huggingface-token.md               (3-source cascade guide)
- scripts/validate-install-docs.py              (INST-06 docs-drift gate)
- tests/scripts/test_validate_install_docs.py   (B-5: validator self-tests)
- .github/workflows/ci.yml step running the validator on every PR

Implements INST-02 (README routing), INST-03 (macOS Gatekeeper anchor),
INST-12 docs half (Windows torch-compile-oom anchor), DOCS-01..05.

The validator is a one-way diff: every `<!-- validate -->`-tagged line
in docs must appear in scripts/desktop-prod.sh after normalisation
(prompt-prefix strip, CRLF, trailing whitespace, blank-and-comment skip).
A `<!-- validate: skip -->` marker opts out for human-readability blocks.
Its own 10 unit tests catch regressions in the gate itself.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(deeplinks): links.py + error_docs_map (Python + TS mirror)

Adds the single source of truth for the project repo URL and the 4-class
error → docs taxonomy that both the in-app ErrorBoundary deeplink button
(Wave 2 Task 3) and the Phase 5 bug reporter will consume.

New:
- backend/core/links.py            — PROJECT_REPO_URL + BLOB_MAIN resolver
                                      (Tauri config first, pyproject fallback)
- backend/core/error_docs_map.py   — lookup(error_class) → docs URL
- frontend/src/utils/errorDocsMap.ts (TS mirror with classifyError helper)
- tests/backend/core/test_links.py + test_error_docs_map.py
- frontend/src/utils/errorDocsMap.test.ts

Resolves checker B-6 (links.py ownership) and Open Question #3 (which fork
the deeplinks resolve to — the Tauri updater endpoint wins, which points
at the desktop app fork debpalash/OmniVoice-Studio).

The TS BASE constant is documented as the second hardcoded URL drift site;
the keys-sync test (`test_keys_match_python_map` equivalent) guards the
4-class taxonomy contract between Python + TS halves.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(ui): Settings → API Keys panel + ErrorBoundary docs deeplink

Wave 2 AUTH-03 UI half + ErrorBoundary deeplink wiring.

ErrorBoundary fallback now renders an "Open docs for this error" button
that classifies the thrown Error message (heuristic: pkg_resources → 401 /
HfHubHTTP → WebKit / white screen → quarantine / Gatekeeper) and opens the
matching docs anchor via Tauri shell.open (with a window.open fallback
in browser dev mode).

ApiKeysPanel consumes the Wave 1 resolver state endpoint:
  - 3 source rows (App / Env var / HF CLI) with set/unset indicator,
    masked token preview, whoami username + green check
  - "Active" badge on whichever source is currently serving the cascade
  - App-row only: Save (POST /api/settings/hf-token) +
    Clear (DELETE with optional "also clear HF CLI" confirm dialog)
  - "Test now" button refetches state (invalidates the resolver's
    validation cache via the same endpoint hit)

Panel mounted in the existing Settings → Credentials tab; the legacy
HF_TOKEN row from CREDENTIAL_FIELDS is filtered out so the two paths
don't fight over the same key.

Threat T-02-02: the panel never displays the full token. The masked
value comes from the resolver state endpoint; the full token only
crosses the IPC boundary on Save (POST) and is cleared from local
state on success.

Closes AUTH-03 fully (Wave 1 backend + this Wave 2 UI).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(perf): INST-12 Disable torch.compile (Windows) toggle (backend + UI)

Wave 2 Task 4 — full INST-12 delivery per checker B-2/B-7 v0.3.0 fat-release
decision. Both the docs half (windows.md anchor, shipped in earlier commit)
and the runtime toggle are now in Phase 1.

Backend:
- backend/services/settings_store.py: adds get_text/set_text helpers for
  non-secret config (refuses to write to the encrypted hf_token key).
- backend/api/routers/settings.py: GET + PUT
  /api/settings/perf/torch-compile-disabled, both under the existing
  loopback guard (threat T-02-04).
- backend/services/engine_env.py: new `build_engine_env()` helper that
  centralises HF_TOKEN/YOUR_HF_TOKEN injection from the 3-source resolver
  AND injects TORCH_COMPILE_DISABLE=1 when the flag is set on win32.
  Phase 2 SubprocessBackend launchers should adopt the same helper.
- backend/services/sonitranslate.py: migrated to engine_env.build_engine_env()
  while preserving the source-level `env["HF_TOKEN"]` sentinel that
  test_sonitranslate_module_uses_resolver checks.

Frontend:
- frontend/src/components/settings/PerformancePanel.{jsx,css,test.jsx}:
  toggle UI with the explainer for #65; renders disabled with a "not
  applicable" badge on macOS/Linux.
- frontend/src/pages/Settings.jsx: mounts the panel into the Credentials
  tab alongside the API Keys panel.

Tests:
- tests/backend/test_perf_settings.py: 7 backend tests (default state,
  PUT persistence, T-02-04 non-loopback rejection, settings_store round-
  trip, env injection on win32, NO injection on macOS/Linux, NO injection
  when disabled).
- frontend PerformancePanel.test.jsx: 5 tests (renders from GET state,
  PUT on toggle, disabled on non-Windows platforms, pre-enabled state).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(planning): Wave 2 SUMMARY + REQUIREMENTS status updates

- .planning/phases/01.../01-02-SUMMARY.md: full implementation report
  per template (truths, commits, tests, deviations, drift-site
  acknowledgments per W-3, launcher seam name for Phase 2,
  taxonomy keys for Phase 5).
- .planning/REQUIREMENTS.md: flips Wave 2 closures to Done:
    AUTH-03, INST-02, INST-03 (docs half), INST-06, INST-12,
    DOCS-01..05.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 06:22:10 +05:30