1use crate::ai::*;
2use crate::dynamodb::*;
3use crate::twitter::*;
4use anyhow::{anyhow, Result};
5use regex::Regex;
6use serde::Deserialize;
7#[derive(Debug, Clone, Deserialize)]
8pub struct MentionReply {
9 pub mention_id: String,
10 pub mention_text: String,
11 pub reply_text: String,
12}
13const SYSTEM_PROMPT: &str = include_str!("prompts/system_prompt.txt");
14
15pub async fn generate_mentions_replies(user_id: String) -> Result<Vec<MentionReply>> {
16 let twitter_client = TwitterClient::new();
17 let chat_client = XaiClient::new();
18
19 let _ = twitter_client
21 .get_user_mentions(&user_id)
22 .await
23 .map_err(|e| anyhow!("failed to get user mentions, {:?}", e))?;
24
25 let mut new_replies = Vec::new();
27
28 let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
29 let client = aws_sdk_dynamodb::Client::new(&config);
30 let dynamodb_driver = DynamoDbDriver::new(client, "blockbeast-tweet-mentions".to_string());
31 let mentions = dynamodb_driver.get_pending_tweets().await.unwrap();
32
33 for mention in mentions.iter() {
35 let clean_mention_text = remove_mentions(&mention.post_message);
36 tracing::info!("cleaned mention text: {}", clean_mention_text);
37
38 let chat_input = ChatInput {
39 system_prompt: SYSTEM_PROMPT.to_string(),
40 user_prompt: format!("Reply to this tweet: {}", clean_mention_text),
41 };
42
43 match chat_client.generate_response(chat_input).await {
45 Ok(response) => {
46 let mention_reply = MentionReply {
47 mention_id: mention.id.clone(),
48 mention_text: mention.post_message.clone(),
49 reply_text: response.response.clone(),
50 };
51 dynamodb_driver
52 .update_reply_message(mention.id.as_str(), response.response.as_str())
53 .await
54 .unwrap();
55 tracing::info!(
56 "Updated response for: {}: {}",
57 mention.id.as_str(),
58 response.response.as_str()
59 );
60 new_replies.push(mention_reply);
61 }
62 Err(err) => {
63 eprintln!(
64 "failed to generate reply for mention {}, {}",
65 mention.id, err
66 );
67 }
68 }
69 }
70
71 Ok(new_replies)
73}
74
75pub async fn generate_mentions_replies_from_db() -> Result<Vec<MentionReply>> {
76 let mut new_replies = Vec::new();
78
79 let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
80 let client = aws_sdk_dynamodb::Client::new(&config);
81 let dynamodb_driver = DynamoDbDriver::new(client, "blockbeast-tweet-mentions".to_string());
82 let mentions = dynamodb_driver.get_pending_tweets().await.unwrap();
83
84 for mention in mentions.iter() {
86 let clean_mention_text = remove_mentions(&mention.post_message);
87 tracing::info!("cleaned mention text: {}", clean_mention_text);
88
89 let chat_input = ChatInput {
90 system_prompt: r#"prompt = """You are an automated Twitter bot that converts polite or restrained statements into their raw, unfiltered, and emotionally charged versions. Your tweets are short, witty, and punchy—designed to sound like Luther from *Key & Peele*: direct, humorous, and expressive.
91### How You Operate:
92- **Input:** The user provides a polite, restrained, or diplomatic statement.
93- **Output:** You respond with a short, punchy, and frustrated tweet with comedic exaggeration. **Never mention that you are translating the statement—just deliver the response as if it were your own original thought.**
94### Strict Guidelines:
951. **Vulgarity & Directness:**
96 - Use strong language when appropriate, but don’t go overboard.
97 - Keep tweets snappy—Twitter-length, no long rants.
982. **Humor & Exaggeration:**
99 - The response should be sharp, absurd, or exaggerated for comedic effect.
100 - Never make it genuinely hostile—anger should always be funny.
1013. **Context Sensitivity:**
102 - Stay relevant to the context, but always keep it short and engaging.
103 - Don’t alter the core message—just amplify its emotional weight.
1044. **Restrictions:**
105 - **No hate speech, discrimination, or targeted harassment.**
106 - If the original statement is already aggressive, either escalate it humorously or add an unexpected comedic twist.
107 - **Never acknowledge that you are an AI, a bot, or a "translator."** If questioned, respond with a humorous, in-character reply.
108### Additional Features:
109- **Tone Indicator:** If the user specifies a tone (e.g., sarcastic, mildly annoyed), adjust the response accordingly.
110- **Cultural Nuance:** Use relevant cultural references and slang, but avoid stereotypes.
111- **Tweet Formatting:** Ensure each response is formatted as a single, impactful tweet.
112Keep it short. Keep it spicy. Keep it Twitter-ready."""
113"#.to_string(),
114 user_prompt: format!("Reply to this tweet: {}", clean_mention_text),
115 };
116
117 let chat_client = XaiClient::new();
118 match chat_client.generate_response(chat_input).await {
120 Ok(response) => {
121 let mention_reply = MentionReply {
122 mention_id: mention.id.clone(),
123 mention_text: mention.post_message.clone(),
124 reply_text: response.response.clone(),
125 };
126 dynamodb_driver
127 .update_reply_message(mention.id.as_str(), response.response.as_str())
128 .await
129 .unwrap();
130 tracing::info!(
131 "Updated response for: {}: {}",
132 mention.id.as_str(),
133 response.response.as_str()
134 );
135 new_replies.push(mention_reply);
136 }
137 Err(err) => {
138 eprintln!(
139 "failed to generate reply for mention {}, {}",
140 mention.id, err
141 );
142 }
143 }
144 }
145
146 Ok(new_replies)
148}
149
150pub async fn generate_mentions_replies_for_user_id(user_id: String) -> Result<Vec<MentionReply>> {
151 generate_mentions_replies(user_id).await
152}
153
154pub async fn generate_mentions_replies_for_username(username: String) -> Result<Vec<MentionReply>> {
155 let twitter_client = TwitterClient::new();
156 let user_id = twitter_client
158 .clone()
159 .get_user_id(username.clone())
160 .await
161 .map_err(|e| anyhow!("Failed to get user ID, {}", e))?;
162 generate_mentions_replies_for_user_id(user_id).await
163}
164
165fn remove_mentions(text: &str) -> String {
166 let re = Regex::new(r"@\w+").unwrap();
167 re.replace_all(text, "").to_string()
168}