team6/roast
0
1import logging2import os3import re4import time5import traceback6from threading import Thread7from pathlib import Path8 9import openai10import pandas as pd11import requests12import tweepy13from huggingface_hub import upload_file14import gradio as gr15logger = logging.getLogger()16logging.basicConfig(level=logging.INFO)17logger.setLevel(logging.INFO)18 19bot_user_id = 161210681509699993620bot_user_name = "RoastOrToastGPT"21 22persistent_storage_repo_id = "team6/roast-history"23persistent_storage_file_name = "history.csv"24persistent_storage_file_url = (25 f"https://huggingface.co/datasets/{persistent_storage_repo_id}/resolve/main/{persistent_storage_file_name}"26)27 28# will be used to remove the @roastortoastgpt from the tweet text (case insensitive)29pattern_at_mention = re.compile(re.escape("@roastortoastgpt"), re.IGNORECASE)30 31print(persistent_storage_file_url)32 33openai_key = os.environ.get("openai_api_key")34consumer_key = os.environ.get("consumer_key")35consumer_secret_key = os.environ.get("consumer_secret_key")36access_token = os.environ.get("access_token")37access_token_secret = os.environ.get("access_token_secret")38bearer_token = os.environ.get("bearer_token")39hf_token = os.environ.get("hf_token")40 41client = tweepy.Client(42 bearer_token=bearer_token,43 consumer_key=consumer_key,44 consumer_secret=consumer_secret_key,45 access_token=access_token,46 access_token_secret=access_token_secret,47 wait_on_rate_limit=True,48)49 50 51def response(text):52 openai.api_key = openai_key53 response = openai.Completion.create(54 engine="text-davinci-002",55 prompt=text,56 temperature=0.9,57 max_tokens=60,58 top_p=1,59 frequency_penalty=0,60 presence_penalty=1.0,61 )62 63 return response.choices[0].text.strip()64 65 66def roast(text):67 return response(68 f"Humorously mock, humiliate and hurt the user's feelings with a well-timed joke, diss or comeback based on the info.\n\nInfo: {text}\n\nResponse:"69 )70 71 72def toast(text):73 return response(74 f"Give the user a genuine and unique compliment to make them feel good about themselves based on the info in a good style manner.\n\nInfo: {text}\n\nResponse:"75 )76 77 78def reply_to_mentions():79 df = pd.read_csv(persistent_storage_file_url)80 last_tweet_id = df.iloc[-1]["id"]81 82 # List of unique conversation ids that we've already responded to.83 # This is to prevent us from responding to the same conversation twice.84 all_convo_ids = df["conversation_id"].unique().tolist()85 86 # get the mentions. These are both direct mentions and replies to our tweets87 mentions = client.get_users_mentions(88 id=bot_user_id,89 expansions=["author_id", "in_reply_to_user_id", "referenced_tweets.id"],90 tweet_fields=["conversation_id"],91 since_id=last_tweet_id,92 )93 94 # if there are no new mentions, return95 if mentions.data is None:96 # log it97 logger.info("No new mentions found")98 return99 100 data_to_add = {"id": [], "conversation_id": []}101 # otherwise, iterate through the mentions and respond to them102 # we iterate through the mentions in reverse order so that we respond to the oldest mentions first103 for mention in reversed(mentions.data):104 105 if mention.author_id == bot_user_id:106 # don't respond to our own tweets107 logger.info(f"Skipping {mention.id} as it is from the bot")108 continue109 110 if mention.in_reply_to_user_id == bot_user_id:111 # don't respond to our own tweets112 logger.info(f"Skipping {mention.id} as the tweet to roast is from the bot")113 continue114 115 if not mention.referenced_tweets:116 logger.info(f"Skipping {mention.id} as it is not a reply")117 continue118 119 # if we've already responded to this conversation, skip it120 # also should catch the case where we've already responded to this tweet (though that shouldn't happen)121 if mention.conversation_id in all_convo_ids:122 logger.info(f"Skipping {mention.id} as we've already responded to this conversation")123 continue124 125 logger.info(f"Responding to {mention.id}, which said {mention.text}")126 127 tweet_to_roast_id = mention.referenced_tweets[0].id128 tweet_to_roast = client.get_tweet(tweet_to_roast_id)129 text_to_roast = tweet_to_roast.data.text130 131 mention_text = mention.text132 mention_text = pattern_at_mention.sub("", mention_text)133 logger.info(f"Mention Text: {mention_text}")134 135 if "roast" in mention_text.lower():136 logger.info(f"Roasting {mention.id}")137 text_out = roast(text_to_roast)138 elif "toast" in mention_text.lower():139 logger.info(f"Toasting {mention.id}")140 text_out = toast(text_to_roast)141 else:142 logger.info(f"Skipping {mention.id} as it is not a roast or toast")143 continue144 145 # Quote tweet the tweet to roast146 logger.info(f"Quote tweeting {tweet_to_roast_id} with response: {text_out}")147 quote_tweet_response = client.create_tweet(148 text=text_out,149 quote_tweet_id=tweet_to_roast_id,150 )151 print("QUOTE TWEET RESPONSE", quote_tweet_response.data)152 response_quote_tweet_id = quote_tweet_response.data.get("id")153 logger.info(f"Response Quote Tweet ID: {response_quote_tweet_id}")154 response_quote_tweet_url = f"https://twitter.com/{bot_user_name}/status/{response_quote_tweet_id}"155 logger.info(f"Response Quote Tweet URL: {response_quote_tweet_url}")156 157 # reply to the mention with the link to the response tweet158 logger.info(f"Responding to: {mention.id}")159 response_reply = client.create_tweet(160 text=f"Here's my response: {response_quote_tweet_url}",161 in_reply_to_tweet_id=mention.id,162 )163 response_reply_id = response_reply.data.get("id")164 logger.info(f"Response Reply ID: {response_reply_id}")165 166 # add the mention to the history167 data_to_add["id"].append(mention.id)168 data_to_add["conversation_id"].append(mention.conversation_id)169 170 # add a line break to the log171 logger.info("-" * 100)172 173 # update the history df and upload it to the persistent storage repo174 if len(data_to_add["id"]) == 0:175 logger.info("No new mentions to add to the history")176 return177 178 logger.info(f"Adding {len(data_to_add['id'])} new mentions to the history")179 180 df_to_add = pd.DataFrame(data_to_add)181 df = pd.concat([df, df_to_add], ignore_index=True)182 df.to_csv(persistent_storage_file_name, index=False)183 upload_file(184 repo_id=persistent_storage_repo_id,185 path_or_fileobj=persistent_storage_file_name,186 path_in_repo=persistent_storage_file_name,187 repo_type="dataset",188 token=hf_token,189 )190 191 192def main():193 logger.info("Starting up...")194 195 while True:196 try:197 # Dummy request to keep the Hugging Face Space awake198 # Not really working as far as I can tell199 # logger.info("Pinging Hugging Face Space...")200 # requests.get("https://team6-roast.hf.space/", timeout=5)201 logger.info("Replying to mentions...")202 reply_to_mentions()203 except Exception as e:204 logger.error(e)205 traceback.print_exc()206 207 logger.info("Sleeping for 30 seconds...")208 time.sleep(30)209 210with gr.Blocks() as demo:211 gr.Markdown(Path('README.md').read_text())212 213thread = Thread(target=main, daemon=True)214 215if __name__ == "__main__":216 thread.start()217 demo.launch()