diff --git a/examples/foundational/07e-interruptible-playht.py b/examples/foundational/07e-interruptible-playht.py index 8a2af47bb..293e0b74d 100644 --- a/examples/foundational/07e-interruptible-playht.py +++ b/examples/foundational/07e-interruptible-playht.py @@ -49,7 +49,7 @@ async def main(): tts = PlayHTTTSService( user_id=os.getenv("PLAYHT_USER_ID"), api_key=os.getenv("PLAYHT_API_KEY"), - voice_url="s3://voice-cloning-zero-shot/801a663f-efd0-4254-98d0-5c175514c3e8/jennifer/manifest.json", + voice_url="s3://voice-cloning-zero-shot/d9ff78ba-d016-47f6-b0ef-dd630f59414e/female-cs/manifest.json", params=PlayHTTTSService.InputParams(language=Language.EN), ) diff --git a/src/pipecat/services/aws.py b/src/pipecat/services/aws.py index 8faeec03d..d913bf37e 100644 --- a/src/pipecat/services/aws.py +++ b/src/pipecat/services/aws.py @@ -5,7 +5,6 @@ # import asyncio - from typing import AsyncGenerator, Optional from loguru import logger @@ -33,6 +32,40 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +def language_to_aws_language(language: Language) -> str | None: + language_map = { + Language.CA: "ca-ES", + Language.ZH: "cmn-CN", + Language.DA: "da-DK", + Language.NL: "nl-NL", + Language.NL_BE: "nl-BE", + Language.EN: "en-US", + Language.EN_US: "en-US", + Language.EN_AU: "en-AU", + Language.EN_GB: "en-GB", + Language.EN_NZ: "en-NZ", + Language.EN_IN: "en-IN", + Language.FI: "fi-FI", + Language.FR: "fr-FR", + Language.FR_CA: "fr-CA", + Language.DE: "de-DE", + Language.HI: "hi-IN", + Language.IT: "it-IT", + Language.JA: "ja-JP", + Language.KO: "ko-KR", + Language.NO: "nb-NO", + Language.PL: "pl-PL", + Language.PT: "pt-PT", + Language.PT_BR: "pt-BR", + Language.RO: "ro-RO", + Language.RU: "ru-RU", + Language.ES: "es-ES", + Language.SV: "sv-SE", + Language.TR: "tr-TR", + } + return language_map.get(language) + + class AWSTTSService(TTSService): class InputParams(BaseModel): engine: Optional[str] = None @@ -65,7 +98,7 @@ class AWSTTSService(TTSService): "engine": params.engine, "language": self.language_to_service_language(params.language) if params.language - else Language.EN, + else "en-US", "pitch": params.pitch, "rate": params.rate, "volume": params.volume, @@ -77,62 +110,7 @@ class AWSTTSService(TTSService): return True def language_to_service_language(self, language: Language) -> str | None: - match language: - case Language.CA: - return "ca-ES" - case Language.ZH: - return "cmn-CN" - case Language.DA: - return "da-DK" - case Language.NL: - return "nl-NL" - case Language.NL_BE: - return "nl-BE" - case Language.EN | Language.EN_US: - return "en-US" - case Language.EN_AU: - return "en-AU" - case Language.EN_GB: - return "en-GB" - case Language.EN_NZ: - return "en-NZ" - case Language.EN_IN: - return "en-IN" - case Language.FI: - return "fi-FI" - case Language.FR: - return "fr-FR" - case Language.FR_CA: - return "fr-CA" - case Language.DE: - return "de-DE" - case Language.HI: - return "hi-IN" - case Language.IT: - return "it-IT" - case Language.JA: - return "ja-JP" - case Language.KO: - return "ko-KR" - case Language.NO: - return "nb-NO" - case Language.PL: - return "pl-PL" - case Language.PT: - return "pt-PT" - case Language.PT_BR: - return "pt-BR" - case Language.RO: - return "ro-RO" - case Language.RU: - return "ru-RU" - case Language.ES: - return "es-ES" - case Language.SV: - return "sv-SE" - case Language.TR: - return "tr-TR" - return None + return language_to_aws_language(language) def _construct_ssml(self, text: str) -> str: ssml = "" diff --git a/src/pipecat/services/azure.py b/src/pipecat/services/azure.py index fb6606010..96c2a9004 100644 --- a/src/pipecat/services/azure.py +++ b/src/pipecat/services/azure.py @@ -61,6 +61,67 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +def language_to_azure_language(language: Language) -> str | None: + language_map = { + Language.BG: "bg-BG", + Language.CA: "ca-ES", + Language.ZH: "zh-CN", + Language.ZH_TW: "zh-TW", + Language.CS: "cs-CZ", + Language.DA: "da-DK", + Language.NL: "nl-NL", + Language.EN: "en-US", + Language.EN_US: "en-US", + Language.EN_AU: "en-AU", + Language.EN_GB: "en-GB", + Language.EN_NZ: "en-NZ", + Language.EN_IN: "en-IN", + Language.ET: "et-EE", + Language.FI: "fi-FI", + Language.NL_BE: "nl-BE", + Language.FR: "fr-FR", + Language.FR_CA: "fr-CA", + Language.DE: "de-DE", + Language.DE_CH: "de-CH", + Language.EL: "el-GR", + Language.HI: "hi-IN", + Language.HU: "hu-HU", + Language.ID: "id-ID", + Language.IT: "it-IT", + Language.JA: "ja-JP", + Language.KO: "ko-KR", + Language.LV: "lv-LV", + Language.LT: "lt-LT", + Language.MS: "ms-MY", + Language.NO: "nb-NO", + Language.PL: "pl-PL", + Language.PT: "pt-PT", + Language.PT_BR: "pt-BR", + Language.RO: "ro-RO", + Language.RU: "ru-RU", + Language.SK: "sk-SK", + Language.ES: "es-ES", + Language.SV: "sv-SE", + Language.TH: "th-TH", + Language.TR: "tr-TR", + Language.UK: "uk-UA", + Language.VI: "vi-VN", + } + return language_map.get(language) + + +def sample_rate_to_output_format(sample_rate: int) -> SpeechSynthesisOutputFormat: + sample_rate_map = { + 8000: SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm, + 16000: SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm, + 22050: SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm, + 24000: SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm, + 44100: SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm, + 48000: SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm, + } + return sample_rate_map.get(sample_rate, SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm) + + class AzureLLMService(BaseOpenAILLMService): def __init__( self, *, api_key: str, endpoint: str, model: str, api_version: str = "2023-12-01-preview" @@ -89,23 +150,6 @@ class AzureLLMService(BaseOpenAILLMService): return OpenAIContextAggregatorPair(_user=user, _assistant=assistant) -def sample_rate_to_output_format(sample_rate: int) -> SpeechSynthesisOutputFormat: - match sample_rate: - case 8000: - return SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm - case 16000: - return SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm - case 22050: - return SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm - case 24000: - return SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm - case 44100: - return SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm - case 48000: - return SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm - return SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm - - class AzureBaseTTSService(TTSService): class InputParams(BaseModel): emphasis: Optional[str] = None @@ -134,7 +178,7 @@ class AzureBaseTTSService(TTSService): "emphasis": params.emphasis, "language": self.language_to_service_language(params.language) if params.language - else Language.EN_US, + else "en-US", "pitch": params.pitch, "rate": params.rate, "role": params.role, @@ -152,92 +196,7 @@ class AzureBaseTTSService(TTSService): return True def language_to_service_language(self, language: Language) -> str | None: - match language: - case Language.BG: - return "bg-BG" - case Language.CA: - return "ca-ES" - case Language.ZH: - return "zh-CN" - case Language.ZH_TW: - return "zh-TW" - case Language.CS: - return "cs-CZ" - case Language.DA: - return "da-DK" - case Language.NL: - return "nl-NL" - case Language.EN | Language.EN_US: - return "en-US" - case Language.EN_AU: - return "en-AU" - case Language.EN_GB: - return "en-GB" - case Language.EN_NZ: - return "en-NZ" - case Language.EN_IN: - return "en-IN" - case Language.ET: - return "et-EE" - case Language.FI: - return "fi-FI" - case Language.NL_BE: - return "nl-BE" - case Language.FR: - return "fr-FR" - case Language.FR_CA: - return "fr-CA" - case Language.DE: - return "de-DE" - case Language.DE_CH: - return "de-CH" - case Language.EL: - return "el-GR" - case Language.HI: - return "hi-IN" - case Language.HU: - return "hu-HU" - case Language.ID: - return "id-ID" - case Language.IT: - return "it-IT" - case Language.JA: - return "ja-JP" - case Language.KO: - return "ko-KR" - case Language.LV: - return "lv-LV" - case Language.LT: - return "lt-LT" - case Language.MS: - return "ms-MY" - case Language.NO: - return "nb-NO" - case Language.PL: - return "pl-PL" - case Language.PT: - return "pt-PT" - case Language.PT_BR: - return "pt-BR" - case Language.RO: - return "ro-RO" - case Language.RU: - return "ru-RU" - case Language.SK: - return "sk-SK" - case Language.ES: - return "es-ES" - case Language.SV: - return "sv-SE" - case Language.TH: - return "th-TH" - case Language.TR: - return "tr-TR" - case Language.UK: - return "uk-UA" - case Language.VI: - return "vi-VN" - return None + return language_to_azure_language(language) def _construct_ssml(self, text: str) -> str: language = self._settings["language"] diff --git a/src/pipecat/services/cartesia.py b/src/pipecat/services/cartesia.py index 7f30df448..7fad02fee 100644 --- a/src/pipecat/services/cartesia.py +++ b/src/pipecat/services/cartesia.py @@ -44,29 +44,24 @@ except ModuleNotFoundError as e: def language_to_cartesia_language(language: Language) -> str | None: - match language: - case Language.DE: - return "de" - case ( - Language.EN - | Language.EN_US - | Language.EN_GB - | Language.EN_AU - | Language.EN_NZ - | Language.EN_IN - ): - return "en" - case Language.ES: - return "es" - case Language.FR | Language.FR_CA: - return "fr" - case Language.JA: - return "ja" - case Language.PT | Language.PT_BR: - return "pt" - case Language.ZH | Language.ZH_TW: - return "zh" - return None + language_map = { + Language.DE: "de", + Language.EN: "en", + Language.EN_US: "en", + Language.EN_GB: "en", + Language.EN_AU: "en", + Language.EN_NZ: "en", + Language.EN_IN: "en", + Language.ES: "es", + Language.FR: "fr", + Language.FR_CA: "fr", + Language.JA: "ja", + Language.PT: "pt", + Language.PT_BR: "pt", + Language.ZH: "zh", + Language.ZH_TW: "zh", + } + return language_map.get(language) class CartesiaTTSService(WordTTSService): @@ -117,7 +112,7 @@ class CartesiaTTSService(WordTTSService): }, "language": self.language_to_service_language(params.language) if params.language - else Language.EN, + else "en", "speed": params.speed, "emotion": params.emotion, } @@ -331,7 +326,7 @@ class CartesiaHttpTTSService(TTSService): }, "language": self.language_to_service_language(params.language) if params.language - else Language.EN, + else "en", "speed": params.speed, "emotion": params.emotion, } diff --git a/src/pipecat/services/elevenlabs.py b/src/pipecat/services/elevenlabs.py index 9b1f54351..d13859af5 100644 --- a/src/pipecat/services/elevenlabs.py +++ b/src/pipecat/services/elevenlabs.py @@ -42,6 +42,48 @@ except ModuleNotFoundError as e: ElevenLabsOutputFormat = Literal["pcm_16000", "pcm_22050", "pcm_24000", "pcm_44100"] +def language_to_elevenlabs_language(language: Language) -> str | None: + language_map = { + Language.BG: "bg", + Language.ZH: "zh", + Language.CS: "cs", + Language.DA: "da", + Language.NL: "nl", + Language.EN: "en", + Language.EN_US: "en", + Language.EN_AU: "en", + Language.EN_GB: "en", + Language.EN_NZ: "en", + Language.EN_IN: "en", + Language.FI: "fi", + Language.FR: "fr", + Language.FR_CA: "fr", + Language.DE: "de", + Language.DE_CH: "de", + Language.EL: "el", + Language.HI: "hi", + Language.HU: "hu", + Language.ID: "id", + Language.IT: "it", + Language.JA: "ja", + Language.KO: "ko", + Language.MS: "ms", + Language.NO: "no", + Language.PL: "pl", + Language.PT: "pt-PT", + Language.PT_BR: "pt-BR", + Language.RO: "ro", + Language.RU: "ru", + Language.SK: "sk", + Language.ES: "es", + Language.SV: "sv", + Language.TR: "tr", + Language.UK: "uk", + Language.VI: "vi", + } + return language_map.get(language) + + def sample_rate_from_output_format(output_format: str) -> int: match output_format: case "pcm_16000": @@ -135,7 +177,7 @@ class ElevenLabsTTSService(WordTTSService): "sample_rate": sample_rate_from_output_format(output_format), "language": self.language_to_service_language(params.language) if params.language - else Language.EN, + else "en", "output_format": output_format, "optimize_streaming_latency": params.optimize_streaming_latency, "stability": params.stability, @@ -158,73 +200,7 @@ class ElevenLabsTTSService(WordTTSService): return True def language_to_service_language(self, language: Language) -> str | None: - match language: - case Language.BG: - return "bg" - case Language.ZH: - return "zh" - case Language.CS: - return "cs" - case Language.DA: - return "da" - case Language.NL: - return "nl" - case ( - Language.EN - | Language.EN_US - | Language.EN_AU - | Language.EN_GB - | Language.EN_NZ - | Language.EN_IN - ): - return "en" - case Language.FI: - return "fi" - case Language.FR | Language.FR_CA: - return "fr" - case Language.DE | Language.DE_CH: - return "de" - case Language.EL: - return "el" - case Language.HI: - return "hi" - case Language.HU: - return "hu" - case Language.ID: - return "id" - case Language.IT: - return "it" - case Language.JA: - return "ja" - case Language.KO: - return "ko" - case Language.MS: - return "ms" - case Language.NO: - return "no" - case Language.PL: - return "pl" - case Language.PT: - return "pt-PT" - case Language.PT_BR: - return "pt-BR" - case Language.RO: - return "ro" - case Language.RU: - return "ru" - case Language.SK: - return "sk" - case Language.ES: - return "es" - case Language.SV: - return "sv" - case Language.TR: - return "tr" - case Language.UK: - return "uk" - case Language.VI: - return "vi" - return None + return language_to_elevenlabs_language(language) def _set_voice_settings(self): voice_settings = {} diff --git a/src/pipecat/services/gladia.py b/src/pipecat/services/gladia.py index 75555ca13..574cfcb59 100644 --- a/src/pipecat/services/gladia.py +++ b/src/pipecat/services/gladia.py @@ -34,6 +34,53 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +def language_to_gladia_language(language: Language) -> str | None: + language_map = { + Language.BG: "bg", + Language.CA: "ca", + Language.ZH: "zh", + Language.CS: "cs", + Language.DA: "da", + Language.NL: "nl", + Language.EN: "en", + Language.EN_US: "en", + Language.EN_AU: "en", + Language.EN_GB: "en", + Language.EN_NZ: "en", + Language.EN_IN: "en", + Language.ET: "et", + Language.FI: "fi", + Language.FR: "fr", + Language.FR_CA: "fr", + Language.DE: "de", + Language.DE_CH: "de", + Language.EL: "el", + Language.HI: "hi", + Language.HU: "hu", + Language.ID: "id", + Language.IT: "it", + Language.JA: "ja", + Language.KO: "ko", + Language.LV: "lv", + Language.LT: "lt", + Language.MS: "ms", + Language.NO: "no", + Language.PL: "pl", + Language.PT: "pt", + Language.PT_BR: "pt", + Language.RO: "ro", + Language.RU: "ru", + Language.SK: "sk", + Language.ES: "es", + Language.SV: "sv", + Language.TH: "th", + Language.TR: "tr", + Language.UK: "uk", + Language.VI: "vi", + } + return language_map.get(language) + + class GladiaSTTService(STTService): class InputParams(BaseModel): sample_rate: Optional[int] = 16000 @@ -79,50 +126,7 @@ class GladiaSTTService(STTService): self._confidence = confidence def language_to_service_language(self, language: Language) -> str | None: - language_map = { - Language.BG: "bg", - Language.CA: "ca", - Language.ZH: "zh", - Language.CS: "cs", - Language.DA: "da", - Language.NL: "nl", - Language.EN: "en", - Language.EN_US: "en", - Language.EN_AU: "en", - Language.EN_GB: "en", - Language.EN_NZ: "en", - Language.EN_IN: "en", - Language.ET: "et", - Language.FI: "fi", - Language.FR: "fr", - Language.FR_CA: "fr", - Language.DE: "de", - Language.DE_CH: "de", - Language.EL: "el", - Language.HI: "hi", - Language.HU: "hu", - Language.ID: "id", - Language.IT: "it", - Language.JA: "ja", - Language.KO: "ko", - Language.LV: "lv", - Language.LT: "lt", - Language.MS: "ms", - Language.NO: "no", - Language.PL: "pl", - Language.PT: "pt", - Language.PT_BR: "pt", - Language.RO: "ro", - Language.RU: "ru", - Language.SK: "sk", - Language.ES: "es", - Language.SV: "sv", - Language.TH: "th", - Language.TR: "tr", - Language.UK: "uk", - Language.VI: "vi", - } - return language_map.get(language) + return language_to_gladia_language(language) async def start(self, frame: StartFrame): await super().start(frame) diff --git a/src/pipecat/services/google.py b/src/pipecat/services/google.py index c1114e44e..c81f78386 100644 --- a/src/pipecat/services/google.py +++ b/src/pipecat/services/google.py @@ -55,6 +55,53 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +def language_to_google_language(language: Language) -> str | None: + language_map = { + Language.BG: "bg-BG", + Language.CA: "ca-ES", + Language.ZH: "cmn-CN", + Language.ZH_TW: "cmn-TW", + Language.CS: "cs-CZ", + Language.DA: "da-DK", + Language.NL: "nl-NL", + Language.EN: "en-US", + Language.EN_US: "en-US", + Language.EN_AU: "en-AU", + Language.EN_GB: "en-GB", + Language.EN_IN: "en-IN", + Language.ET: "et-EE", + Language.FI: "fi-FI", + Language.NL_BE: "nl-BE", + Language.FR: "fr-FR", + Language.FR_CA: "fr-CA", + Language.DE: "de-DE", + Language.EL: "el-GR", + Language.HI: "hi-IN", + Language.HU: "hu-HU", + Language.ID: "id-ID", + Language.IT: "it-IT", + Language.JA: "ja-JP", + Language.KO: "ko-KR", + Language.LV: "lv-LV", + Language.LT: "lt-LT", + Language.MS: "ms-MY", + Language.NO: "nb-NO", + Language.PL: "pl-PL", + Language.PT: "pt-PT", + Language.PT_BR: "pt-BR", + Language.RO: "ro-RO", + Language.RU: "ru-RU", + Language.SK: "sk-SK", + Language.ES: "es-ES", + Language.SV: "sv-SE", + Language.TH: "th-TH", + Language.TR: "tr-TR", + Language.UK: "uk-UA", + Language.VI: "vi-VN", + } + return language_map.get(language) + + class GoogleUserContextAggregator(OpenAIUserContextAggregator): async def _push_aggregation(self): if len(self._aggregation) > 0: @@ -499,7 +546,7 @@ class GoogleTTSService(TTSService): "emphasis": params.emphasis, "language": self.language_to_service_language(params.language) if params.language - else Language.EN, + else "en-US", "gender": params.gender, "google_style": params.google_style, } @@ -530,88 +577,7 @@ class GoogleTTSService(TTSService): return True def language_to_service_language(self, language: Language) -> str | None: - match language: - case Language.BG: - return "bg-BG" - case Language.CA: - return "ca-ES" - case Language.ZH: - return "cmn-CN" - case Language.ZH_TW: - return "cmn-TW" - case Language.CS: - return "cs-CZ" - case Language.DA: - return "da-DK" - case Language.NL: - return "nl-NL" - case Language.EN | Language.EN_US: - return "en-US" - case Language.EN_AU: - return "en-AU" - case Language.EN_GB: - return "en-GB" - case Language.EN_IN: - return "en-IN" - case Language.ET: - return "et-EE" - case Language.FI: - return "fi-FI" - case Language.NL_BE: - return "nl-BE" - case Language.FR: - return "fr-FR" - case Language.FR_CA: - return "fr-CA" - case Language.DE: - return "de-DE" - case Language.EL: - return "el-GR" - case Language.HI: - return "hi-IN" - case Language.HU: - return "hu-HU" - case Language.ID: - return "id-ID" - case Language.IT: - return "it-IT" - case Language.JA: - return "ja-JP" - case Language.KO: - return "ko-KR" - case Language.LV: - return "lv-LV" - case Language.LT: - return "lt-LT" - case Language.MS: - return "ms-MY" - case Language.NO: - return "nb-NO" - case Language.PL: - return "pl-PL" - case Language.PT: - return "pt-PT" - case Language.PT_BR: - return "pt-BR" - case Language.RO: - return "ro-RO" - case Language.RU: - return "ru-RU" - case Language.SK: - return "sk-SK" - case Language.ES: - return "es-ES" - case Language.SV: - return "sv-SE" - case Language.TH: - return "th-TH" - case Language.TR: - return "tr-TR" - case Language.UK: - return "uk-UA" - case Language.VI: - return "vi-VN" - return None + return language_to_google_language(language) def _construct_ssml(self, text: str) -> str: ssml = "" diff --git a/src/pipecat/services/lmnt.py b/src/pipecat/services/lmnt.py index d41bacf98..7717358de 100644 --- a/src/pipecat/services/lmnt.py +++ b/src/pipecat/services/lmnt.py @@ -35,6 +35,27 @@ except ModuleNotFoundError as e: raise Exception(f"Missing module: {e}") +def language_to_lmnt_language(language: Language) -> str | None: + language_map = { + Language.DE: "de", + Language.EN: "en", + Language.EN_US: "en", + Language.EN_AU: "en", + Language.EN_GB: "en", + Language.EN_NZ: "en", + Language.EN_IN: "en", + Language.ES: "es", + Language.FR: "fr", + Language.FR_CA: "fr", + Language.PT: "pt", + Language.PT_BR: "pt", + Language.ZH: "zh", + Language.ZH_TW: "zh", + Language.KO: "ko", + } + return language_map.get(language) + + class LmntTTSService(TTSService): def __init__( self, @@ -72,29 +93,7 @@ class LmntTTSService(TTSService): return True def language_to_service_language(self, language: Language) -> str | None: - match language: - case Language.DE: - return "de" - case ( - Language.EN - | Language.EN_US - | Language.EN_AU - | Language.EN_GB - | Language.EN_NZ - | Language.EN_IN - ): - return "en" - case Language.ES: - return "es" - case Language.FR | Language.FR_CA: - return "fr" - case Language.PT | Language.PT_BR: - return "pt" - case Language.ZH | Language.ZH_TW: - return "zh" - case Language.KO: - return "ko" - return None + return language_to_lmnt_language(language) async def start(self, frame: StartFrame): await super().start(frame) diff --git a/src/pipecat/services/playht.py b/src/pipecat/services/playht.py index 167181586..9b5890554 100644 --- a/src/pipecat/services/playht.py +++ b/src/pipecat/services/playht.py @@ -47,63 +47,40 @@ except ModuleNotFoundError as e: def language_to_playht_language(language: Language) -> str | None: - match language: - case Language.BG: - return "BULGARIAN" - case Language.CA: - return "CATALAN" - case Language.CS: - return "CZECH" - case Language.DA: - return "DANISH" - case Language.DE: - return "GERMAN" - case ( - Language.EN - | Language.EN_US - | Language.EN_GB - | Language.EN_AU - | Language.EN_NZ - | Language.EN_IN - ): - return "ENGLISH" - case Language.ES: - return "SPANISH" - case Language.FR | Language.FR_CA: - return "FRENCH" - case Language.EL: - return "GREEK" - case Language.HI: - return "HINDI" - case Language.HU: - return "HUNGARIAN" - case Language.ID: - return "INDONESIAN" - case Language.IT: - return "ITALIAN" - case Language.JA: - return "JAPANESE" - case Language.KO: - return "KOREAN" - case Language.MS: - return "MALAY" - case Language.NL: - return "DUTCH" - case Language.PL: - return "POLISH" - case Language.PT | Language.PT_BR: - return "PORTUGUESE" - case Language.RU: - return "RUSSIAN" - case Language.SV: - return "SWEDISH" - case Language.TH: - return "THAI" - case Language.TR: - return "TURKISH" - case Language.UK: - return "UKRAINIAN" - return None + language_map = { + Language.BG: "bulgarian", + Language.CA: "catalan", + Language.CS: "czech", + Language.DA: "danish", + Language.DE: "german", + Language.EN: "english", + Language.EN_US: "english", + Language.EN_GB: "english", + Language.EN_AU: "english", + Language.EN_NZ: "english", + Language.EN_IN: "english", + Language.ES: "spanish", + Language.FR: "french", + Language.FR_CA: "french", + Language.EL: "greek", + Language.HI: "hindi", + Language.HU: "hungarian", + Language.ID: "indonesian", + Language.IT: "italian", + Language.JA: "japanese", + Language.KO: "korean", + Language.MS: "malay", + Language.NL: "dutch", + Language.PL: "polish", + Language.PT: "portuguese", + Language.PT_BR: "portuguese", + Language.RU: "russian", + Language.SV: "swedish", + Language.TH: "thai", + Language.TR: "turkish", + Language.UK: "ukrainian", + } + return language_map.get(language) class PlayHTTTSService(TTSService): @@ -118,7 +95,7 @@ class PlayHTTTSService(TTSService): api_key: str, user_id: str, voice_url: str, - voice_engine: str = "PlayHT3.0-mini", + voice_engine: str = "Play3.0-mini", sample_rate: int = 24000, output_format: str = "wav", params: InputParams = InputParams(), @@ -140,7 +117,7 @@ class PlayHTTTSService(TTSService): "sample_rate": sample_rate, "language": self.language_to_service_language(params.language) if params.language - else Language.EN, + else "english", "output_format": output_format, "voice_engine": voice_engine, "speed": params.speed, @@ -153,8 +130,7 @@ class PlayHTTTSService(TTSService): return True def language_to_service_language(self, language: Language) -> str | None: - # Keep your existing language mapping logic here - pass + return language_to_playht_language(language) async def start(self, frame: StartFrame): await super().start(frame) @@ -234,17 +210,11 @@ class PlayHTTTSService(TTSService): async def _receive_task_handler(self): try: - header_size = 78 # Size of the WAV header + extra bytes we want to skip - header_received = False async for message in self._get_websocket(): if isinstance(message, bytes): - chunk_size = len(message) - - # Skip the WAV header - if not header_received and chunk_size == header_size: - header_received = True + # Skip the WAV header message + if message.startswith(b"RIFF"): continue - await self.stop_ttfb_metrics() frame = TTSAudioRawFrame(message, self._settings["sample_rate"], 1) await self.push_frame(frame) @@ -254,7 +224,6 @@ class PlayHTTTSService(TTSService): msg = json.loads(message) if "request_id" in msg and msg["request_id"] == self._request_id: await self.push_frame(TTSStoppedFrame()) - header_received = False # Reset for the next audio stream self._request_id = None elif "error" in msg: logger.error(f"{self} error: {msg}") @@ -334,7 +303,7 @@ class PlayHTHttpTTSService(TTSService): api_key: str, user_id: str, voice_url: str, - voice_engine: str = "PlayHT3.0-mini", + voice_engine: str = "Play3.0-mini", sample_rate: int = 24000, params: InputParams = InputParams(), **kwargs, @@ -352,7 +321,7 @@ class PlayHTHttpTTSService(TTSService): "sample_rate": sample_rate, "language": self.language_to_service_language(params.language) if params.language - else Language.EN, + else "english", "format": Format.FORMAT_WAV, "voice_engine": voice_engine, "speed": params.speed, diff --git a/src/pipecat/services/xtts.py b/src/pipecat/services/xtts.py index bcdb132fa..97e7ee021 100644 --- a/src/pipecat/services/xtts.py +++ b/src/pipecat/services/xtts.py @@ -31,6 +31,34 @@ from loguru import logger # https://github.com/coqui-ai/xtts-streaming-server +def language_to_xtts_language(language: Language) -> str | None: + language_map = { + Language.CS: "cs", + Language.DE: "de", + Language.EN: "en", + Language.EN_US: "en", + Language.EN_AU: "en", + Language.EN_GB: "en", + Language.EN_NZ: "en", + Language.EN_IN: "en", + Language.ES: "es", + Language.FR: "fr", + Language.HI: "hi", + Language.HU: "hu", + Language.IT: "it", + Language.JA: "ja", + Language.KO: "ko", + Language.NL: "nl", + Language.PL: "pl", + Language.PT: "pt", + Language.PT_BR: "pt", + Language.RU: "ru", + Language.TR: "tr", + Language.ZH: "zh-cn", + } + return language_map.get(language) + + class XTTSService(TTSService): def __init__( self, @@ -56,47 +84,7 @@ class XTTSService(TTSService): return True def language_to_service_language(self, language: Language) -> str | None: - match language: - case Language.CS: - return "cs" - case Language.DE: - return "de" - case ( - Language.EN - | Language.EN_US - | Language.EN_AU - | Language.EN_GB - | Language.EN_NZ - | Language.EN_IN - ): - return "en" - case Language.ES: - return "es" - case Language.FR: - return "fr" - case Language.HI: - return "hi" - case Language.HU: - return "hu" - case Language.IT: - return "it" - case Language.JA: - return "ja" - case Language.KO: - return "ko" - case Language.NL: - return "nl" - case Language.PL: - return "pl" - case Language.PT | Language.PT_BR: - return "pt" - case Language.RU: - return "ru" - case Language.TR: - return "tr" - case Language.ZH: - return "zh-cn" - return None + return language_to_xtts_language(language) async def start(self, frame: StartFrame): await super().start(frame)