add email alert for low rate limit X
This commit is contained in:
+21
-11
@@ -31,7 +31,7 @@ AUTHORS = [
|
|||||||
"username": "aishapatel",
|
"username": "aishapatel",
|
||||||
"password": os.getenv("AISHAPATEL_PASSWORD"),
|
"password": os.getenv("AISHAPATEL_PASSWORD"),
|
||||||
"persona": "Trend Scout",
|
"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.",
|
"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"
|
"dob": "1999-03-15"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@ AUTHORS = [
|
|||||||
"username": "keishareid",
|
"username": "keishareid",
|
||||||
"password": os.getenv("KEISHAREID_PASSWORD"),
|
"password": os.getenv("KEISHAREID_PASSWORD"),
|
||||||
"persona": "African-American Soul Food Sage",
|
"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.",
|
"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"
|
"dob": "1994-06-10"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -116,7 +116,7 @@ PERSONA_CONFIGS = {
|
|||||||
"description": "a commanding food editor with a borderless view",
|
"description": "a commanding food editor with a borderless view",
|
||||||
"tone": "a polished and insightful tone, like 'This redefines culinary excellence.'",
|
"tone": "a polished and insightful tone, like 'This redefines culinary excellence.'",
|
||||||
"article_prompt": (
|
"article_prompt": (
|
||||||
"You’re {description}. Summarize this article in {tone}. "
|
"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. "
|
"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. "
|
"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."
|
"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."
|
||||||
@@ -133,7 +133,7 @@ PERSONA_CONFIGS = {
|
|||||||
"description": "a seasoned foodie reviewer with a sharp eye",
|
"description": "a seasoned foodie reviewer with a sharp eye",
|
||||||
"tone": "a professional yet engaging tone, like 'This dish is a revelation.'",
|
"tone": "a professional yet engaging tone, like 'This dish is a revelation.'",
|
||||||
"article_prompt": (
|
"article_prompt": (
|
||||||
"You’re {description}. Summarize this article in {tone}. "
|
"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. "
|
"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. "
|
"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."
|
"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."
|
||||||
@@ -148,12 +148,12 @@ PERSONA_CONFIGS = {
|
|||||||
},
|
},
|
||||||
"Trend Scout": {
|
"Trend Scout": {
|
||||||
"description": "a forward-thinking editor obsessed with trends",
|
"description": "a forward-thinking editor obsessed with trends",
|
||||||
"tone": "an insightful and forward-looking tone, like 'This sets the stage for what’s next.'",
|
"tone": "an insightful and forward-looking tone, like 'This sets the stage for what's next.'",
|
||||||
"article_prompt": (
|
"article_prompt": (
|
||||||
"You’re {description}. Summarize this article in {tone}. "
|
"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. "
|
"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. "
|
"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."
|
"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": (
|
"x_prompt": (
|
||||||
"Craft a tweet as {description}. Keep it under 280 characters, using {tone}. "
|
"Craft a tweet as {description}. Keep it under 280 characters, using {tone}. "
|
||||||
@@ -167,7 +167,7 @@ PERSONA_CONFIGS = {
|
|||||||
"description": "a cultured food writer who loves storytelling",
|
"description": "a cultured food writer who loves storytelling",
|
||||||
"tone": "a warm and thoughtful tone, like 'This evokes a sense of tradition.'",
|
"tone": "a warm and thoughtful tone, like 'This evokes a sense of tradition.'",
|
||||||
"article_prompt": (
|
"article_prompt": (
|
||||||
"You’re {description}. Summarize this article in {tone}. "
|
"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. "
|
"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. "
|
"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."
|
"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."
|
||||||
@@ -184,7 +184,7 @@ PERSONA_CONFIGS = {
|
|||||||
"description": "a vibrant storyteller rooted in African-American culinary heritage",
|
"description": "a vibrant storyteller rooted in African-American culinary heritage",
|
||||||
"tone": "a heartfelt and authentic tone, like 'This captures the essence of heritage.'",
|
"tone": "a heartfelt and authentic tone, like 'This captures the essence of heritage.'",
|
||||||
"article_prompt": (
|
"article_prompt": (
|
||||||
"You’re {description}. Summarize this article in {tone}. "
|
"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. "
|
"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. "
|
"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."
|
"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."
|
||||||
@@ -201,7 +201,7 @@ PERSONA_CONFIGS = {
|
|||||||
"description": "an adventurous explorer of global street food",
|
"description": "an adventurous explorer of global street food",
|
||||||
"tone": "a bold and adventurous tone, like 'This takes you on a global journey.'",
|
"tone": "a bold and adventurous tone, like 'This takes you on a global journey.'",
|
||||||
"article_prompt": (
|
"article_prompt": (
|
||||||
"You’re {description}. Summarize this article in {tone}. "
|
"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. "
|
"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. "
|
"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."
|
"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."
|
||||||
@@ -282,4 +282,14 @@ def get_clean_source_name(source_name):
|
|||||||
for feed_url, (clean_name, _) in RSS_FEED_NAMES.items():
|
for feed_url, (clean_name, _) in RSS_FEED_NAMES.items():
|
||||||
if feed_url == source_name:
|
if feed_url == source_name:
|
||||||
return clean_name
|
return clean_name
|
||||||
return source_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
|
||||||
|
}
|
||||||
@@ -1435,6 +1435,46 @@ def get_next_author_round_robin():
|
|||||||
logger.warning("No authors available due to tweet rate limits.")
|
logger.warning("No authors available due to tweet rate limits.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def send_account_lock_alert(username, error_message):
|
||||||
|
"""Send email alert for account lockout."""
|
||||||
|
try:
|
||||||
|
import smtplib
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from foodie_config import EMAIL_CONFIG # Add this to your config file
|
||||||
|
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg['From'] = EMAIL_CONFIG['from_email']
|
||||||
|
msg['To'] = EMAIL_CONFIG['to_email']
|
||||||
|
msg['Subject'] = f"🚨 X Account Lock Alert: {username}"
|
||||||
|
|
||||||
|
body = f"""
|
||||||
|
X Account Lock Alert!
|
||||||
|
|
||||||
|
Username: {username}
|
||||||
|
Time: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}
|
||||||
|
Error: {error_message}
|
||||||
|
|
||||||
|
Action Required:
|
||||||
|
1. Visit https://twitter.com
|
||||||
|
2. Log in to {username}
|
||||||
|
3. Complete verification if prompted
|
||||||
|
4. Unlock the account
|
||||||
|
|
||||||
|
This is an automated alert from your foodie_automator system.
|
||||||
|
"""
|
||||||
|
|
||||||
|
msg.attach(MIMEText(body, 'plain'))
|
||||||
|
|
||||||
|
with smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server:
|
||||||
|
server.starttls()
|
||||||
|
server.login(EMAIL_CONFIG['smtp_username'], EMAIL_CONFIG['smtp_password'])
|
||||||
|
server.send_message(msg)
|
||||||
|
|
||||||
|
logger.info(f"Sent account lock alert email for {username}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to send account lock alert email: {e}")
|
||||||
|
|
||||||
def get_x_rate_limit_status(author):
|
def get_x_rate_limit_status(author):
|
||||||
"""
|
"""
|
||||||
Check the X API Free tier rate limit by posting a test tweet.
|
Check the X API Free tier rate limit by posting a test tweet.
|
||||||
@@ -1485,6 +1525,15 @@ def get_x_rate_limit_status(author):
|
|||||||
logger.error(f"User 24-hour limit headers missing for {username}: {headers}")
|
logger.error(f"User 24-hour limit headers missing for {username}: {headers}")
|
||||||
return None, None
|
return None, None
|
||||||
logger.info(f"Rate limit exceeded for {username}")
|
logger.info(f"Rate limit exceeded for {username}")
|
||||||
|
elif response.status_code == 403:
|
||||||
|
error_data = response.json()
|
||||||
|
error_message = error_data.get('detail', '')
|
||||||
|
if "account is temporarily locked" in error_message.lower():
|
||||||
|
logger.error(f"Account lock detected for {username}: {error_message}")
|
||||||
|
send_account_lock_alert(username, error_message)
|
||||||
|
else:
|
||||||
|
logger.error(f"Unexpected 403 response for {username}: {error_message}")
|
||||||
|
return None, None
|
||||||
else:
|
else:
|
||||||
logger.error(f"Unexpected response for {username}: {response.status_code} - {response.text}")
|
logger.error(f"Unexpected response for {username}: {response.status_code} - {response.text}")
|
||||||
return None, None
|
return None, None
|
||||||
|
|||||||
Reference in New Issue
Block a user