129 lines
4.4 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
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}")
# Fetch the appropriate bot configuration
bot = get_object_or_404(WhatsAppBot, phone_number_id=phone_number_id, is_active=True)
# Initialize the assistant and get a response
assistant = OpenAIAssistant(name=bot.assistant.name)
try:
bot_response = assistant.handle_message(user_message)
except Exception as e:
bot_response = f"Assistant error: {e}"
logger.error(bot_response)
# Send the response back to the user
send_whatsapp_message(bot.phone_number_id, sender_number, bot_response, bot.graph_api_token)
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")