Asking a girl out with a telegram bot
Introduction
So, when I first mooted this idea to my colleagues, they were not exactly the most impressed. “Zach,” these wise, married 30-year olds said, “she’s not going to be impressed with a telegram bot… that’s literally the lamest, most geeky idea in the world…if you write the bot in R” And with that challenge, I HAD to attempt to use Python to write it.
Having been working with R for the entire summer and not having touched Python in ages, it felt nasty using =
instead of the ever so beautiful <-
. The loss of %>%
was also a pretty sad thing. (what I did not realize at this juncture, was that I wouldn’t even have to use these because my bot would truly be one of the lamest bots around).
Steps:
- Request a new bot to be birthed from the BotFather
- Plan out my bot
- Write some code to get the bot running
- Send and receive messages
- Send stickers
- Send a location
- Send a random number generator (RNG) dartboard
- Cry because I get rejected
The Bot Begins
Step 1: The birth of a new bot
This step was relatively simple. All you had to do was create a telegram account and then initiate a chat with @BotFather. Then, send him a /newbot
, give your bot a name and a username (that has to end in _bot) and he’ll give birth to your bot and give your bot a token (not of appreciation; just a token)
Take care of your token because, as the BotFather says, anyone with the token can access your bot!
Step 2: Planning out the bot
This turned out to be the actual hardest part of the entire project (and there was absolutely no coding involved in this). I had to spend time thinking about what I wanted the bot to do and how I was to incorporate it into the process of asking her out. This really wasn’t easy so I went to sketch out a diagram (the only reason I’m including this here because I wanted to show off typora, this amazing markdown editor which allows you to create diagrams super elegantly and simply)
st=>start: "Pretend to forget we're going out for dinner"
cond=>condition: "She gets mad"
sucks=>operation: "That sucks. I guess it's the end"
telebot=>operation: "Send her the telegram bot"
e=>end
st->cond
cond(yes)->sucks
cond(no)->telebot
Was basically what I had in my head. But then I realized that I also needed to design the telegram bot (I mean, it couldn’t just be a literal:
opens up telegram bot
“Will you get together with me?”
right..?)
So back to more flowcharts…
st=>start: "She opens the bot"
cond=>condition: "Does she start the bot?"
sucks=>operation: "That sucks. I guess it's the end"
telebot=>operation: "Apologise for tricking her and
tell her we're still going for dinner!"
part2=>operation: "Send her dinner location"
part3=>operation: "Send her cute sticker"
part4=>operation: "Ask her (by using telegram's inbuilt RNG)"
e=>end
st->cond
cond(no)->sucks
cond(yes)->telebot->part2->part3->part4
I obviously needed the flowchart to help me craft out such an intricate plan. But at least I was clear now! I needed to make the bot send her our dinner location, send her a cute telegram sticker, and then send her a (RIGGED) RNG to trick her into agreeing to get together.
Step 3: Coding the bot
This was honestly the simplest part of the entire project. There’s a fantastic telegram wrapper that has fantastic documentation and code examples which allowed me to more or less copy borrow what I needed for this bot.
The first step was to import the telegram library and enable logging on the bot. This turned out to be super useful later on (when I struggled to send the stupid sticker and couldn’t figure out what the issue was)
import logging
import telegram
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
After the standard (template) headers, it was time to start defining some functions for our bot. The first two standard ones that one has to define is /start
and /help
. Which is exactly what I did.
def start(bot, context):
context.bot.send_chat_action(chat_id=bot.message.chat_id, action=telegram.ChatAction.TYPING)
bot.message.reply_text("I'm not actually busy. We're still going for dinner.")
def help(update, context):
update.message.reply_text("Help!")
I added the action=telegram.ChatAction.TYPING
to create more realism. With this, the bot would pretend to type (wow so cool) before sending the message.
I then added the standard template bits below to get the bot running. We needed a dispatcher to send and receive from the telegram API and then needed to add CommandHandlers to respond to the incoming telegram commands.
def main():
updater = Updater("BOTTOKEN", use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler("start", start))
dp.add_handler(CommandHandler("help", help))
dp.add_error_handler(error)
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
And it was live.
Now came the tricky bit, sending her a sticker! I really struggled with this one for awhile because I could not for the life of me figure out how to identify the sticker - each telegram sticker has a unique ID. I tried using the “Sticker ID bots” on telegram but they kept giving me incorrect IDs. I eventually figured out that the easiest way to do it was to run the bot, send yourself a sticker and then check the log for the sticker ID.
In order to check the log, I stopped the bot and then headed over to: https://api.telegram.org/botYOURTOKENHERE/getUpdates (so to clarify, it’s /bot[yourBotToken]/getUpdates) and sent myself a sticker.
(yes, the sticker pack I sent it from was indeed beymax kmn). The file_id is (incidentally) the id of the sticker, and to send the sticker, we just had to create the sticker function:
def sticker(update, context):
update.message.reply_sticker(sticker="CAACAgQAAxkBAAP8X3fhTE1oKX3aziRqZ9jC8EifIe4AAh8AA7mQDgABvw5_ATZHWfkbBA")
and add it in as a command:
dp.add_handler(CommandHandler("sticker", sticker))
Next, we needed to send her our dinner location, which was easily done with reply_location
. Note that the location has to be given in lat, long (which you can easily get from Google Maps)
def dinnerplace(update, context):
update.message.reply_location(1.29053,103.84646)
context.bot.send_chat_action(chat_id=update.message.chat_id, action=telegram.ChatAction.TYPING)
update.message.reply_text("Here's where we're going for dinner!")
And finally, the RNG (which I rigged to force her to agree to getting together with me). You could choose between three different emojis (dice, dartboard, and basketball) and by setting the “value”, it would pre-determine what the outcome was. For dartboards, setting it to ‘6’ meant that it would hit the BULLSEYE
def decision(update, context):
context.bot.send_dice(chat_id=update.message.chat_id, emoji="🎯", value=6)
update.message.reply_text("Heh, I think that's a yes..?")
Throw all these into CommandHandlers
… (its ‘24’ for one of the commands because I made her do some sort of quiz before finding out the dinner place and ‘24’ was the correct answer to the quiz)
dp.add_handler(CommandHandler("24",dinnerplace))
dp.add_handler(CommandHandler("decision",decision))
And presto~ the bot is DONE!
Conclusion: Getting to the BOTtom of it
So, the clear question on everyone’s mind is… did it work? Can I impress potential partners by doing nerdy things like coding a telegram bot? Does lying to a potential partner BUT then sending them a telegram bot make up for the lying? The answer, I guess, is for me to know and for you to (now that you have the rough skeleton of how to code a telegram bot) find out :p