| .github | ||
| .vscode | ||
| books@ca23747023 | ||
| docs | ||
| models/piper | ||
| src | ||
| tests | ||
| .gitignore | ||
| .gitmodules | ||
| extract_text.py | ||
| generate_podcast.py | ||
| LICENSE | ||
| optimize_text.py | ||
| README.md | ||
| regenerate_feeds.py | ||
| requirements | ||
| test_quality.py | ||
| TODO.txt | ||
| translate.py | ||
PDF-to-Audiobook Pipeline
Python-Pipeline, die PDFs in Hörbücher (MP3) umwandelt – mit optionaler Übersetzung und Podcast-Feed-Generierung.
Pipeline-Übersicht
PDF ──► extract_text.py ──► books/<name>/text.txt
books/<name>/chapters/*.txt
──► translate.py ──► books/<name>/chapters/de/*.txt
──► optimize_text.py ► books/<name>/chapters/*.txt (in-place)
books/<name>/chapters/de/*.txt (in-place)
──► generate_podcast.py ──► books/<name>/out/*.mp3
books/<name>/out/feed.xml books/out/<name>_<lang>.mp3 (Overall)
books/out/feed.xml (Overall-Feed)```
Vier High-Level-Skripte steuern die Pipeline:
| Schritt | Skript | Beschreibung |
| -------------------- | --------------------- | ----------------------------------------------------------- |
| 1. Extraktion | `extract_text.py` | PDF → Text → Kapitel (automatisch via Lesezeichen oder LLM) |
| 2. Übersetzung | `translate.py` | Kapitel EN↔DE übersetzen (Google oder OpenRouter) |
| 2b. TTS-Optimierung | `optimize_text.py` | Kapitel-Texte mittels LLM für TTS aufbereiten (optional) |
| 3. Audio | `generate_podcast.py` | Kapitel → MP3 + optionaler Podcast-RSS-Feed + Overall-Feed |
| 4. Feed-Regeneration | `regenerate_feeds.py` | Podcast-Feeds und Cover neu generieren |
## Voraussetzungen
- Python 3.11+
- ffmpeg (`apt install ffmpeg` / `brew install ffmpeg`)
- Für GPU-Provider: SSH-Key im jeweiligen Dashboard hinterlegt
- API-Keys je nach Provider:
- `OPENROUTER_API_KEY` – für OpenRouter TTS und LLM-Übersetzung
- `RUNPOD_API_KEY` – für RunPod GPU-Instanzen
- Google Cloud: `gcloud auth application-default login` (Application Default Credentials)
- vast.ai CLI (`vastai`) – für vast.ai GPU-Instanzen
## Installation
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements
Verwendung
1. Text aus PDF extrahieren
# Kapitel-Erkennung über PDF-Lesezeichen (Standard)
python3 extract_text.py buch.pdf --name meinbuch
# Kapitel-Erkennung über LLM (OpenRouter)
python3 extract_text.py buch.pdf --name meinbuch --provider openrouter
# Mit JSON-Konfiguration für manuelle Kapitel-Grenzen
python3 extract_text.py buch.pdf --name meinbuch --config chapters.json
Ergebnis: books/meinbuch/text.txt und books/meinbuch/chapters/*.txt
2. Kapitel übersetzen (optional)
# Englisch → Deutsch mit Google Translate (kostenlos)
python3 translate.py meinbuch
# Englisch → Deutsch mit OpenRouter (LLM, höhere Qualität)
python3 translate.py meinbuch --provider openrouter
# Deutsch → Englisch
python3 translate.py meinbuch --direction de-en
Bei OpenRouter wird vor der Übersetzung eine Kostenprognose angezeigt und nach Abschluss mit den tatsächlichen Kosten verglichen.
2b. Text für TTS optimieren (optional)
Optimiert Kapitel-Texte mittels LLM für die TTS-Synthese: entfernt Klammern, Referenzen, Fußzeilen-Fragmente, schreibt Abschnittsnummern wie "1.3.1" und Abkürzungen lesbar aus, und wandelt Tabellen/Figur-Verweise in fließenden Text um. Zeigt vor dem Start eine Kostenprognose und vergleicht nach Abschluss die tatsächlichen Kosten.
# Alle Kapitel optimieren (EN + DE)
python3 optimize_text.py meinbuch
# Nur Deutsch
python3 optimize_text.py meinbuch -l de
# Mit anderem Modell
python3 optimize_text.py meinbuch -m google/gemini-2.5-flash
Ergebnis: Die Kapitel-Dateien werden direkt überschrieben (in-place). Eine Tracking-Datei .tts_optimized merkt sich, welche Dateien bereits optimiert wurden.
3. Audio generieren
# Cloud-TTS über OpenRouter API (kein GPU nötig)
python3 generate_podcast.py meinbuch --provider openrouter
# Nach optimize_text.py werden die optimierten Texte automatisch verwendet
python3 generate_podcast.py meinbuch --provider google
# Google TTS mit bestimmter Stimme
python3 generate_podcast.py meinbuch --provider google --voice Kore
# GPU-Instanz auf vast.ai (Coqui XTTS v2)
python3 generate_podcast.py meinbuch --provider vast
# GPU-Instanz auf RunPod
python3 generate_podcast.py meinbuch --provider runpod
# Mit Podcast-Feed (Nextcloud-Freigabelink)
python3 generate_podcast.py meinbuch --provider openrouter \
--share-url https://cloud.example.com/s/TOKEN
# Nur eine Sprache verarbeiten
python3 generate_podcast.py meinbuch --provider openrouter --lang de
# Overall-Feed nicht aktualisieren
python3 generate_podcast.py meinbuch --provider openrouter --no-overall-feed
# Cloud-TTS über Google Cloud Chirp 3: HD (kein GPU nötig, hohe Qualität)
Ergebnis: `books/meinbuch/out/*.mp3` (und ggf. `feed.xml`)
## TTS-Provider
| Provider | Modell | GPU nötig | Kosten |
| ------------ | --------------------------------- | ---------------------- | ------------------------------------- |
| `openrouter` | OpenAI gpt-4o-mini-tts | Nein | ~$0.60 / 1M Zeichen |
| `google` | Google Chirp 3: HD | Nein | $30 / 1M Zeichen (1M/Monat kostenlos) |
| `mistral` | Voxtral Mini TTS | Nein | $16 / 1M Zeichen |
| `voxtral` | Voxtral 4B TTS | Ja (lokal, 16 GB VRAM) | Kostenlos (lokaler vLLM-Server) |
| `local` | XTTS v2 / F5-TTS / Kokoro / Piper | Ja (lokal) | Kostenlos |
| `vast` | Coqui XTTS v2 | Ja (gemietet) | Variabel (Stundenpreis) |
| `runpod` | Coqui XTTS v2 | Ja (gemietet) | Variabel (Stundenpreis) |
Bei GPU-Providern werden automatisch Angebote gesucht und eine Auswahl mit Kostenprognose angezeigt (günstigste Gesamtkosten, günstigste Stundenrate, beste Preis-Leistung, schnellste). Nach Abschluss wird ein Vergleich zwischen prognostizierten und tatsächlichen Kosten ausgegeben.
### Lokale TTS-Engines
Die Skripte `text_to_audio.py`, `batch_to_audio.py` und `pdf_to_audio.py` unterstützen zwei lokale TTS-Engines:
| Engine | Flag | Modell | Besonderheiten |
| ------------- | -------------------- | ----------------------------------------------- | ---------------------------------------- |
| Coqui XTTS v2 | `-e xtts` (Standard) | `tts_models/multilingual/multi-dataset/xtts_v2` | Eingebaute Stimme oder Voice-Cloning |
| F5-TTS | `-e f5tts` | F5TTS_v1_Base (DE: hvoss-techfak/F5-TTS-German) | Voice-Cloning, Referenz-WAV erforderlich |
**F5-TTS Installation:** `pip install f5-tts`
**Beispiele:**
```bash
# Lokale TTS mit Coqui XTTS v2 (Standard)
python3 src/text_to_audio.py kapitel.txt -o out.mp3
# Lokale TTS mit F5-TTS (Referenz-WAV erforderlich)
python3 src/text_to_audio.py kapitel.txt -o out.mp3 -e f5tts -s stimme.wav
# F5-TTS mit expliziter Transkription der Referenz-WAV
python3 src/text_to_audio.py kapitel.txt -o out.mp3 -e f5tts -s stimme.wav \
--ref-text "Text der Referenzaufnahme"
# Batch mit F5-TTS
python3 src/batch_to_audio.py -e f5tts -s stimme.wav --chapters-dir books/meinbuch/chapters
# PDF direkt mit F5-TTS
python3 src/pdf_to_audio.py buch.pdf -o out.mp3 -e f5tts -s stimme.wav
Für Deutsch wird automatisch das Community-Modell hvoss-techfak/F5-TTS-German geladen. Für andere Sprachen wird das Standard-Multilingual-Modell (zh & en) verwendet.
Projektstruktur
├── extract_text.py # Schritt 1: PDF → Kapitel (CLI)
├── translate.py # Schritt 2: Kapitel übersetzen (CLI)
├── optimize_text.py # Schritt 2b: Texte für TTS optimieren (CLI)
├── generate_podcast.py # Schritt 3: Kapitel → MP3 + Feed (CLI)
├── regenerate_feeds.py # Feed-Regenerierung (CLI)
├── requirements # pip-Abhängigkeiten
├── src/
│ ├── models.py # Datenmodelle (Cost, ChapterBoundary, Book)
│ ├── metadata.py # Metadaten-Verwaltung (Metadata-Klasse + Funktionen)
│ ├── orchestrate_extraction.py # Extraktions-Orchestrator
│ ├── orchestrate_translation.py # Übersetzungs-Orchestrator
│ ├── orchestrate_optimization.py # Optimierungs-Orchestrator
│ ├── orchestrate_audio.py # Audio-Orchestrator
│ ├── orchestrate_feed.py # Feed-Orchestrator
│ ├── providers/ # Provider-Interfaces (Protocol) und Implementierungen
│ │ ├── tts.py # TTSProvider-Protocol + Registry (8 Provider)
│ │ ├── translate.py # TranslateProvider-Protocol + Registry
│ │ ├── splitter.py # ChapterSplitter-Protocol + Registry
│ │ └── remote.py # RemoteExecutor-Protocol + Registry
│ ├── pdf_to_text.py # PDF-Textextraktion (pypdf)
│ ├── split_chapters.py # Kapitel-Erkennung (Lesezeichen/LLM/JSON)
│ ├── clean_chapters.py # Textbereinigung für TTS
│ ├── optimize_for_tts.py # LLM-gestützte TTS-Textoptimierung
│ ├── translate_chapters.py # Übersetzungs-Engine (Google/OpenRouter)
│ ├── text_to_audio.py # Lokale TTS (XTTS v2 / F5-TTS / Kokoro / Piper)
│ ├── openrouter_run.py # OpenRouter TTS-API Batch
│ ├── google_run.py # Google Cloud TTS (Chirp 3: HD) Batch
│ ├── mistral_run.py # Mistral Voxtral Mini TTS Batch
│ ├── voxtral_run.py # Voxtral 4B TTS (lokaler vLLM-Server) Batch
│ ├── vast_run.py # vast.ai GPU-Automatisierung
│ ├── runpod_run.py # RunPod GPU-Automatisierung
│ ├── generate_feed.py # Podcast-RSS-Feed-Generator
│ ├── overall_feed.py # Overall-Feed für alle Bücher (books/out/)
│ ├── audio.py # AudioAssembler (MP3/WAV-Zusammenfügung)
│ ├── cover.py # CoverProcessor (Podcast-Cover)
│ ├── cost.py # CostEstimator (Kostenprognose/-vergleich)
│ ├── retry.py # Zentrale Retry-Logik
│ ├── chunk_splitter.py # Zentraler Chunk-Splitter
│ ├── file_utils.py # Datei-Hilfsfunktionen
│ ├── http_client.py # HTTP-Client mit Retry
│ ├── gpu.py # GPU-Erkennung
│ ├── ssh_utils.py # SSH/rsync-Hilfsfunktionen
│ ├── batch_to_audio.py # Standalone-Batch-TTS
│ └── pdf_to_audio.py # All-in-One PDF → MP3
├── books/
│ └── <name>/
│ ├── text.txt # Extrahierter Volltext
│ ├── metadata.txt # Key-Value-Metadaten
│ ├── chapters.txt # Kapitel-Titel-Zuordnung
│ ├── chapters/*.txt # Kapitel (EN, ggf. TTS-optimiert)
│ ├── chapters/de/*.txt # Kapitel (DE, ggf. TTS-optimiert)
│ └── out/{model}/{lang}/*.mp3 # Generierte Audiodateien
├── books/
│ └── out/ # Overall-Feed: zusammengefügte MP3s + feed.xml
├── tests/ # pytest-Testsuite
└── docs/ # Architektur, SWDD, Provider-Dokumentation
Umgebungsvariablen
| Variable | Verwendung |
|---|---|
OPENROUTER_API_KEY |
OpenRouter API (TTS + Übersetzung + LLM-Kapitel-Erkennung) |
RUNPOD_API_KEY |
RunPod GPU-Pods |
GOOGLE_APPLICATION_CREDENTIALS |
Google Cloud TTS (optional, alternativ gcloud auth application-default login) |
Für vast.ai wird die vastai CLI verwendet (Authentifizierung über vastai set api-key). |
Lizenz
Apache License 2.0 – siehe LICENSE.