update consistency
This commit is contained in:
@@ -6,6 +6,8 @@ import signal
|
|||||||
import sys
|
import sys
|
||||||
import fcntl
|
import fcntl
|
||||||
import os
|
import os
|
||||||
|
from foodie_config import ENGAGEMENT_REFERENCE_DATE_FILE
|
||||||
|
REFERENCE_DATE_FILE = ENGAGEMENT_REFERENCE_DATE_FILE
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from foodie_utils import post_tweet, AUTHORS, SUMMARY_MODEL, load_post_counts, save_post_counts
|
from foodie_utils import post_tweet, AUTHORS, SUMMARY_MODEL, load_post_counts, save_post_counts
|
||||||
|
|||||||
@@ -197,17 +197,18 @@ def filter_posts_for_week(posts, start_date, end_date):
|
|||||||
return filtered_posts
|
return filtered_posts
|
||||||
|
|
||||||
def generate_intro_tweet(author):
|
def generate_intro_tweet(author):
|
||||||
"""Generate an intro tweet for the weekly thread."""
|
|
||||||
credentials = next((cred for cred in X_API_CREDENTIALS if cred["username"] == author["username"]), None)
|
credentials = next((cred for cred in X_API_CREDENTIALS if cred["username"] == author["username"]), None)
|
||||||
if not credentials:
|
if not credentials:
|
||||||
logging.error(f"No X credentials found for {author['username']}")
|
logging.error(f"No X credentials found for {author['username']}")
|
||||||
return None
|
return None
|
||||||
author_handle = credentials["x_username"]
|
author_handle = credentials["x_username"]
|
||||||
logging.debug(f"Generating intro tweet for {author_handle}")
|
persona = author["persona"] # Add persona
|
||||||
|
persona_config = PERSONA_CONFIGS[persona]
|
||||||
|
logging.debug(f"Generating intro tweet for {author_handle} as {persona}")
|
||||||
|
|
||||||
prompt = (
|
prompt = (
|
||||||
f"Generate a concise tweet (under 280 characters) for {author_handle}. "
|
f"Generate a concise tweet (under 280 characters) for {author_handle} as {persona_config['description']}. "
|
||||||
f"Introduce a thread of their top 10 foodie posts of the week on InsiderFoodie.com. "
|
f"Introduce a thread of their top 10 foodie posts of the week on InsiderFoodie.com in {persona_config['tone']}. "
|
||||||
f"Make it engaging, create curiosity, and include a call to action to visit InsiderFoodie.com, follow {author_handle}, or like the thread. "
|
f"Make it engaging, create curiosity, and include a call to action to visit InsiderFoodie.com, follow {author_handle}, or like the thread. "
|
||||||
f"Avoid using the word 'elevate'—use more humanized language like 'level up' or 'bring to life'. "
|
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"Do not include emojis, hashtags, or reward-driven incentives (e.g., giveaways)."
|
||||||
|
|||||||
+42
-20
@@ -6,6 +6,7 @@ import time
|
|||||||
import sys
|
import sys
|
||||||
import signal
|
import signal
|
||||||
import os
|
import os
|
||||||
|
from foodie_utils import load_post_counts, save_post_counts # Add imports
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from foodie_config import OPENAI_API_KEY, AUTHORS, LIGHT_TASK_MODEL, PERSONA_CONFIGS, AUTHOR_BACKGROUNDS_FILE
|
from foodie_config import OPENAI_API_KEY, AUTHORS, LIGHT_TASK_MODEL, PERSONA_CONFIGS, AUTHOR_BACKGROUNDS_FILE
|
||||||
@@ -16,6 +17,8 @@ load_dotenv()
|
|||||||
|
|
||||||
LOG_FILE = "/home/shane/foodie_automator/foodie_x_poster.log"
|
LOG_FILE = "/home/shane/foodie_automator/foodie_x_poster.log"
|
||||||
LOG_PRUNE_DAYS = 30
|
LOG_PRUNE_DAYS = 30
|
||||||
|
MAX_RETRIES = 3
|
||||||
|
RETRY_BACKOFF = 2
|
||||||
|
|
||||||
def setup_logging():
|
def setup_logging():
|
||||||
if os.path.exists(LOG_FILE):
|
if os.path.exists(LOG_FILE):
|
||||||
@@ -76,35 +79,54 @@ def generate_engagement_tweet(author, persona):
|
|||||||
"For engagement tweets, ask a question about food trends, foods, or articles to engage the public.",
|
"For engagement tweets, ask a question about food trends, foods, or articles to engage the public.",
|
||||||
f"Generate an engagement tweet asking a question about {theme} to engage the public."
|
f"Generate an engagement tweet asking a question about {theme} to engage the public."
|
||||||
)
|
)
|
||||||
try:
|
for attempt in range(MAX_RETRIES):
|
||||||
response = client.chat.completions.create(
|
try:
|
||||||
model=LIGHT_TASK_MODEL,
|
response = client.chat.completions.create(
|
||||||
messages=[
|
model=LIGHT_TASK_MODEL,
|
||||||
{"role": "system", "content": prompt},
|
messages=[
|
||||||
{"role": "user", "content": f"Generate engagement tweet for {author['username']} about {theme}."}
|
{"role": "system", "content": prompt},
|
||||||
],
|
{"role": "user", "content": f"Generate engagement tweet for {author['username']} about {theme}."}
|
||||||
max_tokens=100,
|
],
|
||||||
temperature=0.9
|
max_tokens=100,
|
||||||
)
|
temperature=0.9
|
||||||
tweet = response.choices[0].message.content.strip()
|
)
|
||||||
if len(tweet) > 280:
|
tweet = response.choices[0].message.content.strip()
|
||||||
tweet = tweet[:277] + "..."
|
if len(tweet) > 280:
|
||||||
logging.info(f"Generated engagement tweet for {author['username']}: {tweet}")
|
tweet = tweet[:277] + "..."
|
||||||
return tweet
|
logging.info(f"Generated engagement tweet for {author['username']}: {tweet}")
|
||||||
except Exception as e:
|
return tweet
|
||||||
logging.error(f"Failed to generate engagement tweet for {author['username']}: {e}")
|
except Exception as e:
|
||||||
return f"What’s your take on {theme}? Let’s talk!"
|
logging.warning(f"Failed to generate engagement tweet for {author['username']} (attempt {attempt + 1}): {e}")
|
||||||
|
if attempt < MAX_RETRIES - 1:
|
||||||
|
time.sleep(RETRY_BACKOFF * (2 ** attempt))
|
||||||
|
else:
|
||||||
|
logging.error(f"Failed to generate engagement tweet after {MAX_RETRIES} attempts")
|
||||||
|
return f"What’s your take on {theme}? Let’s talk!"
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global is_posting
|
global is_posting
|
||||||
logging.info("***** X Poster Launched *****")
|
logging.info("***** X Poster Launched *****")
|
||||||
|
post_counts = load_post_counts() # Load counts
|
||||||
for author in AUTHORS:
|
for author in AUTHORS:
|
||||||
|
# Check limits
|
||||||
|
author_count = next((entry for entry in post_counts if entry["username"] == author["username"]), None)
|
||||||
|
if not author_count:
|
||||||
|
logging.error(f"No post count entry for {author['username']}, skipping")
|
||||||
|
continue
|
||||||
|
if author_count["monthly_count"] >= 500:
|
||||||
|
logging.warning(f"Monthly post limit (500) reached for {author['username']}, skipping")
|
||||||
|
continue
|
||||||
|
if author_count["daily_count"] >= 20:
|
||||||
|
logging.warning(f"Daily post limit (20) reached for {author['username']}, skipping")
|
||||||
|
continue
|
||||||
is_posting = True
|
is_posting = True
|
||||||
tweet = generate_engagement_tweet(author, author["persona"])
|
tweet = generate_engagement_tweet(author, author["persona"])
|
||||||
post_tweet(author, tweet)
|
if post_tweet(author, tweet):
|
||||||
|
author_count["monthly_count"] += 1 # Update counts
|
||||||
|
author_count["daily_count"] += 1
|
||||||
|
save_post_counts(post_counts)
|
||||||
is_posting = False
|
is_posting = False
|
||||||
time.sleep(random.uniform(3600, 7200))
|
time.sleep(random.uniform(3600, 7200))
|
||||||
|
|
||||||
logging.info("X posting completed")
|
logging.info("X posting completed")
|
||||||
return random.randint(600, 1800)
|
return random.randint(600, 1800)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user