diff --git a/daras_ai_v2/twilio_bot.py b/daras_ai_v2/twilio_bot.py index f7648a6a8..8d4dd8606 100644 --- a/daras_ai_v2/twilio_bot.py +++ b/daras_ai_v2/twilio_bot.py @@ -126,7 +126,6 @@ def __init__( text: str = None, audio_url: str = None, ): - from routers.twilio_api import get_twilio_tts_voice, get_twilio_asr_language self.convo = convo @@ -149,11 +148,6 @@ def __init__( super().__init__() - self.use_gooey_asr = self.saved_run.state.get( - "asr_model" - ) or not get_twilio_asr_language(self.bi) - self.use_gooey_tts = not get_twilio_tts_voice(self.bi) - def get_input_text(self) -> str | None: return self._text diff --git a/routers/twilio_api.py b/routers/twilio_api.py index 6cecace5a..6913a3ca7 100644 --- a/routers/twilio_api.py +++ b/routers/twilio_api.py @@ -12,11 +12,14 @@ from app_users.models import AppUser from bots.models import Conversation, BotIntegration +from daras_ai_v2.asr import normalised_lang_in_collection from daras_ai_v2.bots import msg_handler +from daras_ai_v2.exceptions import UserError from daras_ai_v2.fastapi_tricks import ( fastapi_request_urlencoded_body, get_api_route_url, ) +from daras_ai_v2.text_to_speech_settings_widgets import TextToSpeechProviders from daras_ai_v2.twilio_bot import TwilioVoice from gooeysite.bg_db_conn import get_celery_result_db_safe from recipes.TextToSpeech import TextToSpeechPage @@ -29,10 +32,26 @@ "http://com.twilio.sounds.music.s3.amazonaws.com/Mellotroniac_-_Flight_Of_Young_Hearts_Flute.mp3", "http://com.twilio.sounds.music.s3.amazonaws.com/MARKOVICHAMP-Borghestral.mp3", ] -DEFAULT_VOICE_NAME = "Google.en-US-Wavenet-F" -DEFAULT_ASR_LANGUAGE = "en-US" -TWILIO_SUPPORTED_VOICES = {"Google.af-ZA-Standard-A", "Polly.Zeina", "Google.ar-XA-Standard-A", "Google.ar-XA-Standard-B", "Google.ar-XA-Standard-C", "Google.ar-XA-Standard-D", "Google.ar-XA-Wavenet-A", "Google.ar-XA-Wavenet-B", "Google.ar-XA-Wavenet-C", "Google.ar-XA-Wavenet-D", "Polly.Hala-Neural", "Polly.Zayd-Neural", "Google.eu-ES-Standard-A", "Google.bn-IN-Standard-C", "Google.bn-IN-Standard-D", "Google.bn-IN-Wavenet-C", "Google.bn-IN-Wavenet-D", "Google.bg-BG-Standard-A", "Polly.Arlet-Neural", "Google.ca-ES-Standard-A", "Polly.Hiujin-Neural", "Google.yue-HK-Standard-A", "Google.yue-HK-Standard-B", "Google.yue-HK-Standard-C", "Google.yue-HK-Standard-D", "Polly.Zhiyu", "Polly.Zhiyu-Neural", "Google.cmn-CN-Standard-A", "Google.cmn-CN-Standard-B", "Google.cmn-CN-Standard-C", "Google.cmn-CN-Standard-D", "Google.cmn-CN-Wavenet-A", "Google.cmn-CN-Wavenet-B", "Google.cmn-CN-Wavenet-C", "Google.cmn-CN-Wavenet-D", "Google.cmn-TW-Standard-A", "Google.cmn-TW-Standard-B", "Google.cmn-TW-Standard-C", "Google.cmn-TW-Wavenet-A", "Google.cmn-TW-Wavenet-B", "Google.cmn-TW-Wavenet-C", "Google.cs-CZ-Standard-A", "Google.cs-CZ-Wavenet-A", "Polly.Mads", "Polly.Naja", "Polly.Sofie-Neural", "Google.da-DK-Standard-A", "Google.da-DK-Standard-C", "Google.da-DK-Standard-D", "Google.da-DK-Standard-E", "Google.da-DK-Wavenet-A", "Google.da-DK-Wavenet-C", "Google.da-DK-Wavenet-D", "Google.da-DK-Wavenet-E", "Polly.Lisa-Neural", "Google.nl-BE-Standard-A", "Google.nl-BE-Standard-B", "Google.nl-BE-Wavenet-A", "Google.nl-BE-Wavenet-B", "Polly.Lotte", "Polly.Ruben", "Polly.Laura-Neural", "Google.nl-NL-Standard-A", "Google.nl-NL-Standard-B", "Google.nl-NL-Standard-C", "Google.nl-NL-Standard-D", "Google.nl-NL-Standard-E", "Google.nl-NL-Wavenet-A", "Google.nl-NL-Wavenet-B", "Google.nl-NL-Wavenet-C", "Google.nl-NL-Wavenet-D", "Google.nl-NL-Wavenet-E", "Polly.Nicole", "Polly.Russell", "Polly.Olivia-Neural", "Google.en-AU-Standard-A", "Google.en-AU-Standard-B", "Google.en-AU-Standard-C", "Google.en-AU-Standard-D", "Google.en-AU-Wavenet-A", "Google.en-AU-Wavenet-B", "Google.en-AU-Wavenet-C", "Google.en-AU-Wavenet-D", "Google.en-AU-Neural2-A", "Google.en-AU-Neural2-B", "Google.en-AU-Neural2-C", "Google.en-AU-Neural2-D", "Polly.Raveena", "Google.en-IN-Standard-A", "Google.en-IN-Standard-B", "Google.en-IN-Standard-C", "Google.en-IN-Standard-D", "Google.en-IN-Wavenet-A", "Google.en-IN-Wavenet-B", "Google.en-IN-Wavenet-C", "Google.en-IN-Wavenet-D", "Google.en-IN-Neural2-A", "Google.en-IN-Neural2-B", "Google.en-IN-Neural2-C", "Google.en-IN-Neural2-D", "Polly.Niamh-Neural", "Polly.Aria-Neural", "Polly.Ayanda-Neural", "Polly.Amy", "Polly.Brian", "Polly.Emma", "Polly.Amy-Neural", "Polly.Emma-Neural", "Polly.Brian-Neural", "Polly.Arthur-Neural", "Google.en-GB-Standard-A", "Google.en-GB-Standard-B", "Google.en-GB-Standard-C", "Google.en-GB-Standard-D", "Google.en-GB-Standard-F", "Google.en-GB-Wavenet-A", "Google.en-GB-Wavenet-B", "Google.en-GB-Wavenet-C", "Google.en-GB-Wavenet-D", "Google.en-GB-Wavenet-F", "Google.en-GB-Neural2-A", "Google.en-GB-Neural2-B", "Google.en-GB-Neural2-C", "Google.en-GB-Neural2-D", "Google.en-GB-Neural2-F", "Polly.Ivy", "Polly.Joanna", "Polly.Joey", "Polly.Justin", "Polly.Kendra", "Polly.Kimberly", "Polly.Matthew", "Polly.Salli", "child) Polly.Ivy-Neural", "Polly.Joanna-Neural*", "Polly.Kendra-Neural", "child) Polly.Kevin-Neural", "Polly.Kimberly-Neural", "Polly.Salli-Neural", "Polly.Joey-Neural", "child) Polly.Justin-Neural", "Polly.Matthew-Neural*", "Polly.Ruth-Neural", "Polly.Stephen-Neural", "Polly.Gregory-Neural", "Polly.Danielle-Neural", "Google.en-US-Standard-A", "Google.en-US-Standard-B", "Google.en-US-Standard-C", "Google.en-US-Standard-D", "Google.en-US-Standard-E", "Google.en-US-Standard-F", "Google.en-US-Standard-G", "Google.en-US-Standard-H", "Google.en-US-Standard-I", "Google.en-US-Standard-J", "Google.en-US-Wavenet-A", "Google.en-US-Wavenet-B", "Google.en-US-Wavenet-C", "Google.en-US-Wavenet-D", "Google.en-US-Wavenet-E", "Google.en-US-Wavenet-F", "Google.en-US-Wavenet-G", "Google.en-US-Wavenet-H", "Google.en-US-Wavenet-I", "Google.en-US-Wavenet-J", "Google.en-US-Neural2-A", "Google.en-US-Neural2-C", "Google.en-US-Neural2-D", "Google.en-US-Neural2-E", "Google.en-US-Neural2-F", "Google.en-US-Neural2-G", "Google.en-US-Neural2-H", "Google.en-US-Neural2-I", "Google.en-US-Neural2-J", "Polly.Geraint", "Google.fil-PH-Standard-A", "Google.fil-PH-Standard-B", "Google.fil-PH-Standard-C", "Google.fil-PH-Standard-D", "Google.fil-PH-Wavenet-A", "Google.fil-PH-Wavenet-B", "Google.fil-PH-Wavenet-C", "Google.fil-PH-Wavenet-D", "Polly.Suvi-Neural", "Google.fi-FI-Standard-A", "Google.fi-FI-Wavenet-A", "Polly.Isabelle-Neural", "Polly.Chantal", "Polly.Gabrielle-Neural", "Polly.Liam-Neural", "Google.fr-CA-Standard-A", "Google.fr-CA-Standard-B", "Google.fr-CA-Standard-C", "Google.fr-CA-Standard-D", "Google.fr-CA-Wavenet-A", "Google.fr-CA-Wavenet-B", "Google.fr-CA-Wavenet-C", "Google.fr-CA-Wavenet-D", "Google.fr-CA-Neural2-A", "Google.fr-CA-Neural2-B", "Google.fr-CA-Neural2-C", "Google.fr-CA-Neural2-D", "Polly.Céline/Polly.Celine", "Polly.Léa/Polly.Lea", "Polly.Mathieu", "Polly.Lea-Neural", "Polly.Remi-Neural", "Google.fr-FR-Standard-A", "Google.fr-FR-Standard-B", "Google.fr-FR-Standard-C", "Google.fr-FR-Standard-D", "Google.fr-FR-Standard-E", "Google.fr-FR-Wavenet-A", "Google.fr-FR-Wavenet-B", "Google.fr-FR-Wavenet-C", "Google.fr-FR-Wavenet-D", "Google.fr-FR-Wavenet-E", "Google.fr-FR-Neural2-A", "Google.fr-FR-Neural2-B", "Google.fr-FR-Neural2-C", "Google.fr-FR-Neural2-D", "Google.fr-FR-Neural2-E", "Google.gl-ES-Standard-A", "Polly.Hannah-Neural", "Polly.Hans", "Polly.Marlene", "Polly.Vicki", "Polly.Vicki-Neural", "Polly.Daniel-Neural", "Google.de-DE-Standard-A", "Google.de-DE-Standard-B", "Google.de-DE-Standard-C", "Google.de-DE-Standard-D", "Google.de-DE-Standard-E", "Google.de-DE-Standard-F", "Google.de-DE-Wavenet-A", "Google.de-DE-Wavenet-B", "Google.de-DE-Wavenet-C", "Google.de-DE-Wavenet-D", "Google.de-DE-Wavenet-E", "Google.de-DE-Wavenet-F", "Google.de-DE-Neural2-A", "Google.de-DE-Neural2-B", "Google.de-DE-Neural2-C", "Google.de-DE-Neural2-D", "Google.de-DE-Neural2-F", "Google.el-GR-Standard-A", "Google.el-GR-Wavenet-A", "Google.gu-IN-Standard-C", "Google.gu-IN-Standard-D", "Google.gu-IN-Wavenet-C", "Google.gu-IN-Wavenet-D", "Google.he-IL-Standard-A", "Google.he-IL-Standard-B", "Google.he-IL-Standard-C", "Google.he-IL-Standard-D", "Google.he-IL-Wavenet-A", "Google.he-IL-Wavenet-B", "Google.he-IL-Wavenet-C", "Google.he-IL-Wavenet-D", "Polly.Aditi", "Polly.Kajal-Neural", "Google.hi-IN-Standard-A", "Google.hi-IN-Standard-B", "Google.hi-IN-Standard-C", "Google.hi-IN-Standard-D", "Google.hi-IN-Wavenet-A", "Google.hi-IN-Wavenet-B", "Google.hi-IN-Wavenet-C", "Google.hi-IN-Wavenet-D", "Google.hi-IN-Neural2-A", "Google.hi-IN-Neural2-B", "Google.hi-IN-Neural2-C", "Google.hi-IN-Neural2-D", "Google.hu-HU-Standard-A", "Google.hu-HU-Wavenet-A", "Polly.Dóra/Polly.Dora", "Polly.Karl", "Google.is-IS-Standard-A", "Google.id-ID-Standard-A", "Google.id-ID-Standard-B", "Google.id-ID-Standard-C", "Google.id-ID-Standard-D", "Google.id-ID-Wavenet-A", "Google.id-ID-Wavenet-B", "Google.id-ID-Wavenet-C", "Google.id-ID-Wavenet-D", "Polly.Bianca", "Polly.Carla", "Polly.Giorgio", "Polly.Bianca-Neural", "Polly.Adriano-Neural", "Google.it-IT-Standard-B", "Google.it-IT-Standard-C", "Google.it-IT-Standard-D", "Google.it-IT-Wavenet-B", "Google.it-IT-Wavenet-C", "Google.it-IT-Wavenet-D", "Google.it-IT-Neural2-A", "Google.it-IT-Neural2-C", "Polly.Mizuki", "Polly.Takumi", "Polly.Takumi-Neural", "Polly.Kazuha-Neural", "Polly.Tomoko-Neural", "Google.ja-JP-Standard-B", "Google.ja-JP-Standard-C", "Google.ja-JP-Standard-D", "Google.ja-JP-Wavenet-B", "Google.ja-JP-Wavenet-C", "Google.ja-JP-Wavenet-D", "Google.kn-IN-Standard-C", "Google.kn-IN-Standard-D", "Google.kn-IN-Wavenet-C", "Google.kn-IN-Wavenet-D", "Polly.Seoyeon", "Polly.Seoyeon-Neural", "Google.ko-KR-Standard-A", "Google.ko-KR-Standard-B", "Google.ko-KR-Standard-C", "Google.ko-KR-Standard-D", "Google.ko-KR-Wavenet-A", "Google.ko-KR-Wavenet-B", "Google.ko-KR-Wavenet-C", "Google.ko-KR-Wavenet-D", "Google.ko-KR-Neural2-A", "Google.ko-KR-Neural2-B", "Google.ko-KR-Neural2-C", "Google.lv-LV-Standard-A", "Google.lt-LT-Standard-A", "Google.ms-MY-Standard-A", "Google.ms-MY-Standard-B", "Google.ms-MY-Standard-C", "Google.ms-MY-Standard-D", "Google.ms-MY-Wavenet-A", "Google.ms-MY-Wavenet-B", "Google.ms-MY-Wavenet-C", "Google.ms-MY-Wavenet-D", "Google.ml-IN-Wavenet-C", "Google.ml-IN-Wavenet-D", "Google.mr-IN-Standard-A", "Google.mr-IN-Standard-B", "Google.mr-IN-Standard-C", "Google.mr-IN-Wavenet-A", "Google.mr-IN-Wavenet-B", "Google.mr-IN-Wavenet-C", "Polly.Liv", "Polly.Ida-Neural", "Google.nb-NO-Standard-A", "Google.nb-NO-Standard-B", "Google.nb-NO-Standard-C", "Google.nb-NO-Standard-D", "Google.nb-NO-Standard-E", "Google.nb-NO-Wavenet-A", "Google.nb-NO-Wavenet-B", "Google.nb-NO-Wavenet-C", "Google.nb-NO-Wavenet-D", "Google.nb-NO-Wavenet-E", "Polly.Jacek", "Polly.Jan", "Polly.Ewa", "Polly.Maja", "Polly.Ola-Neural", "Google.pl-PL-Standard-A", "Google.pl-PL-Standard-B", "Google.pl-PL-Standard-C", "Google.pl-PL-Standard-D", "Google.pl-PL-Standard-E", "Google.pl-PL-Wavenet-A", "Google.pl-PL-Wavenet-B", "Google.pl-PL-Wavenet-C", "Google.pl-PL-Wavenet-D", "Google.pl-PL-Wavenet-E", "Polly.Camila", "Polly.Ricardo", "Polly.Vitória/Polly.Vitoria", "Polly.Camila-Neural", "Polly.Vitoria-Neural", "Polly.Thiago-Neural", "Google.pt-BR-Standard-B", "Google.pt-BR-Standard-C", "Google.pt-BR-Wavenet-B", "Google.pt-BR-Wavenet-C", "Google.pt-BR-Neural2-A", "Google.pt-BR-Neural2-B", "Google.pt-BR-Neural2-C", "Polly.Cristiano", "Polly.Inês/Polly.Ines", "Polly.Ines-Neural", "Google.pt-PT-Standard-A", "Google.pt-PT-Standard-B", "Google.pt-PT-Standard-C", "Google.pt-PT-Standard-D", "Google.pt-PT-Wavenet-A", "Google.pt-PT-Wavenet-B", "Google.pt-PT-Wavenet-C", "Google.pt-PT-Wavenet-D", "Google.pa-IN-Standard-A", "Google.pa-IN-Standard-B", "Google.pa-IN-Standard-C", "Google.pa-IN-Standard-D", "Google.pa-IN-Wavenet-A", "Google.pa-IN-Wavenet-B", "Google.pa-IN-Wavenet-C", "Google.pa-IN-Wavenet-D", "Polly.Carmen", "Google.ro-RO-Standard-A", "Google.ro-RO-Wavenet-A", "Polly.Maxim", "Polly.Tatyana", "Google.ru-RU-Standard-A", "Google.ru-RU-Standard-B", "Google.ru-RU-Standard-C", "Google.ru-RU-Standard-D", "Google.ru-RU-Standard-E", "Google.ru-RU-Wavenet-A", "Google.ru-RU-Wavenet-B", "Google.ru-RU-Wavenet-C", "Google.ru-RU-Wavenet-D", "Google.ru-RU-Wavenet-E", "Google.sr-RS-Standard-A", "Google.sk-SK-Standard-A", "Google.sk-SK-Wavenet-A", "Polly.Mia", "Polly.Mia-Neural", "Polly.Andres-Neural", "Polly.Conchita", "Polly.Enrique", "Polly.Lucia", "Polly.Lucia-Neural", "Polly.Sergio-Neural", "Google.es-ES-Standard-B", "Google.es-ES-Standard-C", "Google.es-ES-Standard-D", "Google.es-ES-Wavenet-B", "Google.es-ES-Wavenet-C", "Google.es-ES-Wavenet-D", "Google.es-ES-Neural2-A", "Google.es-ES-Neural2-B", "Google.es-ES-Neural2-C", "Google.es-ES-Neural2-D", "Google.es-ES-Neural2-E", "Google.es-ES-Neural2-F", "man", "woman", "Polly.Lupe", "Polly.Miguel", "Polly.Penélope/Polly.Penelope", "Polly.Lupe-Neural", "Polly.Pedro-Neural", "Google.es-US-Standard-A", "Google.es-US-Standard-B", "Google.es-US-Standard-C", "Google.es-US-Wavenet-A", "Google.es-US-Wavenet-B", "Google.es-US-Wavenet-C", "Google.es-US-Neural2-A", "Google.es-US-Neural2-B", "Google.es-US-Neural2-C", "Polly.Astrid", "Polly.Elin-Neural", "Google.sv-SE-Standard-A", "Google.sv-SE-Standard-B", "Google.sv-SE-Standard-C", "Google.sv-SE-Standard-D", "Google.sv-SE-Standard-E", "Google.sv-SE-Wavenet-A", "Google.sv-SE-Wavenet-B", "Google.sv-SE-Wavenet-C", "Google.sv-SE-Wavenet-D", "Google.sv-SE-Wavenet-E", "Google.ta-IN-Standard-C", "Google.ta-IN-Standard-D", "Google.ta-IN-Wavenet-C", "Google.ta-IN-Wavenet-D", "Google.te-IN-Standard-A", "Google.te-IN-Standard-B", "Google.th-TH-Standard-A", "Polly.Filiz", "Google.tr-TR-Standard-A", "Google.tr-TR-Standard-B", "Google.tr-TR-Standard-C", "Google.tr-TR-Standard-D", "Google.tr-TR-Standard-E", "Google.tr-TR-Wavenet-A", "Google.tr-TR-Wavenet-B", "Google.tr-TR-Wavenet-C", "Google.tr-TR-Wavenet-D", "Google.tr-TR-Wavenet-E", "Google.uk-UA-Standard-A", "Google.uk-UA-Wavenet-A", "Google.vi-VN-Standard-A", "Google.vi-VN-Standard-B", "Google.vi-VN-Standard-C", "Google.vi-VN-Standard-D", "Google.vi-VN-Wavenet-A", "Google.vi-VN-Wavenet-B", "Google.vi-VN-Wavenet-C", "Google.vi-VN-Wavenet-D", "Polly.Gwyneth"} # fmt:skip -TWILIO_ASR_SUPPORTED_LANGUAGES = ["af-ZA", "am-ET", "hy-AM", "az-AZ", "id-ID", "ms-MY", "bn-BD", "bn-IN", "ca-ES", "cs-CZ", "da-DK", "de-DE", "en-AU", "en-CA", "en-GH", "en-GB", "en-IN", "en-IE", "en-KE", "en-NZ", "en-NG", "en-PH", "en-ZA", "en-TZ", "en-US", "es-AR", "es-BO", "es-CL", "es-CO", "es-CR", "es-EC", "es-SV", "es-ES", "es-US", "es-GT", "es-HN", "es-MX", "es-NI", "es-PA", "es-PY", "es-PE", "es-PR", "es-DO", "es-UY", "es-VE", "eu-ES", "fil-PH", "fr-CA", "fr-FR", "gl-ES", "ka-GE", "gu-IN", "hr-HR", "zu-ZA", "is-IS", "it-IT", "jv-ID", "kn-IN", "km-KH", "lo-LA", "lv-LV", "lt-LT", "hu-HU", "ml-IN", "mr-IN", "nl-NL", "ne-NP", "nb-NO", "pl-PL", "pt-BR", "pt-PT", "ro-RO", "si-LK", "sk-SK", "sl-SI", "su-ID", "sw-TZ", "sw-KE", "fi-FI", "sv-SE", "ta-IN", "ta-SG", "ta-LK", "ta-MY", "te-IN", "vi-VN", "tr-TR", "ur-PK", "ur-IN", "el-GR", "bg-BG", "ru-RU", "sr-RS", "uk-UA", "he-IL", "ar-IL", "ar-JO", "ar-AE", "ar-BH", "ar-DZ", "ar-SA", "ar-IQ", "ar-KW", "ar-MA", "ar-TN", "ar-OM", "ar-PS", "ar-QA", "ar-LB", "ar-EG", "fa-IR", "hi-IN", "th-TH", "ko-KR", "cmn-Hant-TW", "yue-Hant-HK", "ja-JP", "cmn-Hans-HK", "cmn-Hans-CN"] # fmt: skip + +TWILIO_DEFAULT_VOICE = "Google.en-US-Wavenet-F" +TWILIO_SUPPORTED_VOICES = { + "Google.af-ZA-Standard-A", "Polly.Zeina", "Google.ar-XA-Standard-A", "Google.ar-XA-Standard-B", "Google.ar-XA-Standard-C", "Google.ar-XA-Standard-D", "Google.ar-XA-Wavenet-A", "Google.ar-XA-Wavenet-B", "Google.ar-XA-Wavenet-C", "Google.ar-XA-Wavenet-D", "Polly.Hala-Neural", "Polly.Zayd-Neural", "Google.eu-ES-Standard-A", "Google.bn-IN-Standard-C", "Google.bn-IN-Standard-D", "Google.bn-IN-Wavenet-C", "Google.bn-IN-Wavenet-D", "Google.bg-BG-Standard-A", "Polly.Arlet-Neural", "Google.ca-ES-Standard-A", "Polly.Hiujin-Neural", "Google.yue-HK-Standard-A", "Google.yue-HK-Standard-B", "Google.yue-HK-Standard-C", "Google.yue-HK-Standard-D", "Polly.Zhiyu", "Polly.Zhiyu-Neural", "Google.cmn-CN-Standard-A", "Google.cmn-CN-Standard-B", "Google.cmn-CN-Standard-C", "Google.cmn-CN-Standard-D", "Google.cmn-CN-Wavenet-A", "Google.cmn-CN-Wavenet-B", "Google.cmn-CN-Wavenet-C", "Google.cmn-CN-Wavenet-D", "Google.cmn-TW-Standard-A", "Google.cmn-TW-Standard-B", "Google.cmn-TW-Standard-C", "Google.cmn-TW-Wavenet-A", "Google.cmn-TW-Wavenet-B", "Google.cmn-TW-Wavenet-C", "Google.cs-CZ-Standard-A", "Google.cs-CZ-Wavenet-A", "Polly.Mads", "Polly.Naja", "Polly.Sofie-Neural", "Google.da-DK-Standard-A", "Google.da-DK-Standard-C", "Google.da-DK-Standard-D", "Google.da-DK-Standard-E", "Google.da-DK-Wavenet-A", "Google.da-DK-Wavenet-C", "Google.da-DK-Wavenet-D", "Google.da-DK-Wavenet-E", "Polly.Lisa-Neural", "Google.nl-BE-Standard-A", "Google.nl-BE-Standard-B", "Google.nl-BE-Wavenet-A", "Google.nl-BE-Wavenet-B", "Polly.Lotte", "Polly.Ruben", "Polly.Laura-Neural", "Google.nl-NL-Standard-A", "Google.nl-NL-Standard-B", "Google.nl-NL-Standard-C", "Google.nl-NL-Standard-D", "Google.nl-NL-Standard-E", "Google.nl-NL-Wavenet-A", "Google.nl-NL-Wavenet-B", "Google.nl-NL-Wavenet-C", "Google.nl-NL-Wavenet-D", "Google.nl-NL-Wavenet-E", "Polly.Nicole", "Polly.Russell", "Polly.Olivia-Neural", "Google.en-AU-Standard-A", "Google.en-AU-Standard-B", "Google.en-AU-Standard-C", "Google.en-AU-Standard-D", "Google.en-AU-Wavenet-A", "Google.en-AU-Wavenet-B", "Google.en-AU-Wavenet-C", "Google.en-AU-Wavenet-D", "Google.en-AU-Neural2-A", "Google.en-AU-Neural2-B", "Google.en-AU-Neural2-C", "Google.en-AU-Neural2-D", "Polly.Raveena", "Google.en-IN-Standard-A", "Google.en-IN-Standard-B", "Google.en-IN-Standard-C", "Google.en-IN-Standard-D", "Google.en-IN-Wavenet-A", "Google.en-IN-Wavenet-B", "Google.en-IN-Wavenet-C", "Google.en-IN-Wavenet-D", "Google.en-IN-Neural2-A", "Google.en-IN-Neural2-B", "Google.en-IN-Neural2-C", "Google.en-IN-Neural2-D", "Polly.Niamh-Neural", "Polly.Aria-Neural", "Polly.Ayanda-Neural", "Polly.Amy", "Polly.Brian", "Polly.Emma", "Polly.Amy-Neural", "Polly.Emma-Neural", "Polly.Brian-Neural", "Polly.Arthur-Neural", "Google.en-GB-Standard-A", "Google.en-GB-Standard-B", "Google.en-GB-Standard-C", "Google.en-GB-Standard-D", "Google.en-GB-Standard-F", "Google.en-GB-Wavenet-A", "Google.en-GB-Wavenet-B", "Google.en-GB-Wavenet-C", "Google.en-GB-Wavenet-D", "Google.en-GB-Wavenet-F", "Google.en-GB-Neural2-A", "Google.en-GB-Neural2-B", "Google.en-GB-Neural2-C", "Google.en-GB-Neural2-D", "Google.en-GB-Neural2-F", "Polly.Ivy", "Polly.Joanna", "Polly.Joey", "Polly.Justin", "Polly.Kendra", "Polly.Kimberly", "Polly.Matthew", "Polly.Salli", "child) Polly.Ivy-Neural", "Polly.Joanna-Neural*", "Polly.Kendra-Neural", "child) Polly.Kevin-Neural", "Polly.Kimberly-Neural", "Polly.Salli-Neural", "Polly.Joey-Neural", "child) Polly.Justin-Neural", "Polly.Matthew-Neural*", "Polly.Ruth-Neural", "Polly.Stephen-Neural", "Polly.Gregory-Neural", "Polly.Danielle-Neural", "Google.en-US-Standard-A", "Google.en-US-Standard-B", "Google.en-US-Standard-C", "Google.en-US-Standard-D", "Google.en-US-Standard-E", "Google.en-US-Standard-F", "Google.en-US-Standard-G", "Google.en-US-Standard-H", "Google.en-US-Standard-I", "Google.en-US-Standard-J", "Google.en-US-Wavenet-A", "Google.en-US-Wavenet-B", "Google.en-US-Wavenet-C", "Google.en-US-Wavenet-D", "Google.en-US-Wavenet-E", "Google.en-US-Wavenet-F", "Google.en-US-Wavenet-G", "Google.en-US-Wavenet-H", "Google.en-US-Wavenet-I", "Google.en-US-Wavenet-J", "Google.en-US-Neural2-A", "Google.en-US-Neural2-C", "Google.en-US-Neural2-D", "Google.en-US-Neural2-E", "Google.en-US-Neural2-F", "Google.en-US-Neural2-G", "Google.en-US-Neural2-H", "Google.en-US-Neural2-I", "Google.en-US-Neural2-J", "Polly.Geraint", "Google.fil-PH-Standard-A", "Google.fil-PH-Standard-B", "Google.fil-PH-Standard-C", "Google.fil-PH-Standard-D", "Google.fil-PH-Wavenet-A", "Google.fil-PH-Wavenet-B", "Google.fil-PH-Wavenet-C", "Google.fil-PH-Wavenet-D", "Polly.Suvi-Neural", "Google.fi-FI-Standard-A", "Google.fi-FI-Wavenet-A", "Polly.Isabelle-Neural", "Polly.Chantal", "Polly.Gabrielle-Neural", "Polly.Liam-Neural", "Google.fr-CA-Standard-A", "Google.fr-CA-Standard-B", "Google.fr-CA-Standard-C", "Google.fr-CA-Standard-D", "Google.fr-CA-Wavenet-A", "Google.fr-CA-Wavenet-B", "Google.fr-CA-Wavenet-C", "Google.fr-CA-Wavenet-D", "Google.fr-CA-Neural2-A", "Google.fr-CA-Neural2-B", "Google.fr-CA-Neural2-C", "Google.fr-CA-Neural2-D", "Polly.Céline/Polly.Celine", "Polly.Léa/Polly.Lea", "Polly.Mathieu", "Polly.Lea-Neural", "Polly.Remi-Neural", "Google.fr-FR-Standard-A", "Google.fr-FR-Standard-B", "Google.fr-FR-Standard-C", "Google.fr-FR-Standard-D", "Google.fr-FR-Standard-E", "Google.fr-FR-Wavenet-A", "Google.fr-FR-Wavenet-B", "Google.fr-FR-Wavenet-C", "Google.fr-FR-Wavenet-D", "Google.fr-FR-Wavenet-E", "Google.fr-FR-Neural2-A", "Google.fr-FR-Neural2-B", "Google.fr-FR-Neural2-C", "Google.fr-FR-Neural2-D", "Google.fr-FR-Neural2-E", "Google.gl-ES-Standard-A", "Polly.Hannah-Neural", "Polly.Hans", "Polly.Marlene", "Polly.Vicki", "Polly.Vicki-Neural", "Polly.Daniel-Neural", "Google.de-DE-Standard-A", "Google.de-DE-Standard-B", "Google.de-DE-Standard-C", "Google.de-DE-Standard-D", "Google.de-DE-Standard-E", "Google.de-DE-Standard-F", "Google.de-DE-Wavenet-A", "Google.de-DE-Wavenet-B", "Google.de-DE-Wavenet-C", "Google.de-DE-Wavenet-D", "Google.de-DE-Wavenet-E", "Google.de-DE-Wavenet-F", "Google.de-DE-Neural2-A", "Google.de-DE-Neural2-B", "Google.de-DE-Neural2-C", "Google.de-DE-Neural2-D", "Google.de-DE-Neural2-F", "Google.el-GR-Standard-A", "Google.el-GR-Wavenet-A", "Google.gu-IN-Standard-C", "Google.gu-IN-Standard-D", "Google.gu-IN-Wavenet-C", "Google.gu-IN-Wavenet-D", "Google.he-IL-Standard-A", "Google.he-IL-Standard-B", "Google.he-IL-Standard-C", "Google.he-IL-Standard-D", "Google.he-IL-Wavenet-A", "Google.he-IL-Wavenet-B", "Google.he-IL-Wavenet-C", "Google.he-IL-Wavenet-D", "Polly.Aditi", "Polly.Kajal-Neural", "Google.hi-IN-Standard-A", "Google.hi-IN-Standard-B", "Google.hi-IN-Standard-C", "Google.hi-IN-Standard-D", "Google.hi-IN-Wavenet-A", "Google.hi-IN-Wavenet-B", "Google.hi-IN-Wavenet-C", "Google.hi-IN-Wavenet-D", "Google.hi-IN-Neural2-A", "Google.hi-IN-Neural2-B", "Google.hi-IN-Neural2-C", "Google.hi-IN-Neural2-D", "Google.hu-HU-Standard-A", "Google.hu-HU-Wavenet-A", "Polly.Dóra/Polly.Dora", "Polly.Karl", "Google.is-IS-Standard-A", "Google.id-ID-Standard-A", "Google.id-ID-Standard-B", "Google.id-ID-Standard-C", "Google.id-ID-Standard-D", "Google.id-ID-Wavenet-A", "Google.id-ID-Wavenet-B", "Google.id-ID-Wavenet-C", "Google.id-ID-Wavenet-D", "Polly.Bianca", "Polly.Carla", "Polly.Giorgio", "Polly.Bianca-Neural", "Polly.Adriano-Neural", "Google.it-IT-Standard-B", "Google.it-IT-Standard-C", "Google.it-IT-Standard-D", "Google.it-IT-Wavenet-B", "Google.it-IT-Wavenet-C", "Google.it-IT-Wavenet-D", "Google.it-IT-Neural2-A", "Google.it-IT-Neural2-C", "Polly.Mizuki", "Polly.Takumi", "Polly.Takumi-Neural", "Polly.Kazuha-Neural", "Polly.Tomoko-Neural", "Google.ja-JP-Standard-B", "Google.ja-JP-Standard-C", "Google.ja-JP-Standard-D", "Google.ja-JP-Wavenet-B", "Google.ja-JP-Wavenet-C", "Google.ja-JP-Wavenet-D", "Google.kn-IN-Standard-C", "Google.kn-IN-Standard-D", "Google.kn-IN-Wavenet-C", "Google.kn-IN-Wavenet-D", "Polly.Seoyeon", "Polly.Seoyeon-Neural", "Google.ko-KR-Standard-A", "Google.ko-KR-Standard-B", "Google.ko-KR-Standard-C", "Google.ko-KR-Standard-D", "Google.ko-KR-Wavenet-A", "Google.ko-KR-Wavenet-B", "Google.ko-KR-Wavenet-C", "Google.ko-KR-Wavenet-D", "Google.ko-KR-Neural2-A", "Google.ko-KR-Neural2-B", "Google.ko-KR-Neural2-C", "Google.lv-LV-Standard-A", "Google.lt-LT-Standard-A", "Google.ms-MY-Standard-A", "Google.ms-MY-Standard-B", "Google.ms-MY-Standard-C", "Google.ms-MY-Standard-D", "Google.ms-MY-Wavenet-A", "Google.ms-MY-Wavenet-B", "Google.ms-MY-Wavenet-C", "Google.ms-MY-Wavenet-D", "Google.ml-IN-Wavenet-C", "Google.ml-IN-Wavenet-D", "Google.mr-IN-Standard-A", "Google.mr-IN-Standard-B", "Google.mr-IN-Standard-C", "Google.mr-IN-Wavenet-A", "Google.mr-IN-Wavenet-B", "Google.mr-IN-Wavenet-C", "Polly.Liv", "Polly.Ida-Neural", "Google.nb-NO-Standard-A", "Google.nb-NO-Standard-B", "Google.nb-NO-Standard-C", "Google.nb-NO-Standard-D", "Google.nb-NO-Standard-E", "Google.nb-NO-Wavenet-A", "Google.nb-NO-Wavenet-B", "Google.nb-NO-Wavenet-C", "Google.nb-NO-Wavenet-D", "Google.nb-NO-Wavenet-E", "Polly.Jacek", "Polly.Jan", "Polly.Ewa", "Polly.Maja", "Polly.Ola-Neural", "Google.pl-PL-Standard-A", "Google.pl-PL-Standard-B", "Google.pl-PL-Standard-C", "Google.pl-PL-Standard-D", "Google.pl-PL-Standard-E", "Google.pl-PL-Wavenet-A", "Google.pl-PL-Wavenet-B", "Google.pl-PL-Wavenet-C", "Google.pl-PL-Wavenet-D", "Google.pl-PL-Wavenet-E", "Polly.Camila", "Polly.Ricardo", "Polly.Vitória/Polly.Vitoria", "Polly.Camila-Neural", "Polly.Vitoria-Neural", "Polly.Thiago-Neural", "Google.pt-BR-Standard-B", "Google.pt-BR-Standard-C", "Google.pt-BR-Wavenet-B", "Google.pt-BR-Wavenet-C", "Google.pt-BR-Neural2-A", "Google.pt-BR-Neural2-B", "Google.pt-BR-Neural2-C", "Polly.Cristiano", "Polly.Inês/Polly.Ines", "Polly.Ines-Neural", "Google.pt-PT-Standard-A", "Google.pt-PT-Standard-B", "Google.pt-PT-Standard-C", "Google.pt-PT-Standard-D", "Google.pt-PT-Wavenet-A", "Google.pt-PT-Wavenet-B", "Google.pt-PT-Wavenet-C", "Google.pt-PT-Wavenet-D", "Google.pa-IN-Standard-A", "Google.pa-IN-Standard-B", "Google.pa-IN-Standard-C", "Google.pa-IN-Standard-D", "Google.pa-IN-Wavenet-A", "Google.pa-IN-Wavenet-B", "Google.pa-IN-Wavenet-C", "Google.pa-IN-Wavenet-D", "Polly.Carmen", "Google.ro-RO-Standard-A", "Google.ro-RO-Wavenet-A", "Polly.Maxim", "Polly.Tatyana", "Google.ru-RU-Standard-A", "Google.ru-RU-Standard-B", "Google.ru-RU-Standard-C", "Google.ru-RU-Standard-D", "Google.ru-RU-Standard-E", "Google.ru-RU-Wavenet-A", "Google.ru-RU-Wavenet-B", "Google.ru-RU-Wavenet-C", "Google.ru-RU-Wavenet-D", "Google.ru-RU-Wavenet-E", "Google.sr-RS-Standard-A", "Google.sk-SK-Standard-A", "Google.sk-SK-Wavenet-A", "Polly.Mia", "Polly.Mia-Neural", "Polly.Andres-Neural", "Polly.Conchita", "Polly.Enrique", "Polly.Lucia", "Polly.Lucia-Neural", "Polly.Sergio-Neural", "Google.es-ES-Standard-B", "Google.es-ES-Standard-C", "Google.es-ES-Standard-D", "Google.es-ES-Wavenet-B", "Google.es-ES-Wavenet-C", "Google.es-ES-Wavenet-D", "Google.es-ES-Neural2-A", "Google.es-ES-Neural2-B", "Google.es-ES-Neural2-C", "Google.es-ES-Neural2-D", "Google.es-ES-Neural2-E", "Google.es-ES-Neural2-F", "man", "woman", "Polly.Lupe", "Polly.Miguel", "Polly.Penélope/Polly.Penelope", "Polly.Lupe-Neural", "Polly.Pedro-Neural", "Google.es-US-Standard-A", "Google.es-US-Standard-B", "Google.es-US-Standard-C", "Google.es-US-Wavenet-A", "Google.es-US-Wavenet-B", "Google.es-US-Wavenet-C", "Google.es-US-Neural2-A", "Google.es-US-Neural2-B", "Google.es-US-Neural2-C", "Polly.Astrid", "Polly.Elin-Neural", "Google.sv-SE-Standard-A", "Google.sv-SE-Standard-B", "Google.sv-SE-Standard-C", "Google.sv-SE-Standard-D", "Google.sv-SE-Standard-E", "Google.sv-SE-Wavenet-A", "Google.sv-SE-Wavenet-B", "Google.sv-SE-Wavenet-C", "Google.sv-SE-Wavenet-D", "Google.sv-SE-Wavenet-E", "Google.ta-IN-Standard-C", "Google.ta-IN-Standard-D", "Google.ta-IN-Wavenet-C", "Google.ta-IN-Wavenet-D", "Google.te-IN-Standard-A", "Google.te-IN-Standard-B", "Google.th-TH-Standard-A", "Polly.Filiz", "Google.tr-TR-Standard-A", "Google.tr-TR-Standard-B", "Google.tr-TR-Standard-C", "Google.tr-TR-Standard-D", "Google.tr-TR-Standard-E", "Google.tr-TR-Wavenet-A", "Google.tr-TR-Wavenet-B", "Google.tr-TR-Wavenet-C", "Google.tr-TR-Wavenet-D", "Google.tr-TR-Wavenet-E", "Google.uk-UA-Standard-A", "Google.uk-UA-Wavenet-A", "Google.vi-VN-Standard-A", "Google.vi-VN-Standard-B", "Google.vi-VN-Standard-C", "Google.vi-VN-Standard-D", "Google.vi-VN-Wavenet-A", "Google.vi-VN-Wavenet-B", "Google.vi-VN-Wavenet-C", "Google.vi-VN-Wavenet-D", "Polly.Gwyneth" +} # fmt:skip + +TWILIO_DEFAULT_ASR_LANGUAGE = "en-US" +TWILIO_SUPPORTED_ASR_LANGUAGES = { + "af-ZA", "am-ET", "hy-AM", "az-AZ", "id-ID", "ms-MY", "bn-BD", "bn-IN", "ca-ES", "cs-CZ", "da-DK", "de-DE", "en-AU", + "en-CA", "en-GH", "en-GB", "en-IN", "en-IE", "en-KE", "en-NZ", "en-NG", "en-PH", "en-ZA", "en-TZ", "en-US", "es-AR", + "es-BO", "es-CL", "es-CO", "es-CR", "es-EC", "es-SV", "es-ES", "es-US", "es-GT", "es-HN", "es-MX", "es-NI", "es-PA", + "es-PY", "es-PE", "es-PR", "es-DO", "es-UY", "es-VE", "eu-ES", "fil-PH", "fr-CA", "fr-FR", "gl-ES", "ka-GE", + "gu-IN", "hr-HR", "zu-ZA", "is-IS", "it-IT", "jv-ID", "kn-IN", "km-KH", "lo-LA", "lv-LV", "lt-LT", "hu-HU", "ml-IN", + "mr-IN", "nl-NL", "ne-NP", "nb-NO", "pl-PL", "pt-BR", "pt-PT", "ro-RO", "si-LK", "sk-SK", "sl-SI", "su-ID", "sw-TZ", + "sw-KE", "fi-FI", "sv-SE", "ta-IN", "ta-SG", "ta-LK", "ta-MY", "te-IN", "vi-VN", "tr-TR", "ur-PK", "ur-IN", "el-GR", + "bg-BG", "ru-RU", "sr-RS", "uk-UA", "he-IL", "ar-IL", "ar-JO", "ar-AE", "ar-BH", "ar-DZ", "ar-SA", "ar-IQ", "ar-KW", + "ar-MA", "ar-TN", "ar-OM", "ar-PS", "ar-QA", "ar-LB", "ar-EG", "fa-IR", "hi-IN", "th-TH", "ko-KR", "cmn-Hant-TW", + "yue-Hant-HK", "ja-JP", "cmn-Hans-HK", "cmn-Hans-CN" +} # fmt: skip + SILENCE_RESPONSE = ( "Sorry, I didn't get that. Please call again in a more quiet environment." @@ -43,51 +62,6 @@ router = APIRouter() -def get_twilio_tts_voice(bi: BotIntegration) -> str | None: - from recipes.TextToSpeech import TextToSpeechProviders - - run = bi.get_active_saved_run() - state: dict = run.state - tts_provider = state.get("tts_provider") - if tts_provider and tts_provider == TextToSpeechProviders.GOOGLE_TTS.name: - voice = "Google." + state.get("google_voice_name", "en-US-Wavenet-F") - if voice not in TWILIO_SUPPORTED_VOICES: - logger.warning(f"Unsupported voice {voice=} for {bi=}") - return None - return voice - return None - - -def get_twilio_asr_language(bi: BotIntegration) -> str | None: - from daras_ai_v2.asr import normalised_lang_in_collection - from daras_ai_v2.exceptions import UserError - - run = bi.get_active_saved_run() - state: dict = run.state - - asr_language = state.get("asr_language") - if asr_language: - try: - asr_language = normalised_lang_in_collection( - asr_language, TWILIO_ASR_SUPPORTED_LANGUAGES - ) - return asr_language - except UserError: - pass - - user_language = state.get("user_language") - if user_language: - try: - user_language = normalised_lang_in_collection( - user_language, TWILIO_ASR_SUPPORTED_LANGUAGES - ) - return user_language - except UserError: - pass - - return None - - @router.post("/__/twilio/voice/") def twilio_voice_call( background_tasks: BackgroundTasks, data: dict = fastapi_request_urlencoded_body @@ -159,22 +133,8 @@ def create_voice_call_response( # the URL to send the user's question to action = get_api_route_url(twilio_voice_call_asked) - if bot.use_gooey_asr: - # record does not support nesting, so we can't support interrupting the response with the next question - if audio_url: - resp.play(audio_url) - elif text: - resp_say_or_tts_play(bot, resp, text, should_translate=should_translate) - - # try recording 3 times to give the user a chance to start speaking - resp.record( - action=action, - method="POST", - timeout=5, - finish_on_key="0", - play_beep=False, - ) - else: + twilio_asr_lang = resolve_twilio_asr_language(bot) + if twilio_asr_lang: gather = Gather( input="speech", # also supports dtmf (keypad input) and a combination of both timeout=20, # users get 20 to start speaking @@ -182,7 +142,7 @@ def create_voice_call_response( action=action, method="POST", finish_on_key="0", # user can press 0 to end the input - language=get_twilio_asr_language(bot.bi) or DEFAULT_ASR_LANGUAGE, + language=twilio_asr_lang, speech_model="phone_call", # optimized for phone call audio enhanced=True, # only phone_call model supports enhanced ) @@ -194,6 +154,21 @@ def create_voice_call_response( resp_say_or_tts_play(bot, gather, text, should_translate=should_translate) resp.append(gather) + else: + # record does not support nesting, so we can't support interrupting the response with the next question + if audio_url: + resp.play(audio_url) + elif text: + resp_say_or_tts_play(bot, resp, text, should_translate=should_translate) + + # try recording 3 times to give the user a chance to start speaking + resp.record( + action=action, + method="POST", + timeout=5, + finish_on_key="0", + play_beep=False, + ) # if the user doesn't say anything, we'll ask them to call back in a quieter environment resp_say_or_tts_play(bot, resp, SILENCE_RESPONSE, should_translate=True) @@ -201,6 +176,22 @@ def create_voice_call_response( return resp +def resolve_twilio_asr_language(bot: TwilioVoice) -> str | None: + # custom asr model specified: use it + if bot.saved_run.state.get("asr_model"): + return None + # asr model not supplied, try to use twilio inbuilt asr + user_language = ( + bot.saved_run.state.get("user_language") or TWILIO_DEFAULT_ASR_LANGUAGE + ) + try: + return normalised_lang_in_collection( + user_language, TWILIO_SUPPORTED_ASR_LANGUAGES + ) + except UserError: + return None + + @router.post("/__/twilio/voice/asked/") def twilio_voice_call_asked( background_tasks: BackgroundTasks, data: dict = fastapi_request_urlencoded_body @@ -208,6 +199,7 @@ def twilio_voice_call_asked( """After the initial call, the user has asked a question via Twilio/Gooey ASR. Handle their question.""" bot = TwilioVoice.from_data(data) + resolve_twilio_tts_voice(bot) background_tasks.add_task(msg_handler, bot) resp = VoiceResponse() @@ -262,7 +254,8 @@ def resp_say_or_tts_play( if should_translate: text = bot.translate_response(text) - if bot.use_gooey_tts: + twilio_tts_voice = resolve_twilio_tts_voice(bot) + if not twilio_tts_voice: try: # submit the TTS request tts_state = TextToSpeechPage.RequestModel.parse_obj( @@ -287,7 +280,29 @@ def resp_say_or_tts_play( else: return - resp.say(text, voice=get_twilio_tts_voice(bot.bi) or DEFAULT_VOICE_NAME) + resp.say(text, voice=twilio_tts_voice or TWILIO_DEFAULT_VOICE) + + +def resolve_twilio_tts_voice(bot: TwilioVoice) -> str | None: + # bot is not using any TTS provider, use twilio inbuilt tts with default voice + tts_provider = bot.saved_run.state.get("tts_provider") + if not tts_provider: + return TWILIO_DEFAULT_VOICE + + # bot is not using Google TTS, use gooey tts + google_voice_name = bot.saved_run.state.get("google_voice_name") + if not google_voice_name or tts_provider != TextToSpeechProviders.GOOGLE_TTS.name: + return None + + # voice is not supported by twilio, use gooey tts + twilio_voice = "Google." + google_voice_name + if twilio_voice not in TWILIO_SUPPORTED_VOICES: + logger.warning(f"Unsupported {twilio_voice=} for {bot.bi=}, using gooey tts") + return None + + # use twilio inbuilt tts, disable the gooey tts + bot.request_overrides = dict(tts_provider=None) + return twilio_voice @router.post("/__/twilio/voice/error/")