Bot “Smart Scheduler” — quick in the uptake

Usage of reminders becomes more and more valuable thing, because human time tends to be more valuable as well. And services for planning your schedule can be really handy for this task.

Demonstration of “Smart Scheduler” usage

That’s why I’ve came up with an idea to create Telegram bot for jotting down users’ affairs and remind of them. Main feature of this bot is it’s ability to create reminders directly from natural language.
In addition to it, this bot can also:

  1. Understand words with errors.
  2. Understand voice messages.
  3. Pin files to your reminders.
  4. Be integrated to your Trello board.

If you want to try it out right now here’s link to the bot.

For everyone else who’s interested how 16 year old schoolboy happened to write it, I will tell small story of development and how “Smart Scheduler” parsing system works behind the scenes.

Brief history of creation

Why Telegram?

There are 3 reasons why I’ve decided to create bot in Telegram messenger:

  1. Huge users base
  2. Many companies locate their work chats in this messenger
  3. There are many guides in internet how to set up bot in Telegram

Why Node.js?

Simply because javascript is currently one of the most popular programming languages. I was also thinking of trying to write bot on Python or php, but I stayed with js, as it had similar syntax to familiar to me C++.

How it all started

First version of “Smart Scheduler” had a very different technical side, but served the same purpose — creating reminders from natural speech. It was just a pilot project to see if my hypothesis was correct, so I didn’t bother myself about the quality of code. Main goal was to create MVP, so the whole application was nothing but a monolith. I presented it at russian IT-themed web-site Habrahabr. Then, after seeing that people appreciate the idea of project, I decided to improve code structure and continue on developing the bot.

I won’t tell you about this awkward clumsy first version, which was created almost a year ago, because it’s add no relevant information. Better let’s get directly to the current version.

Bot application architecture

The operating algorithm is as follows:

Checking of reminders is made using one minute timer. On the diagram this part is named “Tasks Scheduler”. It loads all reminders from data base, checks their time, and if their time is up, executes them. Expired reminders are deleted.

Originally bot was planned to understand both Russian and English, so I wrote each bot reply in two languages. To determine user’s language bot counts number of cyrillic and latin letters in message’s text. If there are more cyrillic letters than the latin, then the language is Russian, otherwise English.

Just to keep things safer I added text encryption using default Node.js library crypto.

Data base: PostgreSQL

Choice of DBMS is due to the fact that it’s already integrated to Heroku, where the bot is hosted, and it’s free. There are 3 tables in bot’s DB: User IDs, Chats and Schedules.

Also I’ve made ORM tool from scratch. I know, that it has definitely been done already, but I wanted to make it on my own and thus create fewer dependencies.

Date parsing

Parsing numbers

To extract time from natural language message, we first need to replace all numbers written in words with real numbers. For this I’ve made npm library parse-word-to-number. It takes a string and returns a string in which all possible words were replaced with numbers.
For matching words from source string with corresponding words from dictionary I’ve used Damerau-Levenshtein distance. This allows the library to understand words even with few mistakes.

parse-word-to-number features

The library works this way:

  1. Select the next word and search for it in dictionary.
  2. If it’s found in dictionary, then:
    ⠀⠀If previous word is number:
    ⠀⠀⠀⠀If previous number rank is bigger than current, then sum current number with previous and merge them.
    ⠀⠀⠀⠀Else if current number can be multiplied by previous number, then multiply it and merge with previous number.
  3. Otherwise write it to string.

It also supports russian language.

Time and text parsing

After all numbers in message were replaced with actual numbers, we can finally extract time definitions. For that I’ve made another npm library date-parser. It takes a string and returns array of objects of class ParsedDate (more information about in readme). Each of this objects represents one event with it’s time and text description. Thereby library can extract multiple reminders from string with one call.

date-parser usage

This library also supports recurring reminders and time limits for them, for example: “Warm-up every 30 minutes until 20:00”.

Process of parsing is divided in three stages: simplifying, finding and forming.

To make search for human time definition patterns easier, we need first to simplify source string. This is done by creating reduced string, in which all words from source string are replaced with corresponding symbols from dictionary. Let’s take a look at the message “Pick up parcel tomorrow at 3 p.m.” and see how library shortens it.

Source string simplification

(Word “tomorrow corresponds to symbol A, “atp, “3n, “p.m.O. All not found words are replaced with dots.)

Now we can just apply different regular expressions to this shortened string to find time definitions. This allows us to handle every possible pattern, even the most complex ones! All we need to do is just write enough regular expressions:

Parsing using regular expressions

In the end we form event’s description from the left words:

Unused words become a description

This is the most basic, but also most important part of parsing. The actual date-parser library is way more complex. I haven’t covered other technical nuances, such as contexts processing, validation levels and search for suitable time definitions. But for very simple parser this algorithm is more than enough.

Timezone setting

Last but not least part of creating reminders is user’s timezone. It’s necessary to allow every people on globe to use bot correctly. To adjust timezone I’ve made two options, both of them are started via /tz command.

Send geolocation

If you’re chatting with bot from smartphone, then you can set up your timezone in 1 click: just send your geolocation and bot will automatically determine your timezone.

To determine timezone by longitude and latitude bot uses web-site GeoNames.

Type manually

Or, if you’re using telegram from PC, you can simply write your timezone GMT offset in “±HH:MM” format.
This is valid for mobile version as well.

Future updates

Even with so many usefull features, Smart Scheduler is still can be much better. My main tasks for improving this bot are:

  1. Adding ability to integrate bot with user’s Google calendar.
  2. Adding ability to define time for common words, such as “morning, day, evening, night”.
  3. Improvement of user-bot interface by removing most of text commands and replacing them with convenient inline buttons.

Other minor tasks are listed in project’s issues on GitHub.

Smart Scheduler” is an open-source project, so feel free to report any bugs or suggest improvements, I will greatly appreciate it.

Thank you for attention, hope you’ll have more free time with my bot!

Student