mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
WhatsApp Brain (4 files, ~1,200 lines): whatsapp_brain.py (350 lines): - Central router: identify caller → detect intent → route → respond - 5 modes: SALES, SUPPORT, MARKETER, DEALS, GENERAL - Connected to DB: queries leads, users, affiliates by phone - Arabic/English language detection - 11 intent types with keyword matching - Conversation history (last 50 messages per caller) - Contextual responses using caller profile data whatsapp_knowledge.py (250 lines): - 6 features with Arabic descriptions + selling points - 3 pricing plans with Arabic feature lists - 8 objection responses (Arabic + English) - 3 competitor battlecards (Zoho, Salesforce, HubSpot) - 10 FAQ + 5 Marketer FAQ - FAQ search by keyword matching comparison_engine.py (200 lines): - 5 competitors × 12 dimensions scoring (0-10) - Chart data for radar/bar charts (frontend-ready) - Feature comparison matrix (8 features × 5 competitors) - "Why Dealix Wins" lists (Arabic + English) - Per-competitor comparison summaries whatsapp_webhook.py (120 lines): - POST /webhooks/whatsapp/incoming — Meta + Twilio format parsing - GET /webhooks/whatsapp/verify — Meta challenge verification - POST /webhooks/whatsapp/status — Delivery/read receipts https://claude.ai/code/session_01LsnvBa7HwF5hs99VZbgLGj
136 lines
5.0 KiB
Python
136 lines
5.0 KiB
Python
"""
|
|
WhatsApp Webhook — Dealix AI Revenue OS
|
|
Handles incoming WhatsApp messages, verification, and delivery status.
|
|
"""
|
|
import logging
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Request, Depends, HTTPException
|
|
from fastapi.responses import PlainTextResponse
|
|
|
|
from app.database import get_db
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/webhooks/whatsapp", tags=["WhatsApp Webhook"])
|
|
|
|
|
|
@router.post("/incoming")
|
|
async def handle_incoming(request: Request, db=Depends(get_db)):
|
|
"""Handle incoming WhatsApp messages from Meta Cloud API or Twilio."""
|
|
try:
|
|
body = await request.json()
|
|
except Exception:
|
|
raise HTTPException(status_code=400, detail="Invalid JSON body")
|
|
|
|
phone = ""
|
|
message = ""
|
|
|
|
# Meta Cloud API format
|
|
if "entry" in body:
|
|
try:
|
|
entry = body["entry"][0]
|
|
changes = entry.get("changes", [{}])[0]
|
|
value = changes.get("value", {})
|
|
messages = value.get("messages", [])
|
|
if messages:
|
|
msg = messages[0]
|
|
phone = msg.get("from", "")
|
|
if msg.get("type") == "text":
|
|
message = msg.get("text", {}).get("body", "")
|
|
elif msg.get("type") == "interactive":
|
|
interactive = msg.get("interactive", {})
|
|
if "button_reply" in interactive:
|
|
message = interactive["button_reply"].get("title", "")
|
|
elif "list_reply" in interactive:
|
|
message = interactive["list_reply"].get("title", "")
|
|
else:
|
|
message = f"[{msg.get('type', 'unknown')} message]"
|
|
except (IndexError, KeyError) as e:
|
|
logger.warning(f"Failed to parse Meta webhook: {e}")
|
|
return {"status": "ok"}
|
|
|
|
# Twilio format
|
|
elif "From" in body or "from" in body:
|
|
phone = body.get("From", body.get("from", "")).replace("whatsapp:", "")
|
|
message = body.get("Body", body.get("body", ""))
|
|
|
|
if not phone or not message:
|
|
logger.debug("Webhook received but no actionable message")
|
|
return {"status": "ok"}
|
|
|
|
# Process through WhatsApp Brain
|
|
from app.services.whatsapp_brain import whatsapp_brain
|
|
|
|
try:
|
|
response = await whatsapp_brain.handle_incoming(phone, message, db)
|
|
except Exception as e:
|
|
logger.error(f"WhatsApp brain error for {phone}: {e}")
|
|
response = "عذراً، حدث خطأ. حاول مرة أخرى أو تواصل مع support@dealix.sa"
|
|
|
|
# Send response via WhatsApp API
|
|
try:
|
|
from app.integrations.whatsapp import send_whatsapp_message
|
|
await send_whatsapp_message(phone, response)
|
|
except Exception as e:
|
|
logger.error(f"Failed to send WhatsApp response to {phone}: {e}")
|
|
|
|
logger.info(f"[WhatsApp] {phone}: '{message[:50]}...' → response sent")
|
|
return {"status": "ok", "phone": phone, "response_length": len(response)}
|
|
|
|
|
|
@router.get("/verify")
|
|
async def verify_webhook(request: Request):
|
|
"""Meta webhook verification challenge."""
|
|
params = request.query_params
|
|
mode = params.get("hub.mode")
|
|
token = params.get("hub.verify_token")
|
|
challenge = params.get("hub.challenge")
|
|
|
|
import os
|
|
verify_token = os.environ.get("WHATSAPP_VERIFY_TOKEN", "dealix-whatsapp-verify-2026")
|
|
|
|
if mode == "subscribe" and token == verify_token:
|
|
logger.info("WhatsApp webhook verified successfully")
|
|
return PlainTextResponse(content=challenge or "", status_code=200)
|
|
|
|
logger.warning(f"WhatsApp webhook verification failed: mode={mode}, token={token}")
|
|
raise HTTPException(status_code=403, detail="Verification failed")
|
|
|
|
|
|
@router.post("/status")
|
|
async def delivery_status(request: Request):
|
|
"""Handle delivery/read status updates from WhatsApp."""
|
|
try:
|
|
body = await request.json()
|
|
except Exception:
|
|
return {"status": "ok"}
|
|
|
|
# Meta format
|
|
if "entry" in body:
|
|
try:
|
|
entry = body["entry"][0]
|
|
changes = entry.get("changes", [{}])[0]
|
|
value = changes.get("value", {})
|
|
statuses = value.get("statuses", [])
|
|
|
|
for status in statuses:
|
|
recipient = status.get("recipient_id", "")
|
|
status_type = status.get("status", "") # sent, delivered, read, failed
|
|
timestamp = status.get("timestamp", "")
|
|
logger.debug(
|
|
f"[WhatsApp Status] {recipient}: {status_type} at {timestamp}"
|
|
)
|
|
|
|
# Update message status in database if needed
|
|
if status_type == "failed":
|
|
errors = status.get("errors", [])
|
|
error_msg = errors[0].get("title", "Unknown") if errors else "Unknown"
|
|
logger.error(
|
|
f"[WhatsApp] Message to {recipient} FAILED: {error_msg}"
|
|
)
|
|
except (IndexError, KeyError) as e:
|
|
logger.warning(f"Failed to parse status webhook: {e}")
|
|
|
|
return {"status": "ok"}
|