diff --git a/foodie_engagement_tweet.py b/foodie_engagement_tweet.py index f21f935..59c4b4e 100644 --- a/foodie_engagement_tweet.py +++ b/foodie_engagement_tweet.py @@ -3,6 +3,7 @@ import logging from datetime import datetime, timedelta, timezone from openai import OpenAI # Add this import from foodie_utils import post_tweet, AUTHORS, SUMMARY_MODEL +from foodie_config import X_API_CREDENTIALS from dotenv import load_dotenv # Add this import # Setup logging @@ -14,8 +15,14 @@ load_dotenv() # Initialize OpenAI client client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) + def generate_engagement_tweet(author): - author_handle = author["x_username"] # Updated to use x_username from X_API_CREDENTIALS + # Fetch x_username from X_API_CREDENTIALS + credentials = next((cred for cred in X_API_CREDENTIALS if cred["username"] == author["username"]), None) + if not credentials: + logging.error(f"No X credentials found for {author['username']}") + return None + author_handle = credentials["x_username"] prompt = ( f"Generate a concise tweet (under 280 characters) for {author_handle}. " f"Create an engaging food-related question or statement to spark interaction. " diff --git a/foodie_utils.py b/foodie_utils.py index 0206683..64ab9da 100644 --- a/foodie_utils.py +++ b/foodie_utils.py @@ -178,16 +178,22 @@ def generate_article_tweet(author, post, persona): # Strip leading or trailing quotation marks tweet = tweet.strip('"\'') + # Remove the URL if it already exists in the tweet to avoid duplication + tweet = re.sub(rf'\s*{re.escape(url)}$', '', tweet).strip() + # Ensure tweet fits within 280 characters, accounting for URL (Twitter shortens to 23 chars) url_length = 23 max_tweet_length = 280 - url_length - 1 # Subtract 1 for the space before URL if len(tweet) > max_tweet_length: - tweet = tweet[:max_tweet_length-3] + "... " + url + tweet = tweet[:max_tweet_length-3] + "..." + + # Append the URL exactly once + tweet = tweet + " " + url logging.info(f"Generated tweet: {tweet}") return tweet -def post_tweet(author, tweet): +def post_tweet(author, tweet, reply_to_id=None): credentials = next((cred for cred in X_API_CREDENTIALS if cred["username"] == author["username"]), None) if not credentials: logging.error(f"No X credentials found for {author['username']}") @@ -209,12 +215,15 @@ def post_tweet(author, tweet): access_token=credentials["access_token"], access_token_secret=credentials["access_token_secret"] ) - response = client.create_tweet(text=tweet) + response = client.create_tweet( + text=tweet, + in_reply_to_tweet_id=reply_to_id # Add threading support + ) author_count["monthly_count"] += 1 author_count["daily_count"] += 1 save_post_counts(post_counts) logging.info(f"Posted tweet for {author['username']}: {tweet}") - return True + return {"id": response.data["id"]} # Return dict with tweet ID except Exception as e: logging.error(f"Failed to post tweet for {author['username']}: {e}") return False diff --git a/foodie_weekly_thread.py b/foodie_weekly_thread.py index 73baf9f..9c2f30e 100644 --- a/foodie_weekly_thread.py +++ b/foodie_weekly_thread.py @@ -38,7 +38,11 @@ def filter_posts_for_week(posts, start_date, end_date): return filtered_posts def generate_intro_tweet(author): - author_handle = author["handle"] + credentials = next((cred for cred in X_API_CREDENTIALS if cred["username"] == author["username"]), None) + if not credentials: + logging.error(f"No X credentials found for {author['username']}") + return None + author_handle = credentials["x_username"] prompt = ( f"Generate a concise tweet (under 280 characters) for {author_handle}. " f"Introduce a thread of their top 10 foodie posts of the week on InsiderFoodie.com. " diff --git a/foodie_x_poster.py b/foodie_x_poster.py index 4d5d683..5326abf 100644 --- a/foodie_x_poster.py +++ b/foodie_x_poster.py @@ -93,7 +93,7 @@ def generate_engagement_tweet(author, persona): return tweet except Exception as e: logging.error(f"Failed to generate engagement tweet for {author['username']}: {e}") - return f"What’s your take on {theme}? Let’s talk! #FoodieTrends" + return f"What’s your take on {theme}? Let’s talk!" def main(): global is_posting