38274-vm/core/utils.py
Flatlogic Bot 84f67bc019 v4
2026-02-07 18:16:19 +00:00

120 lines
4.3 KiB
Python

import requests
import logging
from .models import Fanpage, Flow, Node, Edge, ChatSession, MessageLog
logger = logging.getLogger(__name__)
def send_fb_message(psid, access_token, message_content):
"""
Sends a message to a Facebook user via the Graph API.
message_content: dict matching Facebook's message object (e.g., {"text": "..."})
"""
url = f"https://graph.facebook.com/v12.0/me/messages?access_token={access_token}"
payload = {
"recipient": {"id": psid},
"message": message_content
}
try:
response = requests.post(url, json=payload)
response.raise_for_status()
return response.json()
except Exception as e:
logger.error(f"Error sending message to Facebook: {e}")
return None
def get_next_node(session, message_text):
"""
Determines the next node in the flow based on user input.
"""
fanpage = session.fanpage
if not session.current_node:
# Start of conversation: find the default flow and its start node
flow = Flow.objects.filter(fanpage=fanpage, is_default=True).first()
if not flow:
flow = Flow.objects.filter(fanpage=fanpage).first()
if flow:
return Node.objects.filter(flow=flow, is_start_node=True).first()
return None
# We are in an active session, look for a matching edge
edges = Edge.objects.filter(source_node=session.current_node)
message_text_clean = message_text.strip().lower()
for edge in edges:
if edge.condition.lower() == message_text_clean:
return edge.target_node
# If no matching edge, we might want to stay at the current node or find a global start
# For now, let's just return the current node (re-prompting) if it was a text node,
# or None if we don't know what to do.
return session.current_node
def handle_webhook_event(data):
"""
Main entry point for processing Facebook webhook POST data.
"""
if data.get('object') != 'page':
return
for entry in data.get('entry', []):
for messaging_event in entry.get('messaging', []):
sender_id = messaging_event.get('sender', {}).get('id')
recipient_id = messaging_event.get('recipient', {}).get('id')
if not sender_id or not recipient_id:
continue
# 1. Identify Fanpage
try:
fanpage = Fanpage.objects.get(page_id=recipient_id, is_active=True)
except Fanpage.DoesNotExist:
logger.warning(f"Received event for unknown or inactive Page ID: {recipient_id}")
continue
# 2. Extract Message
message_text = ""
if 'message' in messaging_event:
message_text = messaging_event['message'].get('text', "")
elif 'postback' in messaging_event:
# Handle button clicks
message_text = messaging_event['postback'].get('payload', "")
if not message_text:
continue
# 3. Get or Create Session
session, created = ChatSession.objects.get_or_create(
psid=sender_id,
fanpage=fanpage
)
# 4. Log User Message
MessageLog.objects.create(
session=session,
sender_type='user',
message_text=message_text
)
# 5. Determine Next Node
next_node = get_next_node(session, message_text)
if next_node:
# 6. Send Reply
# next_node.content is a JSONField, expected to be {"text": "..."} or similar
result = send_fb_message(sender_id, fanpage.access_token, next_node.content)
if result:
# 7. Update Session
session.current_node = next_node
session.save()
# 8. Log Bot Response
bot_text = next_node.content.get('text', '[Non-text message]')
MessageLog.objects.create(
session=session,
sender_type='bot',
message_text=bot_text
)