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 )