Skip to main content

chainvault/
reply.rs

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    // Fetch mentions for the user
20    let _ = twitter_client
21        .get_user_mentions(&user_id)
22        .await
23        .map_err(|e| anyhow!("failed to get user mentions, {:?}", e))?;
24
25    // Prepare a vector to store new replies
26    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    // Iterate over the mentions and generate replies
34    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        // Generate a response using the chat client
44        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    // Return the newly generated replies
72    Ok(new_replies)
73}
74
75pub async fn generate_mentions_replies_from_db() -> Result<Vec<MentionReply>> {
76    // Prepare a vector to store new replies
77    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    // Iterate over the mentions and generate replies
85    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        // Generate a response using the chat client
119        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    // Return the newly generated replies
147    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    // Get the user ID for the given username
157    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}