In this post, we will make a Telegram bot with a Python/Flask Back-end. As example use case we will be making a chatbot where you can request more information about a Pokemon.
Creating A Telegram Bot
To create a Telegram Bot we first have to register it. Telegram actually has there own chatbot for this! The Botfather! You’ll need a Telegram account to talk to him. Afterwards, you can follow the link or search for @Botfather.
Afterwards you can use the /newbot
command to create a new bot.
The first prompt will ask you for a display name. The second one will ask you for a username, this one has to be unique.
Afterwards you need to save the Access Token for later use in the Python code.
🔒 SECURITY TIP Make sure you never share your access token or other keys with other people. If you use a Version Control System like Github. Make sure you remove your keys before you commit your code!
Set Up Python Dev Environment
- Create a new folder
mkdir telegram-pokedex
cd telegram-pokedex
- Create a Python Environment
python -m venv .venv
source .venv/bin/activate
- Install Flask, Requests and a Telegram API Wrapper
pip install flask
pip install python-telegram-bot 3pip install requests
Back-End Code
Create a new file named [bot.py](http://bot.py)
and paste the following code in it. You will need to enter the Access Token you got from the BotFather as the BOT_TOKEN.
You can run your code with the python bot.py
command.
import re
import logging
import requests
from telegram.ext import Updater, CommandHandler
BOT_TOKEN = "YOUR_API_TOKEN"
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
)
logger = logging.getLogger(__name__)
def start(update, context):
"""Send a message when the command /start is issued."""
update.message.reply_text(
'Hello, my Name is Professor Oak! \n'
'I can give you more information on Pokemon!'
)
def main():
updater = Updater(BOT_TOKEN, use_context=True)
# Get the dispatcher to register handlers
dp = updater.dispatcher
# on different commands - answer in Telegram
dp.add_handler(CommandHandler("start", start))
# Start the Bot
updater.start_polling()
# Run the bot until you press Ctrl-C or shutdown the process
updater.idle()
if __name__ == '__main__':
main()
Explanation
In the main
function, you’ll find an Updater, this is your connection to Telegram and will listen for new messages.
The dispatcher attaches logic to certain messages and commands. For example on the next line we add a command handler to the start command which means that when someone types the /start command in Telegram, your server will execute the start
function.
In this case our start
function will reply with a welcome message.
If your bot is running you can test this by searching your bot on Telegram and send it a /start message.
Adding The Pokemon Lookup Functionality
PokéAPI is a great, free API if you want to use Pokemon Data. In our example, we want to call the API with a Pokemon name and it will return its PokeDex ID, some flavour text and an image of the Pokemon, just like a Pokedex.
To implement this functionality we’ll create a pokedex()
function that gets the user query for the command, calls the API
Get The Pokemon From The User Command
Telegram will trigger our function when somebody sends the /pokedex command in chat. When we check the message in our code we’ll see that it also sends the command in the message. So we will need to strip /pokedex from the message, to prevent errors we’ll also strip all the spaces and make the query lowercase.
Next up we’ll check if our query is not empty, the user might have sent just the command without a Pokemon name. To help them we’ll send a message back with an example query.
Call The API
If we explore the API documentation, we’ll find that the https://pokeapi.co/api/v2/pokemon/[POKEMON_NAME
] route provides all the data except for the flavour text.
If we look a bit further we can find that the https://pokeapi.co/api/v2/pokemon-species/[POKEMON_NAME]
link returns all the data we need, except for the image. Luckily we don’t have to call both API’s since the image link is the same for all Pokemon except for the Pokemon ID which is provided by this API so we can get all the data we need. All we need to do is append the user query from the previous step as [POKEMON_NAME] in the URL.
Check The API Response
The user might have sent a name of a Pokemon that doesn’t exist. In this case, the API will return a 404 Not Found error. When this happens we’ll send a message back that we couldn’t find the Pokemon.
Get The Data From The Response
If the Pokemon is found, the API will return a JSON object. We’ll first have to parse this. Afterwards, we can get all the data we need from the object.
To get the Pokemon image link will have to paste the ID in the link.
To get the Pokemon description we add a default “NO DESCRIPTION FOUND”. Afterwards we’ll go the flavor_text_entries
object and look for the first English object. If there is one we’ll replace the default description with the English flavour text. We do this because the flavor_text_entries
object has flavour texts in different languages.
Send A Message Back To The User
Now that we have all the required data we can format it and send it back to the user. To keep this tutorial simple, I just send it back in plain text. But Telegram does support Markdown, images, and much more, check out the docs at https://python-telegram-bot.readthedocs.io/en/stable/ for more information.
Add A Command Handler To The Main Function.
Last, we have to couple the pokedex command to the pokedex()
function. You can do this by adding dp.add_handler(CommandHandler("pokedex", pokedex))
under the start command handler in the main function.
You can find the full code below or on Github.
import re
import logging
import requests
from telegram.ext import Updater, CommandHandler
BOT_TOKEN = "1396000569:AAHCXgPCh8UgPwkiPW-gp7PXw7RjYz2Mtgk"
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
)
logger = logging.getLogger(__name__)
def start(update, context):
"""Send a message when the command /start is issued."""
update.message.reply_text(
'Hello, my Name is Professor Oak! \n'
'I can give you more information on Pokemon!'
)
def pokedex(update, context):
""" Searches the Pokemon API for more information and return the data """
# Get the pokemon from the command and check if it's not empty
pokemon_query = update.message.text.replace('/pokedex', '').replace(" ", "").lower()
if len(pokemon_query) == 0:
update.message.reply_text(
'Please add a pokemon name to your command \n'
'Example: /pokedex Pikachu'
)
else:
# Call the API
response = requests.get('https://pokeapi.co/api/v2/pokemon-species/' + pokemon_query +'/')
# Check if the data is found by the server
if response.status_code == 404:
update.message.reply_text(
"I could not find the pokemon: {pokemon_query}".format(pokemon_query=pokemon_query)
)
else:
# Get the data from the response
pokemon_data = response.json()
pokemon_id = pokemon_data['id']
pokemon_name = pokemon_data['name'].capitalize()
pokemon_desc = "NO DESCRIPTION FOUND"
pokemon_image = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/" + str(pokemon_id) + ".png"
for desc in pokemon_data['flavor_text_entries']:
if desc['language']['name'] == 'en':
pokemon_desc = desc['flavor_text'].replace('\n', ' ')
# Send a message back to the user
update.message.reply_text(
"[{pokemon_id}] {pokemon_name} \n\n{pokemon_desc}\n{pokemon_image}".format(
pokemon_id=pokemon_id, pokemon_name=pokemon_name, pokemon_desc=pokemon_desc,
pokemon_image=pokemon_image
)
)
def main():
updater = Updater(BOT_TOKEN, use_context=True)
# Get the dispatcher to register handlers
dp = updater.dispatcher
# on different commands - answer in Telegram
dp.add_handler(CommandHandler("start", start))
dp.add_handler(CommandHandler("pokedex", pokedex))
# Start the Bot
updater.start_polling()
# Run the bot until you press Ctrl-C or shutdown the process
updater.idle()
if __name__ == '__main__':
main()
Finishing Up
To finish up we can add a profile image to our Telegram bot. You can do this in the BotFather chat by using the /setuserpic command, selecting your bot and uploading a photo.
You can also host your bot on a service like Heroku.
The final product should look something like this: