Piper - Local Text-to-Speech Service
Table of Contents
Overview
Piper is a fast, local text-to-speech (TTS) service deployed in the Fako cluster. It converts text into natural-sounding speech using neural voice models and exposes its functionality via the Wyoming protocol, making it compatible with voice assistant platforms like Home Assistant.
Key Features
- CPU-Optimized: Runs efficiently on CPU without requiring GPU
- Wyoming Protocol: Compatible with Home Assistant and other voice platforms
- Multiple Voice Support: Various voice models with different qualities
- Voice Management: Automatic voice model management via sidecar container
- Persistent Storage: Voice models cached to avoid re-downloading
- Scalable: Supports multiple concurrent TTS processes
Architecture
Components
- Deployment: Single-replica deployment with node affinity rules
- Service: ClusterIP service on port 10200 (Wyoming protocol)
- Storage: PersistentVolumeClaim for voice model storage
- ConfigMap: Configuration for default voice settings
- Sidecar Container: Voice manager for monitoring voice models
Resource Requirements
- GPU: Not required (CPU-only)
- Memory: 4Gi (request), 8Gi (limit)
- CPU: 2 cores (request), 4 cores (limit)
- Storage: Persistent volume for voice model storage
Configuration
Environment Settings
| Parameter | Default | Description |
|---|---|---|
DEFAULT_VOICE | en_US-amy-medium | Default voice model to use |
--max-piper-procs | 8 | Maximum concurrent TTS processes |
--data-dir | /data | Directory for voice data |
--download-dir | /data | Directory for downloading voices |
Available Voice Models
Piper supports various voice models with different qualities:
English (US) Voices
- amy: low, medium quality variants
- lessac: medium quality, clear pronunciation
- ryan: high quality male voice
- kusal: medium quality
- ljspeech: high quality, trained on LJSpeech dataset
English (GB) Voices
- alan: low quality British accent
Each voice has different characteristics:
- Low: Faster, smaller size (~15-30MB), lower quality
- Medium: Balanced speed and quality (~50-100MB)
- High: Best quality, larger size (~100-200MB), slower
Usage
Accessing the Service
Within the cluster:
piper.piper.svc.cluster.local:10200
Wyoming Protocol Integration
The service implements the Wyoming protocol for TTS:
Home Assistant Configuration
# In configuration.yaml
wyoming:
- name: "Piper"
host: piper.piper.svc.cluster.local
port: 10200
Testing the Service
Port-forward for local testing:
kubectl port-forward -n piper svc/piper 10200:10200
Example TTS Request
Using Wyoming protocol client:
from wyoming.tts import synthesize
# Connect to Piper
async with WyomingClient('piper.piper.svc.cluster.local', 10200) as client:
# Generate speech
audio = await client.synthesize(
text="Hello, this is Piper speaking",
voice="en_US-amy-low"
)
Operations
Checking Service Status
# Check pod status
kubectl get pods -n piper
# View main container logs
kubectl logs -n piper deployment/piper -c piper
# View voice manager logs
kubectl logs -n piper deployment/piper -c voice-manager
# Check available voices
kubectl exec -n piper deployment/piper -- ls -la /data/*.onnx
Managing Voice Models
List Available Voices
kubectl exec -n piper deployment/piper -- ls -la /data/
Voice Model Sizes
- Low quality: ~15-30 MB per voice
- Medium quality: ~50-100 MB per voice
- High quality: ~100-200 MB per voice
Manual Voice Download
If needed, you can manually download voices:
kubectl exec -n piper deployment/piper -- wget \
https://github.com/rhasspy/piper/releases/download/2023.11.14-2/en_US-amy-medium.onnx \
-O /data/en_US-amy-medium.onnx
Changing Default Voice
- Edit the ConfigMap:
kubectl edit configmap piper-configmap -n piper
- Update deployment args if needed:
kubectl edit deployment piper -n piper
- Restart the deployment:
kubectl rollout restart deployment/piper -n piper
Troubleshooting
Pod Not Starting
- Check node availability:
kubectl get nodes -o wide
- Verify node affinity:
kubectl describe pod -n piper -l app=piper
- Check storage:
kubectl get pvc -n piper
No Audio Output
- Verify voice model exists:
kubectl exec -n piper deployment/piper -- ls -la /data/*.onnx
- Check logs for errors:
kubectl logs -n piper deployment/piper -c piper | grep ERROR
- Test with different voice:
- Try using a different voice model
- Ensure the voice file and its JSON config exist
High CPU Usage
- Monitor CPU:
kubectl top pod -n piper
- Reduce concurrent processes:
- Lower
--max-piper-procsvalue - Use lower quality voices for better performance
- Lower
Voice Download Issues
- Check voice manager logs:
kubectl logs -n piper deployment/piper -c voice-manager
- Verify internet connectivity:
kubectl exec -n piper deployment/piper -- wget -O- https://github.com
- Check storage space:
kubectl exec -n piper deployment/piper -- df -h /data
Performance Tuning
CPU Optimization
- Process count: Adjust
--max-piper-procsbased on CPU cores - Voice selection: Use lower quality voices for faster synthesis
- Caching: Voice models are cached in memory after first use
Quality vs Speed Trade-offs
| Voice Quality | Speed | CPU Usage | Use Case |
|---|---|---|---|
| Low | Fast | Low | Real-time responses, IoT |
| Medium | Moderate | Moderate | General use, assistants |
| High | Slow | High | Audiobooks, presentations |
Scaling Considerations
For high-traffic scenarios:
# Increase replicas
spec:
replicas: 2
# Add HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: piper-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: piper
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Integration Examples
Python Integration
import asyncio
from wyoming.client import AsyncTcpClient
from wyoming.tts import Synthesize
async def text_to_speech(text, voice="en_US-amy-low"):
client = AsyncTcpClient('piper.piper.svc.cluster.local', 10200)
await client.connect()
# Send synthesize request
await client.send(Synthesize(
text=text,
voice=voice
))
# Receive audio data
audio_data = await client.receive_audio()
await client.disconnect()
return audio_data
Node.js Integration
const net = require('net');
function synthesizeSpeech(text, voice = 'en_US-amy-low') {
return new Promise((resolve, reject) => {
const client = net.createConnection({
host: 'piper.piper.svc.cluster.local',
port: 10200
});
client.on('connect', () => {
// Send Wyoming protocol message
const message = {
type: 'synthesize',
data: { text, voice }
};
client.write(JSON.stringify(message));
});
let audioBuffer = Buffer.alloc(0);
client.on('data', (data) => {
audioBuffer = Buffer.concat([audioBuffer, data]);
});
client.on('end', () => {
resolve(audioBuffer);
});
});
}
Home Assistant Automation
automation:
- alias: "Announce Weather"
trigger:
platform: time
at: "08:00:00"
action:
- service: tts.speak
data:
entity_id: media_player.living_room
message: "Good morning! Today's weather is sunny with a high of 75 degrees."
options:
voice: "en_US-amy-medium"
Security Considerations
- Service runs as non-root user (UID 1000)
- No external network access required after initial setup
- Voice models are read-only after download
- Consider network policies to restrict access
Monitoring
Recommended metrics to monitor:
- CPU and memory usage
- TTS request rate and latency
- Voice model disk usage
- Error rates by voice model
- Concurrent process count
Prometheus Metrics
Add Prometheus annotations:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
Backup and Recovery
Voice Model Backup
Voice models are stored in the PVC. To backup:
# Create snapshot of PVC
kubectl snapshot create piper-voices-backup -n piper
Recovery
- Restore PVC from backup
- Restart deployment
- Voice manager will verify models
Future Improvements
- Add Prometheus metrics exporter
- Implement voice model version management
- Create web UI for voice selection
- Add support for SSML (Speech Synthesis Markup Language)
- Implement request queuing for better resource management
- Add voice cloning capabilities
- Create Grafana dashboard for monitoring
- Add multi-language support