aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: dd51735a2d10911816851497f7076d3576b73050 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# tts-audiobook-generator

Generate audiobooks from books (epub, txt, pdf) using text-to-speech backends such as `audio.cpp` and `qwen-tts`. Installs and manages 

## Overview

The converter sends text extracted from your books to a locally running TTS server and assembles the returned audio into a single audiobook file.

- Input: `.txt`, `.pdf`, or `.epub`
- Output: `.m4b`, `.mp3`, `.ogg`, or `.flac`
- Supports [audio.cpp](https://github.com/0xShug0/audio.cpp), [qwen-tts](https://pypi.org/project/qwen-tts/), and [faster-qwen3-tts](https://github.com/andimarafioti/faster-qwen3-tts) backend servers
- Output a single file or one per chapter
- Automatic metadata (title/artist/album tags, chapter track numbers) and a generated cover
- Supports text-to-speech, voice cloning, voice design, and per-model controls like emotion/speed

| Backend                                                              | Description                                            |
| -------------------------------------------------------------------- | ------------------------------------------------------ |
| [audio.cpp](https://github.com/0xShug0/audio.cpp)                    | Newer C++ TTS backend that supports many recent models |
| [Qwen-TTS](https://pypi.org/project/qwen-tts/)                       | Qwen demo server (qwen-tts-demo); one model at a time — CustomVoice, Base or VoiceDesign  |
| [Faster-Qwen-TTS](https://github.com/andimarafioti/faster-qwen3-tts) | Qwen server with 2-8x faster inference for NVidia GPUs |

## Prerequisites

- Python 3.12+
- ffmpeg

## Quick Start

1. Download the project

```bash
git clone https://git.historia.vg/git/tts-audiobook-generator
cd tts-audiobook-generator
```

2. Put your files in the directories

- `./input` - Text files to be processed (`epub`, etc.)
- `./output` - Audio files will output here
- `./voices` - `.wav` files of voices to clone (10-20 seconds)

These directories (and output format, language, speed, debug, and more) can be changed any time in `app/converter/config.py` or the TUI's **Settings** menu.

3. Run `audiobook.py`. It will automatically create the app's virtual environment and install its requirements (each pip-installed TTS backend later gets a managed venv of its own under `app/envs/`).
```
python audiobook.py
```

4. When the TUI comes up, go to `Configure Backends > Install Backend`. Install `audio.cpp`, which supports numerous TTS models.

5. On the "Select TTS Models to Host" screen, install one or more TTS models. `qwen3_tts_1_7b_base_q8_0` is a good model for cloning and `qwen3_tts_1_7b_customvoice_q8_0` is good for built-in speakers.

6. Run through the rest of the wizard. The defaults are probably all correct. The script will simultaneously build audiocpp_server and download the model files. This will take a while.

## Updating Backends

`Configure Backends > Update Backends` refreshes every installed backend to the latest upstream version in one run: `pip install -U` for the pip packages (`qwen-tts`, `faster-qwen3-tts`) and a git fetch + hard reset to the remote's HEAD for the checkouts (`app/audio.cpp`, `app/faster-qwen3-tts`) — downloaded models, `server.json`, and `voices.json` are untouched. audiocpp_server is rebuilt automatically when the audio.cpp checkout moved or the on-disk binary is older than the checked-out sources (which also heals an update whose build was cancelled or failed); an up-to-date checkout with a fresh binary costs one fetch. Updates are always-latest with no version pinning; managed servers are stopped before their code is refreshed.

## CLI Options

Everything the TUI does can also be scripted with flags: `python audiobook.py --backend audiocpp --model higgs --voice narrator`.

## Options

| Flag                               | Description                                                                                                                                                                                                                                                        |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--backend {audiocpp,qwen,faster}` | TTS server to use (default `audiocpp`).                                                                                                                                                                                                                            |
| `--format {mp3,m4b,ogg,flac}`      | Output format (default: the `AUDIO_FORMAT` setting in `app/converter/config.py`, `m4b`).                                                                                                                                                                           |
| `--input <dir>`                    | Directory containing the books to convert (default: the `INPUT_DIR` setting in `app/converter/config.py`, `./input`; relative paths resolve against the project root).                                                                                             |
| `--output <dir>`                   | Directory to write finished audiobooks to (default: the `OUTPUT_DIR` setting in `app/converter/config.py`, `./output`).                                                                                                                                            |
| `--speed <n>`                      | Playback speed, pitch-preserving (`1.0` = normal). A normal-speed copy is also output. Defaults to the `SPEED` setting in `app/converter/config.py`.                                                                                                               |
| `--single-file`                    | Merge all chapters into a single file. `m4b` is always one file.                                                                                                                                                                                                   |
| `--language <lang>`                | Output language for the synthesized speech. Can add an accent even if the text is English.                                                                                                                                                                         |
| `--debug`                          | Dump each chunk's raw audio and sent text to `debug/` and log every request. Forces the `DEBUG` setting in `app/converter/config.py` on for this run.                                                                                                              |
| `--model <id>`                     | `audiocpp`: Choose the model from `server.json`                                                                                                                                                                                                               |
| `--instructions "..."`             | `audiocpp`: voice design or style instruction (required for voice design models, task `vdes`). `qwen`: selects the VoiceDesign model and describes the voice to synthesize with.                                    |
| `--option KEY=VALUE`               | `audiocpp`: Some models support custom options (e.g. `emotion=netural`) that can be passed with this flag                                                                                                                                                          |
| `--voice <name>`                   | `audiocpp`, `faster`: Voice to request. `audiocpp`: on the Qwen3-TTS CustomVoice entry a built-in speaker (e.g. `Vivian`, `Ryan`, `Uncle_Fu`); on every other family a `voice_preset`/`voice_dir` entry for cloning (with `AUDIOCPP_CLONE_MODEL_ID` set it reroutes to the clone model — typically the Qwen Base model). `faster`: a key in the server's `voices.json`. |
| `--clone <path>`                   | `qwen`: Reference audio (`wav`) for voice cloning.                                                                                                                                                                                                                 |
| `--transcription "..."`            | `qwen`: Override whisper auto-transcription with manual audio transcript.                                                                                                                                                                                          |
| `--no-transcription`               | `qwen`: Skip auto-transcription of the reference audio.                                                                                                                                                                                                            |
| `--api-url <url>`                  | URL of the TTS server to talk to, overriding the configured endpoint for the selected backend. Accepts `host:port` or a full `http(s)://` URL.                                                                                                                     |

Other options — including the input/output directories, output format, language, speed, debug, backend server URLs, ports, and the remote-server URLs the hub probes for `[remote]` entries — are configured in `app/converter/config.py` (or the TUI's **Settings** menu, whose **Language** entry is the same static language picker).

The **Generate Audiobooks** TUI form exposes the per-run controls as flags: for `audiocpp` the Model picker labels each entry's voice capability (`speaker` / `clone` / `design`), the Voice field is labelled **Built-in voice** on CustomVoice entries and **Voice to clone** everywhere else, Instructions work on every entry (required for `vdes`, optional style/delivery control elsewhere — or the voice itself on families without built-in speakers), a Request options field accepts `KEY=VALUE` items (the `--option` equivalent, shown only for model families whose audio.cpp spec declares request options), and a **Combine all chapters** toggle mirrors `--single-file` (hidden for `m4b`, which is always a single file). Output format, Language, Speed, Debug, and Stop-server-and-exit are configured once in the **Settings** menu and apply to every run. For `qwen-tts` a single **Model** picker selects which demo the server hosts — Base (voice cloning), CustomVoice (built-in voices) or VoiceDesign (design) — with the matching controls shown below it; the choice is remembered, and switching models restarts the managed server on its single port. The Instructions and Request options editors show dim hints with examples while editing.

## Manual TTS Backend Setup

If the TUI auto-install doesn't work, you may need to set up the backends manually.

- [audio.cpp instructions](app/docs/backend-audiocpp.md)
- [qwen-tts instructions](app/docs/backend-qwen.md)
- [faster-qwen-tts instructions](app/docs/backend-faster.md)

`./audiobook.py` can also connect to external servers running these backends. Point the relevant `*_REMOTE_URL` in `app/converter/config.py` (or the **Settings** → remote URL fields) at the server's `host:port` — the hub probes it and offers a `[remote]` entry in **Generate Audiobooks…** next to the managed one. The defaults are the local ports (`127.0.0.1:<port>`), so a server started outside this tool on the local port is picked up automatically. For scripting, `--api-url` targets any server directly.

## Development

The test suite runs against any Python that has the app's dependencies
(the managed venv works fine):

```bash
pytest app/tests   # from the repo root
```

## Tips

Transcription affects the output a lot. Whisper does not always give perfect transcription. Manual transcription is better.

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.