Make A Telegram Bot Using Python

Make A Telegram Bot Using Python

Introduction to Bot

Hello guys. In this tutorial, we will learn how to make a Telegram Bot Using Python. It will remind the user of a certain event on a specified day and time.

We will be using Python and the module python-telegram-bot.

So let’s get started!

Features of Bot

What can this Telegram Bot do?

  • Remind a user of a specific event on a specific date and time
  • Make a conversation with a user to add reminders
  • Save a user reminders history
  • Let a user delete a reminder from his history

Let’s Get Started!

1- Install the required modules

As we said, we will be using the python-telegram-bot module to run our bot. To install it, we will be using pip. Just run the following command in your terminal/cmd

pip install python-telegram-bot

Now the module should start installing.

2- Create a Bot on Telegram and get its API Token

We obviously need a Bot on Telegram in order to continue our project. To do so, go to BotFather on Telegram and he will assist you in creating your bot. When finished, in the final step you’ll get a Token. Save it somewhere safe and private, we’ll be using it soon. Do not share it with anyone! If leaked, it can be used to control your Bot.

3- Setting up the main functions

Now let’s get into the coding part. Create a new Python file and insert in it the following.

import json
from datetime import datetime, timedelta

from telegram import (
    ReplyKeyboardMarkup,
    ReplyKeyboardRemove,
    InlineKeyboardMarkup,
    InlineKeyboardButton,
)
from telegram.ext import (
    Updater,
    Filters,
    CommandHandler,
    MessageHandler,
    ConversationHandler,
)

def main():
    BOT_TOKEN = "YOUR TOKEN HERE"
    updater = Updater(BOT_TOKEN, use_context=True)
    dp = updater.dispatcher

    # leave here empty, we will add some code later

    updater.start_polling()
    updater.idle()


if __name__ == "__main__":
    print("Bot is running...")
    main()

Here we are importing all the modules that we are going to need. Then, we are defining a ‘main’ function that will handle everything: running the Telegram Bot Using Python, handling messages sent to the Telegram bot, etc…

Now, remember the Token you saved in step 2? Just insert it where it says “YOUR_TOKEN_HERE”.

4- Create our Main Menu and Variables

We need a menu to navigate the users of the bot, and some variables to handle conversations! To do so, add the following to your code, above the main function.

main_keyboard = [
    ["βž• Add Reminder", "βž– Delete History"],
    ["πŸ“ƒ All Reminders", "🌐 Change UTC"],
    ["πŸ’° Donate"],
]

REMINDER_TITLE, REMINDER_DATE, REMINDER_TIME, REMINDER_INFO = range(4)
DELETE_REMINDER_INDEX = range(1)
ADD_UTC = range(1)

5- Create functions to save the data

This is a Reminder Bot, so we need to store the data given to us! For simplicity’s sake, we are going to store them in a JSON file. Create a data.json file and insert in it the following code.

{
    "users": {

    }
}

Now that you have created this file, let’s go back to our python file. To handle and write the data to our data.json file, we need more functions! Let’s add them.

def is_new_user(user, username, first_name, last_name):
    user = str(user)
    with open("data.json", "r+") as file:
        content = json.load(file)
        if user not in content["users"]:
            content["users"][user] = {
                "username": username,
                "first name": first_name,
                "last name": last_name,
                "utc": "",
                "reminders": [],
            }
            file.seek(0)
            json.dump(content, file)
            file.truncate()

            return True
        else:
            return False


def json_add_utc(user, utc):
    user = str(user)
    with open("data.json", "r+") as file:
        content = json.load(file)
        content["users"][user]["utc"] = utc
        file.seek(0)
        json.dump(content, file)
        file.truncate()


def json_get_utc(user):
    user = str(user)
    with open("data.json", "r") as file:
        content = json.load(file)
        return content["users"][user]["utc"]


def json_get_info(user):
    user = str(user)
    with open("data.json", "r") as file:
        content = json.load(file)
        return content["users"][user]["reminders"][0]


def json_add_reminder(user):
    user = str(user)
    with open("data.json", "r+") as file:
        content = json.load(file)
        content["users"][user]["reminders"].insert(
            0, {"title": "", "date": "", "time": "", "info": ""}
        )
        file.seek(0)
        json.dump(content, file)
        file.truncate()


def json_add_reminder_info(user, key, value):
    user = str(user)
    key = str(key)
    with open("data.json", "r+") as file:
        content = json.load(file)
        content["users"][user]["reminders"][0][key] = value
        file.seek(0)
        json.dump(content, file)
        file.truncate()


def json_cancel_add_reminder_process(user):
    user = str(user)
    with open("data.json", "r+") as file:
        content = json.load(file)
        del content["users"][user]["reminders"][0]
        file.seek(0)
        json.dump(content, file)
        file.truncate()


def json_delete_reminder(user, index):
    user = str(user)
    index = index - 1

    with open("data.json", "r+") as file:
        content = json.load(file)

        del content["users"][user]["reminders"][index]
        file.seek(0)
        json.dump(content, file)
        file.truncate()


def json_get_reminders_list(user):
    user = str(user)
    with open("data.json", "r+") as file:
        content = json.load(file)
        content = content["users"][user]["reminders"]

        if len(content) == 0:
            message = "πŸ“ͺ You have no reminders!"
            return message

        else:
            message = ""
            for i in range(len(content)):
                title = content[i]["title"]
                date = content[i]["date"]
                time = content[i]["time"]
                info = content[i]["info"]

                message += f"""
*Reminder {i+1}*
------------------
_Title_ : {title}
_Date_ : {date}
_Time_ : {time}
_Info_ : {info}
"""
            return message

These are actually basic python functions, that take a certain data given, and store it in the data.json file. Every function has a specific role clearly defined in its name. For example, there’s one that adds new users to our data, another one adds the reminders, another one gives us the full reminders history of a user, another one deletes the history of a user, and so on…

6- Handle messages and conversations with the Telegram Bot Using Python

Now that we created our data handling functions, we should create functions that handle messages and conversations with bots. Add the following functions to your code.

def start_command(update, context):
    update.message.reply_text(
        "πŸ‘‹ Welcome to my bot! It can remind you of anything in time!",
        reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
    )

    new_user = is_new_user(
        update.message.from_user.id,
        update.message.from_user.username,
        update.message.from_user.first_name,
        update.message.from_user.last_name,
    )

    if new_user is True:
        update.message.reply_text(
            "β€Ό Set your timezone β€Ό\n\n"
            "Send me your UTC (exp: +2, -1)\n\n"
            "You can always change it later",
            reply_markup=ReplyKeyboardRemove(),
        )
        return ADD_UTC
    else:
        pass


def request_utc(update, context):
    update.message.reply_text(
        "🌐 Please send me your UTC\n\nπŸ‘‰ exemple: +2, -1",
        reply_markup=ReplyKeyboardRemove(),
    )
    return ADD_UTC


def add_utc(update, context):
    utc = str(update.message.text)

    try:
        utc = int(utc)
        json_add_utc(update.message.from_user.id, utc)
        update.message.reply_text(
            "βœ… Your timezone was successfully set",
            reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
        )
        return ConversationHandler.END
    except:
        update.message.reply_text("❌ Wrong format, please send again")
        return ADD_UTC


def donate(update, context):
    update.message.reply_text(
        "Thank you for donating! ❀",
        reply_markup=InlineKeyboardMarkup(
            [
                [
                    InlineKeyboardButton(
                        "Buy Me A Coffee", "https://www.buymeacoffee.com/simonfarah"
                    )
                ]
            ]
        ),
    )


def all_reminders(update, context):
    update.message.reply_text(
        f"{json_get_reminders_list(update.message.from_user.id)}", parse_mode="Markdown"
    )


def add_reminder(update, context):
    """Starts the conversation and asks the user about the reminder title."""
    update.message.reply_text(
        "⚑ Adding a new reminder\n\n" "Send /cancel to stop the process.",
        reply_markup=ReplyKeyboardRemove(),
    )

    json_add_reminder(update.message.from_user.id)

    update.message.reply_text("πŸ’‘ Reminder title :")

    return REMINDER_TITLE


def add_reminder_title(update, context):
    """Stores the reminder title and asks for a reminder date."""
    json_add_reminder_info(update.message.from_user.id, "title", update.message.text)

    update.message.reply_text("πŸ“… Reminder date :\n\nFormat : dd/mm/yyyy")

    return REMINDER_DATE


def add_reminder_date(update, context):
    """Stores the reminder date and asks for a reminder time."""
    json_add_reminder_info(update.message.from_user.id, "date", update.message.text)

    update.message.reply_text("⏲ Reminder time :\n\nFormat : HH:MM AM/PM")

    return REMINDER_TIME


def add_reminder_time(update, context):
    """Stores the reminder time and asks for a reminder info."""
    json_add_reminder_info(update.message.from_user.id, "time", update.message.text)

    update.message.reply_text("β„Ή Reminder info :")

    return REMINDER_INFO


def add_reminder_info(update, context):
    """Stores reminder info and ends the conversation."""
    json_add_reminder_info(update.message.from_user.id, "info", update.message.text)

    all_info = json_get_info(update.message.from_user.id)
    reminder_title, reminder_date, reminder_time, reminder_info = (
        all_info["title"],
        all_info["date"],
        all_info["time"],
        all_info["info"],
    )

    utc = json_get_utc(update.message.from_user.id)
    user = update.message.chat_id

    try:
        hours, minutes, m = (
            int(reminder_time.split(" ")[0].split(":")[0]),
            int(reminder_time.split(" ")[0].split(":")[1]),
            reminder_time.split(" ")[1],
        )

    except:
        update.message.reply_text(
            "❌ Wrong time format! We're sorry, you'll have to restart the process...",
            reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
        )
        json_cancel_add_reminder_process(update.message.from_user.id)

        return ConversationHandler.END

    if "pm" in m.lower():
        hours = hours + 12

    try:
        seconds = datetime.timestamp(
            datetime.strptime(reminder_date, "%d/%m/%Y")
            + timedelta(hours=hours, minutes=minutes)
        ) - (datetime.timestamp(datetime.now()) + (utc * 3600))

        if seconds < 0:
            update.message.reply_text(
                "❌ The time and date you entered are in the past! We're sorry, you'll have to restart the process...",
                reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
            )
            json_cancel_add_reminder_process(update.message.from_user.id)

            return ConversationHandler.END

        else:
            pass

    except:
        update.message.reply_text(
            "❌ Wrong date format! We're sorry, you'll have to restart the process...",
            reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
        )
        json_cancel_add_reminder_process(update.message.from_user.id)

        return ConversationHandler.END

    context.job_queue.run_once(
        notify,
        seconds,
        context=[user, reminder_title, reminder_date, reminder_time, reminder_info],
    )

    update.message.reply_text(
        "βœ… Reminder succesfully added!",
        reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
    )

    return ConversationHandler.END


def cancel_add_reminder_process(update, context):
    """Cancels and ends the reminder process."""
    update.message.reply_text(
        "❌ Process ended.",
        reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
    )
    json_cancel_add_reminder_process(update.message.from_user.id)

    return ConversationHandler.END


def delete_reminder(update, context):
    with open("data.json", "r+") as file:
        content = json.load(file)
        content = content["users"][str(update.message.from_user.id)]["reminders"]

        if len(content) == 0:
            update.message.reply_text("πŸ“ͺ You have no reminders to delete!")

            return ConversationHandler.END

        else:
            update.message.reply_text(
                "Choose the number of the reminder you want to delete\n\n"
                "Send /cancel to stop the process.\n\n"
                "Note that deleting the reminder will only remove it from the reminders history list, you will be reminded of it anyway.\n\n"
                f"{json_get_reminders_list(update.message.from_user.id)}",
                reply_markup=ReplyKeyboardRemove(),
                parse_mode="Markdown",
            )

            return DELETE_REMINDER_INDEX


def delete_reminder_status(update, context):
    try:
        index = int(str(update.message.text))

        if index <= 0:
            update.message.reply_text(
                "❌ Please try again and send me only existing reminder number."
            )
            return DELETE_REMINDER_INDEX
        else:
            json_delete_reminder(update.message.from_user.id, index)

            update.message.reply_text(
                "βœ… Reminder Deleted Succesfully",
                reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
            )

            return ConversationHandler.END

    except:
        update.message.reply_text(
            "❌ Please try again and send me only existing reminder number."
        )
        return DELETE_REMINDER_INDEX


def cancel_delete_reminder_process(update, context):

    update.message.reply_text(
        "❌ Process ended.",
        reply_markup=ReplyKeyboardMarkup(main_keyboard, resize_keyboard=True),
    )

    return ConversationHandler.END


def notify(context):
    job = context.job

    chat_id = job.context[0]
    reminder_title = job.context[1]
    reminder_date = job.context[2]
    reminder_time = job.context[3]
    reminder_info = job.context[4]

    context.bot.send_message(
        chat_id=chat_id,
        text="🚨 REMINDER 🚨\n\n"
        f"*{reminder_title}*\n"
        f"_Info_ : {reminder_info}\n\n"
        f"_Date_ : {reminder_date}\n"
        f"_Time_ : {reminder_time}",
        parse_mode="Markdown",
    )

As we said regarding the data functions, those functions also have a role each, and clearly state the role in their names. So a function will handle the “start” command with the bot, another one will take the reminders info for the user, another one will send him his history, the other will notify him about a reminder, etc… Bot now that we created these functions, we should tell the bot how to use them! We should let him know which function to use when a message is sent.

7- Telling the bot what functions to use

So we created our functions, now we should tell the bot how to use them! In the main function that we created at the very beginning, add the following code right where we said to leave some space.

start_command_handler = ConversationHandler(
        entry_points=[CommandHandler("start", start_command)],
        states={
            ADD_UTC: [MessageHandler(Filters.text, add_utc)],
        },
        fallbacks=[CommandHandler("nevermind", start_command)],
    )
    dp.add_handler(start_command_handler)

    change_utc_handler = ConversationHandler(
        entry_points=[MessageHandler(Filters.regex("Change UTC"), request_utc)],
        states={
            ADD_UTC: [MessageHandler(Filters.text, add_utc)],
        },
        fallbacks=[CommandHandler("nevermind", request_utc)],
    )
    dp.add_handler(change_utc_handler)

    dp.add_handler(MessageHandler(Filters.regex("Donate"), donate))
    dp.add_handler(MessageHandler(Filters.regex("All Reminders"), all_reminders))

    add_reminder_handler = ConversationHandler(
        entry_points=[MessageHandler(Filters.regex("Add Reminder"), add_reminder)],
        states={
            REMINDER_TITLE: [
                MessageHandler(
                    Filters.text & ~Filters.regex("/cancel"), add_reminder_title
                )
            ],
            REMINDER_DATE: [
                MessageHandler(
                    Filters.text & ~Filters.regex("/cancel"), add_reminder_date
                )
            ],
            REMINDER_TIME: [
                MessageHandler(
                    Filters.text & ~Filters.regex("/cancel"), add_reminder_time
                )
            ],
            REMINDER_INFO: [
                MessageHandler(
                    Filters.text & ~Filters.regex("/cancel"), add_reminder_info
                )
            ],
        },
        fallbacks=[CommandHandler("cancel", cancel_add_reminder_process)],
    )
    dp.add_handler(add_reminder_handler)

    delete_reminder_handler = ConversationHandler(
        entry_points=[MessageHandler(Filters.regex("Delete History"), delete_reminder)],
        states={
            DELETE_REMINDER_INDEX: [
                MessageHandler(
                    Filters.text & ~Filters.regex("/cancel"), delete_reminder_status
                )
            ]
        },
        fallbacks=[CommandHandler("cancel", cancel_delete_reminder_process)],
    )
    dp.add_handler(delete_reminder_handler)

What this code is basically doing, is telling our bot that if you receive a “start” command, use the start_command function and the same thing for other bot commands. We are also telling him how to handle a conversation with a person willing to add a reminder. That way the bot will use the correct function on each step, so the user doesn’t get lost or confused.

Hurry! we successfully created Telegram Bot Using Python.

8- Run the BOT!

Now that we are done writing all our functions, save the file and run it! Go to Telegram, search for the Bot that you created and start talking to him! You’ll see that every function that we wrote is running based on a specific sent message, along with a keyboard menu (that one that we created in step 4).

I hope that this tutorial was helpful to help you understand the basics of creating a Telegram Bot and how to implement certain functions with it. You can get the full source code of this tutorial here.

Thanks for visiting our website


Also Read:



Share:
Avatar of Simon Farah

Author: Simon Farah