diff --git a/foodie_utils.py b/foodie_utils.py index ff46f45..9833897 100644 --- a/foodie_utils.py +++ b/foodie_utils.py @@ -62,12 +62,19 @@ def save_json_file(filename, key, value): # Remove duplicates by title data = [item for item in data if item["title"] != key] data.append(entry) - # Special handling for used_images.json to save as a flat list + # Special handling for used_images.json to save as a flat list with one URL per line if filename.endswith('used_images.json'): - # Update the used_images set directly to keep it in sync used_images.add(key) with open(filename, 'w') as f: - json.dump(list(used_images), f) + f.write('[\n') + urls = list(used_images) + for i, url in enumerate(urls): + f.write(f'"{url}"') + if i < len(urls) - 1: + f.write(',\n') + else: + f.write('\n') + f.write(']') else: with open(filename, 'w') as f: for item in data: @@ -139,20 +146,23 @@ def generate_article_tweet(author, post, persona): prompt = ( f"Craft a sharp tweet (under 230 characters) for {author_handle} with the voice of '{persona}'. " - f"Distill the essence of the article '{title}' and include the raw URL '{url}' at the end. " + f"Distill the essence of the article '{title}' into a concise, engaging message. " + f"Include the raw URL '{url}' at the end. " + f"Do not wrap the tweet in quotation marks. " f"Make it bold, spark curiosity, and invite engagement with a human touch. " f"Swap 'elevate' for dynamic terms like 'ignite' or 'unleash'. " f"Absolutely do not include hashtags, emojis, or phrases like '[Read more]' or 'Read more'. " - f"Skip any extra fluff or formatting around the URL—just append the raw URL after a space." + f"Skip any extra fluff or formatting around the URL—just append the raw URL after a space. " + f"Example: 'Love food trends? Check this out! {url}'" ) - response = openai.chat.completions.create( + response = client.chat.completions.create( model=SUMMARY_MODEL, messages=[ {"role": "system", "content": "You are a social media viral expert crafting engaging tweets."}, {"role": "user", "content": prompt} ], - max_tokens=100, + max_tokens=80, temperature=0.7 ) @@ -161,12 +171,19 @@ def generate_article_tweet(author, post, persona): # Post-generation check: Strip any emojis using regex tweet = re.sub(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U0001F700-\U0001F77F\U0001F780-\U0001F7FF\U0001F800-\U0001F8FF\U0001F900-\U0001F9FF\U0001FA00-\U0001FA6F\U0001FA70-\U0001FAFF\U00002702-\U000027B0\U000024C2-\U0001F251]', '', tweet).strip() - # Optionally, strip "[Read more]" or similar phrases as an additional failsafe + # Strip "[Read more]" or similar phrases as an additional failsafe tweet = re.sub(r'\[Read more\]\(.*?\)|\bRead more\b', '', tweet).strip() - if len(tweet) > 280: - tweet = tweet[:277] + "..." + # Strip leading or trailing quotation marks + tweet = 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 + + logging.info(f"Generated tweet: {tweet}") return tweet def post_tweet(author, tweet): @@ -1015,7 +1032,15 @@ if os.path.exists(used_images_file): def save_used_images(): try: with open(used_images_file, 'w') as f: - json.dump(list(used_images), f) + f.write('[\n') + urls = list(used_images) + for i, url in enumerate(urls): + f.write(f'"{url}"') + if i < len(urls) - 1: + f.write(',\n') + else: + f.write('\n') + f.write(']') logging.info(f"Saved {len(used_images)} used image URLs to {used_images_file}") except Exception as e: logging.warning(f"Failed to save used images to {used_images_file}: {e}")