Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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()
Example #6
0
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
Example #7
0
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
Example #8
0
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
Example #9
0
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
Example #10
0
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
Example #11
0
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
Example #12
0
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")