diff --git a/bots/tasks.py b/bots/tasks.py index 26fb71ff9..7b0ae76b8 100644 --- a/bots/tasks.py +++ b/bots/tasks.py @@ -154,6 +154,7 @@ def send_broadcast_msgs_chunked( buttons: list[ReplyButton] = None, convo_qs: QuerySet[Conversation], bi: BotIntegration, + medium: str = "Voice Call", ): convo_ids = list(convo_qs.values_list("id", flat=True)) for i in range(0, len(convo_ids), 100): @@ -165,6 +166,7 @@ def send_broadcast_msgs_chunked( documents=documents, bi_id=bi.id, convo_ids=convo_ids[i : i + 100], + medium=medium, ) diff --git a/daras_ai_v2/bot_integration_widgets.py b/daras_ai_v2/bot_integration_widgets.py index b6324ce5f..226bb35a2 100644 --- a/daras_ai_v2/bot_integration_widgets.py +++ b/daras_ai_v2/bot_integration_widgets.py @@ -5,6 +5,7 @@ from django.db import transaction from django.utils.text import slugify from furl import furl +import langcodes import gooey_ui as st from app_users.models import AppUser @@ -17,6 +18,9 @@ from recipes.CompareLLM import CompareLLMPage from routers.root import RecipeTabs, chat_route, chat_lib_route +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 + def general_integration_settings(bi: BotIntegration, current_user: AppUser): if st.session_state.get(f"_bi_reset_{bi.id}"): @@ -29,24 +33,21 @@ def general_integration_settings(bi: BotIntegration, current_user: AppUser): st.session_state["analysis_urls"] = [] st.session_state.pop("--list-view:analysis_urls", None) - bi.streaming_enabled = st.checkbox( - "**📡 Streaming Enabled**", - value=bi.streaming_enabled, - key=f"_bi_streaming_enabled_{bi.id}", - ) - st.caption("Responses will be streamed to the user in real-time if enabled.") - bi.show_feedback_buttons = st.checkbox( - "**👍🏾 👎🏽 Show Feedback Buttons**", - value=bi.show_feedback_buttons, - key=f"_bi_show_feedback_buttons_{bi.id}", - ) - st.caption( - "Users can rate and provide feedback on every copilot response if enabled." - ) - - st.caption( - "Please note that this language is distinct from the one provided in the workflow settings. Hence, this allows you to integrate the same bot in many languages." - ) + if bi.platform != Platform.TWILIO: + bi.streaming_enabled = st.checkbox( + "**📡 Streaming Enabled**", + value=bi.streaming_enabled, + key=f"_bi_streaming_enabled_{bi.id}", + ) + st.caption("Responses will be streamed to the user in real-time if enabled.") + bi.show_feedback_buttons = st.checkbox( + "**👍🏾 👎🏽 Show Feedback Buttons**", + value=bi.show_feedback_buttons, + key=f"_bi_show_feedback_buttons_{bi.id}", + ) + st.caption( + "Users can rate and provide feedback on every copilot response if enabled." + ) st.write( """ @@ -128,6 +129,71 @@ def render_workflow_url_input(key: str, del_key: str | None, d: dict): st.write("---") +def twilio_specific_settings(bi: BotIntegration): + SETTINGS_FIELDS = ["twilio_use_missed_call", "twilio_initial_text", "twilio_initial_audio_url", "twilio_waiting_text", "twilio_waiting_audio_url", "twilio_tts_voice", "twilio_asr_language"] # fmt:skip + if st.session_state.get(f"_bi_reset_{bi.id}"): + for field in SETTINGS_FIELDS: + st.session_state[f"_bi_{field}_{bi.id}"] = BotIntegration._meta.get_field( + field + ).default + + bi.twilio_tts_voice = ( + st.selectbox( + "##### 🗣️ Twilio Voice", + options=TWILIO_SUPPORTED_VOICES, + value=bi.twilio_tts_voice, + format_func=lambda x: x.capitalize(), + key=f"_bi_twilio_tts_voice_{bi.id}", + ) + or "Woman" + ) + st.caption("Used when the underlying run does not have a Gooey TTS model enabled.") + bi.twilio_asr_language = ( + st.selectbox( + "##### 🌐 Twilio ASR Language", + options=TWILIO_ASR_SUPPORTED_LANGUAGES, + key=f"_bi_twilio_asr_language_{bi.id}", + format_func=lambda x: langcodes.Language.get(x).display_name(), + value=bi.twilio_asr_language, + ) + or "en-US" + ) + st.caption("Used when the underlying run does not have a Gooey ASR model enabled.") + bi.twilio_initial_text = st.text_area( + "###### 📝 Initial Text (said at the beginning of each call)", + value=bi.twilio_initial_text, + key=f"_bi_twilio_initial_text_{bi.id}", + ) + bi.twilio_initial_audio_url = ( + st.file_uploader( + "###### 🔊 Initial Audio (played at the beginning of each call)", + accept=["audio/*"], + key=f"_bi_twilio_initial_audio_url_{bi.id}", + ) + or "" + ) + bi.twilio_waiting_audio_url = ( + st.file_uploader( + "###### 🎵 Waiting Audio (played while waiting for a response -- Voice)", + accept=["audio/*"], + key=f"_bi_twilio_waiting_audio_url_{bi.id}", + ) + or "" + ) + bi.twilio_waiting_text = st.text_area( + "###### 📝 Waiting Text (texted while waiting for a response -- SMS)", + key=f"_bi_twilio_waiting_text_{bi.id}", + ) + bi.twilio_use_missed_call = st.checkbox( + "📞 Use Missed Call", + value=bi.twilio_use_missed_call, + key=f"_bi_twilio_use_missed_call_{bi.id}", + ) + st.caption( + "When enabled, immediately hangs up incoming calls and calls back the user so they don't incur charges (depending on their carrier/plan)." + ) + + def slack_specific_settings(bi: BotIntegration, default_name: str): if st.session_state.get(f"_bi_reset_{bi.id}"): st.session_state[f"_bi_name_{bi.id}"] = default_name @@ -185,20 +251,30 @@ def broadcast_input(bi: BotIntegration): optional=True, accept=["audio/*"], ) - video = st.file_uploader( - "**🎥 Video**", - key=key + ":video", - help="Attach a video to this message.", - optional=True, - accept=["video/*"], - ) - documents = st.file_uploader( - "**📄 Documents**", - key=key + ":documents", - help="Attach documents to this message.", - accept_multiple_files=True, - optional=True, - ) + video = None + documents = None + medium = "Voice Call" + if bi.platform == Platform.TWILIO: + medium = st.selectbox( + "###### 📱 Medium", + ["Voice Call", "SMS/MMS"], + key=key + ":medium", + ) + else: + video = st.file_uploader( + "**🎥 Video**", + key=key + ":video", + help="Attach a video to this message.", + optional=True, + accept=["video/*"], + ) + documents = st.file_uploader( + "**📄 Documents**", + key=key + ":documents", + help="Attach documents to this message.", + accept_multiple_files=True, + optional=True, + ) should_confirm_key = key + ":should_confirm" confirmed_send_btn = key + ":confirmed_send" @@ -219,6 +295,7 @@ def broadcast_input(bi: BotIntegration): documents=documents, bi=bi, convo_qs=convos, + medium=medium, ) else: if not convos.exists(): @@ -254,6 +331,8 @@ def get_bot_test_link(bi: BotIntegration) -> str | None: integration_name=slugify(bi.name) or "untitled", ), ) + elif bi.twilio_phone_number_sid: + return f"https://console.twilio.com/us1/develop/phone-numbers/manage/incoming/{bi.twilio_phone_number_sid}/calls" else: return None diff --git a/recipes/VideoBots.py b/recipes/VideoBots.py index f8a3b8534..94eaec718 100644 --- a/recipes/VideoBots.py +++ b/recipes/VideoBots.py @@ -33,6 +33,7 @@ from daras_ai_v2.bot_integration_widgets import ( general_integration_settings, slack_specific_settings, + twilio_specific_settings, broadcast_input, get_bot_test_link, web_widget_config, @@ -1248,6 +1249,12 @@ def render_integrations_settings( unsafe_allow_html=True, new_tab=True, ) + if bi.twilio_phone_number: + copy_to_clipboard_button( + f' Copy Phone Number', + value=bi.twilio_phone_number.as_e164, + type="secondary", + ) col1, col2 = st.columns(2, style={"alignItems": "center"}) with col1: @@ -1267,6 +1274,8 @@ def render_integrations_settings( unsafe_allow_html=True, new_tab=True, ) + elif bi.platform == Platform.TWILIO and test_link: + pass elif test_link: st.anchor( f"{icon} Message {bi.get_display_name()}", @@ -1277,6 +1286,24 @@ def render_integrations_settings( else: st.write("Message quicklink not available.") + if bi.twilio_phone_number: + st.anchor( + ' Start Voice Call', + f"tel:{bi.twilio_phone_number.as_e164}", + unsafe_allow_html=True, + new_tab=True, + ) + st.anchor( + ' Send SMS', + f"sms:{bi.twilio_phone_number.as_e164}", + unsafe_allow_html=True, + new_tab=True, + ) + elif bi.platform == Platform.TWILIO: + st.write( + "Phone number incorrectly configured. Please re-add the integration and double check spelling. [Contact Us](support@gooey.ai) if you need help." + ) + if bi.platform == Platform.WEB: embed_code = get_web_widget_embed_code(bi) copy_to_clipboard_button( @@ -1305,6 +1332,13 @@ def render_integrations_settings( ), new_tab=True, ) + if bi.platform == Platform.TWILIO and test_link: + st.anchor( + f"{icon} View Calls/Messages", + test_link, + unsafe_allow_html=True, + new_tab=True, + ) if bi.platform == Platform.WHATSAPP and bi.wa_business_waba_id: col1, col2 = st.columns(2, style={"alignItems": "center"}) @@ -1339,9 +1373,11 @@ def render_integrations_settings( with st.expander("Configure Settings 🛠️"): if bi.platform == Platform.SLACK: slack_specific_settings(bi, run_title) + if bi.platform == Platform.TWILIO: + twilio_specific_settings(bi) general_integration_settings(bi, self.request.user) - if bi.platform in [Platform.SLACK, Platform.WHATSAPP]: + if bi.platform in [Platform.SLACK, Platform.WHATSAPP, Platform.TWILIO]: st.newline() broadcast_input(bi) st.write("---")