From 248206e234def6c6a65dd7b348610b8337d65ab1 Mon Sep 17 00:00:00 2001 From: Yohan Liyanage Date: Sat, 2 Aug 2025 12:49:29 +0530 Subject: [PATCH] Fixes 2277 - SSML reserved characters in LLM generated text causes Azure TTS to fail. --- src/pipecat/services/azure/tts.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/pipecat/services/azure/tts.py b/src/pipecat/services/azure/tts.py index 0cf029c6b..49470f85a 100644 --- a/src/pipecat/services/azure/tts.py +++ b/src/pipecat/services/azure/tts.py @@ -128,6 +128,14 @@ class AzureBaseTTSService(TTSService): "volume": params.volume, } + # Define SSML escape mappings based on SSML reserved characters + # See - https://learn.microsoft.com/en-us/azure/ai-services/speech-service/speech-synthesis-markup-structure + self.ssml_escape_chars = { + '&': '&', + '<': '<', + '>': '>' + } + self._api_key = api_key self._region = region self._voice_id = voice @@ -154,6 +162,10 @@ class AzureBaseTTSService(TTSService): def _construct_ssml(self, text: str) -> str: language = self._settings["language"] + + # Escape special characters + escaped_text = self._escape_text(text) + ssml = ( f"" - ssml += text + ssml += escaped_text if self._settings["emphasis"]: ssml += "" @@ -197,6 +209,20 @@ class AzureBaseTTSService(TTSService): return ssml + def _escape_text(self, text: str) -> str: + """Escape special characters in text for SSML. + + Args: + text: The text to escape. + + Returns: + The escaped text. + """ + escaped_text = text + for char, escape_code in self.ssml_escape_chars.items(): + escaped_text = escaped_text.replace(char, escape_code) + return escaped_text + class AzureTTSService(AzureBaseTTSService): """Azure Cognitive Services streaming TTS service.