From 757261ebfdff7c314db30644740a2f96e3bf7cab Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Fri, 7 Aug 2026 20:23:21 -0400 Subject: [PATCH] Enable live real-time TTS voice synchronization between VoiceManager and KokoroTTS --- bot.py | 2 +- spoken_text.py | 6 ++++++ voice_manager.py | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/bot.py b/bot.py index 881ca50..e232840 100644 --- a/bot.py +++ b/bot.py @@ -345,7 +345,7 @@ def build_tts(args: argparse.Namespace, voice_manager=None): logger.info(f"Text to speech: Kokoro {voice}") tts = KokoroTTSService( settings=KokoroTTSService.Settings(voice=voice, language=Language.EN), - text_filters=[SpokenTextFilter()], + text_filters=[SpokenTextFilter(voice_manager=voice_manager)], ) if voice_manager: voice_manager.set_tts_processor(tts) diff --git a/spoken_text.py b/spoken_text.py index 25b805e..7c06f76 100644 --- a/spoken_text.py +++ b/spoken_text.py @@ -34,7 +34,13 @@ _EXTRA_SPACE = re.compile(r"[ \t]{2,}") class SpokenTextFilter(MarkdownTextFilter): """Markdown filtering, plus the leftovers that matter when read aloud.""" + def __init__(self, voice_manager=None, **kwargs): + super().__init__(**kwargs) + self._voice_manager = voice_manager + async def filter(self, text: str) -> str: + if self._voice_manager: + self._voice_manager.sync_voice() text = _TIMES.sub(" times ", text) text = await super().filter(text) text = _STRIKETHROUGH.sub(r"\1", text) diff --git a/voice_manager.py b/voice_manager.py index 6483955..5d4eb5f 100644 --- a/voice_manager.py +++ b/voice_manager.py @@ -77,6 +77,19 @@ class VoiceManager: logger.warning(f"Could not load saved voice settings: {e}") return self._active_voice + def sync_voice(self) -> str: + """Check if voice_settings.json was updated on disk and update TTS live.""" + current_disk_voice = self.load_saved_voice() + if self._tts_processor and current_disk_voice: + if hasattr(self._tts_processor, "_settings"): + current_tts_voice = getattr(self._tts_processor._settings, "voice", None) + if current_tts_voice != current_disk_voice: + self._tts_processor._settings.voice = current_disk_voice + logger.info(f"Live TTS voice synced to: {current_disk_voice}") + elif hasattr(self._tts_processor, "set_voice"): + self._tts_processor.set_voice(current_disk_voice) + return current_disk_voice + def save_voice(self, voice_name: str): try: self._config_file.write_text(json.dumps({"voice": voice_name}, indent=2))