# 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") FLICKR_API_KEY = os.getenv("FLICKR_API_KEY") FLICKR_API_SECRET = os.getenv("FLICKR_API_SECRET") 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 = { "owenjohnson": { "x_username": "@mrowenjohnson", "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") }, "javiermorales": { "x_username": "@mrjaviermorales", "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") }, "aishapatel": { "x_username": "@missaishapatel", "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") }, "trangnguyen": { "x_username": "@mrtrangnguyen", "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") }, "keishareid": { "x_username": "@misskeishareid", "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") }, "lilamoreau": { "x_username": "@misslilamoreau", "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://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://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", "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 = [ "Buzz", "Trends", "Lifestyle", "Culture", "Health", "Drink", "Food", "Eats" ] 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", "KoreanFood", "JapaneseFood", "DessertPorn", "ChineseFood", "IndianFood" ] 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 # Email configuration for alerts EMAIL_CONFIG = { 'from_email': 'hi@insiderfoodie.com', # System alerts email 'to_email': 'hi@insiderfoodie.com', # Same email for receiving alerts 'smtp_server': 'mail.insiderfoodie.com', # Your SMTP server 'smtp_port': 587, # STARTTLS port 'smtp_username': 'hi', # SMTP username 'smtp_password': os.getenv('INSIDERFOODIE_EMAIL_PASSWORD') # Store password in .env }