tts-voice-creator-clone-and.../architecture/vocal-isolation.md
mARTin-B78 91843e95e6 feat(voices): optional vocal isolation for URL imports
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:50:14 +02:00

43 lines
3.2 KiB
Markdown

# Vocal isolation for URL/YouTube imports
Status: implemented behind a flag, default OFF. Goal: remove music/background from a downloaded
clip before trimming and cloning (`/api/download-yt` -> `/api/isolate-vocals` -> trim -> `quick-import-voice`).
## Findings (read-only inspection, 2026-10-04)
- App image: `python:3.11-slim-bookworm`, `requirements.txt` has no torch/onnx/demucs. The live app
container has no `torch` (`import torch` fails). It is `read_only: true`, `cap_drop: ALL`, 8 GB mem
limit, no GPU reservation. Source dirs are bind-mounted read-only.
- GPU/torch live in other service containers (tts-faster-qwen3-*, aligner, ...), not reusable: different
images, no shared API for source separation.
- There is no VAD, denoise or separation anywhere in the app today.
## Options
| Option | Footprint | Verdict |
|---|---|---|
| Demucs `htdemucs` (MIT code; weights MIT, ~80 MB, from dl.fbaipublicfiles.com via torch hub) in the main image | torch + torchaudio on ARM64 ~ 2-3 GB image growth | rejected: heavy, unconditional |
| Demucs in a separate sidecar container | no growth of main image, GPU optional | best long-term, but needs a new image, compose service and network contract |
| **Optional external Demucs CLI**, called as a subprocess, only when the flag is on and the binary + weights exist | zero deps in the main image; the owner picks where Demucs lives (venv on a bind mount, or a derived image) | **chosen** |
| Lighter: RNNoise/DeepFilterNet/spectral gating | small, but removes noise only, not music/singing | does not meet the goal |
Why the CLI: `demucs --two-stems=vocals -n htdemucs` is the stable public interface; no import-time cost,
no behaviour change when absent. ARM64: `torch`/`torchaudio` publish aarch64 wheels (CUDA wheels exist for
DGX Spark / GB10; CPU wheels work everywhere), `demucs` itself is pure Python (`pip install demucs`).
A sidecar can later expose the same CLI via `VOCAL_ISOLATION_CMD` (e.g. `docker exec ...` wrapper) without code changes.
## Safety rules
- `VOCAL_ISOLATION=1` required; otherwise the feature reports unavailable and the API answers 503.
- Available only if the command resolves AND the htdemucs weights file (`955717e8-*.th`) is already in
`$TORCH_HOME/hub/checkpoints` (default `~/.cache/torch`). The app never downloads weights: the owner
installs them once (documented in Manual.md). This prevents Demucs' silent first-run download.
- Input bounded to `VOCAL_ISOLATION_MAX_SECONDS` (default 900), runtime to `VOCAL_ISOLATION_TIMEOUT`
(default 900 s), one job at a time (409 when busy), client disconnect cancels and kills the process.
- Work happens in a private temp dir that is always removed; the result is converted to 24 kHz mono WAV
and registered as a new temp id. The original id is untouched (compare / undo in the UI).
- Subprocess started with an argument list (no shell); the path comes from the registry, never from the client.
## Contract
- `GET /api/version` gains `features.vocal_isolation: bool`.
- `POST /api/isolate-vocals {id}` -> `{id, duration}`. Errors: 400 bad id, 404 unknown id, 413 too long,
409 busy, 503 disabled/unavailable, 504 timeout, 500 failed (message without internals).
- Offline behaviour: fully local; no network access.