Ekaropolus f2180483f0
All checks were successful
continuous-integration/drone/push Build is passing
Adding DB to Whatsaap AI
2025-05-19 23:04:20 -06:00

187 lines
6.3 KiB
Python

import os
import json
import requests
import logging
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.shortcuts import get_object_or_404
from pxy_openai.assistants import OpenAIAssistant
from .models import WhatsAppBot
from .models import WhatsAppBot, Conversation, Message
from django.utils import timezone
logger = logging.getLogger(__name__)
# Utility Functions
def send_whatsapp_message(phone_number_id, sender_number, bot_response, graph_api_token):
"""
Sends a message back to the user via WhatsApp.
"""
try:
response = requests.post(
f"https://graph.facebook.com/v18.0/{phone_number_id}/messages",
headers={"Authorization": f"Bearer {graph_api_token}"},
json={
"messaging_product": "whatsapp",
"to": sender_number,
"text": {"body": bot_response},
},
)
response.raise_for_status()
except Exception as e:
logger.error(f"Error sending message via WhatsApp: {e}")
def verify_webhook_token(mode, token, challenge, verify_token):
"""
Verifies the webhook token and mode.
"""
if mode == "subscribe" and token == verify_token:
return HttpResponse(challenge, status=200)
return HttpResponse("Forbidden", status=403)
def parse_webhook_payload(payload):
"""
Parses the webhook payload and extracts relevant data.
"""
entry = payload.get("entry", [{}])[0]
changes = entry.get("changes", [{}])[0]
value = changes.get("value", {})
message = value.get("messages", [{}])[0]
return value, message
# Webhook Endpoint
@csrf_exempt
def webhook(request):
"""
Handles incoming webhook requests from WhatsApp.
"""
if request.method == "GET":
# Webhook verification
mode = request.GET.get("hub.mode")
token = request.GET.get("hub.verify_token")
challenge = request.GET.get("hub.challenge")
# Use the first active bot for verification
bot = WhatsAppBot.objects.filter(is_active=True).first()
if bot:
return verify_webhook_token(mode, token, challenge, bot.webhook_verify_token)
return HttpResponse("No active bots configured", status=500)
elif request.method == "POST":
try:
# Parse the incoming payload
payload = json.loads(request.body)
value, message = parse_webhook_payload(payload)
if message.get("type") == "text":
user_message = message["text"]["body"]
phone_number_id = value.get("metadata", {}).get("phone_number_id")
sender_number = message["from"]
logger.info(f"Received phone_number_id from webhook payload: {phone_number_id}")
# 1) Fetch the active bot
bot = get_object_or_404(
WhatsAppBot,
phone_number_id=phone_number_id,
is_active=True
)
# 2) Get or create Conversation
conv, _ = Conversation.objects.get_or_create(
bot=bot,
user_number=sender_number,
defaults={'started_at': timezone.now()}
)
# 3) Save inbound message
Message.objects.create(
conversation=conv,
direction="in",
content=user_message
)
# 4) Generate assistant response and measure time
assistant = OpenAIAssistant(name=bot.assistant.name)
start = timezone.now()
try:
bot_response = assistant.handle_message(user_message)
except Exception as e:
bot_response = f"Assistant error: {e}"
logger.error(bot_response)
end = timezone.now()
# 5) Send the response back to the user
send_whatsapp_message(
phone_number_id,
sender_number,
bot_response,
bot.graph_api_token
)
# 6) Save outbound message with response time
resp_ms = int((end - start).total_seconds() * 1000)
Message.objects.create(
conversation=conv,
direction="out",
content=bot_response,
response_time_ms=resp_ms
)
except Exception as e:
logger.error(f"Error processing webhook: {e}")
return JsonResponse({}, status=200)
return HttpResponse("Method Not Allowed", status=405)
# Webhook Verification Endpoint
@require_http_methods(["GET"])
def webhook_verification(request):
"""
Verifies the webhook token from WhatsApp.
"""
mode = request.GET.get("hub.mode")
token = request.GET.get("hub.verify_token")
challenge = request.GET.get("hub.challenge")
# Use the first active bot for verification
bot = WhatsAppBot.objects.filter(is_active=True).first()
if bot:
return verify_webhook_token(mode, token, challenge, bot.webhook_verify_token)
return HttpResponse("No active bots configured", status=500)
# Root Endpoint
def root(request):
"""
A root endpoint for basic connectivity testing.
"""
return HttpResponse("<pre>Nothing to see here.\nCheckout README.md to start.</pre>", content_type="text/html")
from django.contrib.auth.decorators import login_required
from django.db.models import Avg
from .models import Conversation, Message
@login_required
def whatsapp_stats(request):
from django.utils import timezone
since = timezone.now() - timezone.timedelta(days=1)
total_convos = Conversation.objects.count()
msgs_in = Message.objects.filter(direction="in", timestamp__gte=since).count()
msgs_out = Message.objects.filter(direction="out", timestamp__gte=since).count()
avg_rt = Message.objects.filter(direction="out", response_time_ms__isnull=False).aggregate(Avg("response_time_ms"))
return JsonResponse({
"total_conversations": total_convos,
"messages_in": msgs_in,
"messages_out": msgs_out,
"avg_response_time": avg_rt["response_time_ms__avg"] or 0,
})