Процесс создания простого бота Телеграм для отслеживания времени

Сьогодні кожен має Telegram. Усі ми користуємося цим месенджером щодня - він зручний, простий у використанні, інтуїтивно зрозумілий, безпечний і, звичайно, ми всі любимо стікери. Крім особистих повідомлень, ми часто використовуємо групові чати - з родиною, друзями та колегами. Крім звичайних користувачів, є також бот API Telegram. Вони створені для автоматизації відповідей, тобто API-бот Telegram відповідає на конкретні повідомлення - команди та виконує певні дії.

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

Особисто я, постійно користуюся чат-ботом @vkmusic_bot_news. Це простий бот для пошуку та прослуховування музики. Користувач надсилає повідомлення з назвою композиції або автора, а API-бот Telegram надає варіанти, які відповідають запиту.

У своєму прикладі я запросив пісню «show must go on» і отримав кілька варіантів на вибір. Вибравши перший варіант, я отримав трек у наступному повідомленні. Зручно, що слухати музику можна прямо в чаті з ботом. Таким чином бот може повноцінно замінити сторонній додаток, наприклад плеєр на телефоні. Ви просто шукаєте та одразу слухаєте музику.

Отже, бачимо, що API телеграм-ботів є досить зручною та багатофункціональною функцією месенджера. Тому ця стаття присвячена створенню простого чат-бота. Я вирішив зробити примітивний таймтрекер, щоб показати вам приклад. Це найпростіший випадок взаємодії з API телеграми.

Просте створення Telegram Bot API

Отже, почнемо.

Ви можете знайти документи тут: https://core.telegram.org/bots/api.

Для початку необхідно створити та зареєструвати бота в Telegram. Давайте знайдемо ботів Father @BotFather. Це бот для реєстрації ботів.

Повідомляємо йому, що хочемо створити власного чат-бота:

    /newbot

Наступним запитом він просить створити назву для бота. Так як мій бот буде стежити за часом, я даю йому відповідне ім'я і пишу:

timeTrackerBot

Следующим шагом нужно задать юзернейм для бота (будет использоваться для поиска @username). Условие: username должен заканчиваться на bot или _bot. Пишу:

my_time_tracker_bot

Готово! У відповідь отримуємо токен, це означає, що ми зареєстрували нового чат-бота.

Розробка

Для початку я вирішив подивитися, які бібліотеки пропонує нам Інтернет. Варіантів безліч. З повним переліком запропонованих варіантів можна ознайомитися тут. Я вибрав TelegramBotApiBundle для Symfony. Встановлюємо:

    composer require borsaco/telegram-bot-api-bundle

і продовжуйте.

Пакет підтримує роботу з декількома телеграм-ботами API одночасно, крім того, є можливість налаштування (відправка тільки розробнику) і робота через проксі. Для тестового прикладу нам багато не потрібно, тому прибираємо непотрібне.

    config/packages/telegram.yaml

Я також переніс токен у змінну APP_TELEGRAM_TOKEN в .env

Трохи теорії

Telegram API, працює в двох режимах: ви можете отримувати оновлення з сервера через метод getUpdates() або налаштувати webHook. Перший варіант хороший, тому що він гранично простий, але його недолік в тому, що потрібно постійно запитувати сервер, чи є якісь оновлення. Варіант webHook дозволяє не думати про те, як отримати оновлення, а зосередитися на їх рендерингу. У цьому випадку Telegram сам надішле оновлення за вказаною нами URL-адресою.

Перевага другого підходу очевидна).

Щоб зареєструвати Webhook, ми зробимо наступне:

    $bot=$botService->getBot('timeTracker');$bot->setWebhook(['url'=>'https://myWebSite.com/webhook']);

Webhook у значенні url - це маршрут, який ми зробимо трохи пізніше. $botService - це об’єкт сервісу Borsaco\TelegramBotApiBundle\Service\Bot, який можна вставити в будь-яке місце проекту.

Важливо: Telegram API підтримує лише надсилання на https!

Давайте перевіримо наш Webhook: якщо ви надішлете повідомлення нашому телеграм-боту, він надішле нам у відповідь такий набір даних:

    {"update_id":21406673,"message":{"message_id":24,"from":{"id":701891111,"is_bot":false,"first_name":"aleksei","language_code":"ru"},"chat":{"id":701891111,"first_name":"aleksei","type":"private"},"date":1580672814,"text":"/help","entities":[{"offset":0,"length":5,"type":"bot_command"}]}}

Нас цікавить частина з текстом повідомлення. В даному випадку зрозуміло, що я надіслав бот «/help». Очевидно, він не відповідає.

Наявність суб'єктів у відповіді свідчить про те, що повідомлення було сприйнято ботом як команда (все, що починається зі слеша і написано латиницею, є командою для Telegram).

Давайте створимо контролер. Це буде точка входу для запитів від Telegram API, куди надходитимуть оновлення.

Для зручності я заношу всю логіку в сервіс MessageProcessor, куди передаю рядок, отриманий з Telegram.

Суть проста - є 4 команди: допомогти, запустити, зупинити, повідомити.

Кожна команда передбачає певну поведінку.

Також є 2 ситуації, коли відповідь скаже користувачеві, що ця дія на даний момент заборонена (поки таймтрекер не зупинено - запустити новий не можна. Відповідно, поки немає активності - зупинити нічого не можна).

Я додав такі суб'єкти:

    • Користувач, який має поля name, telegramId і collection timelines,
    • Часова шкала, яка має дату початку та дату завершення: startedAt, stopedAt.

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

Ми отримуємо рядок json, і перше, що я роблю, це декодую рядок і отримую об’єкт.

    $response= \json_decode((string)$telegramUpdate);

Далі перевіряю, чи є такий користувач у базі (дані про користувача, який написав боту, беруться з response-> message-> from). Якщо такого користувача немає, створюємо його.

Оскільки ми хочемо, щоб команди «help» і «/ help» сприймалися ботом однаково, ми перекладаємо текст повідомлення від користувача в нижній регістр і видаляємо звичайну та зворотну косу риску.

    $messageText=mb_strtolower($response->message->text);$messageText=str_replace([’\\’,’/’],’’,$messageText);

Тепер перевіряємо отриману команду - чи є вона в списку команд, які ми можемо обробити. І тепер, виходячи з того, що маємо, ми надсилаємо відповідь.

    $messageCommand=$this->isSupports($messageText) ? $messageText:false;

Якщо це команда «start» або «stop», ми створюємо часову шкалу для цього користувача або відповідно завершуємо поточну та інформуємо про це користувача.

Якщо це «report», ми обчислюємо час у всій шкалі часу на сьогодні та надсилаємо загальну кількість годин і хвилин користувачеві.

Ми надсилаємо повідомлення за допомогою методу sendMessage, який приймає масив параметрів. Обов’язкові параметри: «chat_id» і «text».

Оскільки це тестовий випадок, я обмежився простим switch / case для вибору команди.

    switch($messageCommand){caseself::HELP_COMMAND:$this->bot->sendMessage(['chat_id'=>$user->getTelegramId(),'text'=>self::ANSWERS[self::HELP_COMMAND]]);break;caseself::START_COMMAND:if($this->timelineService->doesActiveExist($user)){$this->bot->sendMessage(['chat_id'=>$user->getTelegramId(),'text'=>self::BAD_ANSWERS['existNotStoppedTimeLine']]);break;}$this->telegramService->startTimeForUser($user);$this->bot->sendMessage(['chat_id'=>$user->getTelegramId(),'text'=>self::ANSWERS[self::START_COMMAND]]);break;caseself::STOP_COMMAND:if($this->timelineService->doesActiveExist($user)){$this->bot->sendMessage(['chat_id'=>$user->getTelegramId(),'text'=>self::ANSWERS[self::STOP_COMMAND]]);break;};$this->bot->sendMessage(['chat_id'=>$user->getTelegramId(),'text'=>self::BAD_ANSWERS['timeLineNotFound']]);break;caseself::REPORT_COMMAND:$timeForToday=$this->timelineService->getTodayTotalByUser($user);$this->bot->sendMessage(['chat_id'=>$user->getTelegramId(),'text'=> \sprintf(self::REPORT_COMMAND,$timeForToday)]);break;default:$this->bot->sendMessage(['chat_id'=>$user->getTelegramId(),'text'=>self::ANSWERS[self::HELP_COMMAND]]);}

Загальний вигляд сервісу виглядає так:

Таким чином, у нас є бот, який допоможе відстежувати час протягом дня.

Висновок

Підводячи підсумки, можна сміливо сказати, що бот Telegram API досить функціональний і простий в освоєнні. Великою перевагою є хороша документація та готові бібліотеки, доступні для використання.