Ekaropolus e033604cc5
All checks were successful
continuous-integration/drone/push Build is passing
getthing the right from id
2025-07-22 03:06:57 -06:00

260 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import requests
from pxy_openai.assistants import OpenAIAssistant as OpenAIService # Import the assistant service
import logging
from .models import FacebookPageAssistant
from django.core.exceptions import ObjectDoesNotExist
from pxy_neo4j.neo4j_connector import Neo4jDatabase
logger = logging.getLogger(__name__)
class FacebookService:
"""
A service to interact with the Facebook Graph API.
"""
def __init__(self, user_access_token, facebook_api_version="v22.0"):
self.user_access_token = user_access_token
self.facebook_api_version = facebook_api_version
self.base_url = f"https://graph.facebook.com/{self.facebook_api_version}"
self.neo4j_db = Neo4jDatabase() # Initialize Neo4j connection
def get_system_user_id(self):
"""
Retrieves the system user ID using the user access token.
"""
try:
return '122106889202727657'
except requests.exceptions.RequestException as e:
logger.error(f"Error fetching system user ID: {e}")
return None
def get_page_access_token(self, page_id):
"""
Retrieves the Page Access Token for a specific Page ID.
"""
url = f"{self.base_url}/122106889202727657/accounts?access_token={self.user_access_token}"
try:
response = requests.get(url)
response.raise_for_status()
data = response.json()
if "data" in data:
for page in data["data"]:
if page.get("id") == str(page_id):
page_name = page.get("name", "Unknown")
access_token = page.get("access_token", "No Token")
logger.info(f"Retrieved access token for page {page_id}: {page_name}")
return access_token
logger.error(f"Error: Page ID {page_id} not found.")
else:
logger.error("Error: Unexpected response format from Facebook API.")
except requests.exceptions.RequestException as e:
logger.error(f"Error fetching Page Access Token: {e}")
return None
def post_comment_on_share(self, page_id, post_id, message, sender_id=None):
"""
Posts a comment on a shared post using the Facebook API.
Fetches post details (description, parent_id) to improve the comment.
If parent_id exists, posts the same comment on the original post.
"""
# Retrieve the Page Access Token dynamically
page_access_token = self.get_page_access_token(page_id)
if not page_access_token:
logger.error(f"Unable to retrieve access token for page ID: {page_id}")
return None
# Fetch post details (description, parent_id)
post_details = self.get_post_details(post_id, page_access_token)
if not post_details:
logger.error(f"Failed to retrieve post details for post ID: {post_id}")
return None
description = post_details.get("description", "")
parent_id = post_details.get("parent_id", None)
author_page_id = post_details.get("parent_from_id", None)
# Fetch the appropriate OpenAI assistant for the page
try:
page_assistant = FacebookPageAssistant.objects.get(page_id=page_id)
openai_assistant_model = page_assistant.assistant
logger.info(f"Using assistant '{openai_assistant_model.name}' for page '{page_assistant.page_name}'")
except ObjectDoesNotExist:
logger.error(f"No assistant configured for page ID: {page_id}")
return None
# Generate a meaningful comment based on available data
if not message or message.strip() == "":
if description:
prompt = (
f"Dr. Dr. Ekaropolus previously said: '{description}'. "
"Based on this, write an insightful response in the most appropriate language that engages people in scientific discussion."
)
else:
prompt = "Say something truly inspiring about science, a fact or idea that will amaze people."
else:
if description:
prompt = (
f"Dr. Dr. Ekaropolus previously said: '{message}', "
f"and the shared post describes: '{description}'. "
"Combine these thoughts into an engaging, fun, and insightful response in the most appropriate language."
)
else:
prompt = f"Dr. Dr. Ekaropolus said: '{message}'. Expand on this with an insightful scientific thought."
openai_service = OpenAIService(name=openai_assistant_model.name)
bot_response = openai_service.handle_message(prompt)
sender_id = author_page_id
# Post a comment on the shared post
shared_comment_response = self._post_facebook_comment(post_id, bot_response, page_access_token, sender_id)
# If the comment on the shared post was successful, store in Neo4j
if shared_comment_response:
self.neo4j_db.store_interaction(
user_id=f"fb_bot_{page_id}",
bot_id=f"fb_bot_{page_id}",
user_message=description if description else "Shared post comment",
bot_response=bot_response,
platform="Facebook"
)
# If parent_id exists and the first comment was successful, post the same comment on the original post
if parent_id and shared_comment_response:
logger.info(f"Also commenting on the original post: {parent_id}")
original_comment_response = self._post_facebook_comment(parent_id, bot_response, page_access_token)
# If the comment on the original post was successful, store in Neo4j
if original_comment_response:
self.neo4j_db.store_interaction(
user_id=f"fb_bot_{page_id}",
bot_id=f"fb_bot_{page_id}",
user_message=description if description else "Original post comment",
bot_response=bot_response,
platform="Facebook (Original Post)"
)
return shared_comment_response
def get_post_details(self, post_id, access_token):
"""
Retrieves details of a post, including:
- description (from attachments)
- parent_id (if its a share)
- from_id (author of THIS post)
- parent_from_id (author of the ORIGINAL post, if shared)
"""
# 1st call: get this posts description, parent_id, and its own from()
url = (
f"{self.base_url}/{post_id}"
"?fields=attachments.limit(10){description,media,media_type,target,url},"
"parent_id,from"
f"&access_token={access_token}"
)
try:
response = requests.get(url)
response.raise_for_status()
data = response.json()
attachments = data.get("attachments", {}).get("data", [{}])
description = attachments[0].get("description", "") if attachments else ""
parent_id = data.get("parent_id")
from_id = data.get("from", {}).get("id")
# default if there is no parent
parent_from_id = None
# If this is a share, fetch the ORIGINAL posts author
if parent_id:
parent_url = (
f"{self.base_url}/{parent_id}"
"?fields=from"
f"&access_token={access_token}"
)
p_resp = requests.get(parent_url)
p_resp.raise_for_status()
p_data = p_resp.json()
parent_from_id = p_data.get("from", {}).get("id")
return {
"description": description,
"parent_id": parent_id,
"from_id": from_id,
"parent_from_id": parent_from_id
}
except requests.exceptions.RequestException as e:
logger.error(f"Failed to fetch post details for {post_id}. Error: {e}")
return {}
def _post_facebook_comment(self, post_id, message, access_token, sender_id=None):
"""
Helper function to post a comment to a specific post.
"""
# Prepend mention if sender_id provided
if sender_id:
mention = f"https://www.facebook.com/{sender_id} "
message = f"{mention}{message}{post_id}"
url = f"{self.base_url}/{post_id}/comments"
payload = {"message": message, "access_token": access_token}
try:
response = requests.post(url, data=payload)
response.raise_for_status()
logger.info(f"Posted a comment on post ID: {post_id}")
return response.json()
except requests.exceptions.RequestException as e:
logger.error(f"Failed to comment on post ID: {post_id}. Error: {e}")
return None
def reply_to_comment(self, page_id, comment_id, message):
"""
Replies to a specific comment using the Facebook API and OpenAI Assistant.
"""
# Retrieve the Page Access Token dynamically
page_access_token = self.get_page_access_token(page_id)
if not page_access_token:
logger.error(f"Unable to retrieve access token for page ID: {page_id}")
return None
# Fetch the appropriate OpenAI assistant for the page
try:
page_assistant = FacebookPageAssistant.objects.get(page_id=page_id)
openai_assistant_model = page_assistant.assistant
logger.info(f"Using assistant '{openai_assistant_model.name}' for page '{page_assistant.page_name}'")
except ObjectDoesNotExist:
logger.error(f"No assistant configured for page ID: {page_id}")
return None
# Use a default message if the received message is empty
if not message or message.strip() == "":
message = "Thank you for sharing this comment! What do you think about it?"
openai_service = OpenAIService(name=openai_assistant_model.name) # Pass the model's name to the service
bot_response = openai_service.handle_message(message)
# Send the response to Facebook
url = f"{self.base_url}/{comment_id}/comments"
payload = {"message": bot_response, "access_token": page_access_token}
try:
response = requests.post(url, data=payload)
response.raise_for_status()
logger.info(f"Replied to comment ID: {comment_id}")
# Store the interaction in Neo4j
self.neo4j_db.store_interaction(
user_id=f"fb_user_{comment_id}",
bot_id=f"fb_bot_{page_id}",
user_message=message,
bot_response=bot_response,
platform="Facebook"
)
return response.json()
except requests.exceptions.RequestException as e:
logger.error(f"Failed to reply to comment ID: {comment_id}. Error: {e}")
return None