Ekaropolus c954488c28
All checks were successful
continuous-integration/drone/push Build is passing
FIX AGAIN
2025-09-07 03:28:08 -06:00

198 lines
7.5 KiB
Python

import json
import logging
from django.http import JsonResponse, HttpResponse
from django.conf import settings
from .services import FacebookService
from .models import FacebookPageAssistant, EventType, FacebookEvent
import requests
from pxy_openai.assistants import OpenAIAssistant as OpenAIService
# Configure logging
logger = logging.getLogger(__name__)
PAGE_ACCESS_TOKEN = settings.PAGE_ACCESS_TOKEN
def verify_webhook_token(mode, token, challenge, verify_token):
"""
Verifies the webhook token and mode.
"""
if mode == "subscribe" and token == verify_token:
logger.info("Webhook verified successfully.")
return HttpResponse(challenge, status=200)
else:
logger.warning(f"Webhook verification failed. Mode: {mode}, Token: {token}")
return HttpResponse("Forbidden", status=403)
def parse_webhook_payload(payload):
"""
Parses the webhook payload and extracts relevant data.
"""
try:
entry = payload.get("entry", [{}])[0]
changes = entry.get("changes", [{}])[0]
value = changes.get("value", {})
return value
except Exception as e:
logger.error(f"Error parsing payload: {e}")
raise
def handle_comment_event(page_id, sender_id, data):
"""
Handles incoming comment events:
1) Persiste el evento en la BD.
2) Responde al comentario vía FacebookService.
"""
# Si el comentario viene de la propia página, lo saltamos
if sender_id == page_id:
logger.info(f"Skipping self-generated comment. Sender ID: {sender_id}, Page ID: {page_id}")
return JsonResponse({"status": "skipped"}, status=200)
comment_id = data.get("comment_id")
original_message = data.get("message")
# 1) Registrar en la base de datos
try:
page = FacebookPageAssistant.objects.get(page_id=page_id)
et = EventType.objects.get(code="comment")
FacebookEvent.objects.create(
page=page,
event_type=et,
sender_id=sender_id,
object_id=comment_id,
message=original_message
)
except Exception as e:
logger.error(f"Error logging FB comment event: {e}")
# 2) Responder al comentario via API de Facebook
if comment_id and original_message:
try:
fb_service = FacebookService(PAGE_ACCESS_TOKEN)
fb_service.reply_to_comment(page_id, comment_id, original_message)
logger.info(f"Successfully replied to comment ID: {comment_id} with bot response: {original_message}")
except Exception as e:
logger.error(f"Error replying to comment via FacebookService: {e}")
return JsonResponse({"status": "comment_handled"}, status=200)
def handle_share_event(page_id, data):
"""
Handles incoming share events:
1) Persiste el evento en la BD.
2) Publica un comentario en la share vía FacebookService.
"""
share_id = data.get("share_id")
post_id = data.get("post_id")
original_message = data.get("message")
share_link = data.get("link")
logger.info(f"Post {post_id} was shared. Share ID: {share_id}, Link: {share_link}")
# 1) Registrar en la base de datos
try:
page = FacebookPageAssistant.objects.get(page_id=page_id)
et = EventType.objects.get(code="share")
FacebookEvent.objects.create(
page=page,
event_type=et,
object_id=share_id,
message=original_message
)
except Exception as e:
logger.error(f"Error logging FB share event: {e}")
# 2) Comentar en la publicación compartida via API de Facebook
try:
fb_service = FacebookService(PAGE_ACCESS_TOKEN)
fb_service.post_comment_on_share(page_id, post_id, original_message)
except Exception as e:
logger.error(f"Error posting comment on share via FacebookService: {e}")
return JsonResponse({"status": "share_logged"}, status=200)
def handle_message_event(page_id: str, sender_psid: str, message: dict):
"""
Handles incoming Messenger messages:
1) Log event to DB (like comments/shares)
2) Generate AI reply with your configured OpenAI assistant for this page
3) Send the sreply via the Send API (using the page's access token)
"""
try:
# 0) ignore echoes to prevent loops
if not message or message.get("is_echo"):
return JsonResponse({"status": "ignored"}, status=200)
text = (message.get("text") or "").strip()
mid = message.get("mid") or ""
# 1) Persist event to DB (EventType 'message'; create if missing)
try:
page = FacebookPageAssistant.objects.get(page_id=page_id)
et, _ = EventType.objects.get_or_create(code="message", defaults={"label": "Message"})
FacebookEvent.objects.create(
page=page,
event_type=et,
sender_id=sender_psid,
object_id=mid,
message=text
)
except Exception as e:
logger.error(f"Error logging Messenger event: {e}")
# 2) Build prompt and get AI reply from the page's configured assistant
try:
page_assistant = FacebookPageAssistant.objects.get(page_id=page_id).assistant
prompt = text if text else "Say hello and ask how you can help."
openai_service = OpenAIService(name=page_assistant.name)
bot_reply = openai_service.handle_message(prompt)
except Exception as e:
logger.exception(f"AI reply failed; falling back. Reason: {e}")
bot_reply = "Gracias por tu mensaje 🙌. ¿En qué puedo ayudarte?"
# 3) Send the reply via Send API
try:
fb_service = FacebookService(PAGE_ACCESS_TOKEN) # reuse your token flow
page_token = fb_service._get_page_access_token(page_id) or PAGE_ACCESS_TOKEN
url = "https://graph.facebook.com/v22.0/me/messages"
payload = {
"recipient": {"id": sender_psid},
"messaging_type": "RESPONSE",
"message": {"text": bot_reply},
}
resp = requests.post(url, params={"access_token": page_token}, json=payload, timeout=5)
resp.raise_for_status()
logger.info(f"Sent Messenger reply to psid={sender_psid}")
return JsonResponse({"status": "message_replied"}, status=200)
except requests.RequestException as e:
logger.exception(f"Send API failed: {e}")
return JsonResponse({"status": "send_failed"}, status=200)
except Exception as e:
logger.exception(f"handle_message_event crashed: {e}")
return JsonResponse({"status": "error", "detail": str(e)}, status=200)
def handle_postback_event(page_id: str, sender_psid: str, postback: dict):
"""
Minimal stub so views.py import succeeds.
Logs and immediately 200s. We'll upgrade it later to AI-reply if you want.
"""
try:
payload = (postback or {}).get("payload")
title = (postback or {}).get("title")
logger.info(f"[HANDLER] postback page={page_id} psid={sender_psid} payload={payload!r} title={title!r}")
return JsonResponse({"status": "postback_handled", "payload": payload}, status=200)
except Exception as e:
logger.exception(f"postback handler failed: {e}")
return JsonResponse({"status": "error", "detail": str(e)}, status=200)