feat: integrate Silero TTS as default TTS engine
- Add SileroTTS service with GPU/CPU support - Update TTS API to support configurable engines (silero/edge) - Add TTS_ENGINE and SILERO_SPEAKER config options - Set Silero as default TTS engine - Update requirements.txt with silero dependency
This commit is contained in:
87
app/services/silero_tts_service.py
Normal file
87
app/services/silero_tts_service.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""Silero TTS service for text-to-speech conversion."""
|
||||
import os
|
||||
import logging
|
||||
from typing import Optional
|
||||
import torch
|
||||
import numpy as np
|
||||
import soundfile as sf
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SileroTTSService:
|
||||
"""Service for converting text to speech using Silero TTS."""
|
||||
|
||||
def __init__(self, device: str = 'cuda', speaker: str = 'v5_ru'):
|
||||
"""
|
||||
Initialize Silero TTS service.
|
||||
|
||||
Args:
|
||||
device: Device to use ('cuda' or 'cpu')
|
||||
speaker: Speaker model to use (e.g., 'v5_ru')
|
||||
"""
|
||||
self.device = device if torch.cuda.is_available() else 'cpu'
|
||||
self.speaker = speaker
|
||||
self.model = None
|
||||
self._load_model()
|
||||
logger.info(f"Silero TTS Service initialized with speaker: {speaker}, device: {self.device}")
|
||||
|
||||
def _load_model(self):
|
||||
"""Load Silero TTS model."""
|
||||
try:
|
||||
# Import silero here to avoid loading at module level
|
||||
from silero import silero_tts
|
||||
self.model, _ = silero_tts(
|
||||
language='ru',
|
||||
speaker=self.speaker,
|
||||
device=self.device
|
||||
)
|
||||
logger.info(f"Silero TTS model loaded successfully on {self.device}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load Silero TTS model: {e}")
|
||||
raise
|
||||
|
||||
def text_to_speech(self, text: str, output_path: str, speed: float = 1.0) -> str:
|
||||
"""
|
||||
Convert text to speech and save to file.
|
||||
|
||||
Args:
|
||||
text: Text to convert
|
||||
output_path: Path to save audio file
|
||||
speed: Speech speed multiplier (not supported by Silero, kept for API compatibility)
|
||||
|
||||
Returns:
|
||||
Path to generated audio file
|
||||
"""
|
||||
logger.info(f"Generating TTS with Silero for text: {text[:50]}...")
|
||||
|
||||
try:
|
||||
# Generate audio
|
||||
audio = self.model.apply_tts(text=text)
|
||||
|
||||
# Convert to numpy array
|
||||
audio_np = audio.numpy() if torch.is_tensor(audio) else np.array(audio)
|
||||
|
||||
# Ensure float32 format
|
||||
audio_np = audio_np.astype(np.float32)
|
||||
|
||||
# Save as WAV (Silero uses 16000 Hz by default)
|
||||
sf.write(output_path, audio_np, 16000)
|
||||
|
||||
logger.info(f"Silero TTS generated: {output_path}")
|
||||
return output_path
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Silero TTS generation failed: {e}")
|
||||
raise
|
||||
|
||||
def get_supported_voices(self) -> list:
|
||||
"""Get list of supported speakers."""
|
||||
# Silero Russian models
|
||||
voices = [
|
||||
"v5_ru", # Default Russian voice (best quality)
|
||||
"v4_ru",
|
||||
"v3_1_ru",
|
||||
"v3_ru",
|
||||
]
|
||||
return voices
|
||||
Reference in New Issue
Block a user