How I built a Telegram Reminder bot with Node JS, the IBM Watson API and Firebase

Written by _Obbap | Published 2018/12/04
Tech Story Tags: bots | nodejs | telegram | automation | telegram-reminder-bot

TLDRvia the TL;DR App

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Create the bot with Node JS
  4. Connecting the bot to a real time DB(Firebase)
  5. Run the Cron Job
  6. Script to connect to the IBM Watson API
  7. Deploy to Glitch
  8. Conclusion

Introduction

This Telegram bot, would simply take three commands.

  • /start — Initializes our bot.
  • /save — Saves the string we will like to be reminded of later.
  • /time — Saves the time we would love to carry out this task.

Then, this data is saved to firebase, and a cron job is initialized, which will run at the set time. This cron job, sends a text reminder to the user, and is then converted to an audio file, using the Text to Speech IBM Watson API, and is also sent to the user.

Prerequisites

  • A Telegram bot, This bot can be created by sending a ‘/start’ message to the Bot Father account on Telegram. The bot token should also be gotten.
  • An IBM watson account (it’s free).
  • A real-time database, firebase / firestore.
  • A Glitch account, which just needs your Github account.
  • A little bit of regex and bash(Nothing to be worried about).

Create a bot with Node JS

Ok, to begin, we will need to install the modules we will need. So from our directory, we will run this in the terminal:

$ mkdir telegramBot && cd telegramBot$ npm init$ npm install node-telegram-bot-api node-cron firebase-admin shelljs

We will be using the node-telegram-bot-api as a wrapper. To begin, we will create an index.js file in our directory. We will add the following lines to our index.js file:

So we initialize the bot with the token gotten from the Bot Father account. The polling option on line 6, keeps the channel between the bot and the user alive. Its a web socket thing. We also declare a reminder variable, which holds what we want to be reminded of.

/start

Then, we will have our server listen to when the ‘/start’ command is inputted by our user. So we will add an onText listener, to the index.js file.

This listens to when the ‘/start’ command is passed, and then responds with a callback that contains a ‘msg’ object which holds the chat id, the name of the user etc.

When this condition is met, the bot sends a message to the chat id, asking what the user, what he wants to be reminded of. So we are done with the first command!

/save

This command will save what we want to be reminded of. This listener will be triggered after the ‘/start’ command is passed. So we will pass this function, in the promise returned(.then)

So we listen to when the ‘./save’ is entered, and then the ‘match’ variable in the callback returns an array with what is matched.

If the user enters /save ‘wash my clothes’, then the ‘wash my clothes’ string will have the first index in the array i.e [‘/save wash my clothes’, ‘wash my clothes’]. When this is gotten and saved, we then send a message asking for the time. We are done with the second command!

/time

Now, we will save the time. This should be entered in the promise chain of the save command. We want to save the command with the format, HH:MM:SS:(AM OR PM). So our time function should look like this:

So the regex, matches the format, and then we get the time by splitting the match response. The match variable looks like this:

[ '/time 06:33:33:PM','06','33:33','PM',index: 0,input: '/time 06:33:33:PM' ]

So splitting the first item in the array, we get 06:33:33:PM, and then we send a thanks message. But our bot doesn’t actually save the users request yet, and it surely doesn’t remind the user. So we need to fix this.

At this stage, our index.js file should look like this:

Our interaction with our bot, should look like this:

Connecting the bot to a real time DB(Firebase)

Now, we will create a database.js file in the root of our directory, which will handle our connection to the firestore db. Our database.js file should look like this:

Now, we can import our database.js file at the top of our index.js file.

const db = require('./database').database;

We also want to save the user’s request with the user’s chat name, but if the user makes more than one request, it will be a duplicate. So we can attach a random string to each document to be stored on firestore. To do this, we’re going to create a helper.js file in our root, and it would look like this:

This returns a string with whatever length we pass. We can also import this file at the top of our index.js file.

const generator = require('./helper');

Now, we will go back to the function that handles our /time command, before sending the ‘Thank you’ reply, and then we add this:

Initially, i created a collection on my db called ‘reminder’. And then i pass the payload using the .set command to that collection. Now, there is a hasUserBeenReminded key, which helps us keep track of if the user has been reminded of a certain task.

If we interact with our bot again, after running the /time command, our db should look like this:

firestore db

If this works fine, we can then run a cron job, to remind the user at the set time. We can add the dependency at the top of the index.js file.

Run the Cron Job

const cron = require("node-cron");

Then, we can continue with the function that listens to our /time command.

So we basically get the hour and the minute the user wants to be reminded of a certain task, and then schedule it with the cron dependency. Normally, the cron scheduler has a pattern:

* * * * * *

These asterisks represent the second(optional), minute,hour,day,month and year respectively. So we ignored the second option, and chose the hour and minute. When it’s time, the event is triggered, and the reminder is sent, the hasUserBeenReminded key is also set to true.

We should have a message like this, when the time comes.

Script to connect to the IBM Watson API

We also want the bot to send a voice note of our reminder. Something like a ‘wash your clothes’ will do. To do this, we will use the text to speech service on the IBM Watson API. This will convert the file to an audio file of the format we want(Telegram accepts the .ogg format) and then upload it.

To do this, we will be writing a simple shell script. We will name the file, textToAudio.sh, and it should look like this:

The ‘$1’ gets the first argument when the command is run. That will be our text. And then if that argument is not empty, do a post request with curl, else display a string ‘No arguments’. If this runs successfully, the output remindersss.ogg will be added to the root directory.

We can run this in the terminal with the sh command, but to run this in node, we will need to add a dependency at the top of our index.js file.

const shell = require('shelljs')

So now, we will run this with the shell.exec command, and then the first argument will be what we want to be reminded of.

This will execute the shell script, and then pass the reminder as the first argument. Then we send the audio to the user!

Our Interaction with the telegram bot should look like this now:

Audio file sent

Deploy to Glitch

Ok,this is really just plug and play. After creating a project on glitch, just copy and paste your code there, and you’re good to go.

Conclusion

This project still has many rough edges, one of which is queuing, because it takes just one request at a time among others. If you need clarification, there is a repository for it.

Thank you very much for reading,if you liked it, please clap. if you have any questions or you need further clarification, you can leave a comment or a mail([email protected]).


Published by HackerNoon on 2018/12/04