# Qwen3 Audiobook Converter Convert TXT, PDF, and EPUB files into audiobooks using the Qwen3-TTS voice model. This builds upon [WhiskeyCoder/Qwen3-Audiobook-Converter](https://github.com/WhiskeyCoder/Qwen3-Audiobook-Converter) adding more output files, support for faster backends, metadata, generated cover art, transcription/speed/language options, better text cleanup, and clearer instructions. The converter supports three TTS backends, selected with `--backend`: the original Qwen3-TTS Gradio demos (`gradio`, default), [faster-qwen3-tts](https://github.com/andimarafioti/faster-qwen3-tts) (`faster`), and [audio.cpp](https://github.com/0xShug0/audio.cpp) (`audiocpp`) — all serving the same Qwen3-TTS 1.7B model. ## Overview The converter sends text extracted from your books to a locally running Qwen3-TTS server and assembles the returned audio into a single audiobook file. - Input: `.txt`, `.pdf`, or `.epub` - Output: `.m4b`, `.mp3`, `.ogg`, or `.flac` - Supports [qwen-tts](https://pypi.org/project/qwen-tts/), [faster-qwen-tts](https://github.com/andimarafioti/faster-qwen3-tts), and [audio.cpp](https://github.com/0xShug0/audio.cpp) backend servers - Output a single file or one per chapter - Automatic metadata (title/artist/album tags, chapter track numbers) and a generated cover - Clone voices from .wav reference files or use the built-in speaker in the CustomVoice model. ## Prerequisites - Python 3.12 - ffmpeg - Enough VRAM to run the 1.7B model (~6GB) ## Installation ```bash conda create -n qwen3-tts python=3.12 -y conda activate qwen3-tts git clone https://git.historia.vg/git/qwen3-audiobook-converter cd qwen3-audiobook-converter pip install -r requirements.txt ``` Put your book files (epub, etc.) in the `input/` directory. The output goes to `output/`. You will also need to install one of the following backends (see below for installation/usage) | Backend | Description | | -------------------------------------------------------------------- | ------------------------------------------------- | | [Qwen-TTS](https://pypi.org/project/qwen-tts/) | Gradio server released by Qwen | | [Faster-Qwen-TTS](https://github.com/andimarafioti/faster-qwen3-tts) | Server with 2-8x faster inference for NVidia GPUs | | [audio.cpp](https://github.com/0xShug0/audio.cpp) | Newer C++ TTS backend that supports Qwen-TTS | ## Options | Flag | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------ | | `--format {mp3,m4b,ogg,flac}` | Output format (default `m4b`). `m4b` uses AAC audio and has built-in chapters. | | `--clone ` | Reference audio (`wav`) for voice cloning. | | `--transcription "..."` | Override whisper auto-transcription with manual audio transcript. | | `--no-transcription` | Skip auto-transcription of the reference audio. | | `--speed ` | Playback speed, pitch-preserving (`1.0` = normal). A normal-speed copy is also output. | | `--single-file` | Merge all chapters into a single file (default: one file per chapter). `m4b` is always one file. | | `--language ` | Output language for the synthesized speech. Can add an accent even if the text is English. | | `--backend {gradio,faster,audiocpp}` | TTS server to use (default `gradio`). `faster` and `audiocpp` require their server running first — see the backend sections above. | | `--voice ` | Voice to request from a server-side voice configuration (`--backend faster` or `audiocpp` only). | | `--chunk` | Force client-side chunking into `CHUNK_SIZE`-word requests. Only matters for `--backend audiocpp`, which otherwise sends each chapter as one request and lets the server chunk long text itself (may double-chunk); the `gradio` and `faster` backends always chunk. | | `--debug` | Troubleshooting: dump each chunk's raw audio and sent text to `debug/` and log every request. | Other options including backend server URLs/ports are configured in `converter/config.py` ## Backend Option 1: Qwen3-TTS Install qwen-tts with pip: ```bash conda activate qwen3-tts pip install -U qwen-tts ``` Run the backend with `qwen-tts-demo`. Add `--no-flash-attn` if FlashAttention isn't installed (see below). Note that the Base model and CustomVoice model run on different ports. ### Voice clone ```bash qwen-tts-demo Qwen/Qwen3-TTS-12Hz-1.7B-Base --ip 127.0.0.1 --port 7861 [--no-flash-attn] ``` Then in another terminal: ```bash python audiobook.py --clone reference.wav ``` The reference `.wav` should be ~10-15 seconds (3 second minimum, 60 second maximum; ~15 seconds is ideal). Longer is **not** better. Whisper (`faster_whisper` or `whisper`) is used automatically to transcribe the reference audio. Without a Whisper backend it falls back to x-vector-only cloning. Override with `--transcription "What the .wav says"` or skip transcription with `--no-transcription`. ### Custom voice (i.e. built-in voice) ```bash conda activate qwen3-tts qwen-tts-demo Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice --ip 127.0.0.1 --port 7860 [--no-flash-attn] ``` ```bash python audiobook.py ``` Change the voice settings in `converter/config.py`. ## Backend Option 2: faster-qwen-tts `--backend faster` talks to the OpenAI-compatible server from [faster-qwen3-tts](https://github.com/andimarafioti/faster-qwen3-tts), which uses CUDA graph capture for roughly 5-10x faster inference with the same models. **It requires an NVIDIA GPU**. Install into the **same `qwen3-tts` conda environment** used for qwen-tts. ```bash conda activate qwen3-tts pip install -U qwen-tts pip install "faster-qwen3-tts[demo]" ``` ### Voice Clone **This backend always uses voice cloning**. The reference voice and language are configured on the **server**, not through the converter. The server does not transcribe reference audio itself, so do it manually or use the `tools/make_faster_voices_json.py` helper (see below). The pip package does not include the server script, so clone the repository: ```bash git clone https://github.com/andimarafioti/faster-qwen3-tts cd faster-qwen3-tts ``` Create a `voices.json` mapping names to reference configurations (.wav to clone, transcript, language). Optionally run `python ./tools/make_faster_voices_json.py path/to/clone/wavs` to automatically create a `voices.json` using whisper to automatically transcribe the test audio. ```json { "default": {"ref_audio": "voice1.wav", "ref_text": "Transcript of voice 1.", "language": "English"}, "obama": {"ref_audio": "voice2.wav", "ref_text": "Transcript of voice 2.", "language": "English"} } ``` Run the server ```bash python examples/openai_server.py --voices voices.json --port 8000 ``` Then from another terminal, run audiobook.py with `--backend faster` ```bash python audiobook.py --backend faster [--voice NAME] ``` ## Backend Option 3: audio.cpp Build `audiocpp_server` for your platform and backend `(cuda, vulkan, hip, cpu)`. Check [audio.cpp's readme](https://github.com/0xShug0/audio.cpp) for details. I'm using one of the helper scripts: ```bash git clone https://github.com/0xShug0/audio.cpp cd audio.cpp scripts/build_linux.sh --backend cuda --target audiocpp_server ``` Download the Qwen3-TTS GGUF packages (Base for cloning, CustomVoice for built-in speakers) with the python model manager script. This will download these to `./models` ```bash python3 tools/model_manager_v2.py install qwen3_tts_1_7b_base_q8_0 python3 tools/model_manager_v2.py install qwen3_tts_1_7b_customvoice_q8_0 ``` Create a `server.json` file. One server can host multiple models. Note that the `id:` field(s) must match `AUDIOCPP_MODEL_ID` and `AUDIOCPP_CLONE_MODEL_ID` in qwen3_ebook_converter's .`converter/config.py`. Optionally run `tools/make_audiocpp_server_json.py path/to/clone/wavs` to make `server.json` for you with automatic whisper transcription. ```json { "host": "127.0.0.1", "port": 8080, "backend": "cuda", "lazy_load": false, "models": [ { "id": "qwen", "family": "qwen3_tts", "path": "models/Qwen3-TTS-12Hz-1.7B-CustomVoice-GGUF", "task": "tts", "mode": "offline" }, { "id": "qwen3-clone", "family": "qwen3_tts", "path": "models/Qwen3-TTS-12Hz-1.7B-Base-GGUF", "task": "tts", "mode": "offline", "voice_presets": { "narrator": { "voice_ref": "/path/to/reference.wav", "reference_text": "Transcript of the reference audio." }, "obama": { "voice_ref": "/path/to/reference2.wav", "reference_text": "Transcript of reference audio." } } } ] } ``` Run the server. The `audiocpp_server` path will be slightly different depending on your platform and build options: ```bash ./build/linux-cuda-release/bin/audiocpp_server --config server.json ``` Then in a different terminal, run `audiobook.py` ```bash # Built-in speaker python audiobook.py --backend audiocpp # Voice cloning python audiobook.py --backend audiocpp --voice narrator ``` ## Optional: FlashAttention for qwen-tts-demo server FlashAttention provides a small speed boost on the `qwen-tts-demo` backend. It is **not** relevant with the `faster` or `audiocpp` backends, and switching to either of those will provide a bigger speed boost. `qwen-tts-demo` server tries to use FlashAttention 2 by default and requires `--no-flash-attn` without it. You have two options to install FlashAttention in your python environment: 1. Build from source (takes absolutely forever). If you run out of memory, lower MAX_JOBS until you don't. ```bash conda activate qwen3-tts pip install ninja packaging psutil MAX_JOBS=4 pip install --no-build-isolation flash-attn ``` 2. pip install a prebuilt wheel matching your torch / CUDA / Python / CXX11-ABI combination: ```bash conda activate qwen3-tts python -c "import torch; print(torch.__version__, torch.version.cuda, torch._C._GLIBCXX_USE_CXX11_ABI)" ``` - [Official wheels](https://github.com/Dao-AILab/flash-attention/releases) - Pick `cp312` + matching `cuX` + `torchX.Y` + `cxx11abiTRUE/FALSE` - [Third-party wheels](https://mjunya.com/flash-attention-prebuild-wheels/) ## Tips Transcription affects the output a lot. Whisper does not always give perfect transcription. Manual transcription is better. If you're cloning one language and outputting another language, `--no-transcription` will remove the accent. Alternatively, setting the "wrong" output `--language` can add an accent. Even tiny amounts of pause between phrases in the sample audio can have a big impact. Try increasing or decreasing them or find a sample with different cadence. ## License MIT ## Credits - [Qwen3-Audiobook-Converter](https://github.com/WhiskeyCoder/Qwen3-Audiobook-Converter) by WhiskeyCoder. This project was originally built upon this. - [Qwen3-TTS](https://github.com/QwenLM/Qwen3-TTS) voice model. - [audio.cpp](https://github.com/0xShug0/audio.cpp) inference engine for the `audiocpp` backend.