diff --git a/backend/EASY_PIPER_SETUP.md b/backend/EASY_PIPER_SETUP.md new file mode 100644 index 0000000..cd8d4e5 --- /dev/null +++ b/backend/EASY_PIPER_SETUP.md @@ -0,0 +1,130 @@ +# Easy Piper TTS Setup (5 Minutes) + +## The Problem + +Piper voice models can't be auto-downloaded due to HuggingFace's complex repository structure. But don't worry - manual download is quick and easy! + +## Quick Setup (3 Steps) + +### Step 1: Download Voice Files + +Visit this page: **https://github.com/rhasspy/piper/releases/tag/v1.2.0** + +Scroll down to "Assets" section and download these files: + +**Recommended Starter Pack (3 voices):** + +1. **en_US-lessac-medium** (Male, American) + - Download: `en_US-lessac-medium.onnx` (63 MB) + - Download: `en_US-lessac-medium.onnx.json` (8 KB) + +2. **en_US-amy-medium** (Female, American) + - Download: `en_US-amy-medium.onnx` (63 MB) + - Download: `en_US-amy-medium.onnx.json` (8 KB) + +3. **en_GB-alan-medium** (Male, British) + - Download: `en_GB-alan-medium.onnx` (63 MB) + - Download: `en_GB-alan-medium.onnx.json` (8 KB) + +**Total download:** ~190 MB for 3 voices + +### Step 2: Place Files + +Move all downloaded files to: +``` +backend/piper_models/ +``` + +Your directory should look like: +``` +backend/piper_models/ +├── en_US-lessac-medium.onnx +├── en_US-lessac-medium.onnx.json +├── en_US-amy-medium.onnx +├── en_US-amy-medium.onnx.json +├── en_GB-alan-medium.onnx +└── en_GB-alan-medium.onnx.json +``` + +### Step 3: Test + +```bash +cd backend +python test_piper_direct.py +``` + +You should see: "✓ Synthesis successful" + +## Done! 🎉 + +Now you can: +1. Start the backend: `uvicorn main:app --reload` +2. Open the UI +3. Click "Piper TTS" button +4. Select Piper voices +5. Generate audiobooks with pitch control! + +## More Voices (Optional) + +Want more variety? Download additional voices from the same page: + +**More American English:** +- `en_US-libritts-high` (High quality, neutral) +- `en_US-ryan-high` (Male, high quality) + +**More British English:** +- `en_GB-alba-medium` (Female) +- `en_GB-jenny_dioco-medium` (Female) + +**Other Languages:** +- Browse the releases page for Spanish, French, German, etc. + +## Troubleshooting + +### "Model not found" error +- Make sure you downloaded BOTH `.onnx` and `.onnx.json` files +- Check files are in `backend/piper_models/` directory +- Verify filenames match exactly (case-sensitive) + +### Files won't download +- Try a different browser +- Check your internet connection +- Download one at a time if needed + +### Still having issues? +- Fall back to Kokoro TTS (works out of the box) +- Check `backend/PIPER_SETUP.md` for detailed troubleshooting + +## Why Manual Download? + +We tried automatic download but encountered: +- ❌ Complex HuggingFace URL structure +- ❌ SSL certificate issues +- ❌ Unreliable across different systems + +Manual download is: +- ✅ Fast (5 minutes) +- ✅ Reliable (always works) +- ✅ One-time setup +- ✅ You control what you download + +## Alternative: Use Kokoro TTS + +If this seems like too much work, **Kokoro TTS works perfectly with zero setup**: +- ✅ No downloads needed +- ✅ 54 voices, 9 languages +- ✅ High quality +- ❌ No pitch control + +Just keep "Kokoro TTS" selected in the UI! + +## Need Help? + +1. Check the files are in the right place +2. Run `python test_piper_direct.py` to diagnose +3. Check backend logs for errors +4. See `PIPER_STATUS.md` for more troubleshooting + +--- + +**Remember:** This is a one-time setup. Once downloaded, Piper voices work forever! 🚀 diff --git a/backend/PIPER_DOWNLOAD_GUIDE.md b/backend/PIPER_DOWNLOAD_GUIDE.md new file mode 100644 index 0000000..9ea4ebb --- /dev/null +++ b/backend/PIPER_DOWNLOAD_GUIDE.md @@ -0,0 +1,154 @@ +# Piper Voice Download - Visual Guide + +## 📥 Step-by-Step Instructions + +### Step 1: Go to Piper Releases Page + +Open this link in your browser: +``` +https://github.com/rhasspy/piper/releases/tag/v1.2.0 +``` + +### Step 2: Scroll to "Assets" Section + +Scroll down the page until you see a section called "Assets" with a list of files. + +### Step 3: Download Voice Files + +Click on each file to download (you need BOTH files for each voice): + +#### Voice 1: Male American (Lessac) +- ✅ Click: `en_US-lessac-medium.onnx` (63 MB) +- ✅ Click: `en_US-lessac-medium.onnx.json` (8 KB) + +#### Voice 2: Female American (Amy) +- ✅ Click: `en_US-amy-medium.onnx` (63 MB) +- ✅ Click: `en_US-amy-medium.onnx.json` (8 KB) + +#### Voice 3: Male British (Alan) +- ✅ Click: `en_GB-alan-medium.onnx` (63 MB) +- ✅ Click: `en_GB-alan-medium.onnx.json` (8 KB) + +**Total:** 6 files, ~190 MB + +### Step 4: Move Files to Models Directory + +1. Open your terminal +2. Navigate to your project: + ```bash + cd /path/to/audiobook/backend + ``` + +3. Create models directory if it doesn't exist: + ```bash + mkdir -p piper_models + ``` + +4. Move downloaded files: + ```bash + # From your Downloads folder + mv ~/Downloads/en_US-*.onnx* piper_models/ + mv ~/Downloads/en_GB-*.onnx* piper_models/ + ``` + +### Step 5: Verify Files + +Check that files are in place: +```bash +ls -lh piper_models/ +``` + +You should see: +``` +en_US-lessac-medium.onnx (63 MB) +en_US-lessac-medium.onnx.json (8 KB) +en_US-amy-medium.onnx (63 MB) +en_US-amy-medium.onnx.json (8 KB) +en_GB-alan-medium.onnx (63 MB) +en_GB-alan-medium.onnx.json (8 KB) +``` + +### Step 6: Test Installation + +```bash +python test_piper_direct.py +``` + +Expected output: +``` +✓ Piper found +✓ Model found: /path/to/piper_models/en_US-lessac-medium.onnx +✓ Synthesis successful: XXXXX bytes of audio +``` + +## ✅ You're Done! + +Now you can use Piper TTS: + +1. **Start backend:** + ```bash + uvicorn main:app --reload + ``` + +2. **Open frontend** in browser + +3. **Select "Piper TTS"** in Voice Assignment screen + +4. **Choose Piper voices** from dropdown + +5. **Generate audiobook** with pitch control! + +## 🎯 Quick Checklist + +- [ ] Downloaded 6 files (3 voices × 2 files each) +- [ ] Moved files to `backend/piper_models/` +- [ ] Verified files with `ls -lh piper_models/` +- [ ] Tested with `python test_piper_direct.py` +- [ ] Started backend server +- [ ] Selected "Piper TTS" in UI + +## 🆘 Troubleshooting + +### Can't find files on GitHub? +- Make sure you're on the v1.2.0 release page +- Scroll down to "Assets" section +- Files are listed alphabetically + +### Download fails? +- Try a different browser +- Check internet connection +- Download one file at a time + +### Files in wrong place? +```bash +# Check current location +pwd + +# Should show: /path/to/audiobook/backend + +# List models directory +ls piper_models/ +``` + +### Test fails? +- Make sure BOTH .onnx and .onnx.json files are present +- Check filenames match exactly (case-sensitive) +- Verify Piper is installed: `piper --version` + +## 💡 Pro Tips + +1. **Download all at once:** Select all 6 files and download together +2. **Use command line:** Faster to move files with `mv` command +3. **Bookmark the page:** Easy to download more voices later +4. **Try different voices:** Each has unique characteristics + +## 🔗 Useful Links + +- **Download Page:** https://github.com/rhasspy/piper/releases/tag/v1.2.0 +- **Voice Samples:** https://rhasspy.github.io/piper-samples/ +- **Full Setup Guide:** `PIPER_SETUP.md` +- **Troubleshooting:** `PIPER_STATUS.md` + +--- + +**Need more help?** Check `EASY_PIPER_SETUP.md` or ask for assistance! diff --git a/backend/download_piper_voices.py b/backend/download_piper_voices.py new file mode 100755 index 0000000..443b380 --- /dev/null +++ b/backend/download_piper_voices.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 +""" +Simple script to download Piper TTS voice models. +""" +import os +import sys +import urllib.request +import ssl + +# Create SSL context that doesn't verify (for development) +ssl_context = ssl.create_default_context() +ssl_context.check_hostname = False +ssl_context.verify_mode = ssl.CERT_NONE + +# Models directory +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +MODELS_DIR = os.path.join(SCRIPT_DIR, "piper_models") +os.makedirs(MODELS_DIR, exist_ok=True) + +# Available voices with direct download links +VOICES = { + "1": { + "name": "en_US-lessac-medium", + "description": "Male, American, Medium Quality", + "model_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/en_US-lessac-medium.onnx", + "config_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/en_US-lessac-medium.onnx.json", + }, + "2": { + "name": "en_US-amy-medium", + "description": "Female, American, Medium Quality", + "model_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/en_US-amy-medium.onnx", + "config_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/en_US-amy-medium.onnx.json", + }, + "3": { + "name": "en_US-libritts-high", + "description": "Neutral, American, High Quality", + "model_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/en_US-libritts-high.onnx", + "config_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/en_US-libritts-high.onnx.json", + }, + "4": { + "name": "en_GB-alan-medium", + "description": "Male, British, Medium Quality", + "model_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/en_GB-alan-medium.onnx", + "config_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/en_GB-alan-medium.onnx.json", + }, + "5": { + "name": "en_GB-alba-medium", + "description": "Female, British, Medium Quality", + "model_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/en_GB-alba-medium.onnx", + "config_url": "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_GB/en_GB-alba-medium.onnx.json", + }, +} + + +def download_file(url, dest_path): + """Download a file with progress indication.""" + try: + print(f" Downloading from: {url}") + + # Use urllib with SSL context + with urllib.request.urlopen(url, context=ssl_context, timeout=120) as response: + total_size = int(response.headers.get('content-length', 0)) + + with open(dest_path, 'wb') as f: + downloaded = 0 + chunk_size = 8192 + + while True: + chunk = response.read(chunk_size) + if not chunk: + break + + f.write(chunk) + downloaded += len(chunk) + + if total_size > 0: + percent = (downloaded / total_size) * 100 + print(f"\r Progress: {percent:.1f}% ({downloaded}/{total_size} bytes)", end='') + + print() # New line after progress + + # Verify file size + file_size = os.path.getsize(dest_path) + if file_size < 1000: + print(f" ✗ Download failed (file too small: {file_size} bytes)") + os.remove(dest_path) + return False + + print(f" ✓ Downloaded: {file_size:,} bytes") + return True + + except Exception as e: + print(f" ✗ Error: {e}") + if os.path.exists(dest_path): + os.remove(dest_path) + return False + + +def download_voice(voice_key): + """Download a voice model and config.""" + voice = VOICES[voice_key] + name = voice["name"] + + model_path = os.path.join(MODELS_DIR, f"{name}.onnx") + config_path = os.path.join(MODELS_DIR, f"{name}.onnx.json") + + # Check if already exists + if os.path.exists(model_path) and os.path.exists(config_path): + print(f" ✓ {name} - Already downloaded") + return True + + print(f"\n Downloading: {name}") + print(f" Description: {voice['description']}") + + # Download model + print(" [1/2] Model file (.onnx)...") + if not download_file(voice["model_url"], model_path): + return False + + # Download config + print(" [2/2] Config file (.onnx.json)...") + if not download_file(voice["config_url"], config_path): + return False + + print(f" ✓ {name} - Complete!") + return True + + +def main(): + print("=" * 60) + print("Piper TTS Voice Model Downloader") + print("=" * 60) + print(f"\nModels directory: {MODELS_DIR}\n") + + print("Available voices:\n") + for key, voice in VOICES.items(): + print(f" {key}) {voice['name']}") + print(f" {voice['description']}") + print() + + print("Quick options:") + print(" a) Download all voices (recommended)") + print(" s) Download starter pack (1, 2, 4)") + print(" q) Quit") + print() + + choice = input("Enter your choice (1-5, a, s, or q): ").strip().lower() + + if choice == 'q': + print("Exiting...") + return + + print("\n" + "=" * 60) + print("Downloading...") + print("=" * 60) + + success_count = 0 + total_count = 0 + + if choice == 'a': + # Download all + for key in VOICES.keys(): + total_count += 1 + if download_voice(key): + success_count += 1 + elif choice == 's': + # Starter pack + for key in ['1', '2', '4']: + total_count += 1 + if download_voice(key): + success_count += 1 + elif choice in VOICES: + # Single voice + total_count += 1 + if download_voice(choice): + success_count += 1 + else: + print(f"Invalid choice: {choice}") + return + + print("\n" + "=" * 60) + print("Download Summary") + print("=" * 60) + print(f"\nSuccessfully downloaded: {success_count}/{total_count} voices") + + # List downloaded files + print(f"\nFiles in {MODELS_DIR}:") + try: + files = sorted(os.listdir(MODELS_DIR)) + if files: + for f in files: + size = os.path.getsize(os.path.join(MODELS_DIR, f)) + print(f" {f} ({size:,} bytes)") + else: + print(" (empty)") + except Exception as e: + print(f" Error listing files: {e}") + + print("\n" + "=" * 60) + print("Next Steps") + print("=" * 60) + print("\n1. Test Piper installation:") + print(" python test_piper_direct.py") + print("\n2. Start the backend:") + print(" uvicorn main:app --reload") + print("\n3. In the UI, click 'Piper TTS' button") + print("\n4. Select a Piper voice and generate!") + print() + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + print("\n\nDownload cancelled by user.") + sys.exit(1) + except Exception as e: + print(f"\n\nError: {e}") + sys.exit(1) diff --git a/backend/download_piper_voices.sh b/backend/download_piper_voices.sh new file mode 100755 index 0000000..6f4a5ba --- /dev/null +++ b/backend/download_piper_voices.sh @@ -0,0 +1,149 @@ +#!/bin/bash +# Helper script to download Piper TTS voice models + +set -e + +echo "==================================================" +echo "Piper TTS Voice Model Downloader" +echo "==================================================" +echo "" + +# Create models directory +MODELS_DIR="$(dirname "$0")/piper_models" +mkdir -p "$MODELS_DIR" +echo "✓ Models directory: $MODELS_DIR" +echo "" + +# Base URL for Piper voices +BASE_URL="https://huggingface.co/rhasspy/piper-voices/resolve/main" + +# Function to download a voice +download_voice() { + local voice_id=$1 + local lang_code=$2 + + echo "Downloading $voice_id..." + + # Construct URLs + local model_url="${BASE_URL}/${lang_code}/${lang_code}_${voice_id}.onnx" + local config_url="${BASE_URL}/${lang_code}/${lang_code}_${voice_id}.onnx.json" + + local model_file="${MODELS_DIR}/${lang_code}-${voice_id}.onnx" + local config_file="${MODELS_DIR}/${lang_code}-${voice_id}.onnx.json" + + # Check if already exists + if [ -f "$model_file" ] && [ -f "$config_file" ]; then + echo " ✓ Already downloaded" + return 0 + fi + + # Download with curl + if command -v curl &> /dev/null; then + echo " Downloading model file..." + curl -L -o "$model_file" "$model_url" 2>/dev/null || { + echo " ✗ Failed to download model" + return 1 + } + + echo " Downloading config file..." + curl -L -o "$config_file" "$config_url" 2>/dev/null || { + echo " ✗ Failed to download config" + return 1 + } + + # Verify files are not error pages + if [ $(wc -c < "$model_file") -lt 1000 ]; then + echo " ✗ Download failed (file too small)" + rm -f "$model_file" "$config_file" + return 1 + fi + + echo " ✓ Downloaded successfully" + return 0 + else + echo " ✗ curl not found" + return 1 + fi +} + +echo "Select voices to download:" +echo "" +echo "Recommended starter pack (3 voices):" +echo " 1) en_US-lessac-medium (Male, American)" +echo " 2) en_US-amy-medium (Female, American)" +echo " 3) en_GB-alan-medium (Male, British)" +echo "" +echo "All English voices (5 voices):" +echo " 4) All of the above + 2 more" +echo "" +echo "Manual selection:" +echo " 5) Choose specific voices" +echo "" +echo " 0) Exit" +echo "" +read -p "Enter your choice (0-5): " choice + +case $choice in + 1) + echo "" + echo "Downloading starter pack..." + echo "" + download_voice "lessac-medium" "en_US" + download_voice "amy-medium" "en_US" + download_voice "alan-medium" "en_GB" + ;; + 2) + echo "" + echo "Downloading all English voices..." + echo "" + download_voice "lessac-medium" "en_US" + download_voice "amy-medium" "en_US" + download_voice "libritts-high" "en_US" + download_voice "alan-medium" "en_GB" + download_voice "alba-medium" "en_GB" + ;; + 3) + echo "" + echo "Available voices:" + echo " en_US-lessac-medium (Male, American)" + echo " en_US-amy-medium (Female, American)" + echo " en_US-libritts-high (Neutral, American, High Quality)" + echo " en_GB-alan-medium (Male, British)" + echo " en_GB-alba-medium (Female, British)" + echo "" + echo "Enter voice IDs separated by spaces (e.g., lessac-medium amy-medium):" + read -p "> " voices + + for voice in $voices; do + if [[ $voice == *"GB"* ]]; then + download_voice "$voice" "en_GB" + else + download_voice "$voice" "en_US" + fi + done + ;; + 0) + echo "Exiting..." + exit 0 + ;; + *) + echo "Invalid choice" + exit 1 + ;; +esac + +echo "" +echo "==================================================" +echo "Download Summary" +echo "==================================================" +echo "" +echo "Downloaded files in: $MODELS_DIR" +ls -lh "$MODELS_DIR" 2>/dev/null || echo "No files found" +echo "" +echo "✓ Setup complete!" +echo "" +echo "Next steps:" +echo " 1. Test Piper: python test_piper_direct.py" +echo " 2. Start backend: uvicorn main:app --reload" +echo " 3. Select 'Piper TTS' in the UI" +echo ""