test
This commit is contained in:
+40
-15
@@ -7,6 +7,7 @@ from openai import OpenAI
|
|||||||
from foodie_utils import post_tweet, AUTHORS, SUMMARY_MODEL
|
from foodie_utils import post_tweet, AUTHORS, SUMMARY_MODEL
|
||||||
from foodie_config import X_API_CREDENTIALS
|
from foodie_config import X_API_CREDENTIALS
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
import tweepy
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -15,7 +16,6 @@ LOG_FILE = "/home/shane/foodie_automator/foodie_weekly_thread.log"
|
|||||||
LOG_PRUNE_DAYS = 30
|
LOG_PRUNE_DAYS = 30
|
||||||
|
|
||||||
def setup_logging():
|
def setup_logging():
|
||||||
# Prune old logs
|
|
||||||
if os.path.exists(LOG_FILE):
|
if os.path.exists(LOG_FILE):
|
||||||
with open(LOG_FILE, 'r') as f:
|
with open(LOG_FILE, 'r') as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
@@ -31,10 +31,9 @@ def setup_logging():
|
|||||||
with open(LOG_FILE, 'w') as f:
|
with open(LOG_FILE, 'w') as f:
|
||||||
f.writelines(pruned_lines)
|
f.writelines(pruned_lines)
|
||||||
|
|
||||||
# Set up logging to file and console
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
filename=LOG_FILE,
|
filename=LOG_FILE,
|
||||||
level=logging.DEBUG, # Set to DEBUG for detailed output
|
level=logging.DEBUG,
|
||||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||||
datefmt='%Y-%m-%d %H:%M:%S'
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
)
|
)
|
||||||
@@ -51,19 +50,49 @@ if not os.getenv("OPENAI_API_KEY"):
|
|||||||
logging.error("OPENAI_API_KEY is not set in environment variables")
|
logging.error("OPENAI_API_KEY is not set in environment variables")
|
||||||
raise ValueError("OPENAI_API_KEY is required")
|
raise ValueError("OPENAI_API_KEY is required")
|
||||||
|
|
||||||
# Validate X_API_CREDENTIALS
|
# Validate X_API_CREDENTIALS and test API access
|
||||||
if not X_API_CREDENTIALS:
|
def validate_twitter_credentials():
|
||||||
logging.error("X_API_CREDENTIALS is empty in foodie_config.py")
|
logging.info("Validating Twitter API credentials for all authors")
|
||||||
raise ValueError("X_API_CREDENTIALS is required")
|
valid_credentials = []
|
||||||
|
for author in AUTHORS:
|
||||||
|
credentials = next((cred for cred in X_API_CREDENTIALS if cred["username"] == author["username"]), None)
|
||||||
|
if not credentials:
|
||||||
|
logging.error(f"No X credentials found for {author['username']} in X_API_CREDENTIALS")
|
||||||
|
print(f"No X credentials found for {author['username']}")
|
||||||
|
continue
|
||||||
|
logging.debug(f"Testing credentials for {author['username']} (handle: {credentials['x_username']})")
|
||||||
|
try:
|
||||||
|
client = tweepy.Client(
|
||||||
|
consumer_key=credentials["api_key"],
|
||||||
|
consumer_secret=credentials["api_secret"],
|
||||||
|
access_token=credentials["access_token"],
|
||||||
|
access_token_secret=credentials["access_token_secret"]
|
||||||
|
)
|
||||||
|
# Test API access by fetching the user's profile
|
||||||
|
user = client.get_me()
|
||||||
|
logging.info(f"Credentials valid for {author['username']} (handle: {credentials['x_username']}, user_id: {user.data.id})")
|
||||||
|
print(f"Credentials valid for {author['username']} (handle: {credentials['x_username']})")
|
||||||
|
valid_credentials.append(credentials)
|
||||||
|
except tweepy.TweepyException as e:
|
||||||
|
logging.error(f"Failed to validate credentials for {author['username']} (handle: {credentials['x_username']}): {e}")
|
||||||
|
if hasattr(e, 'response') and e.response:
|
||||||
|
logging.error(f"Twitter API response: {e.response.text}")
|
||||||
|
print(f"Failed to validate credentials for {author['username']}: {e}")
|
||||||
|
if not valid_credentials:
|
||||||
|
logging.error("No valid Twitter credentials found for any author")
|
||||||
|
raise ValueError("No valid Twitter credentials found")
|
||||||
|
return valid_credentials
|
||||||
|
|
||||||
|
# Run credential validation
|
||||||
|
validate_twitter_credentials()
|
||||||
|
|
||||||
RECENT_POSTS_FILE = "/home/shane/foodie_automator/recent_posts.json"
|
RECENT_POSTS_FILE = "/home/shane/foodie_automator/recent_posts.json"
|
||||||
|
|
||||||
def load_recent_posts():
|
def load_recent_posts():
|
||||||
posts = []
|
posts = []
|
||||||
unique_posts = {} # To track unique posts by title, URL, and author
|
unique_posts = {}
|
||||||
logging.debug(f"Attempting to load posts from {RECENT_POSTS_FILE}")
|
logging.debug(f"Attempting to load posts from {RECENT_POSTS_FILE}")
|
||||||
|
|
||||||
# Check if file exists and is readable
|
|
||||||
if not os.path.exists(RECENT_POSTS_FILE):
|
if not os.path.exists(RECENT_POSTS_FILE):
|
||||||
logging.error(f"Recent posts file {RECENT_POSTS_FILE} does not exist")
|
logging.error(f"Recent posts file {RECENT_POSTS_FILE} does not exist")
|
||||||
return posts
|
return posts
|
||||||
@@ -82,18 +111,15 @@ def load_recent_posts():
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
entry = json.loads(line.strip())
|
entry = json.loads(line.strip())
|
||||||
# Validate required fields
|
|
||||||
required_fields = ["title", "url", "author_username", "timestamp"]
|
required_fields = ["title", "url", "author_username", "timestamp"]
|
||||||
if not all(key in entry for key in required_fields):
|
if not all(key in entry for key in required_fields):
|
||||||
logging.warning(f"Skipping invalid entry at line {i}: missing fields {entry}")
|
logging.warning(f"Skipping invalid entry at line {i}: missing fields {entry}")
|
||||||
continue
|
continue
|
||||||
# Validate timestamp format
|
|
||||||
try:
|
try:
|
||||||
datetime.fromisoformat(entry["timestamp"])
|
datetime.fromisoformat(entry["timestamp"])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logging.warning(f"Skipping entry at line {i}: invalid timestamp {entry['timestamp']}")
|
logging.warning(f"Skipping entry at line {i}: invalid timestamp {entry['timestamp']}")
|
||||||
continue
|
continue
|
||||||
# Deduplicate based on title, URL, and author
|
|
||||||
key = (entry["title"], entry["url"], entry["author_username"])
|
key = (entry["title"], entry["url"], entry["author_username"])
|
||||||
if key in unique_posts:
|
if key in unique_posts:
|
||||||
logging.debug(f"Skipping duplicate entry at line {i}: {entry['title']}")
|
logging.debug(f"Skipping duplicate entry at line {i}: {entry['title']}")
|
||||||
@@ -173,8 +199,7 @@ def post_weekly_thread():
|
|||||||
print("Entering post_weekly_thread")
|
print("Entering post_weekly_thread")
|
||||||
|
|
||||||
today = datetime.now(timezone.utc)
|
today = datetime.now(timezone.utc)
|
||||||
# Fix week calculation to target the previous week (Monday to Sunday)
|
days_to_monday = today.weekday()
|
||||||
days_to_monday = today.weekday() # 0 for Monday, 1 for Tuesday, etc.
|
|
||||||
start_date = (today - timedelta(days=days_to_monday + 7)).replace(hour=0, minute=0, second=0, microsecond=0)
|
start_date = (today - timedelta(days=days_to_monday + 7)).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
end_date = start_date + timedelta(days=6, hours=23, minutes=59, seconds=59)
|
end_date = start_date + timedelta(days=6, hours=23, minutes=59, seconds=59)
|
||||||
|
|
||||||
@@ -231,7 +256,7 @@ def post_weekly_thread():
|
|||||||
|
|
||||||
intro_response = post_tweet(author, intro_tweet)
|
intro_response = post_tweet(author, intro_tweet)
|
||||||
if not intro_response:
|
if not intro_response:
|
||||||
logging.error(f"Failed to post intro tweet for {author['username']}")
|
logging.error(f"Failed to post intro tweet for {author['username']}, skipping thread")
|
||||||
print(f"Failed to post intro tweet for {author['username']}")
|
print(f"Failed to post intro tweet for {author['username']}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user