diff --git a/foodie_automator_google.py b/foodie_automator_google.py index 4ab3403..a1cf3d7 100644 --- a/foodie_automator_google.py +++ b/foodie_automator_google.py @@ -314,14 +314,36 @@ def curate_from_google_trends(geo_list=['US']): final_summary = insert_link_naturally(final_summary, source_name, link) - post_data, author, category, image_url, image_source, uploader, page_url = prepare_post_data(final_summary, title, main_topic) - if not post_data: - attempts += 1 - continue - - image_url, image_source, uploader, page_url = get_flickr_image(image_query, relevance_keywords, main_topic) - if not image_url: - image_url, image_source, uploader, page_url = get_image(image_query) + # Balanced author selection + x_post_counts = load_json_file('/home/shane/foodie_automator/x_post_counts.json', expiration_hours=24*30) + monthly_counts = {entry['username']: entry['monthly_count'] for entry in x_post_counts} + low_post_authors = [u for u, c in monthly_counts.items() if c < 3] + + if low_post_authors: + author_username = random.choice(low_post_authors) + author = next(a for a in AUTHORS if a['username'] == author_username) + logging.info(f"Prioritizing low-post author: {author_username}") + post_data = { + "title": generate_title_from_summary(final_summary), + "content": final_summary, + "status": "publish", + "author": author_username, + "categories": [generate_category_from_summary(final_summary)] + } + category = post_data["categories"][0] + image_url, image_source, uploader, page_url = get_flickr_image(image_query, relevance_keywords, main_topic) + if not image_url: + image_url, image_source, uploader, page_url = get_image(image_query) + if not image_url: + logging.warning(f"All image uploads failed for '{title}' - posting without image") + image_source = None + uploader = None + page_url = None + else: + post_data, author, category, image_url, image_source, uploader, page_url = prepare_post_data(final_summary, title, main_topic) + if not post_data: + attempts += 1 + continue hook = get_dynamic_hook(post_data["title"]).strip() diff --git a/foodie_automator_reddit.py b/foodie_automator_reddit.py index 8fbc926..9cce3fd 100644 --- a/foodie_automator_reddit.py +++ b/foodie_automator_reddit.py @@ -346,14 +346,36 @@ def curate_from_reddit(): final_summary = insert_link_naturally(final_summary, source_name, link) - post_data, author, category, image_url, image_source, uploader, page_url = prepare_post_data(final_summary, title, main_topic) - if not post_data: - attempts += 1 - continue - - image_url, image_source, uploader, page_url = get_flickr_image(image_query, relevance_keywords, main_topic) - if not image_url: - image_url, image_source, uploader, page_url = get_image(image_query) + # Balanced author selection + x_post_counts = load_json_file('/home/shane/foodie_automator/x_post_counts.json', expiration_hours=24*30) + monthly_counts = {entry['username']: entry['monthly_count'] for entry in x_post_counts} + low_post_authors = [u for u, c in monthly_counts.items() if c < 3] + + if low_post_authors: + author_username = random.choice(low_post_authors) + author = next(a for a in AUTHORS if a['username'] == author_username) + logging.info(f"Prioritizing low-post author: {author_username}") + post_data = { + "title": generate_title_from_summary(final_summary), + "content": final_summary, + "status": "publish", + "author": author_username, + "categories": [generate_category_from_summary(final_summary)] + } + category = post_data["categories"][0] + image_url, image_source, uploader, page_url = get_flickr_image(image_query, relevance_keywords, main_topic) + if not image_url: + image_url, image_source, uploader, page_url = get_image(image_query) + if not image_url: + logging.warning(f"All image uploads failed for '{title}' - posting without image") + image_source = None + uploader = None + page_url = None + else: + post_data, author, category, image_url, image_source, uploader, page_url = prepare_post_data(final_summary, title, main_topic) + if not post_data: + attempts += 1 + continue hook = get_dynamic_hook(post_data["title"]).strip() diff --git a/foodie_automator_rss.py b/foodie_automator_rss.py index 6e94460..e310931 100644 --- a/foodie_automator_rss.py +++ b/foodie_automator_rss.py @@ -335,25 +335,43 @@ def curate_from_rss(): final_summary = insert_link_naturally(final_summary, source_name, link) - post_data, author, category, image_url, image_source, uploader, page_url = prepare_post_data(final_summary, title, main_topic) - if not post_data: - print(f"Post data preparation failed for '{title}'") - logging.info(f"Post data preparation failed for '{title}'") - attempts += 1 - continue - - image_url, image_source, uploader, page_url = get_flickr_image(image_query, relevance_keywords, main_topic) - if not image_url: - print(f"Flickr image fetch failed for '{image_query}', trying fallback") - logging.warning(f"Flickr image fetch failed for '{image_query}', trying fallback") - image_url, image_source, uploader, page_url = get_image(image_query) + # Insert balanced author selection logic here + x_post_counts = load_json_file('/home/shane/foodie_automator/x_post_counts.json', expiration_hours=24*30) + monthly_counts = {entry['username']: entry['monthly_count'] for entry in x_post_counts} + low_post_authors = [u for u, c in monthly_counts.items() if c < 3] # Authors with <3 posts + + if low_post_authors: + author_username = random.choice(low_post_authors) + author = next(a for a in AUTHORS if a['username'] == author_username) + logging.info(f"Prioritizing low-post author: {author_username}") + post_data = { + "title": generate_title_from_summary(final_summary), + "content": final_summary, + "status": "publish", + "author": author_username, + "categories": [generate_category_from_summary(final_summary)] + } + category = post_data["categories"][0] + image_url, image_source, uploader, page_url = get_flickr_image(image_query, relevance_keywords, main_topic) if not image_url: - print(f"All image uploads failed for '{title}' - posting without image") - logging.warning(f"All image uploads failed for '{title}' - posting without image") - image_source = None - uploader = None - page_url = None + print(f"Flickr image fetch failed for '{image_query}', trying fallback") + logging.warning(f"Flickr image fetch failed for '{image_query}', trying fallback") + image_url, image_source, uploader, page_url = get_image(image_query) + if not image_url: + print(f"All image uploads failed for '{title}' - posting without image") + logging.warning(f"All image uploads failed for '{title}' - posting without image") + image_source = None + uploader = None + page_url = None + else: + post_data, author, category, image_url, image_source, uploader, page_url = prepare_post_data(final_summary, title, main_topic) + if not post_data: + print(f"Post data preparation failed for '{title}'") + logging.info(f"Post data preparation failed for '{title}'") + attempts += 1 + continue + # ... (rest of the function: image fetching, posting logic, etc.) hook = get_dynamic_hook(post_data["title"]).strip() share_prompt = get_viral_share_prompt(post_data["title"], final_summary) diff --git a/foodie_utils.py b/foodie_utils.py index 5510818..30c191e 100644 --- a/foodie_utils.py +++ b/foodie_utils.py @@ -1137,29 +1137,37 @@ def get_flickr_image(search_query, relevance_keywords, main_topic): logging.warning(f"No valid Flickr image found for query '{search_query}' after all attempts.") return None, None, None, None -def select_best_author(summary): +def select_best_author(content, interest_score): try: - response = client.chat.completions.create( - model=LIGHT_TASK_MODEL, - messages=[ - {"role": "system", "content": ( - "Based on this restaurant/food industry trend summary, pick the most suitable author from: " - "owenjohnson, javiermorales, aishapatel, trangnguyen, keishareid, lilamoreau. " - "Consider their expertise: owenjohnson (global dining trends), javiermorales (food critique), " - "aishapatel (emerging food trends), trangnguyen (cultural dining), keishareid (soul food heritage), " - "lilamoreau (global street food). Return only the username." - )}, - {"role": "user", "content": summary} - ], - max_tokens=20 - ) - author = response.choices[0].message.content.strip() - valid_authors = ["owenjohnson", "javiermorales", "aishapatel", "trangnguyen", "keishareid", "lilamoreau"] - logging.info(f"Selected author: {author}") - return author if author in valid_authors else "owenjohnson" + x_post_counts = load_json_file('/home/shane/foodie_automator/x_post_counts.json', expiration_hours=24*30) + monthly_counts = {entry['username']: entry['monthly_count'] for entry in x_post_counts} + + best_score = -1 + best_author = None + for author, persona in PERSONA_CONFIGS.items(): + prompt = persona["prompt"] + current_score = interest_score + if "trend" in prompt.lower(): + current_score += 2 + elif "recipe" in prompt.lower(): + current_score += 1 + + # Penalize authors with high post counts + post_count = monthly_counts.get(author, 0) + current_score -= post_count * 0.5 + + if current_score > best_score: + best_score = current_score + best_author = author + + if not best_author: + best_author = min(monthly_counts, key=monthly_counts.get, default=random.choice(list(PERSONA_CONFIGS.keys()))) + + logging.info(f"Selected author: {best_author} with adjusted score: {best_score}") + return best_author except Exception as e: - logging.error(f"Author selection failed: {e}") - return "owenjohnson" + logging.error(f"Error in select_best_author: {e}") + return random.choice(list(PERSONA_CONFIGS.keys())) def prepare_post_data(summary, title, main_topic=None): try: