def magic8ball(update: Update, context: CallbackContext) -> int: """Asks the user for the question.""" chat_id = update.effective_chat.id name = get_nick(update, context) initiate = ( "If you have a doubt, just type it here", f"{name}, are you confused? Ask me and I'll search for some sow...so..solutions" " okay?", "I can predict the future like you say . Just ask me. I'm just trying to find you option", "Fast fast no time ask me!", "See tell me what's the confusion", f"Yes {name}?") context.bot.send_chat_action(chat_id=chat_id, action='typing') sleep(1) # Sends message with a force reply context.bot.send_message( chat_id=chat_id, text=f"{r.choice(initiate)}🔮\nOr, type /cancel so I won't mind that\n" f"(Reply to this message for this to work!)", reply_markup=ForceReply(force_reply=True, selective=True), reply_to_message_id=update.message.message_id) logger(message=f"/8ball", command=True, update=update) del chat_id, name return PROCESSING # Will go into first (and only) state in convo handler in main.py
def bday_mod(update: Update, context: CallbackContext) -> int: # MODIFY """Asks user for input so we can update their birthday""" name = get_nick(update, context) context.bot.send_message(chat_id=update.effective_chat.id, text=f"{name}, I know your birthday yes? If it is" f" wrong you can come and tell me the correct" f" one okay?" f"\nEnter your DOB as: YYYY-MM-DD", reply_to_message_id=update.message.message_id, reply_markup=ForceReply(selective=True)) return INPUT
def bday_del(update: Update, context: CallbackContext) -> int: # MODIFY """Deletes birthday from our records. Then goes back to main menu.""" name = get_nick(update, context) context.bot.send_message(chat_id=update.effective_chat.id, text=f"Ok {name}, I forgot your birthday", reply_to_message_id=update.message.message_id, reply_markup=markup) logger(message=f"{update.effective_user.first_name} just deleted their birthday.") del context.user_data['birthday'] return CHOICE
def leave(update: Update, context: CallbackContext) -> int: """This is called when user clicks 'Nothing'. Exits from the /tell conversation.""" name = get_nick(update, context) context.bot.send_message( chat_id=update.effective_chat.id, text= f'Bye {name}, sit and solve the past papers like you say, I want to put a test okay?', reply_to_message_id=update.message.message_id, reply_markup=ReplyKeyboardRemove(selective=True)) del name return -1
def receive_answer(update: Update, context: CallbackContext) -> None: """ Saves quiz related user data. Runs everytime a user answers a quiz. This data is used later in generating the leaderboard. """ user = update.poll_answer.user chosen_answer = update.poll_answer.option_ids # Get quiz id and correct option id- for quiz in context.bot_data['sent_quizzes']: if quiz.poll.id == update.poll_answer.poll_id: correct_answer = quiz.poll.correct_option_id logger(message=f"tms quiz was answered by {user.first_name}") break else: # Only happens when /quizizz quiz was answered. logger(message=f"/quizizz was answered by {user.first_name}") return assert correct_answer is not None # Storing quiz related user data- if 'quizizz' not in context.bot_data: context.bot_data['quizizz'] = {} if user.id not in context.bot_data['quizizz']: # Note: `answers_wrong` below is only for one quiz. For the next quiz, they are reset. context.bot_data['quizizz'][user.id] = {'answers_right': 0, 'questions_answered': 0, 'answers_wrong': 0} # Update/add entries if changed- lad = context.bot_data['quizizz'][user.id] lad['name'] = get_nick(update, context) lad['profile_pic'] = f"profile_pics/{get_nick(update, context)}.jpg" lad['questions_answered'] += 1 if correct_answer != chosen_answer[0]: # If guy got it wrong lad['answers_wrong'] += 1 else: lad['answers_right'] += 1 context.dispatcher.persistence.flush()
def group(update: Update, context: CallbackContext) -> None: """ Checks for profanity in messages and responds to that. Also checks if the bot was mentioned in the chat, if it was, replies to that message. """ chat_id = update.effective_chat.id text = update.message.text if any(bad_word in text.lower().split() for bad_word in prohibited): query = f"SELECT PROFANE_PROB FROM CHAT_SETTINGS WHERE CHAT_ID={chat_id};" true = connection(query, update) logger( message= f"The query executed on the database was:\n{query}\nand the result was:\n{true=}" ) false = 1 - true if r.choices([0, 1], weights=[ false, true ])[0]: # Probabilities are 0.8 - False, 0.2 - True by default. name = get_nick(update, context) out = f"{r.choice(rebukes)} {name}" context.bot.send_message( chat_id=chat_id, text=out, reply_to_message_id=update.message.message_id) # Sends message logger( message= f"{update.effective_user.first_name} used profane language in {get_chat_name(update)}." f"\nThe rebuke by the bot was: '{out}'.") elif context.bot.name in text: # If username was mentioned in group chat, reply to it. shanifier(update, context, is_group=True, the_id=update.message.message_id) del chat_id, text
def bday_add_or_update(update: Update, context: CallbackContext) -> int: # INPUT """Changes or adds the user's birthday into our records.""" bday_date = update.message.text try: dt_obj = datetime.datetime.strptime(bday_date, "%Y-%m-%d") except Exception as e: # If user didn't enter birthday in the right format logger(message=f"The traceback is: {e}", warning=True) wrong(update, context) # Asks for a valid input else: name = get_nick(update, context) context.user_data['birthday'] = dt_obj context.bot.send_message(chat_id=update.effective_chat.id, text=f"Ok {name}, I'll remember your birthday like you say.", reply_markup=markup) logger(message=f"{update.effective_user.first_name} just changed their birthday to {bday_date}.") return CHOICE
def initiate(update: Update, context: CallbackContext) -> int: # Entry_point """This function is called when user uses /tell. It branches into 3- 'birthday', 'nickname' and 'nothing'.""" chat = update.effective_chat first_name = update.effective_user.first_name if chat.type != "private": link = create_deep_linked_url(bot_username=context.bot.username, payload="tell") tell_markup = InlineKeyboardMarkup( [[InlineKeyboardButton(text="Let's go like you say!", url=link)]]) context.bot.send_message( chat_id=chat.id, text="Just come to another chat I want to talk to you like you say", reply_markup=tell_markup) logger( message=f"{first_name} just tried using /tell in a {chat.type}. " f"A message telling them to use it in private was sent.") del chat, first_name, link, tell_markup return -1 name = get_nick(update, context) context.bot.send_message( chat_id=chat.id, text= f'What do you want to tell me {name}? Type /cancel anytime to switch me off', reply_to_message_id=update.message.message_id, reply_markup=markup) logger(message=f"/tell", update=update, command=True) del name return CHOICE
def thinking(update: Update, context: CallbackContext) -> int: """ First sends a message indicating his thinking process for 3 seconds, then on the 4th second he gives the answer by editing his message. """ name = get_nick(update, context) chat_id = update.effective_chat.id if update.message.reply_to_message.from_user.username != context.bot.name.replace( '@', ''): logger( message= f"{update.effective_user.first_name} used /8ball in {get_chat_name(update)}" f" and on {update.message.reply_to_message.from_user.first_name}'s message." ) actual_msg = update.message.reply_to_message.message_id # Gets the message id of the replied message. else: actual_msg = update.message.message_id thoughts = ( "See I'm spending time because your question normally comes mistake", "*scratching nose*", "Uhmmm", "Ok, there is one option", "*sniffs*", "What you say like") answers = ( "No no I'm sure not", "I don't want to tell you like you say", "I don't know like", f"No {name}, I'm so sowry", "Obviously like you say", r"Yes\. No other option like", "I didn't say wrong, I don't know", "See just do the worksheet no other importance of the situation", "This may be hard, but I think no okay?", "The laws of physics say yes 😄", f"Yes yes", "Maybe okay?", "Ah yea", "My feeling says no, now I feel very bad I told you like that", "That's not my policy I'm not answering", "See don't waste my time like you say with these easy questions okay, fine?", f"The universe says yes {name}", "That's going to be broken now", "Sorry no idea") thought = r.choice(thoughts) answer = r.choice(answers) seconds = list(range(1, 5)) msg_sent = context.bot.send_message( chat_id=chat_id, text=f"`{thought}`", # Will be monospaced parse_mode='MarkdownV2', reply_to_message_id=actual_msg) # Editing message rapidly- for second in seconds: if second < 4: dots = r'\.' * second # Edits message so the ... (thinking) effect is achieved, \ is an escape seq needed- text = rf"`{thought + dots}`" # for MarkdownV2 else: edit_add = rf'\.\.\.🔮' # When thinking is done and answer is ready text = f"_{answer + edit_add}_" # Answer will be in italic sleep( 1 ) # So all of this doesn't happen instantly and is visible to user context.bot.edit_message_text( chat_id=chat_id, message_id=msg_sent.message_id, text=f"{text}", parse_mode='MarkdownV2') # Edits message sent by bot accordingly del thought, answer, seconds, name, chat_id return -1 # End of conversation
def start(update: Update, context: CallbackContext) -> int: """ Called when user uses /settings. If it is the first time using it, it creates and uses default bot settings. Can only be used in groups where user is admin, or in private chats. """ global morn_setting, conn, c chat_id = update.effective_chat.id user_id = update.message.from_user.id try: admins = context.bot.get_chat_administrators( chat_id=chat_id) # Get group admins except BadRequest: # When it is a private chat pass else: for admin in admins: if user_id in ( samir, harshil ) or admin.user.id == user_id: # Check if admin/creators are calling /settings break else: responses = ("I'm not allowing you like you say", "Ask the permission then only", "This is not for you okay?", "Only few of them can do this not all okay?", "See not you so sowry") context.bot.send_message( chat_id=chat_id, text=r.choice(responses), reply_to_message_id=update.message.message_id) del responses return -1 # Stop convo since a regular user called /settings logger(message=f"/settings", command=True, update=update) conn = sqlite3.connect('./files/bot_settings.db') c = conn.cursor() name = get_nick(update, context) c.executescript(sql_table) # If table is not made conn.commit() c.execute( f"SELECT EXISTS(SELECT * FROM CHAT_SETTINGS WHERE chat_id = {chat_id});" ) # Returns 0 if doesn't exist result = c.fetchone() if not result[0]: c.execute( f"INSERT INTO CHAT_SETTINGS VALUES({chat_id},'{name}','❌',0.3,0.2);" ) # First time use conn.commit() c.execute( f"SELECT MORNING_MSGS FROM CHAT_SETTINGS WHERE chat_id = {chat_id};") result = c.fetchone() morn_setting = result[0] # Sends the current settings applied- if update.callback_query is None: context.bot.send_message(chat_id=chat_id, text=setting_msg(update), reply_markup=setting_markup, parse_mode="MarkdownV2") return UPDATED
def media(update: Update, context: CallbackContext) -> None: """Sends a reaction to media messages (pictures, videos, documents, voice notes)""" global last_reacted_at if cur_time() - last_reacted_at < 60: # If a reaction was sent less than a minute ago return # Don't send a reaction last_reacted_at = cur_time() chat_id = update.effective_chat.id msg_id = update.message.message_id name = get_nick(update, context) query = f"SELECT MEDIA_PROB FROM CHAT_SETTINGS WHERE CHAT_ID={chat_id};" true = connection(query, update) logger(message=f"The query executed on the database was:\n{query}\nand the result was:\n{true=}") false = 1 - true prob = r.choices([0, 1], weights=[false, true])[0] # Probabilities are 0.7 - False, 0.3 - True by default if not prob: return if hasattr(update.message.audio, 'performer'): if update.message.audio.performer == 'Shani Sir': # Don't send reaction to its own inline clips. return try: doc = update.message.document.file_name.split('.')[-1] except Exception as e: # When there is no document sent (most likely AttributeError) logger(message=f"File extension was not assigned. The warning is: \n{e}", warning=True) doc = '' img_reactions = ("😂", "🤣", "�", f"Not funny {name} okay?", "This is not fine like you say", "*giggles*", f"This is embarrassing to me {name}", "What your doing?! Go for the worksheet", "I don't like this now", "This is beneficial to me like", f"I don't understand this {name}", f"See {name}, I want you to delete this") vid_reactions = ("😂", "🤣", "�", f"I've never seen anything like this {name}", "What is this", f"Tell me the physics behind it {name}", "This is like you say boring", "Now I feel very bad like", f"Are you fine {name}?", f"See {name}, I want you to delete this") voice_reactions = ("What is this", f"I can't hear you {name}", f"Are you fine {name}?", "Now your on the track like", "Your voice is funny like you say", f"See I can't tolerate this {name}", "What your saying??", f"See {name}, I want you to delete this") app_reactions = ("Is this a virus", "I'm just suggesting like, don't open this", "We just don't mind that okay?") doc_reactions = (f"Did you read this {name}", "I'm not in agreement like", "I don't like this okay", "This is very good like you say", "Now your on the track like", "Nice for reading okay", "This is fake news delete this like", "This is like you say cut and paste from somewhere") context.bot.send_chat_action(chat_id=chat_id, action='typing') sleep(2) if update.message.photo or doc in ('jpg', 'jpeg', 'png'): context.bot.send_message(chat_id=chat_id, text=r.choice(img_reactions), reply_to_message_id=msg_id) logger(message=f"Bot sent a reaction to a photo to {name}.") elif update.message.voice or update.message.audio: context.bot.send_message(chat_id=chat_id, text=r.choice(voice_reactions), reply_to_message_id=msg_id) logger(message=f"Bot sent a reaction to a voice message/audio to {name}.") elif update.message.video or doc in ('mp4', 'gif'): context.bot.send_message(chat_id=chat_id, text=r.choice(vid_reactions), reply_to_message_id=msg_id) logger(message=f"Bot sent a reaction to a video to {name}.") elif doc in ('apk', 'exe'): context.bot.send_message(chat_id=chat_id, text=r.choice(app_reactions), reply_to_message_id=msg_id) logger(message=f"Bot sent a reaction to a executable to {name}.") elif doc in ('pdf', 'doc', 'docx', 'txt'): context.bot.send_message(chat_id=chat_id, text=r.choice(doc_reactions), reply_to_message_id=msg_id) logger(message=f"Bot sent a reaction to a text document to {name}.") else: logger(message=f"This shouldn't be happening, bot needs to respond to at least one of the media." f"The file extension was {doc=}.", warning=True) del chat_id, name, msg_id, query, true, false, prob, app_reactions, img_reactions, vid_reactions, voice_reactions, \ doc_reactions
def shanifier(update: Update, context: CallbackContext, is_group: bool = False, the_id: int = None) -> None: """ This function shanifies text using NLP (Natural Language Processing) and sends the resulting text to the respective chat. It also writes the input and output to a file. Only private chat responses are 'learned' by the bot for future use. Args: update (:obj:`Update`): Update object provided by Telegram. context (:obj:'CallbackContext`): CallbackContext passed in by Python Telegram Bot. is_group (:obj:`bool`, optional): Set to True, if received message is from a group. Default is `False`. the_id (:obj:`int`, int): The message_id of the message to reply to in a chat. """ user = update.message.from_user full_name = user.full_name bot_username = context.bot.name # Bot username with @ today = update.message.date org_text = update.message.text chat_id = update.effective_chat.id flag = 0 # To check if a modal is present in the sentence lydcount = 0 # Counts the number of times "like you do" has been added JJ_RBcount = 0 # Counts the number of times a phrase from JJ_RB has been added temp = 0 name = get_nick(update, context) add_update_records(update, context) context.bot.send_chat_action( chat_id=chat_id, action='typing') # Sends 'typing...' status for 5 sec if bot_username in org_text: # Sends response if bot is @'ed in group msg_text = re.sub( rf"(\s*){bot_username}(\s*)", ' ', org_text) # Remove mention from text so response is better the_id = update.message.message_id else: msg_text = org_text reply_to, bot_msg, user_msg = get_response(update, text=msg_text) if not is_group: shanisirbot.learn_response( user_msg, bot_response) # Learn response if it's a private chat chat_type = "(PRIVATE)" # for interactions.txt else: chat_type = f"(GROUP: {update.effective_chat.title})" nlp = spacy.load("en_core_web_sm") sentence = nlp(bot_msg) word_list = [word.text for word in sentence] # Get words used in the sentence # Begin shanifying text- if len(word_list) < 20: lydlim = 1 # to limit the number of times we add JJ_RBlim = 1 # lyd and JJ_RB else: lydlim = len(word_list) // 20 JJ_RBlim = len(word_list) // 20 for index, word in enumerate( sentence): # returns list of tuples which tells the POS if index - temp < 7: # Do not add lad things too close to each other continue if word.tag_ == 'MD' and not flag: # Modal word_list.insert(index + 1, "(if the laws of physics allow it)") flag = 1 if word.tag_ in ('JJ', 'JJR', 'JJS', 'RB', 'RBR', 'RBS' ) and JJ_RBcount < JJ_RBlim: # Adjective or Adverb word_list.insert(index + 1, r.choice(JJ_RB)) JJ_RBcount += 1 temp = index elif word.tag_ in ('VB', 'VBD', 'VBG', 'VBN', 'VBP', 'VBZ') and lydcount < lydlim: # Verb word_list.insert(index + 1, "like you do") lydcount += 1 temp = index if r.choice([0, 1]): if r.choice([0, 1]): word_list.append(r.choice(responses1 + responses2)) word_list.insert(0, name) elif r.choice([0, 1]): if '?' in bot_msg: # Insert name at beginning if it's a question word_list.insert(0, name.capitalize()) else: word_list.append(f"{name}.") if len(word_list) < 5 and r.choice([0, 1 ]): # Might run if input is too short word_list.append( r.choice(("*draws perfect circle*", " *scratches nose*"))) if re.search('when|time', ' '.join(word_list), flags=re.IGNORECASE): word_list.append('decide a date') for word in update.message.text: if word in emoji.UNICODE_EMOJI: # Checks if emoji is present in message word_list.append(r.choice(list( emoji.UNICODE_EMOJI))) # Adds a random emoji # Text processing and replacing- shanitext = re.sub(r" (?=[.!,:;?])", '', ' '.join( word_list)) # Remove spaces before .!,:;? - Lookahead assertion shanitext = re.sub( r"(\s*)*(\w?)'", r"\1\2'", shanitext) # Remove spaces before contractions (Let 's, ca n't, etc) shanitext = re.sub("(^|[.?!])\s*([a-zA-Z])", lambda p: p.group(0).upper(), shanitext) # Capitalize letter after .?! shanitext = re.sub( f"[.] ({name})", r", \1", shanitext) # Convert . into , if . is followed by name (usually @ end) shanitext = shanitext[0].upper() + shanitext[ 1:] # Make only first letter capital inp = f"UTC+0 {today} {chat_type} {reply_to} {full_name} ({user.username}) SAID: {msg_text}\n" out = shanitext context.bot.send_message( chat_id=chat_id, text=out, reply_to_message_id=the_id) # Sends message to respective chat logger( message= f"\nThe input by {full_name} to the bot in {get_chat_name(update)} was:\n{msg_text}" f"\n\n\nThe output by the bot was:\n{out}") with open("files/interactions.txt", "a") as f1: f1.write(emoji.demojize(inp)) f1.write(f"BOT REPLY: {emoji.demojize(out)}\n\n")