Бот «Умный планировщик»: понимает с полуслова

Если вы когда-нибудь желали иметь личного слугу, который бы напоминал вам обо всем, о чем вы ему скажете, но не имели возможности нанять такого, то разработанный мною бот станет ему достойной заменой.



Хотите проверить функционал? Напишите в лс боту по этой ссылке и он ответит вам.

А тем, кому интересно как он работает и как 16-летний школьник смог написать его, я с удовольствием расскажу всё в подробностях в этой статье.

Предыстория


Началось все с другого моего бота для вк на node js, который расшифровывал голосовые сообщения (и так как таких ботов пруд пруди, я решил не писать статью о его разработке, хотя и он имеет несколько отличительных особенностей). После того, как я запустил его, мой отец предложил мне разработать другого бота для нашего семейного чата в телеграмме. Суть этого бота была простой – извлекать дату и время из текстового сообщения человека, и, используя телеграмовские отложенные сообщения, создавать напоминания прямо в семейном чате.

Но вскоре меня ждало разочарование. Оказалось, что боты не могут делать отложенных сообщений, поэтому я решил написать свою систему хранения и выполнения напоминаний.

Разработка


Общие сведения


Этот бот написан на node js и живет на heroku.

Он способен хранить любые текстовые напоминания с точностью до минуты.

Также он может работать в групповых беседах.

На данный момент бот распознает дату и время только на русском языке.

SmartScheduler — open source проект, доступный на моем гитхабе.

Извлечение даты и времени из сообщения


Начать я решил с самой сложной задачи: разбиения текстового напоминания на дату и на само напоминание. Для этого пришлось учесть все возможные стандарты написания даты человеком, от «в 12:00« до «в следующее воскресенье в без двадцати пяти восемь вечера«.

Была создана большая база данных (constValues.js), хранящая в себе константные выражения и их свойства, которые человек использует в своей речи. Затем были написаны функции для распознавания каждого варианта написания времени.

К примеру для распознавания даты в виде «через X %тип_времени%» используется функция FindAdditiveLiterals, а для поиска дня недели FindDayOfWeek.

Для каждого варианта обозначения времени выставлялся свой приоритет.

В итоге алгоритм работы парсера выглядит следующим образом:

  1. Исходная строка делится на слова. Слов, в которых производится поиск времени, не может быть больше 40.
  2. Массив слов пропускается через функцию конвертации слов в числа.
  3. Находятся все указания времени в сообщении, а также помечаются использованные в указаниях слова (например в указании «будильник 8 часов» отмечаются слова «8» и «часов»).
  4. Если какая-то характеристика времени не была найдена (например месяц) в текстовом сообщении, то берется текущее значение этой характеристики.
  5. Для окончательного вердикта выбираются указания времени с наибольшим приоритетом и смежные указания, имеющие одинаковое исходное слово (например в слове «10:30» одновременно указан и час, и минута).
  6. После выбора окончательных характеристик времени формируется штамп времени из выбранных минуты, часа, дня, месяца и года.
  7. Из массива слов удаляются все помеченные слова, а из оставшихся формируется текст напоминания.
  8. Если сформированный штамп времени больше текущего времени, то мы считаем что такое напоминание пригодно и функция возвращает объект типа
    { string: answer, string: text, date: date }

    В противном случае функция возвращает объект
    { string: answer, string: text }
    (answer – ответ для пользователя, text – текст напоминания, date – дата напоминания).

База данных напоминаний


Следующими вопросами были где хранить все напоминания и как следить за их выполнением.

Изначально я хотел воспользоваться библиотекой node-schedule, но отказался от этой идеи, так как я не хотел засорять оперативную память всеми напоминаниями.

Вместо этого я решил изучить принцип работы SQL баз данных и создать свою.

После прочтения множество статей в интернете я создал postgresql базу данных на платформе heroku, так как в ней можно встраивать бдшки в свои приложения, что очень удобно.

Чтобы взаимодействовать с бд я написал небольшой скрипт (db.js), в котором реализовал все необходимые функции, такие как инициализация бд, получение списка напоминаний и т.д.

В моей базе данных присутствует две таблицы: первая для хранения напоминаний, вторая для хранения часовых зон пользователей (о ней чуть позже).

После этого я реализовал сохранение распарсенного напоминания из текстового сообщения в базу данных. Проверкой времени напоминаний занимается таймер, срабатывающий раз в минуту. Если же пришло время для какого-то напоминания, то оно удаляется из базы данных, а пользователю, сделавшему его, отправляется сообщение с текстом из напоминания.

Также я добавил отображение всех напоминаний через команду /list.



(рядом с каждым напоминанием есть кликабельная команда /N, которая удаляет его при клике на неё)

Настройка часового пояса


До того, как я решил написать эту статью и выложить её на Хабр, в переменных среды был захардкожен часовой пояс Москвы. Для пользования внутри нашей семьи этого было достаточно, но для того, чтобы воспользоваться всеми прелестями и удобствами жизни с ботом SmartScheduler мог каждый, я решил добавить индивидуальную настройку часового пояса.

Для выполнения настройки требуется написать команду /tz, о чем предупредит бот пользователя, если он еще не указал свой часовой пояс:



(из-за того что часовой пояс не указан, в ответе используется не локальное время, а гринвичское)

При вводе команды /tz запускается процесс определения часового пояса и появляется клавиатура с тремя кнопками:



  1. Использование локации пользователя.
  2. Ручной ввод.
  3. Отмена.

Первая кнопка запрашивает у пользователя его местоположение, на основе которого вычисляется часовой пояс.

Пример использования


Вторая кнопка позволяет вручную ввести свою часовую зону в формате ±HH:MM,
где ± – плюс или минус, HH – часы, MM – минуты.

Пример использования


Третья кнопка отменяет процесс определения.

После того как пользователь указал свой часовой пояс, бот будет верно отображать и сохранять время напоминаний.

Финальные доработки


Закончив с основным функционалом, я добавил главную клавиатуры с основными функциями, откорректировал ответы для команд /start и /help, ну и по мелочам.

Также я решил заменить часовой пояс по умолчанию для всех пользователей на Московский.

Результат


Главным преимуществом бота SmartScheduler является конечно же парсинг даты, который позволяет даже в самых непредсказуемых ситуациях быстро и удобно записать нужную информацию или задачу в форме напоминания.

Больше не нужно листать календарь в поиске нужного дня и крутить часы для выставления нужного времени, достаточно по-человечески сказать боту «что» и «когда», а дальше он сам все сделает.

Заключение


До разработки ботов на node js я был совершенно не знаком с javascript’ом, посему все знания, которые я использовал в написании кода, брались из интернета, где зачастую можно найти не совсем то, что тебе на самом деле нужно. Из-за этого, скорее всего, где-то в моем коде встречаются очень глупые ошибки, для определения которых я еще недостаточно много знаю.

Изначально моей целью не было создание максимально продвинутого и идеального с точки зрения структуры проекта, для меня было важнее всего получить новые знания, изучить новый язык программирования для улучшения понимания информатики в целом, а также создать MVP продукт.

Но если данная разработка будет пользоваться спросом, то я с удовольствием продолжу улучшать её, а если у вас есть какие-то идеи или вы обнаружили баг, то добро пожаловать на гитхаб проекта. У меня уже есть идеи где и как что изменить (например переписать ужасный спагетти-код в модуле парсинга с использованием нормального Visitor-паттерна), а также в планах добавление поддержки английского языка.

Надеюсь, что этот бот поможет вам также, как помогает мне и моей семье в повседневных делах.

Спасибо за внимание!

UPD: По многочисленным просьбам добавлена поддержка голосовых сообщений.

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 41

    +1
    Учитывая что в последнее время пользователи обленились писать и шлют голосовые сообщения, то писать напоминания будут единицы. Увы это реалии нашего текущего мира.
      +7
      Значит прикручу к этому боту сервис распознавания голосовых сообщений, как в моем ВКшном боте.
      Спасибо за идею!
        0
        А что за сервер, если не секрет?
          +1
          Сервер — heroku
          Сервис — wit.ai
          Прочитал про них в этой статье.
            +1

            У SpeechKit Яндекса неплохой SDK и распознавание русскоязычной речи лучше чем у wit.ai.

      0

      image
      Какой-то пробел объявился в "что-нибудь" — баг?
      И бот так и не смог мне ответить, выдаёт ошибку.

        +1
        Какой-то пробел объявился в «что-нибудь» — баг?

        Да, спасибо, исправил, теперь бот не добавляет лишних пробелов.
        И бот так и не смог мне ответить, выдаёт ошибку.

        Можете написать мне в телеграмме или сообщить на гитхабе какую ошибку он пишет?
        +2

        Круто, но все голосовые помощники в телефоне это умеют и очень хорошо((

          0

          назови парочку selfhosted вариантов

            0
            Ну, голос сейчас все в облаке распознают, по-другому просто не бывает.
              0

              Бывает. Вы просто плохо искали:



              Но между "распознавать" и "распознавать хорошо" большая разница, а "хорошо распознавать русский язык" ещё сложнее, потому что тренировочных данных (а тем более хороших) для нейросетей сильно меньше по понятным причинам.

                0
                Именно так. Всё, что не в облаке — отстой, который даже не стоит принимать во внимание.
        • НЛО прилетело и опубликовало эту надпись здесь
            +1
            Спасибо.
            Первую идею я точно реализую, это именно то, чего по моему ощущению не хватало боту.
            По поводу второй идеи — это уже реализовано в групповых беседах: просто упомяните нужного пользователя через @ и бот тоже упомянет его в уведомлении.
            0
            Если в будущем получится сделать голосовое распознавание текста, тогда попробуйте создать приложение для Android: «Голосовые напоминания offline». Сейчас много приложение требуют доступа в интернет т.к. много операций проходят на стороне сервера, а у вас свой сервер и всё свое. Если получится работать в offline тогда часть параноиков пользователей скажет вам большое спасибо.
            • НЛО прилетело и опубликовало эту надпись здесь
                +1
                Если получится отвязаться от все сторонних приложение которые слушают, что ты говоришь и отправляют третьим лицам твои данные — тогда будет еще одно приложение для параноиков и простых людей которые следят за своей безопасностью. Я надеюсь в этом смысл этого приложения.

                  0
                  Кому стоит доверять больше, гуглу или рандомному боту из телеграма? Параноика, вероятно, ни один из вариантов не устроит.
                  • НЛО прилетело и опубликовало эту надпись здесь
                      0
                      Это сейчас бот в телеграме сидит и через него все работает. Но в будущем можно сделать все полностью offline т.к. есть все для этого необходимые части и все алгоритмы.
                  0
                  Можно попробовать прикрутить повторяющиеся напоминания, например: ходить в спорт зал каждую среду и пятницу начиная с…
                    0
                    «по 50 грамм и тост каждый полчаса в ближайшие три часа»
                    0
                    Почему именно бот? Есть разные блокноты, хранящие в себе кучу полезной и рассортированной информации.Для этих целей я использую Notion
                      0

                      Telegram — очень удобная платформа, можно с любого устройства взаимодействовать с чем-либо без приложения.


                      Я, например, настроил себе Gmail в телеграм и еще поднял внутренний бот для баг-репортов из одного проекта

                      +1
                      Очень крутой проект!

                      Для меня именно распознавание даты из обычного текста — главная киллер фича в Todoist
                      Сейчас ваш бот проигрывает ему лишь отсутсвием виджета
                        0
                        Вы молодец. Статье не хватает только неочевидного для некоторых людей, воспринимающих ботов как магию от Дурова, упоминания о том, что вам доступна контактная информация людей, пишущих боту и все их запросы, даже если вы её реально не читаете. Это вообще беда всех ботов — если для сайтов начали упоминать про куки, то в телеге доступно гораздо больше информации.
                          +1
                          Это правда, к сожалению я не могу закрыть самому себе доступ к своей базе данных.
                          И поэтому я и выложил весь исходный код проекта, чтобы каждый человек в случае необходимости мог развернуть подобного бота у себя.
                          Если кому-то интересно, то могу написать небольшую инструкцию в отдельном посте как развернуть этого бота на heroku совершенно бесплатно с бесперебойной работой 24/7.
                            0
                            И поэтому я и выложил весь исходный код проекта

                            Именно поэтому я и написал, что вы молодец.
                              0
                              Мне интересно узнать как залить на хероку чтоб он постоянно не падал.
                                0
                                Для развертки бота на хероку я написал подробную инструкцию.
                            0

                            Мне бы интеграцию с Google Calendar, украинский язык и аудиосообщения — и я бы пользовался)


                            Автор молодец. Лично я "тоже могу такое сделать", но взять идею, реализовать ее, сделать не только продукт "для себя" но и для многих пользователей и еще статью написать — могут единицы.

                              0

                              Хороший инструмент.
                              Нужно поправить его работу в соответствии с несколькими кейсами:


                              Заканчиваем спринт 10 августа в 11
                              Can not schedule for this date


                              Заканчиваем спринт десятого августа в 11
                              Can not schedule for this date


                              Заканчиваем спринт первого августа
                              Can not schedule for this date


                              Заканчиваем спринт у 31 июля в 20
                              Can not schedule for this date


                              Закончить спринт 10 августа 20 года в час дня
                              Can not schedule for this date

                                0
                                В данный момент чтобы сделать напоминание необходимо указать точный час.
                                Распознавание отдельных чисел как часов планируется добавить в виде дополнительной настройки, так как она может сильно загрязнять групповой чат.
                                0
                                Спасибо! аудио распознавание прям необходимо, иначе по трудозатратам равносильно заметке в календаре, а еще лучше к голосовой колонке впоследствии прикреплять с напоминанием в боте в телеграмме, для рабочих задач)
                                  0
                                  Поддержка распознавания голосовых сообщений добавлена.
                                0

                                Интересно, полезно)
                                Я планах есть интеграция с, к примеру, гугл календарем? Было бы очень удобно для наглядности в итоге.

                                  0
                                  С API гугл календаря не знаком, но как будет время постараюсь его изучить, и, возможно, добавлю боту возможность взаимодействия с календарем.
                                  +1
                                  Делал такое для Яндекс.Алисы почти год назад: habr.com/ru/post/471204
                                  Кажется даже больше вариантов учёл
                                  image
                                    +1
                                    Интересная статья, подчеркнул для себя важные моменты для переработки парсера в будущем, за что большое спасибо.
                                    А боту нужно просто час указать, сделано для того, чтобы в групповых беседах меньше реагировал и не так засорял чат:
                                    image
                                    0
                                    Добавлена функция повторного напоминания.
                                    Нажмите на кнопку под уведомлением чтобы бот напомнил о нём ещё раз через 5 минут.
                                    По прошествии 5 минут данная кнопка исчезнет автоматически.
                                    image

                                    image

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое