diff --git a/foodie_engagement_tweet.py b/foodie_engagement_tweet.py index 4541b47..b0c4e18 100644 --- a/foodie_engagement_tweet.py +++ b/foodie_engagement_tweet.py @@ -7,6 +7,7 @@ import sys import fcntl import os import time +import re from datetime import datetime, timedelta, timezone import tweepy from openai import OpenAI @@ -56,7 +57,7 @@ def setup_logging(): logging.basicConfig( filename=LOG_FILE, - level=logging.DEBUG, # Changed to DEBUG to show more details + level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) @@ -149,6 +150,27 @@ def validate_twitter_credentials(author): return False return False +def remove_emojis(text): + """Remove emojis from the given text.""" + # Unicode ranges for emojis + emoji_pattern = re.compile( + "[" + "\U0001F600-\U0001F64F" # Emoticons + "\U0001F300-\U0001F5FF" # Symbols & Pictographs + "\U0001F680-\U0001F6FF" # Transport & Map Symbols + "\U0001F700-\U0001F77F" # Alchemical Symbols + "\U0001F780-\U0001F7FF" # Geometric Shapes Extended + "\U0001F800-\U0001F8FF" # Supplemental Arrows-C + "\U0001F900-\U0001F9FF" # Supplemental Symbols and Pictographs + "\U0001FA00-\U0001FA6F" # Chess Symbols + "\U0001FA70-\U0001FAFF" # Symbols and Pictographs Extended-A + "\U00002700-\U000027BF" # Dingbats + "\U00002600-\U000026FF" # Miscellaneous Symbols + "]+", + flags=re.UNICODE + ) + return emoji_pattern.sub(r"", text) + def get_reference_date(): """Load or initialize the reference date for the 2-day interval.""" os.makedirs(os.path.dirname(REFERENCE_DATE_FILE), exist_ok=True) @@ -185,12 +207,28 @@ def generate_engagement_tweet(author): # Case-insensitive lookup for background with whitespace stripping username_cleaned = username.strip().lower() - background = next( - (bg for bg in AUTHOR_BACKGROUNDS if bg["username"].strip().lower() == username_cleaned), - {} - ) + background = {} + available_usernames = [] + for bg in AUTHOR_BACKGROUNDS: + bg_username = bg.get("username") + if bg_username is None: + logging.warning(f"Skipping background entry with missing username: {bg}") + continue + if not isinstance(bg_username, str): + logging.warning(f"Skipping background entry with non-string username: {bg_username} (type: {type(bg_username)})") + continue + bg_username_cleaned = bg_username.strip().lower() + available_usernames.append(bg_username) + logging.debug( + f"Comparing usernames for {username}: " + f"author username (cleaned) = '{username_cleaned}', " + f"background username (cleaned) = '{bg_username_cleaned}'" + ) + if bg_username_cleaned == username_cleaned: + background = bg + break + if not background or "engagement_themes" not in background: - available_usernames = [bg["username"] for bg in AUTHOR_BACKGROUNDS] logging.warning( f"No background or engagement themes found for {username}. " f"Attempted username (cleaned): {username_cleaned}. " @@ -211,8 +249,7 @@ def generate_engagement_tweet(author): f"Keep it under 230 characters to ensure room for the URL. " f"Use {persona_config['tone']}. " f"Include a call to action to follow {author_handle} or like the tweet, followed by the URL {URL} (do not mention InsiderFoodie.com separately in the text). " - f"Avoid using the word 'elevate'—use more humanized language like 'level up' or 'bring to life'. " - f"Do not include emojis, hashtags, or reward-driven incentives (e.g., giveaways). " + f"Strictly avoid using any emojis, hashtags, or reward-driven incentives (e.g., giveaways)—do not include them under any circumstances. " f"Return only the tweet text." ) @@ -228,6 +265,8 @@ def generate_engagement_tweet(author): temperature=0.7 ) tweet = response.choices[0].message.content.strip() + # Remove emojis as a safeguard + tweet = remove_emojis(tweet) # Check for duplicate URLs and remove if present url_count = tweet.lower().count(URL.lower()) if url_count > 1: @@ -266,6 +305,8 @@ def generate_engagement_tweet(author): if total_length > 280: tweet_without_url = tweet_without_url[:(280 - URL_SHORTENED_LENGTH - 3)] fallback = tweet_without_url + "..." + " " + URL + # Remove emojis from fallback as well + fallback = remove_emojis(fallback) logging.info(f"Using fallback engagement tweet: {fallback}") return fallback return None