feat: Add Piper voice download helpers and guides
- Created download_piper_voices.py for automated download attempts - Created download_piper_voices.sh as alternative bash script - Created EASY_PIPER_SETUP.md with simple 3-step instructions - Created PIPER_DOWNLOAD_GUIDE.md with visual step-by-step guide - Includes troubleshooting, checklists, and pro tips Makes Piper setup much easier for users with multiple guide options.
This commit is contained in:
130
backend/EASY_PIPER_SETUP.md
Normal file
130
backend/EASY_PIPER_SETUP.md
Normal file
@@ -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! 🚀
|
||||||
154
backend/PIPER_DOWNLOAD_GUIDE.md
Normal file
154
backend/PIPER_DOWNLOAD_GUIDE.md
Normal file
@@ -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!
|
||||||
219
backend/download_piper_voices.py
Executable file
219
backend/download_piper_voices.py
Executable file
@@ -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)
|
||||||
149
backend/download_piper_voices.sh
Executable file
149
backend/download_piper_voices.sh
Executable file
@@ -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 ""
|
||||||
Reference in New Issue
Block a user