tools/E2A-SML/README.md
Uses BookNLP to analyze books, extract character dialog, and generate SML-formatted output for multi-speaker audiobook generation with ebook2audiobook.
[voice:]...[/voice] tagged text compatible with ebook2audiobookThe easiest way to run the tool — all dependencies (BookNLP, spaCy, Calibre, Gradio) are pre-installed.
# 1. Build and run
docker compose up --build
Open http://localhost:7860 in your browser. The ebook2audiobook path is pre-filled as /ebook2audiobook.
# Build the image
docker build -t sml-extractor .
# Run the web GUI (mount your ebook2audiobook folder)
docker run -p 7860:7860 -v $(pwd)/../..:/ebook2audiobook sml-extractor
# Run headless mode
docker run -v $(pwd)/../..:/ebook2audiobook -v ./output:/app/output \
-v ./mybook.txt:/app/mybook.txt \
sml-extractor python cli.py /app/mybook.txt -o /app/output
git clone https://github.com/DrewThomasson/ebook2audiobook.git
cd ebook2audiobook
./ebook2audiobook.command #Mac/Linux or ebook2audiobook.cmd #Window | locally install ebook2audiobook first
conda activate ./python_env # Activate the created python env for E2A
cd ebook2audiobook/tools/E2A-SML # Go into E2A dir
pip install -r requirements.txt # Install additional requirments for E2A SML
python -m spacy download en_core_web_sm # Download en_core_web_sm
python cli.py --gui
Opens a browser-based interface where you can:
# Basic - analyze a book and generate SML output
python cli.py mybook.txt
# With custom output directory
python cli.py mybook.txt -o output/
# Process an epub (requires Calibre)
python cli.py mybook.epub
# Use the more accurate (but slower) BookNLP model
python cli.py mybook.txt --model big
# Use pre-existing BookNLP output
python cli.py --booknlp-dir existing_output/ --book-id mybook -o sml_output/
Input Book → [BookNLP Analysis] → Character Detection → Dialog Attribution
↓
Voice Assignment (auto/manual)
↓
SML Output + Characters JSON
BookNLP processes the book text and produces:
The tool converts BookNLP's tagged output into SML format:
BookNLP format (book.txt):
[Narrator] It was a bright cold day in April, and the clocks were striking thirteen. [/]
[Winston] "Freedom is the freedom to say that two plus two make four." [/]
[OBrien] "How many fingers am I holding up, Winston?" [/]
SML output (for ebook2audiobook):
[voice:Narrator]
It was a bright cold day in April, and the clocks were striking thirteen.
[/voice]
[voice:Winston]
"Freedom is the freedom to say that two plus two make four."
[/voice]
[voice:OBrien]
"How many fingers am I holding up, Winston?"
[/voice]
When given the path to an ebook2audiobook installation, voices are automatically matched:
| Character Property | Voice Directory |
|---|---|
| adult + female | voices/eng/adult/female/ |
| adult + male | voices/eng/adult/male/ |
| teen + female | voices/eng/teen/female/ |
| teen + male | voices/eng/teen/male/ |
| child + female | voices/eng/child/female/ |
| child + male | voices/eng/child/male/ |
| elder + female | voices/eng/elder/female/ |
| elder + male | voices/eng/elder/male/ |
| File | Description |
|---|---|
{book_id}.sml.txt | SML-tagged text with [voice:CharacterName] macro tags |
{book_id}.sml.json | SML macros mapping character names to voice file paths |
{book_id}.deprecated.sml.txt | Legacy SML format with raw file paths in tags |
{
"macros": {
"voices": {
"Narrator": "/path/to/narrator_voice.wav",
"Winston": "/path/to/male_voice.wav",
"OBrien": "/path/to/obrien_voice.wav"
}
}
}
usage: cli.py [-h] [-o OUTPUT_DIR] [--model {small,big}] [--e2a-path E2A_PATH]
[--voices-dir VOICES_DIR] [--language LANGUAGE]
[--booknlp-dir BOOKNLP_DIR] [--book-id BOOK_ID]
[--gui] [--host HOST] [--port PORT] [--share]
[input_file]
Options:
input_file Input book file (.txt, .epub, .mobi, .pdf, etc.)
-o, --output-dir Output directory (default: output/)
--model {small,big} BookNLP model size (default: small)
--e2a-path Path to ebook2audiobook repo (auto-detected by default)
--voices-dir Path to custom voice files directory
--language Language code for voice selection (default: eng)
--booknlp-dir Use existing BookNLP output directory
--book-id Book ID for loading existing BookNLP output
--gui Launch web GUI
--host Web GUI host (default: 127.0.0.1)
--port Web GUI port (default: 7860)
--share Create public Gradio share link
MIT