From af62097b78dbdaf69966204bbe83555b903a10b8 Mon Sep 17 00:00:00 2001 From: Dev Aggarwal Date: Tue, 27 Aug 2024 14:22:49 +0530 Subject: [PATCH] - Fix conversation lookups in twilio - Modify Conversation model to include twilio_call_sid in indexes - Update TwilioVoice handler to not create a conversation entry for missed calls - Simplify logic for determining if call will be rejected - rename TwilioVoice.from_data -> TwilioVoice.from_webhook_data --- bots/admin.py | 1 + bots/models.py | 17 +++++++++++++++-- daras_ai_v2/twilio_bot.py | 25 +++++++++++++++++-------- routers/twilio_api.py | 4 ++-- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/bots/admin.py b/bots/admin.py index 4b6a731c8..17990e398 100644 --- a/bots/admin.py +++ b/bots/admin.py @@ -77,6 +77,7 @@ "twilio_username", "twilio_password", "twilio_use_missed_call", + "twilio_fresh_conversation_per_call", "twilio_initial_text", "twilio_initial_audio_url", "twilio_waiting_text", diff --git a/bots/models.py b/bots/models.py index 7829106e1..181eba2f6 100644 --- a/bots/models.py +++ b/bots/models.py @@ -1111,7 +1111,9 @@ class Meta: "slack_channel_is_personal", ], ), - models.Index(fields=["bot_integration", "twilio_phone_number"]), + models.Index( + fields=["bot_integration", "twilio_phone_number", "twilio_call_sid"] + ), models.Index(fields=["-created_at", "bot_integration"]), ] @@ -1121,7 +1123,18 @@ def __str__(self): def get_display_name(self): return ( (self.wa_phone_number and self.wa_phone_number.as_international) - or (self.twilio_phone_number and self.twilio_phone_number.as_international) + or " | ".join( + filter( + None, + [ + ( + self.twilio_phone_number + and self.twilio_phone_number.as_international + ), + self.twilio_call_sid, + ], + ) + ) or self.ig_username or self.fb_page_name or " in #".join( diff --git a/daras_ai_v2/twilio_bot.py b/daras_ai_v2/twilio_bot.py index 4529952ec..cd397ca06 100644 --- a/daras_ai_v2/twilio_bot.py +++ b/daras_ai_v2/twilio_bot.py @@ -24,7 +24,9 @@ def __init__(self, data: dict): twilio_account_sid=account_sid, twilio_phone_number=data["To"][0] ) self.convo = Conversation.objects.get_or_create( - bot_integration=bi, twilio_phone_number=data["From"][0] + bot_integration=bi, + twilio_phone_number=data["From"][0], + twilio_call_sid="", )[0] self.bot_id = bi.twilio_phone_number.as_e164 @@ -86,7 +88,7 @@ class TwilioVoice(BotInterface): platform = Platform.TWILIO @classmethod - def from_data(cls, data: dict): + def from_webhook_data(cls, data: dict): ## data samples: # {'AccountSid': ['XXXX'], 'ApiVersion': ['2010-04-01'], 'CallSid': ['XXXX'], 'CallStatus': ['ringing'], 'CallToken': ['XXXX'], 'Called': ['XXXX'], 'CalledCity': ['XXXX'], 'CalledCountry': ['XXXX'], 'CalledState': ['XXXX'], 'CalledZip': ['XXXX'], 'Caller': ['XXXX'], 'CallerCity': ['XXXX'], 'CallerCountry': ['XXXX'], 'CallerState': ['XXXX'], 'CallerZip': ['XXXX'], 'Direction': ['inbound'], 'From': ['XXXX'], 'FromCity': ['XXXX'], 'FromCountry': ['XXXX'], 'FromState': ['XXXX'], 'FromZip': ['XXXX'], 'StirVerstat': ['XXXX'], 'To': ['XXXX'], 'ToCity': ['XXXX'], 'ToCountry': ['XXXX'], 'ToState': ['XXXX'], 'ToZip': ['XXXX']} # {'AccountSid': ['XXXX'], 'ApiVersion': ['2010-04-01'], 'CallSid': ['XXXX'], 'CallStatus': ['in-progress'], 'Called': ['XXXX'], 'CalledCity': ['XXXX'], 'CalledCountry': ['XXXX'], 'CalledState': ['XXXX'], 'CalledZip': ['XXXX'], 'Caller': ['XXXX'], 'CallerCity': ['XXXX'], 'CallerCountry': ['XXXX'], 'CallerState': ['XXXX'], 'CallerZip': ['XXXX'], 'Confidence': ['0.9128386'], 'Direction': ['inbound'], 'From': ['XXXX'], 'FromCity': ['XXXX'], 'FromCountry': ['XXXX'], 'FromState': ['XXXX'], 'FromZip': ['XXXX'], 'Language': ['en-US'], 'SpeechResult': ['Hello.'], 'To': ['XXXX'], 'ToCity': ['XXXX'], 'ToCountry': ['XXXX'], 'ToState': ['XXXX'], 'ToZip': ['XXXX']} @@ -96,25 +98,29 @@ def from_data(cls, data: dict): if account_sid == settings.TWILIO_ACCOUNT_SID: account_sid = "" call_sid = data["CallSid"][0] - caller_number = data["Caller"][0] user_number, bot_number = data["From"][0], data["To"][0] try: # cases where user is calling the bot bi = BotIntegration.objects.get( twilio_account_sid=account_sid, twilio_phone_number=bot_number ) + will_be_missed = bi.twilio_use_missed_call except BotIntegration.DoesNotExist: # cases where bot is calling the user user_number, bot_number = bot_number, user_number bi = BotIntegration.objects.get( twilio_account_sid=account_sid, twilio_phone_number=bot_number ) + will_be_missed = False - will_be_missed = caller_number == user_number and bi.twilio_use_missed_call if will_be_missed: - # for call_sids that we will reject and re-call, the convo is not used, so we don't want to create a new one - convo = None - if bi.twilio_fresh_conversation_per_call and not will_be_missed: + # for calls that we will reject and callback, the convo is not used so we don't want to create one + convo = Conversation( + bot_integration=bi, + twilio_phone_number=user_number, + twilio_call_sid=call_sid, + ) + elif bi.twilio_fresh_conversation_per_call: convo = Conversation.objects.get_or_create( bot_integration=bi, twilio_phone_number=user_number, @@ -122,8 +128,11 @@ def from_data(cls, data: dict): )[0] else: convo = Conversation.objects.get_or_create( - bot_integration=bi, twilio_phone_number=user_number + bot_integration=bi, + twilio_phone_number=user_number, + twilio_call_sid="", )[0] + return cls( convo, text=data.get("SpeechResult", [None])[0], diff --git a/routers/twilio_api.py b/routers/twilio_api.py index 6913a3ca7..152de7f77 100644 --- a/routers/twilio_api.py +++ b/routers/twilio_api.py @@ -69,7 +69,7 @@ def twilio_voice_call( """Handle incoming Twilio voice call.""" try: - bot = TwilioVoice.from_data(data) + bot = TwilioVoice.from_webhook_data(data) except BotIntegration.DoesNotExist as e: logger.debug(f"could not find bot integration for {data=} {e=}") resp = VoiceResponse() @@ -198,7 +198,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) + bot = TwilioVoice.from_webhook_data(data) resolve_twilio_tts_voice(bot) background_tasks.add_task(msg_handler, bot)