Skip to content

Commit

Permalink
functional
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderGi committed Feb 26, 2024
1 parent 4b3bbc9 commit a3bf5e7
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 4.2.7 on 2024-02-22 22:10

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('bots', '0059_savedrun_is_api_call'),
]

operations = [
migrations.AddField(
model_name='botintegration',
name='wa_business_access_token',
field=models.TextField(blank=True, default=None, help_text="Bot's WhatsApp Business access token (mandatory) -- has these scopes: ['whatsapp_business_management', 'whatsapp_business_messaging', 'public_profile']", null=True),
),
migrations.AddField(
model_name='botintegration',
name='wa_business_account_name',
field=models.TextField(blank=True, default='', help_text="Bot's WhatsApp Business API account name (only for display)"),
),
migrations.AddField(
model_name='botintegration',
name='wa_business_message_template_namespace',
field=models.TextField(blank=True, default='', help_text="Bot's WhatsApp Business API message template namespace"),
),
migrations.AddField(
model_name='botintegration',
name='wa_business_name',
field=models.TextField(blank=True, default='', help_text="Bot's WhatsApp Business API name (only for display)"),
),
migrations.AddField(
model_name='botintegration',
name='wa_business_user_id',
field=models.TextField(blank=True, default=None, help_text="Bot's WhatsApp Business API user id (mandatory)", null=True),
),
migrations.AddField(
model_name='botintegration',
name='wa_business_waba_id',
field=models.TextField(blank=True, default=None, help_text="Bot's WhatsApp Business API WABA id (mandatory) -- this is the one seen on https://business.facebook.com/settings/whatsapp-business-accounts/", null=True),
),
]
38 changes: 37 additions & 1 deletion bots/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,40 @@ class BotIntegration(models.Model):
help_text="Bot's WhatsApp phone number id (mandatory)",
)

wa_business_access_token = models.TextField(
blank=True,
default=None,
null=True,
help_text="Bot's WhatsApp Business access token (mandatory) -- has these scopes: ['whatsapp_business_management', 'whatsapp_business_messaging', 'public_profile']",
)
wa_business_waba_id = models.TextField(
blank=True,
default=None,
null=True,
help_text="Bot's WhatsApp Business API WABA id (mandatory) -- this is the one seen on https://business.facebook.com/settings/whatsapp-business-accounts/",
)
wa_business_user_id = models.TextField(
blank=True,
default=None,
null=True,
help_text="Bot's WhatsApp Business API user id (mandatory)",
)
wa_business_name = models.TextField(
blank=True,
default="",
help_text="Bot's WhatsApp Business API name (only for display)",
)
wa_business_account_name = models.TextField(
blank=True,
default="",
help_text="Bot's WhatsApp Business API account name (only for display)",
)
wa_business_message_template_namespace = models.TextField(
blank=True,
default="",
help_text="Bot's WhatsApp Business API message template namespace",
)

slack_team_id = models.CharField(
max_length=256,
blank=True,
Expand Down Expand Up @@ -935,7 +969,9 @@ def to_df_format(
else None
), # only show first feedback as per Sean's request
"Analysis JSON": message.analysis_result,
"Run Time": message.saved_run.run_time if message.saved_run else 0, # user messages have no run/run_time
"Run Time": (
message.saved_run.run_time if message.saved_run else 0
), # user messages have no run/run_time
}
rows.append(row)
df = pd.DataFrame.from_records(
Expand Down
1 change: 1 addition & 0 deletions bots/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ def send_broadcast_msg(
documents=documents,
bot_number=bi.wa_phone_number_id,
user_number=convo.wa_phone_number.as_e164,
access_token=bi.wa_business_access_token,
)
case Platform.SLACK:
msg_id = SlackBot.send_msg_to(
Expand Down
37 changes: 24 additions & 13 deletions daras_ai_v2/facebook_bots.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

WA_MSG_MAX_SIZE = 1024

WHATSAPP_AUTH_HEADER = {
"Authorization": f"Bearer {settings.WHATSAPP_ACCESS_TOKEN}",
}

def get_wa_auth_header(access_token: str | None = None):
return {"Authorization": f"Bearer {access_token or settings.WHATSAPP_ACCESS_TOKEN}"}


class WhatsappBot(BotInterface):
Expand All @@ -29,6 +29,7 @@ def __init__(self, message: dict, metadata: dict):
self.input_type = message["type"]

bi = BotIntegration.objects.get(wa_phone_number_id=self.bot_id)
self.access_token = bi.wa_business_access_token
self.convo = Conversation.objects.get_or_create(
bot_integration=bi,
wa_phone_number="+" + self.user_id,
Expand All @@ -54,7 +55,7 @@ def get_input_audio(self) -> str | None:
except KeyError:
return None
# download file from whatsapp
data, mime_type = retrieve_wa_media_by_id(media_id)
data, mime_type = retrieve_wa_media_by_id(media_id, self.access_token)
data, _ = audio_bytes_to_wav(data)
mime_type = "audio/wav"
# upload file to firebase
Expand All @@ -80,7 +81,7 @@ def get_input_documents(self) -> list[str] | None:

def _download_wa_media(self, media_id: str) -> str:
# download file from whatsapp
data, mime_type = retrieve_wa_media_by_id(media_id)
data, mime_type = retrieve_wa_media_by_id(media_id, self.access_token)
# upload file to firebase
return upload_file_from_bytes(
filename=self.nice_filename(mime_type),
Expand Down Expand Up @@ -116,10 +117,13 @@ def send_msg(
video=video,
documents=documents,
buttons=buttons,
access_token=self.access_token,
)

def mark_read(self):
wa_mark_read(self.bot_id, self.input_message["id"])
wa_mark_read(
self.bot_id, self.input_message["id"], access_token=self.access_token
)

@classmethod
def send_msg_to(
Expand All @@ -133,6 +137,7 @@ def send_msg_to(
## whatsapp specific
bot_number: str,
user_number: str,
access_token: str | None = None,
) -> str | None:
# see https://developers.facebook.com/docs/whatsapp/api/messages/media/

Expand All @@ -158,6 +163,7 @@ def send_msg_to(
}
for doc in splits[:-1]
],
access_token=access_token,
)

messages = []
Expand Down Expand Up @@ -239,21 +245,24 @@ def send_msg_to(
bot_number=bot_number,
user_number=user_number,
messages=messages,
access_token=access_token,
)


def retrieve_wa_media_by_id(media_id: str) -> (bytes, str):
def retrieve_wa_media_by_id(
media_id: str, access_token: str | None = None
) -> (bytes, str):
# get media info
r1 = requests.get(
f"https://graph.facebook.com/v16.0/{media_id}/",
headers=WHATSAPP_AUTH_HEADER,
headers=get_wa_auth_header(access_token),
)
raise_for_status(r1)
media_info = r1.json()
# download media
r2 = requests.get(
media_info["url"],
headers=WHATSAPP_AUTH_HEADER,
headers=get_wa_auth_header(access_token),
)
raise_for_status(r2)
content = r2.content
Expand All @@ -280,13 +289,15 @@ def _build_msg_buttons(buttons: list[ReplyButton], msg: dict) -> dict:
}


def send_wa_msgs_raw(*, bot_number, user_number, messages: list) -> str | None:
def send_wa_msgs_raw(
*, bot_number, user_number, messages: list, access_token: str | None = None
) -> str | None:
msg_id = None
for msg in messages:
print(f"send_wa_msgs_raw: {msg=}")
r = requests.post(
f"https://graph.facebook.com/v16.0/{bot_number}/messages",
headers=WHATSAPP_AUTH_HEADER,
headers=get_wa_auth_header(access_token),
json={
"messaging_product": "whatsapp",
"to": user_number,
Expand All @@ -304,11 +315,11 @@ def send_wa_msgs_raw(*, bot_number, user_number, messages: list) -> str | None:
return msg_id


def wa_mark_read(bot_number: str, message_id: str):
def wa_mark_read(bot_number: str, message_id: str, access_token: str | None = None):
# send read receipt
r = requests.post(
f"https://graph.facebook.com/v16.0/{bot_number}/messages",
headers=WHATSAPP_AUTH_HEADER,
headers=get_wa_auth_header(access_token),
json={
"messaging_product": "whatsapp",
"status": "read",
Expand Down
2 changes: 2 additions & 0 deletions daras_ai_v2/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@
FB_APP_ID = config("FB_APP_ID", "")
FB_APP_SECRET = config("FB_APP_SECRET", "")
FB_WEBHOOK_TOKEN = config("FB_WEBHOOK_TOKEN", "")
FB_WHATSAPP_CONFIG_ID = config("FB_WHATSAPP_CONFIG_ID", "")
WHATSAPP_2FA_PIN = config("WHATSAPP_2FA_PIN", "190604")
WHATSAPP_ACCESS_TOKEN = config("WHATSAPP_ACCESS_TOKEN", None)
SLACK_VERIFICATION_TOKEN = config("SLACK_VERIFICATION_TOKEN", "")
SLACK_CLIENT_ID = config("SLACK_CLIENT_ID", "")
Expand Down
10 changes: 9 additions & 1 deletion recipes/VideoBots.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ def render_selected_tab(self, selected_tab):
show_landbot_widget()

def messenger_bot_integration(self):
from routers.facebook_api import ig_connect_url, fb_connect_url
from routers.facebook_api import ig_connect_url, fb_connect_url, wa_connect_url
from routers.slack_api import slack_connect_url
from recipes.VideoBotsStats import VideoBotsStatsPage

Expand Down Expand Up @@ -1018,6 +1018,14 @@ def messenger_bot_integration(self):
ℹ️
</a>
</div>
<div style='height: 50px'>
<a target="_blank" class="streamlit-like-btn" href="{wa_connect_url}">
<i class="fa-brands fa-whatsapp" style="color: lightgreen; font-size: 20px"></i>
&nbsp;
Add Your Whatsapp Number
</a>
</div>
<p>To connect a phone number, make sure it is not reserved for some other use on Whatsapp or <a href="https://business.facebook.com/wa/manage/phone-numbers/">connected to a different Whatsapp account</a>. If your business needs exceed the capacity of a free Whatsapp account and/or you don't want to manage the Whatsapp business yourself, contact us for a quote on a managed Whatsapp number through Gooey.</p>
""",
unsafe_allow_html=True,
)
Expand Down
Loading

0 comments on commit a3bf5e7

Please sign in to comment.