* docs: polish README hero hierarchy
* docs: enrich README with audio samples, hardware guide, and doc links
* docs: address review findings on Docker port binding, MCP transport, and privacy
* docs: address CodeRabbit review feedback on cURL format and Colab links
* docs: align Docker quick-start with stable tag and named volume mount
* docs(engines): a guide for every engine + index; fix two engine-metadata bugs
21 new pages under docs/engines/ (10 TTS, 10 ASR, index README) — every
registered engine now has one: what it's for, platform support, model env
vars, quirks with issue refs. Linked from both READMEs' engine sections.
Code fixes found while verifying facts against the registries:
- KittenTTS docstring claimed default voice 'Jasper'; the code default is
expr-voice-2-f
- the isolated-ASR sidecar read only ASR_MODEL_FW while the download
preflight read ASR_MODEL_FASTER — set one and the other quietly used a
different model; both now resolve ASR_MODEL_FW-override → ASR_MODEL_FASTER
- moonshine's install hint named 'useful-moonshine', a package the backend
never imports; now moonshine-onnx / moonshine-voice
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(changelog): entries for the engine guides + sidecar model fix (#1556)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(engines): second-harvest fixes — TLS guidance, matrix/code alignment, CN counts
- README matrix aligned to gpu_compat (the code is the source of truth):
CosyVoice macOS is CPU not MPS, IndexTTS and GGUF gain their real
CUDA/CPU/MPS cells
- gpt-sovits guide: prefer https/tunnel for non-loopback servers, plaintext
warning; first-use download guidance on both OmniVoice pages
- preflight empty-env fallback matches the sidecar (ASR_MODEL_FASTER='' no
longer resolves a different repo)
- nano installs via uv pip; kitten log level wording; index links install
guides incl. the Gatekeeper step; README_CN engine counts 16/11
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(readme-cn): the all-engines-local claim now excludes the remote client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* docs(readme): lead with download + first clone; seed benchmarks page
Quickstart (installers, install guides, a three-step first-clone walkthrough)
moves above What's-new/Features in both READMEs — visitors get the action
before the pitch. New docs/benchmarks.md anchors measured per-engine/device
numbers on the bench_pipeline.py harness, community-contributed, no estimates.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(changelog): entry for the README conversion restructure (#1555)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(bench): emit RTF + CUDA peak VRAM; guard NaN RAM; define the benchmarks schema
Bot harvest on #1555: the tts stage now prints RTF per warm measurement and
CUDA peak VRAM (None elsewhere — no made-up zeros), the stage floor refuses
unmeasurable RAM instead of sailing past a NaN comparison (FLOOR_GB=0
overrides), docs/benchmarks.md columns map 1:1 to what the harness prints,
and the download badges say they open the release page.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(readme): link palash.dev from the maker section
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(bench): name the resolved engine, track VRAM from resolution, comment the guards
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(readme): the quick-switch gif is the hero image
The hero shows motion now; the Launchpad screenshot moves into the 0.5.0
What's-new slot so nothing appears twice.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(bench): peak VRAM is reserved memory; adapter engines name their model
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(bench): subprocess-isolated engines report VRAM n/a, not a parent-side zero
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(bench): out-of-process detection is declarative; sherpa rows name their model
'runs_out_of_process' is now a TTSBackend attribute set by SubprocessBackend
AND omnivoice-gguf (which inherits TTSBackend directly but spawns a binary
per generate — the isinstance check missed it). Duck-typed for the same
module-purge reason as _is_subprocess_isolated. Sherpa-onnx identity comes
from _model_dir's basename when _model_id is absent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(bench): backends self-report model identity via TTSBackend.model_identity()
Greptile enumerated the adapter engines one at a time (mlx _model_id,
sherpa _model_dir, cosyvoice env-only) — the attribute sniffing rots per
engine. The hook fixes the class: each multi-model backend reports its
own identity, the profiler just asks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
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.
GitHub natively recognizes CONTRIBUTING.md, SECURITY.md, SUPPORT.md, and
CODE_OF_CONDUCT.md in .github/ (Contributing link, Security policy tab, and
the community profile all keep resolving), so relocate the four there and
drop four files from the repo root.
Reference fixes in the same commit (no broken links):
- README.md / README_CN.md → .github/CONTRIBUTING.md
- docs/migration/real-time-voice-cloning.md → ../../.github/SUPPORT.md
- SUPPORT→SECURITY link unchanged (both now in .github/, same dir)
- tests/test_issue_fixes.py Discord-link check repointed to .github/
CONTRIBUTING.md (a missing path would silently skip, dropping coverage)
- CLAUDE.md docs-sync rule paths updated to match
Kept at root by design: README/LICENSE/CHANGELOG/CLAUDE/AGENTS (required or
convention), SPONSORS.md (wired to absolute GitHub URLs in FUNDING.yml, the
sponsor issue template, and sponsors.js), LICENSE-NOTICE.md (pairs with
LICENSE), README_CN.md (README translation, 29 relative links).
Also ignore the local memxt agent-memory DB (memxt.db*) so it stops sitting
loose in the working tree.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extends notebooks/OmniVoice_Studio_Colab.ipynb (setup cells 1-7 unchanged —
owner-verified on a real T4) with a Part 2 feature tour: one self-contained,
idempotent cell per feature, inline playback, honest runtime notes, loud
failures pointing at the backend log. Covers multilingual TTS (/generate),
zero-shot cloning (ref_audio multipart, incl. a commented own-voice upload
variant), voice design (/design/describe -> instruct), voice profiles
(save/list/reuse by id), TTS->ASR round trip (/transcribe), AI-watermark
detection with a generated-vs-plain-tone contrast (/watermark/*), the
OpenAI-compatible /v1 audio API via the official openai client, a two-voice
story (/longform/render SSE), a chaptered m4b audiobook (/audiobook SSE),
an optional miniature EN->ES video dub (upload -> prep poll -> transcribe ->
translate -> generate -> mux), and vocal-isolation stems off the dub job.
Every endpoint verified against the router sources and the 254-route
inventory. README/README_CN section text and the CHANGELOG entry now
describe the expanded scope.
Docs-sync for the first-run analytics consent work:
- README + README_CN FAQ ('Does OmniVoice collect any data?'): the app now
ASKS on first run; still nothing without an explicit yes; lists the new
event kinds (install/update/crash/error-type/uninstall ping) and that
source builds never even ask.
- CLAUDE.md: the Local-first constraint bullet and the 'no third-party
telemetry endpoints' note now reflect the owner-sanctioned reality
(opt-in PostHog EU product analytics behind the first-run prompt,
2026-07-16); auto BUG REPORTING stays GitHub-prefill only.
- backend/api/routers/system.py: the /stats/usage comment claimed PostHog
was rejected outright (PR #1110) — reworded: this endpoint stays local
regardless of consent; the consent-gated path lives in core/analytics.py.
- CHANGELOG [Unreleased]: user-facing entry for the consent prompt + new
lifecycle events.
notebooks/OmniVoice_Studio_Colab.ipynb boots the full app (web UI included)
on a free Colab T4: frontend built in-notebook with bun (releases ship no
standalone web bundle), backend installed via 'uv pip install --system .'
(the Docker image's path — keeps Colab's preinstalled CUDA torch), cuDNN 8
compat via scripts/setup.py, UI exposed through Colab's built-in kernel port
proxy (cloudflared alternative documented in-cell). Optional HF-token cell
reads Colab Secrets; smoke-test cell hits /health and plays a real /generate
WAV inline. All cells idempotent and fail loudly with actionable messages.
README.md + README_CN.md: the Colab section now carries the Open-in-Colab
badge for the in-repo notebook. CHANGELOG: [Unreleased] Added entry.
Adds two zero-shot voice-cloning TTS engines requested in #498, both
opt-in and subprocess-isolated with their own dedicated venv — the same
pattern as IndexTTS-2. The dedicated venv is forced, not just chosen:
each upstream pins a transformers version that conflicts with the
parent's >=5.3 (MOSS-TTS-v1.5 ==5.0.0, dots.tts ==4.57.0), so they cannot
share the parent interpreter.
Because they use the clone+venv bootstrap (env var -> clone -> uv venv),
this touches no pyproject.toml / uv.lock / bun.lock — `uv sync
--all-extras` and Docker's `bun install --frozen-lockfile` are unchanged,
so main's CI/Docker matrix stays green.
Engines:
- moss-tts-v15: 8B, 31 langs, ~16 GB weights, 24 kHz. AutoModel/
AutoProcessor via trust_remote_code. gpu_compat=(cuda,cpu) — MPS is
undocumented/untested upstream so it is never claimed; on a Mac it runs
on CPU. Apache-2.0, no license gate.
- dots-tts: 2B, 24 langs, ~9 GB weights, 48 kHz. DotsTtsRuntime;
continuation cloning (prompt_audio_path+prompt_text). Upstream is
Linux/macOS-only, so is_available() gates it off cleanly on Windows
(cross-platform parity rule — it is opt-in, never a broken default).
Wiring: registered in _LAZY_REGISTRY + _INSTALL_HINTS. list_backends()
surfaces both as subprocess/[cuda,cpu]/available-until-installed; the
data-driven Settings engine picker needs no frontend change.
Tests (19, fail-before/pass-after): registry resolution, subprocess
marker, no-MPS gpu_compat, the Windows gate, not-installed honesty, and
the parent-side generate() kwarg arbitration. Existing engine suite still
55 passed / 5 skipped. Sidecar inference follows the upstream-documented
APIs but, like IndexTTS/Supertonic, can't be executed in CI without the
multi-GB model clones.
Docs (same-PR per docs-sync rule): README + README_CN engine tables, new
docs/engines/moss-tts-v15.md + dots-tts.md, disk-usage.md (torch-dedup
note), CHANGELOG.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the Functional Source License with the GNU Affero General Public
License v3 across the project, with a paid commercial license retained for
proprietary/closed-source use without AGPL obligations (open-core, like
Firecrawl).
- LICENSE: verbatim AGPL-3.0 text under an AGPL Notice + Scope header;
drops the FSL "Competing Use" framing and the 2-year Apache-2.0 conversion.
The bundled omnivoice/ TTS model stays Apache-2.0 upstream (AGPL-compatible).
- Manifests now declare SPDX AGPL-3.0-only: pyproject.toml, Cargo.toml
(normalized from bare AGPL-3.0), and both package.json (added license field).
- README.md / README_CN.md: badge, pricing, commercial-use FAQ, License section.
- en.json: in-app Commercial License copy reworded to AGPL; the false
"converts to Apache 2.0" FAQ removed (+ its renderer block in SupportPage.jsx).
Non-English locale strings still describe the old FSL model and are left for a
follow-up translation pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* @
fix: skip torch.compile on Windows where Triton is unavailable
torch.compile with mode="reduce-overhead" depends on Triton, which has no
official Windows support. On Windows the compile call succeeds but generates
code paths that crash at inference time with an OOM-like error
("Cannot find a working triton installation").
Check for Triton availability before compiling so TTS gracefully falls back
to eager mode on platforms without Triton.
Closes#65
SummerSec
@
* feat: comprehensive Chinese (zh-CN) localization for Settings and navigation
Add full Chinese (zh-CN) translation support across the frontend:
- NavRail, Launchpad, Clone/Design tabs, Settings (all tabs)
- Sidebar navigation labels, hero text, action cards, section headings
- Fix: Settings missing General tab in TABS array
- Fix: i18n locale not persisted after page reload (useEffect deps)
- Fix: NavRail key prop spreading into JSX elements
Co-authored-by: SummerSec
* fix: translate production override parameter labels (Speed, t_shift, etc.)
* fix: translate voice design category labels (Gender, Age, Pitch, etc.)
* feat: translate Transcriptions and Voice Gallery pages
* fix: translate gallery category names (Disney, Anime, etc.)
* feat: translate DubTab, personality presets, and voice design presets
* fix: remove duplicated emoji in personality name translations
* fix: correct preset translation keys to match actual preset IDs
* fix: filter natural language from personality instruct to prevent validation error
* fix: handle edge case where instruct has no valid tags
* chore: remove debug logging from personality instruct filter
* fix: address CodeRabbit review — importlib.util, English comment, grammar, theme, placeholder
* fix: localize selected category label in VoiceGallery header
* feat: translate remaining DubTab UI text (CAST, Generate Dub, Translate All, etc.)
* fix: improve ffmpeg detection on Windows, error messages, and yt-dlp download timeout
* feat: add proxy setting in Settings → General for downloading via proxy
* fix: improve ffmpeg detection on Windows, error messages, and yt-dlp download timeout
* feat: allow HTTP_PROXY/HTTPS_PROXY env vars via /system/set-env
* fix: support SOCKS5 proxy, also set ALL_PROXY env var
* fix: increase yt-dlp extractor retries for subtitle 429 errors
* feat: translate prep overlay stage labels (download, extract, demucs, scene)
* feat: translate BatchQueue, VoiceProfile, ToolsPage, Projects pages
* feat: translate SetupWizard, DonatePage, EnterprisePage + fix NotImplementedError handling
* feat: add ffmpeg status + manual path setting in Settings → General
* fix: validate ffmpeg path exists when user sets it manually
* fix: fall back to thread-based subprocess when asyncio raises NotImplementedError on Windows
* fix: pin setuptools<70 — ctranslate2 requires pkg_resources removed in 70+
* fix: translate transcribing overlay text
* fix: complete DubTab zh-CN localization + argostranslate preflight check
* fix: add cmn-Hans language code mapping for Google Translate
* fix: fall back to thread-based pip install on Windows when asyncio subprocess raises NotImplementedError
* feat: add DeepL/Microsoft/LLM credential fields to Settings
* feat(i18n): localize GlossaryPanel, DubSegmentTable, DubSegmentRow
* fix: Windows-safe log rotation handler avoids PermissionError on rename
* feat: persist proxy/FFmpeg/LLM/translation credentials, separate DeepL/Microsoft keys, add glossary max-height scroll and collapse
- /system/set-env writes env.* to prefs.json via prefs.set_()/delete()
- Backend startup reads env.* from prefs.json into os.environ (.setdefault)
- PERSISTENT_KEYS covers proxy, FFmpeg, LLM, DeepL/Microsoft keys
- DeepL uses DEEPL_API_KEY, Microsoft uses MICROSOFT_API_KEY (fallback TRANSLATE_API_KEY)
- DeepL/Microsoft _build_translator reads DEEPL_BASE_URL/MICROSOFT_BASE_URL
- Google/MyMemory/Microsoft translators bypass Windows registry proxy
- Frontend CREDENTIAL_GROUPS splits into 4 groups with password/text fields
- Glossary panel body max-height: 35vh + overflow-y: auto
- Glossary panel can be collapsed via ChevronDown button
- queryClient.invalidateQueries after save for immediate refresh
- SystemInfoResponse adds proxy_url, ffmpeg_ok, ffmpeg_path
* feat(i18n): localize ExportModal with zh-CN support
- Add useTranslation + replace ~50 hardcoded strings with t() calls
- Add exportModal namespace to en.json and zh-CN.json
- Cover presets, tracks, tabs, video/audio/subs/package tabs, license notice, and output footer
* fix: address PR #66 security review feedback
- Regenerate uv.lock against pypi.org (remove TUNA mirror URLs)
- Route HF_TOKEN through huggingface_hub.login() instead of prefs.json
- Add os.chmod(prefs_path, 0o600) for restricted file permissions
- Add warning logs to _WindowsSafeRotatingFileHandler bare except blocks
* docs: add Chinese translation README_CN.md
* docs: add link to Simplified Chinese translation in README.md
* docs: add English/Simplified Chinese cross-links between READMEs
* fix(l10n): restore clickable Discord/email footer links in EnterprisePage
The i18n extraction replaced main's clickable <button onClick=openExternal>
footer links with bare {t()} labels, dropping both the clickable behavior
and the literal Discord URL — which broke test_discord_link_updated
(EnterprisePage missing discord.gg/bzQavDfVV9). Restore both as clickable
links wrapping the translated label, with the hardcoded URL/mailto (URLs are
not translated). Keeps i18n, restores functional parity with main.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(l10n): no-hardcoded-CJK rule + enforce; clean dead LLM block; harden set-env
- Add 'Localization (hard rule)' to CLAUDE.md: no hardcoded non-English UI
text outside frontend/src/i18n/; functional CJK allowed via allowlist.
- New tests/test_no_hardcoded_cjk.py enforces it (allowlists text-processing
regexes, model/engine vocab & IDs, error matching, demo/eval data, fixtures).
- Settings.jsx: remove dead saveLlm block (Chinese toasts + unused llm* state,
flagged by CodeQL js/unused-local-variable); render language-picker native
names from new LANGUAGES export in i18n/index.ts instead of hardcoding.
- main.py: drop unused 'import shutil' (CodeQL py/unused-import).
- system.py: harden FFMPEG_PATH/FFPROBE_PATH set-env (reject control chars;
defense-in-depth for the py/path-injection finding). Endpoint stays
loopback-only — network sharing must never expose /system/set-env.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: drop unused ui import (Panel) + fix implicit str-concat in cjk test
Clears the two CodeQL notes introduced/attributed to this PR:
- Settings.jsx: remove unused 'Panel' from the '../ui' import (js/unused-local-variable).
- test_no_hardcoded_cjk.py: collapse multi-line message strings to single lines
(py/implicit-string-concatenation-in-list).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: SummerSec <summersec@qq.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>