diff --git a/foodie_engagement_tweet.py b/foodie_engagement_tweet.py index b2f3da8..b70b6ca 100644 --- a/foodie_engagement_tweet.py +++ b/foodie_engagement_tweet.py @@ -25,6 +25,8 @@ LOG_FILE = "/home/shane/foodie_automator/logs/foodie_engagement_tweet.log" LOG_PRUNE_DAYS = 30 MAX_RETRIES = 3 RETRY_BACKOFF = 2 +URL = "https://insiderfoodie.com" +URL_SHORTENED_LENGTH = 23 # Twitter's shortened URL length def setup_logging(): """Initialize logging with pruning of old logs.""" @@ -191,7 +193,7 @@ def generate_engagement_tweet(author): f"Generate an engagement tweet for {author_handle} asking a question about {theme} to engage the public. " 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, and mention InsiderFoodie.com with a link to https://insiderfoodie.com. " + 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"Return only the tweet text." @@ -205,15 +207,32 @@ def generate_engagement_tweet(author): {"role": "system", "content": "You are a social media expert crafting engaging tweets."}, {"role": "user", "content": prompt} ], - max_tokens=80, # Reduced to ensure shorter tweets + max_tokens=80, temperature=0.7 ) tweet = response.choices[0].message.content.strip() - # Ensure tweet length is within limits (accounting for URL) - url_length = 23 # Twitter shortens URLs - if len(tweet) > (280 - url_length): - tweet = tweet[:(280 - url_length - 3)] + "..." - logging.debug(f"Generated engagement tweet for {username}: {tweet}") + # Check for duplicate URLs and remove if present + url_count = tweet.lower().count(URL.lower()) + if url_count > 1: + logging.warning(f"Generated tweet for {username} contains duplicate URLs: {tweet}") + # Keep only the last occurrence of the URL + last_url_pos = tweet.rfind(URL) + tweet = tweet[:last_url_pos].replace(URL, "").strip() + " " + URL + logging.debug(f"Revised tweet after removing duplicate URL: {tweet}") + + # Ensure the URL is at the end of the tweet + if not tweet.endswith(URL): + tweet = tweet.replace(URL, "").strip() + " " + URL + + # Calculate tweet length considering Twitter's URL shortening + tweet_without_url = tweet.replace(URL, "") + total_length = len(tweet_without_url) + URL_SHORTENED_LENGTH + if total_length > 280: + logging.warning(f"Tweet for {username} exceeds 280 characters ({total_length}), truncating") + tweet_without_url = tweet_without_url[:(280 - URL_SHORTENED_LENGTH - 3)] + tweet = tweet_without_url + "..." + " " + URL + total_length = len(tweet_without_url) + 3 + URL_SHORTENED_LENGTH + logging.debug(f"Final tweet for {username} (length {total_length}): {tweet}") return tweet except Exception as e: logging.warning(f"Failed to generate engagement tweet for {username} (attempt {attempt + 1}): {e}") @@ -222,11 +241,14 @@ def generate_engagement_tweet(author): else: logging.error(f"Failed to generate engagement tweet after {MAX_RETRIES} attempts") fallback = ( - f"What's the hottest {theme}? Share and follow {author_handle} for more on InsiderFoodie.com! " - f"https://insiderfoodie.com" + f"What's the hottest {theme}? Share and follow {author_handle} for more! {URL}" ) - if len(fallback) > (280 - url_length): - fallback = fallback[:(280 - url_length - 3)] + "..." + # Ensure fallback tweet is within length limits + tweet_without_url = fallback.replace(URL, "") + total_length = len(tweet_without_url) + URL_SHORTENED_LENGTH + if total_length > 280: + tweet_without_url = tweet_without_url[:(280 - URL_SHORTENED_LENGTH - 3)] + fallback = tweet_without_url + "..." + " " + URL logging.info(f"Using fallback engagement tweet: {fallback}") return fallback return None