Files
VoiceStudio/docs/engines/disk-usage.md
T
mergetestandClaude Opus 4.8 3777d3a62c feat(tts): add MOSS-TTS-v1.5 (8B) and dots.tts (2B) as opt-in engines (#498)
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>
2026-06-20 00:02:27 +05:30

3.7 KiB

Engine venvs & disk usage

Most engines run in-process in OmniVoice's main environment. A few (IndexTTS2, MOSS-TTS-v1.5, dots.tts, and any engine whose dependencies conflict with the parent's torch/transformers pins) run in a dedicated sidecar venv so their pins can't break the rest of the app. Those sidecars are where disk adds up — this page explains why, and how the on-disk cost is kept down.

Why a sidecar needs its own venv

IndexTTS2 pins transformers<5, but OmniVoice requires transformers>=5.3. You can't have both in one environment, so IndexTTS2 gets its own venv created on first use (uv venv + uv pip install, see backend/engines/indextts/bootstrap.py). The cost is a second copy of the heavy ML stack — most of which is torch + the bundled CUDA libraries.

How big is "a second torch"?

Measured (2026-06):

Platform torch CUDA wheel + bundled CUDA libs
Linux (cu128) ~0.83 GiB several GiB of nvidia-* packages on top
Windows (cu128) ~3.2 GiB (DLLs bundled in the wheel)

So a sidecar that pins a different torch version than the parent is a multi-GB add. A sidecar that pins the same torch + CUDA build shares almost all of it (see below).

uv dedupes identical wheels — for free, with one condition

uv installs packages by linking from a global wheel cache into each venv's site-packages. The link mode:

  • macOS + Linuxclone (copy-on-write reflink). N venvs that install the same wheel share the bytes until one is modified — effectively one copy on disk.
  • Windowshardlink. Same effect on a single volume.

The one condition: the cache and the venv must be on the same filesystem. If UV_CACHE_DIR lives on a different drive than the engine venvs, uv falls back to a full copy (no dedup, slower). Keep them together.

Dedup is per identical wheel. torch==2.6.0+cu124 and torch==2.8.0+cu128 are different wheels → zero sharing → a full extra multi-GB copy. The single biggest disk decision for a sidecar is therefore: pin the same torch build as the parent whenever the engine allows it. When it doesn't (IndexTTS2's transformers<5 forces an older torch line), the second copy is the unavoidable price of isolation — not a bug.

The opt-in #498 engines illustrate both sides: dots.tts pins torch==2.8.0 — the same build the parent constrains to — so it shares almost all of torch with the main venv and only its transformers==4.57 + model deps are new. MOSS-TTS-v1.5 pins torch==2.9.1+cu128, a different build, so it pays a full extra multi-GB torch copy on CUDA hosts (the price of running an 8B model whose stack pins transformers==5.0).

On Linux, the nvidia-* CUDA packages are separate wheels, so even across different torch versions any nvidia-* whose pinned version happens to match is still shared. On Windows the CUDA DLLs live inside the one torch wheel, so nothing is shared across torch versions.

Practical guidance

  • Keep UV_CACHE_DIR and the engine venvs on one filesystem (the default — both under your home dir — already satisfies this).
  • On Linux ext4 (no reflink), export UV_LINK_MODE=hardlink guarantees dedup on any single filesystem; the default clone only dedupes on reflink-capable filesystems (XFS-with-reflink, btrfs, APFS).
  • Reclaiming space: deleting a sidecar venv (backend/engines/<id>/.venv/) frees its unique files; shared cache bytes stay until uv cache prune.
  • Forward-looking: PyTorch's experimental wheel variants (shipped in 2.8) will eventually let uv install torch auto-pick the right CUDA build, and uv already exposes --torch-backend=auto.