- FastAPI-based TTS server using Piper neural text-to-speech - Poetry for dependency management and virtual environments - OpenAI-compatible API endpoints for seamless integration - Support for multiple voice models (Ryan, Alan, Lessac) - Robust error handling and voice fallback system - Professional logging and configuration management - Docker-ready with proper Python packaging 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
82 lines
2.3 KiB
Python
82 lines
2.3 KiB
Python
"""Main entry point for the voice server."""
|
|
import logging
|
|
import sys
|
|
from pathlib import Path
|
|
import uvicorn
|
|
from .config import config
|
|
from .api import app
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def check_prerequisites():
|
|
"""Check if all prerequisites are met."""
|
|
errors = []
|
|
|
|
# Check if voices directory exists
|
|
if not config.voices_dir.exists():
|
|
errors.append(f"Voices directory not found: {config.voices_dir}")
|
|
errors.append("Run: mkdir -p ~/.local/share/piper-voices")
|
|
|
|
# Check if default voice files exist
|
|
if not config.validate_voice_files():
|
|
voice_name = config.default_voice
|
|
model_path = config.get_voice_model_path()
|
|
errors.append(f"Default voice '{voice_name}' files not found")
|
|
errors.append(f"Expected model at: {model_path}")
|
|
errors.append("Download voice models from: https://huggingface.co/rhasspy/piper-voices")
|
|
|
|
# Check available voices
|
|
available_count = sum(
|
|
1 for voice in config.available_voices
|
|
if config.validate_voice_files(voice)
|
|
)
|
|
|
|
if available_count == 0:
|
|
errors.append("No voice models available")
|
|
errors.append("Please download at least one voice model")
|
|
|
|
return errors
|
|
|
|
|
|
def main():
|
|
"""Main entry point."""
|
|
# Set up logging
|
|
logging.basicConfig(
|
|
level=getattr(logging, config.log_level.upper()),
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
)
|
|
|
|
logger.info("Starting Homelab Voice Server")
|
|
logger.info(f"Configuration: {config.dict()}")
|
|
|
|
# Check prerequisites
|
|
errors = check_prerequisites()
|
|
if errors:
|
|
logger.error("Prerequisites not met:")
|
|
for error in errors:
|
|
logger.error(f" - {error}")
|
|
sys.exit(1)
|
|
|
|
# Log available voices
|
|
available_voices = [
|
|
voice for voice in config.available_voices
|
|
if config.validate_voice_files(voice)
|
|
]
|
|
logger.info(f"Available voices: {available_voices}")
|
|
logger.info(f"Default voice: {config.default_voice}")
|
|
|
|
# Start server
|
|
logger.info(f"Starting server on {config.host}:{config.port}")
|
|
|
|
uvicorn.run(
|
|
app,
|
|
host=config.host,
|
|
port=config.port,
|
|
log_level=config.log_level,
|
|
access_log=True
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |