# PersoDub: local voice-cloned dubbing, with the Docker route marked untested

> A desktop application that drops a video in and gets a dubbed video back in each speaker's own voice, running Demucs, Whisper, CAM++ and Qwen3-TTS on your own machine. Ten languages work offline and 77 need a cloud key, and both the Dockerfile and the compose file carry a note saying the container path is untested.

**stronghamjji/PersoDub** — 100% local video dubbing on your desktop — dub videos in your own voice. Private AI dubbing with no cloud, no uploads, no time-stretching.

- Repository: https://github.com/stronghamjji/PersoDub
- Website: https://github.com/stronghamjji/PersoDub#hear-the-difference
- Stars: 44 · Forks: 5
- Language: Python
- License: AGPL-3.0
- Published: 2026-08-24 · Updated: 2026-08-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/stronghamjji-persodub

## Both container files say the docker path is untested

The most useful thing in this repository is a pair of warnings. The Dockerfile opens with a note dated 2026-07-30 stating that the Docker route is currently untested, and the compose file repeats it. Both name the same root cause: the app expects five separate subprocess interpreters, `SEP_PYTHON`, `DIAR_PYTHON`, `STT_PYTHON`, `QWEN_SCORER_PYTHON` and `NONVERBAL_WHISPER_PYTHON`, defined in `app/config.py`, and neither container builds or mounts them. Without those, the compose note says, local separation, diarization, speech to text and take scoring all fail inside the container. Both files name the alternative in the same words: the supported way to run the app today is the local `uvicorn` command documented in the README. Each file also asks to be updated once the docker path is verified end to end.

## The container is a thin shell around models that live elsewhere

What the images do build is deliberately small. The Dockerfile starts from `python:3.11-slim`, installs ffmpeg so the final video length can be guaranteed in a step called `ensure_video_length`, copies `app`, `static` and `ui`, and starts `uvicorn app.main:app` bound to `127.0.0.1` on port `8860`. Copying `ui` is not optional: a comment notes that `app/main.py` mounts `ui/src` at import time and the container dies on startup without it. The compose file adds an Ollama service for translation on `127.0.0.1:11434`, bound to loopback only and limited to GPU 0 through `NVIDIA_VISIBLE_DEVICES=0`, with the model store mounted from an absolute host path you have to edit yourself. The app service uses `network_mode: host` so it can reach the Qwen3-TTS sidecar and Ollama over localhost, which is also why the compose file describes the app as a lightweight orchestrator.

## Two dependencies are pinned for reasons that are written down

`requirements.txt` is short, with fastapi, uvicorn, httpx, requests, google-auth, python-multipart, pytest, yt-dlp and `mcp==2.2.0` at the top level, and two entries carrying comments longer than the requirement itself. `static-ffmpeg` is pinned to exactly `3.0`, because the ffmpeg install step parses that package's function return shape and an upstream change must not reach a fresh install unpinned; 3.0 is the version a device install produced on 2026-09-03. `huggingface_hub[cli]` is bounded at `>=0.34,<1.0` because the model downloader in `app/models.py` shells out to the `hf` CLI, that CLI arrived in 0.34, and the upper bound keeps the flags the code was verified against. Both packages used to live in the engine virtual environments and were moved into the app environment in 2026-09, on the reasoning that the app environment is the one that always exists.

## The package says 0.1.0 while the releases say 0.7.0

Two version numbers coexist and they are not the same thing. The published releases are v0.7.0 on 29 September 2026, v0.6.5 on 22 September 2026 and v0.6.4 on 21 September 2026, which track the downloadable desktop builds. The `pyproject.toml` at the root declares `version = 0.1.0` for the Python package named `persodub`, described as voice-cloned video dubbing that runs locally. The gap is not explained in either file, so anyone pinning the Python distribution and anyone pinning the installer are pinning different numbers. The same file does explain its Python bound precisely: `requires-python = ">=3.11,<3.13"`, because the supported product is the Mac desktop app whose kit runs Python 3.11, and six modules import `audioop`, which was removed in Python 3.13.

## The lint configuration is a ratchet with counts attached

The `ruff` block in `pyproject.toml` is unusual enough to be worth reading closely, because the comments treat the debt as a work queue. The line length is set to 120, with the note that there are 21 violations at that width, that dropping to 100 would produce 175, and that the longest line in `app/` is 142. The target version is `py38`, described as a conservative floor since the code is written to the 3.8 standard library while running on the kit's 3.11. The selected rule families are `F`, `E`, `W`, `I`, `B`, `C4`, `RET`, `SIM`, `UP`, `PLE` and `PLC`, and the ignore list is called a ratchet list of real findings deferred so the build starts green. `B904` carries the count 8 for raising without `from` inside an except block, and `SIM115` carries 9 for `open()` calls without a context manager. The stated principle is that a green build always means you just broke something.

## The models arrive on the first dub, not at install

Disk usage is split across two moments, and the split is worth planning around. The application itself is under 1 GB. Python, PyTorch and the models download on your first dub rather than during installation: about 9 GB on a Mac, 16 GB on a Windows PC with an NVIDIA GPU, and 9 GB without one. The stated requirements are an Apple Silicon Mac or 64-bit Windows, 16 GB of memory and 30 GB of disk. Rather than spell that out as a checklist, the project hands you a prompt to paste into Claude Code, Codex or any coding agent:

```text
Install PersoDub on this computer and check that it works.
Repository: https://github.com/stronghamjji/PersoDub

1. Check my OS, CPU, memory, free disk and GPU. PersoDub needs an Apple Silicon Mac
   or 64-bit Windows 10/11, 16 GB of memory and 30 GB of free disk.
   If this computer falls short, say so and stop.
2. Install the latest release for my OS:
   https://github.com/stronghamjji/PersoDub/releases/latest
   On Windows, run the installer with /S so no wizard opens.
   If SmartScreen warns (not code-signed yet): More info, then Run anyway.
3. Open PersoDub and wait for the first
```

Note what the prompt authorises: a silent install on Windows, and an instruction to stop rather than continue on a machine that falls short.

## macOS is notarized, Windows is not signed yet

The two platforms differ in a way that is stated plainly rather than buried. On macOS you open the `.dmg` and drag PersoDub into Applications; it is signed and notarized, so it opens on a normal double-click and checks for updates on launch. On Windows you run the `.exe`, which installs for your user account only, and it is not code-signed yet, so SmartScreen shows "Windows protected your PC" on first launch. The documented way past it is to click More info and then Run anyway. The project also asks that downloads come only from its own releases page and states that the GitHub repository is the only official source, which is a reasonable thing for a project distributing an unsigned binary to say out loud.

## Ten languages locally, seventy seven with a key

The capability split is the heart of the product and it is honest about being a split. Dubbing works on your own computer in 10 languages, and 77 become available with Perso's cloud. Translation is either a local model or ChatGPT, free, with no subscription involved. A free Perso key is described as buying better transcription and less to download, which is a smaller claim than a subscription. The pipeline is named in one line: Demucs for separation, Whisper for transcription, CAM++ for diarization, a local LLM or ChatGPT for translation, and Qwen3-TTS for synthesis. Licensing is asymmetric and worth reading closely. Current work is AGPL-3.0, where distributing a changed version or running one as a service shares the changed source under the same terms, while releases up to 0.6.5 were published under Apache 2.0 and stay that way.

## Conclusion

Use PersoDub if you are dubbing short clips on an Apple Silicon Mac or a 64-bit Windows machine with 16 GB of memory and 30 GB of disk, and you want the footage to stay on the machine. Do not plan around the container images, because both the Dockerfile and docker-compose.yml say in terms that the docker path is untested and that the supported route is a local uvicorn command. Before installing, confirm your board qualifies for the local language set, read docs/privacy.md to see what the optional Perso key sends, and remember the licensing asymmetry: current work is AGPL-3.0 while releases up to 0.6.5 remain Apache 2.0.

## FAQ

### Is PeerTube safe to use?

The README does not mention PeerTube. PersoDub is a desktop application for video dubbing that clones each speaker's voice locally, running Demucs, Whisper, CAM++ and Qwen3-TTS on your own computer, and it states that by default your video never leaves that computer.

### Is PeerTube free to use?

Nothing in the README covers PeerTube. What it says about cost for PersoDub is that translation uses a local model or ChatGPT for free with no subscription, that a free Perso key adds better transcription, and that the software is licensed AGPL-3.0 with releases up to 0.6.5 remaining Apache 2.0.

### How much disk does PersoDub need?

The application is under 1 GB, and the Python, PyTorch and model downloads happen on the first dub: about 9 GB on a Mac, 16 GB on a Windows PC with an NVIDIA GPU and 9 GB without one. The stated requirement is 16 GB of memory and 30 GB of free disk.

### Can I run PersoDub in Docker?

Not according to the project's own notes. The Dockerfile and docker-compose.yml both state, with a note dated 2026-07-30, that the docker path is untested, because neither builds or mounts the five subprocess interpreters app/config.py expects. The supported route today is the local uvicorn command.

## Sources

- [Official documentation](https://github.com/stronghamjji/PersoDub#hear-the-difference)
- [Official README](https://github.com/stronghamjji/PersoDub#readme)
- [Project repository](https://github.com/stronghamjji/PersoDub)
- [Release notes](https://github.com/stronghamjji/PersoDub/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stronghamjji-persodub
