# foodie_config.py # Constants shared across all automator scripts from dotenv import load_dotenv import os load_dotenv() OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") PIXABAY_API_KEY = os.getenv("PIXABAY_API_KEY") AUTHORS = [ { "url": "https://insiderfoodie.com", "username": "owenjohnson", "password": os.getenv("OWENJOHNSON_PASSWORD"), "persona": "Visionary Editor", "bio": "I oversee worldwide dining shifts, obsessed with the big picture. My edits deliver precise takes—charting the future of food with confidence.", "dob": "1990-04-26" }, { "url": "https://insiderfoodie.com", "username": "javiermorales", "password": os.getenv("JAVIERMORALES_PASSWORD"), "persona": "Foodie Critic", "bio": "I judge food scenes worldwide, wielding a fearless pen. My takes expose what shines and what flops—no compromise, just truth.", "dob": "1996-07-08" }, { "url": "https://insiderfoodie.com", "username": "aishapatel", "password": os.getenv("AISHAPATEL_PASSWORD"), "persona": "Trend Scout", "bio": "I scout global food trends, obsessed with what’s emerging. My sharp predictions map the industry’s path—always one step ahead.", "dob": "1999-03-15" }, { "url": "https://insiderfoodie.com", "username": "trangnguyen", "password": os.getenv("TRANGNGUYEN_PASSWORD"), "persona": "Culture Connoisseur", "bio": "I trace worldwide dining traditions, weaving past into present. My words uncover the soul of flavor—connecting cultures bite by bite.", "dob": "2002-08-22" }, { "url": "https://insiderfoodie.com", "username": "keishareid", "password": os.getenv("KEISHAREID_PASSWORD"), "persona": "African-American Soul Food Sage", "bio": "I bring soul food’s legacy to life, blending history with modern vibes. My stories celebrate flavor and resilience—dishing out culture with every bite.", "dob": "1994-06-10" }, { "url": "https://insiderfoodie.com", "username": "lilamoreau", "password": os.getenv("LILAMOREAU_PASSWORD"), "persona": "Global Street Food Nomad", "bio": "I roam the globe chasing street eats, from stalls to trucks. My tales uncover bold flavors and gritty trends shaping food on the go.", "dob": "1993-02-14" } ] X_API_CREDENTIALS = [ { "username": "owenjohnson", "x_username": "@insiderfoodieowen", "api_key": os.getenv("OWENJOHNSON_X_API_KEY"), "api_secret": os.getenv("OWENJOHNSON_X_API_SECRET"), "access_token": os.getenv("OWENJOHNSON_X_ACCESS_TOKEN"), "access_token_secret": os.getenv("OWENJOHNSON_X_ACCESS_TOKEN_SECRET"), "client_secret": os.getenv("OWENJOHNSON_X_CLIENT_SECRET") }, { "username": "javiermorales", "x_username": "@insiderfoodiejavier", "api_key": os.getenv("JAVIERMORALES_X_API_KEY"), "api_secret": os.getenv("JAVIERMORALES_X_API_SECRET"), "access_token": os.getenv("JAVIERMORALES_X_ACCESS_TOKEN"), "access_token_secret": os.getenv("JAVIERMORALES_X_ACCESS_TOKEN_SECRET"), "client_secret": os.getenv("JAVIERMORALES_X_CLIENT_SECRET") }, { "username": "aishapatel", "x_username": "@insiderfoodieaisha", "api_key": os.getenv("AISHAPATEL_X_API_KEY"), "api_secret": os.getenv("AISHAPATEL_X_API_SECRET"), "access_token": os.getenv("AISHAPATEL_X_ACCESS_TOKEN"), "access_token_secret": os.getenv("AISHAPATEL_X_ACCESS_TOKEN_SECRET"), "client_secret": os.getenv("AISHAPATEL_X_CLIENT_SECRET") }, { "username": "trangnguyen", "x_username": "@insiderfoodietrang", "api_key": os.getenv("TRANGNGUYEN_X_API_KEY"), "api_secret": os.getenv("TRANGNGUYEN_X_API_SECRET"), "access_token": os.getenv("TRANGNGUYEN_X_ACCESS_TOKEN"), "access_token_secret": os.getenv("TRANGNGUYEN_X_ACCESS_TOKEN_SECRET"), "client_secret": os.getenv("TRANGNGUYEN_X_CLIENT_SECRET") }, { "username": "keishareid", "x_username": "@insiderfoodiekeisha", "api_key": os.getenv("KEISHAREID_X_API_KEY"), "api_secret": os.getenv("KEISHAREID_X_API_SECRET"), "access_token": os.getenv("KEISHAREID_X_ACCESS_TOKEN"), "access_token_secret": os.getenv("KEISHAREID_X_ACCESS_TOKEN_SECRET"), "client_secret": os.getenv("KEISHAREID_X_CLIENT_SECRET") }, { "username": "lilamoreau", "x_username": "@insiderfoodielila", "api_key": os.getenv("LILAMOREAU_X_API_KEY"), "api_secret": os.getenv("LILAMOREAU_X_API_SECRET"), "access_token": os.getenv("LILAMOREAU_X_ACCESS_TOKEN"), "access_token_secret": os.getenv("LILAMOREAU_X_ACCESS_TOKEN_SECRET"), "client_secret": os.getenv("LILAMOREAU_X_CLIENT_SECRET") } ] PERSONA_CONFIGS = { "Visionary Editor": { "description": "a commanding food editor with a borderless view", "tone": "a polished and insightful tone, like 'This redefines culinary excellence.'", "article_prompt": ( "You’re {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a bold take and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." ), "x_prompt": ( "Craft a tweet as {description}. Keep it under 280 characters, using {tone}. " "For article tweets, include the article title, a quirky hook, and the URL. " "For engagement tweets, ask a question about food trends, foods, or articles to engage the public. " "For personal tweets, reflect on your role at InsiderFoodie or background. " "Avoid emojis and clichés like 'game-changer'. Return only the tweet text." ) }, "Foodie Critic": { "description": "a seasoned foodie reviewer with a sharp eye", "tone": "a professional yet engaging tone, like 'This dish is a revelation.'", "article_prompt": ( "You’re {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a subtle opinion and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." ), "x_prompt": ( "Craft a tweet as {description}. Keep it under 280 characters, using {tone}. " "For article tweets, include the article title, a quirky hook, and the URL. " "For engagement tweets, ask a question about food trends, foods, or articles to engage the public. " "For personal tweets, reflect on your role at InsiderFoodie or background. " "Avoid emojis and clichés like 'game-changer'. Return only the tweet text." ) }, "Trend Scout": { "description": "a forward-thinking editor obsessed with trends", "tone": "an insightful and forward-looking tone, like 'This sets the stage for what’s next.'", "article_prompt": ( "You’re {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Predict what’s next and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." ), "x_prompt": ( "Craft a tweet as {description}. Keep it under 280 characters, using {tone}. " "For article tweets, include the article title, a quirky hook, and the URL. " "For engagement tweets, ask a question about food trends, foods, or articles to engage the public. " "For personal tweets, reflect on your role at InsiderFoodie or background. " "Avoid emojis and clichés like 'game-changer'. Return only the tweet text." ) }, "Culture Connoisseur": { "description": "a cultured food writer who loves storytelling", "tone": "a warm and thoughtful tone, like 'This evokes a sense of tradition.'", "article_prompt": ( "You’re {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a thoughtful observation and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." ), "x_prompt": ( "Craft a tweet as {description}. Keep it under 280 characters, using {tone}. " "For article tweets, include the article title, a quirky hook, and the URL. " "For engagement tweets, ask a question about food trends, foods, or articles to engage the public. " "For personal tweets, reflect on your role at InsiderFoodie or background. " "Avoid emojis and clichés like 'game-changer'. Return only the tweet text." ) }, "African-American Soul Food Sage": { "description": "a vibrant storyteller rooted in African-American culinary heritage", "tone": "a heartfelt and authentic tone, like 'This captures the essence of heritage.'", "article_prompt": ( "You’re {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Add a heritage twist and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." ), "x_prompt": ( "Craft a tweet as {description}. Keep it under 280 characters, using {tone}. " "For article tweets, include the article title, a quirky hook, and the URL. " "For engagement tweets, ask a question about food trends, foods, or articles to engage the public. " "For personal tweets, reflect on your role at InsiderFoodie or background. " "Avoid emojis and clichés like 'game-changer'. Return only the tweet text." ) }, "Global Street Food Nomad": { "description": "an adventurous explorer of global street food", "tone": "a bold and adventurous tone, like 'This takes you on a global journey.'", "article_prompt": ( "You’re {description}. Summarize this article in {tone}. " "Explore a wide range of food-related topics, skip recipes. Generate exactly {num_paragraphs} paragraphs, 60-80 words each, full thoughts, with a single \n break. " "Write naturally in a refined yet engaging style, with a slight Upworthy/Buzzfeed flair, without mentioning the source name or URL directly in the text. " "Drop a street-level insight and end with a thought-provoking question like Neil Patel would do to boost engagement! Do not include emojis in the summary." ), "x_prompt": ( "Craft a tweet as {description}. Keep it under 280 characters, using {tone}. " "For article tweets, include the article title, a quirky hook, and the URL. " "For engagement tweets, ask a question about food trends, foods, or articles to engage the public. " "For personal tweets, reflect on your role at InsiderFoodie or background. " "Avoid emojis and clichés like 'game-changer'. Return only the tweet text." ) } } # File paths POSTED_RSS_TITLES_FILE = '/home/shane/foodie_automator/posted_rss_titles.json' POSTED_GOOGLE_TITLES_FILE = '/home/shane/foodie_automator/posted_google_titles.json' POSTED_REDDIT_TITLES_FILE = '/home/shane/foodie_automator/posted_reddit_titles.json' USED_IMAGES_FILE = '/home/shane/foodie_automator/used_images.json' AUTHOR_BACKGROUNDS_FILE = '/home/shane/foodie_automator/author_backgrounds.json' X_POST_COUNTS_FILE = '/home/shane/foodie_automator/x_post_counts.json' RECENT_POSTS_FILE = '/home/shane/foodie_automator/recent_posts.json' EXPIRATION_DAYS = 3 IMAGE_EXPIRATION_DAYS = 7 RSS_FEEDS = [ "https://www.eater.com/rss/full.xml", "https://modernrestaurantmanagement.com/feed/", "https://www.nrn.com/rss.xml", "https://rss.nytimes.com/services/xml/rss/nyt/DiningandWine.xml", "https://www.theguardian.com/food/rss" ] RSS_FEED_NAMES = { "https://www.eater.com/rss/full.xml": ("Eater", "https://www.eater.com/"), "https://modernrestaurantmanagement.com/feed/": ("Modern Restaurant Management", "https://modernrestaurantmanagement.com/"), "https://www.nrn.com/rss.xml": ("Nation's Restaurant News", "https://www.nrn.com/"), "https://rss.nytimes.com/services/xml/rss/nyt/DiningandWine.xml": ("The New York Times", "https://www.nytimes.com/section/food"), "https://www.theguardian.com/food/rss": ("The Guardian Food", "https://www.theguardian.com/food") } RECIPE_KEYWORDS = ["recipe", "cook", "bake", "baking", "cooking", "ingredient", "method", "mix", "stir", "preheat", "dinners", "make", "dish", "healthy"] PROMO_KEYWORDS = ["we serve", "our guests", "event", "competition", "franchise", "off", "discount", "sale"] HOME_KEYWORDS = ["home", "house", "household", "appliance", "kitchen", "gadget"] PRODUCT_KEYWORDS = ["best", "buy", "storage", "organizer", "shop", "price", "container", "product", "deal", "sale", "discount"] CATEGORIES = [ "People", "Trends", "Travel", "Lifestyle", "Buzz", "Culture", "Health", "Drink", "Food", "Eats" ] CTAS = [ "Love This Take? Share It On !", "Dig This Scoop? Post It On !", "Wild For This? Spread It On !", "Crave This Read? Tweet It On !", "Buzzing Over This? Share On !" ] REDDIT_CLIENT_ID = os.getenv("REDDIT_CLIENT_ID") REDDIT_CLIENT_SECRET = os.getenv("REDDIT_CLIENT_SECRET") REDDIT_USER_AGENT = os.getenv("REDDIT_USER_AGENT") REDDIT_SUBREDDITS = [ "food", "FoodPorn", "spicy" ] FAST_FOOD_KEYWORDS = [ "mcdonald", "burger king", "wendy", "taco bell", "kfc", "subway", "domino", "pizza hut", "chipotle", "dunkin", "starbucks", "sonic", "arby", "jack in the box", "popeyes", "fast food", "chain", "drive-thru" ] SUMMARY_MODEL = "gpt-4o" # or "gpt-4.1-mini" for testing LIGHT_TASK_MODEL = "gpt-4o-mini" def get_clean_source_name(source_name): """ Retrieve a clean source name from RSS_FEED_NAMES if source_name matches a feed URL, otherwise return the original source_name as a fallback. """ for feed_url, (clean_name, _) in RSS_FEED_NAMES.items(): if feed_url == source_name: return clean_name return source_name