diff options
| author | historia <historiavg@proton.me> | 2026-08-18 23:27:42 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-18 23:27:42 -0400 |
| commit | f3e21980320c1708ff17cc6f699a9aa4758accdf (patch) | |
| tree | 596ff71ba68600bb24a5a9d88424951c77e02808 /converter/converter.py | |
| parent | a97c0506f8b20cdc5ed8a11892ef10a9fc1938ef (diff) | |
| download | tts-audiobook-generator-f3e21980320c1708ff17cc6f699a9aa4758accdf.tar.gz | |
feat: support for faster-qwen3-tts backend server
Diffstat (limited to 'converter/converter.py')
| -rw-r--r-- | converter/converter.py | 72 |
1 files changed, 46 insertions, 26 deletions
diff --git a/converter/converter.py b/converter/converter.py index 4d20083..ec06bbb 100644 --- a/converter/converter.py +++ b/converter/converter.py @@ -13,7 +13,7 @@ from typing import Dict, List, Optional, Tuple from . import audio, chunking, config, cover, extractors from .audio import TrackMeta -from .tts import QwenTTSClient, normalize_language, speaker_display_name +from .tts import FasterTTSClient, QwenTTSClient, normalize_language, speaker_display_name logger = logging.getLogger(__name__) @@ -89,7 +89,8 @@ class AudiobookConverter: def __init__(self, voice_mode: str = config.VOICE_MODE_CUSTOM, voice_clone_ref_audio: Optional[str] = None, voice_clone_ref_text: Optional[str] = None, skip_transcription: bool = False, speed: float = 1.0, single_file: bool = False, output_format: str = config.AUDIO_FORMAT, - language: Optional[str] = None): + language: Optional[str] = None, faster: bool = False, + faster_voice: Optional[str] = None): if speed <= 0: raise ValueError(f"Speed must be a positive number, got {speed}") if output_format not in config.AUDIO_FORMATS: @@ -103,14 +104,21 @@ class AudiobookConverter: self.speed = speed self.single_file = single_file self.output_format = output_format + self.faster = faster + self.faster_voice = faster_voice self._validate_configuration() - self.tts = QwenTTSClient( - voice_mode=voice_mode, - voice_clone_ref_audio=voice_clone_ref_audio, - voice_clone_ref_text=voice_clone_ref_text, - skip_transcription=skip_transcription, - language=self.language, - ) + if faster: + # The faster backend always voice-clones using a reference voice + # configured on the server, so no local reference audio is needed. + self.tts = FasterTTSClient(voice=faster_voice) + else: + self.tts = QwenTTSClient( + voice_mode=voice_mode, + voice_clone_ref_audio=voice_clone_ref_audio, + voice_clone_ref_text=voice_clone_ref_text, + skip_transcription=skip_transcription, + language=self.language, + ) def _validate_configuration(self) -> None: """Validate configuration settings.""" @@ -119,7 +127,7 @@ class AudiobookConverter: f"Unknown voice mode: {self.voice_mode!r} " f"(expected one of {config.VOICE_MODES})" ) - if self.voice_mode == config.VOICE_MODE_CLONE: + if self.voice_mode == config.VOICE_MODE_CLONE and not self.faster: if not self.voice_clone_ref_audio: raise ValueError( "Voice Clone mode requires a reference audio file. " @@ -142,10 +150,13 @@ class AudiobookConverter: """Narrator name used in output file names. Custom voice mode uses the built-in speaker's display name; voice - clone mode uses the reference audio file's stem. Spaces become - underscores (e.g. "Uncle Fu" -> "Uncle_Fu"). + clone mode uses the reference audio file's stem; the faster backend + uses the server-side voice name. Spaces become underscores + (e.g. "Uncle Fu" -> "Uncle_Fu"). """ - if self.voice_mode == config.VOICE_MODE_CLONE: + if self.faster: + narrator = self.faster_voice or config.FASTER_TTS_VOICE + elif self.voice_mode == config.VOICE_MODE_CLONE: narrator = Path(self.voice_clone_ref_audio).stem else: narrator = speaker_display_name() @@ -371,24 +382,29 @@ class AudiobookConverter: logger.error(traceback.format_exc()) return False - def run(self) -> bool: - """Main conversion process. Returns True if all books converted.""" - api_url = config.VOICE_CLONE_API_URL if self.voice_mode == config.VOICE_MODE_CLONE else config.QWEN_API_URL - + def _print_banner(self) -> None: + """Print the startup summary for the selected backend.""" print("=" * 70) print("QWEN-BASED AUDIOBOOK CONVERTER") print("=" * 70) print(f"Books folder: {config.BOOKS_FOLDER}") print(f"Output folder: {config.AUDIOBOOKS_FOLDER}") - print(f"Qwen API endpoint: {api_url}") - print(f"Voice mode: {self.voice_mode}") - print("Model size: 1.7B (always)") - if self.voice_mode == config.VOICE_MODE_CUSTOM: - print(f"Speaker: {config.CUSTOM_VOICE_SPEAKER}") - print(f"Language: {self.language}") - elif self.voice_mode == config.VOICE_MODE_CLONE: - print(f"Reference audio: {Path(self.voice_clone_ref_audio).name}") - print(f"Language: {self.language}") + if self.faster: + print(f"Faster TTS endpoint: {config.FASTER_TTS_API_URL}") + print("Backend: faster (voice cloning, reference configured on server)") + print(f"Voice: {self.faster_voice or config.FASTER_TTS_VOICE}") + else: + api_url = (config.VOICE_CLONE_API_URL if self.voice_mode == config.VOICE_MODE_CLONE + else config.QWEN_API_URL) + print(f"Qwen API endpoint: {api_url}") + print(f"Voice mode: {self.voice_mode}") + print("Model size: 1.7B (always)") + if self.voice_mode == config.VOICE_MODE_CUSTOM: + print(f"Speaker: {config.CUSTOM_VOICE_SPEAKER}") + print(f"Language: {self.language}") + elif self.voice_mode == config.VOICE_MODE_CLONE: + print(f"Reference audio: {Path(self.voice_clone_ref_audio).name}") + print(f"Language: {self.language}") print(f"Output format: {self.output_format}") if self.single_file and self.output_format != "m4b": print("Chapter mode: single file (--single-file)") @@ -396,6 +412,10 @@ class AudiobookConverter: print(f"Playback speed: {self.speed:g}x") print("=" * 70) + def run(self) -> bool: + """Main conversion process. Returns True if all books converted.""" + self._print_banner() + # Check for books book_files = sorted( f for f in config.BOOKS_FOLDER.iterdir() |
