|
|
|
@ -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) |
|
|
|
|
|
|
|
|
|
|
|
|