Хочу поделиться с вами опытом разработки телеграм-ботов. Расскажу историю своего продукта – что интересного было сделано, и какие вопросы пришлось решать в процессе разработки.
В конце 2016 года мне пришла идея создать конструктор уведомлений в Телеграм. В то время в ИТ-сообществе была довольно популярна тема настройки разных оповещений по событиям – при возникновении ошибок или для каких-либо алертов. Кроме того, я видел, что на Инфостарте уже есть популярные продукты, которые позволяют создавать рассылки через SMS и Email. А мне показалось логичным использовать для внутренних рассылок именно Telegram, потому что это дешевле SMS и удобнее Email.
Я накидал план реализации подсистемы со множеством фич. Как потом оказалось, какие-то из них можно было вообще не делать, но мною двигало желание прокачать свои навыки разработки на интересных лично мне задачах.
Идея состояла в том, чтобы дать возможность простому пользователю в режиме 1С:Предприятие создавать различные уведомления по событиям.
-
Для этого достаточно было двух справочников «События» и «Шаблоны сообщений». Создавалось событие, и на основании этого события создавался шаблон сообщения.
-
Предполагалась, что между 1С и Telegram будет реализована односторонняя связь – просто чтобы была возможность отправлять сообщения.
-
И основным вопросом для реализации первой версии продукта было то, что отправка сообщений в Telegram возможна только по ID пользователя, который никому не известен в отличие от вариантов с SMS и Email, когда координаты адресата заранее известны – это номер телефона и почта.
Получение ID пользователя
Я начал думать, как организовать этот процесс выяснения ID пользователя и придумал следующий вариант.
-
В первой версии был интерфейс, в котором пользователю в 1С предлагалось найти в Telegram бота по его имени и отправить ему предложенный код подтверждения.
-
А в 1С по нажатию кнопки «Проверить сообщение» забирались новые сообщения от бота, в сообщении искался заданный код подтверждения и если находила такое сообщение, то выводила информацию о найденном пользователе, и мы могли его привязать.
-
Привязка означала, что мы можем какой-то конкретный объект 1С, например, конкретный пользователь или контрагент (карточку контрагента) связать с ID конкретного пользователя бота.
Это работало, но пользователи часто хотели получать уведомления не в личку, а в группы. Например, компания хотела, чтобы бот отправлял уведомления по поступлению товаров в группу, где были все сотрудники отдела закупок. В связи с этим была добавлена возможность привязывать к справочникам 1С группы Telegram, а потом – каналы обоих видов – публичные и приватные.
И потом, когда для Telegram появились боты, которые позволяют просто узнать свой ID, пользователю можно было просто вручную вбить свой ID и привязать к нужному объекту в 1С.
Но было понятно, что все эти варианты больше подходят для внутреннего использования в компаниях, потому что эта операция по получению ID выглядит не очень дружелюбно.
Была задумка сделать авторизацию по номеру телефона. Плюс поступали запросы от пользователей подобного характера. Поэтому была разработана кнопка специального вида, которая позволяет отправить номер телефона текущего пользователя в чат.
При старте диалога с ботом пользователю сразу приходит эта кнопка. Если мы на нее нажмем, Telegram нас предупредит, что мы собираемся поделиться своим номером телефона.
Если мы нажмем кнопку «Поделиться контактом», Telegram просто отправляет в чат наш контакт.
В этот момент, когда бот получает контакт, и 1С обрабатывает это событие, мы ищем по всем объектам 1С, есть ли у них такой номер телефона, и, если есть, привязываем найденный объект к ID этого текущего пользователя.
Вот такая механика авторизации по номеру телефона.
Интересный момент: по кнопке отправки номера телефона в сообщении, по сути, приходит обычный контакт – это стандартный объект Telegram. Поэтому нужно обязательно проверять, кому он принадлежит.
Здесь на скриншоте показано, как мы проверяем, соответствует ли ID пользователя, который отправил контакт, ID, привязанному к этому контакту. Это нужно обязательно делать.
Подсистема уведомлений. События и шаблоны сообщений
Возвращаемся к подсистеме уведомлений. Один из основных ее объектов – это справочник «Событие».
Здесь можно выбрать вид события:
-
Проведение документа
-
Запись задачи
-
Запись элемента справочника
-
Регламентное задание (по расписанию)
В основном, сообщения в Telegram отправляются при проведении документов или записи справочников. Также можно было установить различные произвольные условия отбора – для этого динамически формировалось СКД на основании источника события.
На основании события создается шаблон сообщения.
В шаблоне мы можем использовать статический текст, включающий любые поля источника сообщения – в данном случае, источником является документ «Заявка на расход средств».
Если нам не хватает каких-то полей, мы можем зайти в режим редактирования схемы СКД и прямо в режиме 1С:Предприятие добавить нужные поля и потом их использовать в шаблоне.
Кроме текста, конечно, еще нужно указать получателей – ими могут быть какие-то поля источника (например, Ответственный или Контрагент). Либо конкретный элемент справочника, если мы просто хотим, чтобы такое сообщение приходило администратору или какому-то конкретному пользователю.
В первой версии я даже заморочился с интерфейсом выбора смайлов – очень много потратил время на реализацию этой штуки.
И потом в процессе развития и поступления обратной связи от пользователей уже добавил возможность выводить в текст сообщения табличных частей и отправки печатных форм – это тоже можно все в режиме конструктора настроить без знания программирования обычному пользователю
И в таком формате эта подсистема уведомлений использовалась. Но этого было недостаточно.
Кто-то из пользователей хотел получать некоторые поля сообщения в виде хештегов – с помощью хештега можно быстро находить сообщения в Telegram.
И тут я начал думать, как это реализовать универсально, потому что не хотелось каждый раз лезть в код конфигурации у клиента и там вносить изменения, а потом заниматься обновлениями. Пришла мысль, что можно сделать вызов функции прямо из шаблона сообщения. Это бы позволило не только превращать любое поле источника в хештег, но и выводить результат любой функции, которая уже есть в конфигурации.
Например, был кейс, когда у клиента в конфигурации была какая-то кастомная функция, получающая дебиторскую задолженность. И чтобы вывести ее в сообщение, достаточно было заключить ее в специальную конструкцию (скобки со знаком вопроса), вызвать ее и передать в эту функцию поле источника. Например, это может быть контрагент из текущего документа реализации.
В данном случае, на скриншоте мы видим вывод информации по истории бизнес-процесса согласования.
Если очень сильно заморочиться на хештегах, может получиться примерно такая история.
-
Сообщение в центре слайда – это то, что приходит из бота автомойки. Тут почти все в хештегах.
-
А справа – пример карточки бронирования из конфигурации 1С:Отель. Здесь мы видим вывод хештега #Бронирование и для примера номер комнаты выведен в виде смайлов.
Такие хештеги реализованы с помощью вызова функции прямо в шаблоне сообщения.
Пару слов о том, что можно было не делать.
-
В изначальной версии я также реализовал документ массовой рассылки – документ, с помощью которого можно было выбрать список контактов и отправить им одинаковое сообщение.
-
Отправка отчетов по расписанию тоже никому не зашла, никто не понял, в каких кейсах это можно использовать.
-
И была еще функциональность сбора отзывов. Ею тоже никто не пользовался, к сожалению, но наработки по сбору отзывов я в дальнейшем использовал для справочника «Клавиатуры» – чуть позже я покажу пример, как он работает.
Подсистема меню. Двусторонняя связь с Telegram
Логичным продолжением этой подсистемы уведомлений стала подсистема меню. Она родилась из потребности клиентов самостоятельно запрашивать отчеты. В отличие от уведомлений это подразумевало полноценную двустороннюю связь между 1С и Telegram.
Я начал думать, как можно это настроить. И тут возможные варианты – всем, я думаю, известны.
-
Это либо публикация базы на веб-сервере и получение сообщений от Telegram на Webhook.
-
Либо регламентное задание и получение новых сообщений методом getUpdates.
Webhook я изначально не стал рассматривать, потому что не хотел с каждым клиентом решать инфраструктурные вопросы – связываться с публикацией на веб-сервере и настройкой SSL. Это занимает очень много времени.
Поэтому я стал смотреть в сторону getUpdates. Для этого процесса настраивалось регламентное задание, которое с небольшим интервалом, например, каждые 5 секунд, стучалось методом getUpdates на сервер Telegram за очередной порцией сообщений.
Сразу было понятно, что в таком варианте, когда бот будет отвечать по 5 секунд на каждое сообщение, это мало кого устроит. И я стал разбираться.
Полез в документацию ботов, начал читать про метод getUpdates.
Там было написано, что вариант с регламентным заданием и опросом сервера – это, так называемый short polling, который должен использоваться только для тестовых целей.
В противовес short polling есть понятие long polling. Это рекомендуемый метод. Он подразумевает передачу параметра timeout вместе с методом getUpdates. Для сервера Telegram это будет означать, что он будет держать соединение до тех пор, пока либо не произойдет новое событие, либо не закончится таймаут.
Как реализовать это в 1С?
Тут снова не обойтись без регламентного задания, в котором нужно обязательно заполнить свойство Ключ – в этом случае, если уже есть запущенные задания с таким ключом, оно не будет стартовать, и не будет конфликтов методов.
В обработчике получения сообщений находится цикл, который можно прервать двумя способами:
-
либо по флагу в настройках – например, такое может понадобиться, если нужно обновлять базу или произвести какие-то другие действия;
-
либо по какому-то условию – например, если вы хотите, чтобы регламентное задание перезапускалось по истечению какого-то времени.
А в теле цикла размещаем процедуру ПолучитьНовоеСообщение(), где отправляем запрос getUpdates, не забыв указать параметр timeout – обычно рекомендуется 30 секунд, но я ставлю промежуток больше:
-
такое значение таймаута мы передаем в параметрах запроса getUpdates;
-
и на уровне 1С при создании HTTPСоединения мы также указываем такое же значение таймаута, чтобы 1С раньше времени не прервала соединение.
Мы получаем новое сообщение, его обрабатываем и следом сразу отправляем новый запрос на получение сообщения – таким образом получается обрабатывать события практически мгновенно, при этом не публикуя базу на веб-сервере.
Оптимизация скорости
Если хочется еще быстрее, тогда можно попробовать следующий вариант.
Кэширование HTTP-соединения на уровне 1С. Для этого нам просто нужно вынести процедуру создания объекта HTTPСоединение в общий модуль с включенным флагом «Повторное использование возвращаемых значений». Это позволит переиспользовать установленное один раз соединение с сервером Telegram – получается довольно ощутимая скорость отклика.
Второй метод, который позволяет не задерживать обработку сообщений – это использование фоновых заданий. При получении нового сообщения мы запускаем его обработку в фоне и, не дожидаясь его завершения, берем в работу следующее сообщение. Таким образом можно значительно увеличить пропускную способность бота, особенно, если вы отправляете клиентам тяжелые файлы, или, например, изображения.
К сожалению, на этом вопросы по получению событий из Telegram не закончились, потому что у многих компаний вообще нет сервера 1С, они работают на файловых базах. А на файловых базах постоянно запущенное фоновое задание не дает запускаться другим фоновым заданиям. В этом, в принципе, нет ничего страшного – если работа других регламентных заданий не нужна, можно работать. Но зачем отказываться от других заданий ради бота?
Поэтому я искал другие варианты, как можно обеспечить надежную и главное, быструю работу бота на файловой базе. И придумал создать отдельную утилиту на C#, которая держит long poll соединение с сервером Telegram, а события в 1С отправляет по COM-соединению.
Эту программку нужно держать включенной на любом компьютере, где есть доступ к файловой базе. Это довольно надежно работает и по скорости не уступает варианту на базе 1С – при этом, конечно, работа фоновых заданий не блокируется.
Многие мои клиенты продолжают работать на файловых базах и пользуются этим решением.
Справочник Меню. Настройка доступа
Возвращаемся к вопросу реализации отчетов по запросу пользователя.
Входной точкой для взаимодействия с ботом у меня является меню. Меню – это кнопки на месте клавиатуры. Так как хотелось максимально уйти от обновления конфигураций после внедрения был выбран вариант с отдельным справочником, через который можно настраивать состав кнопок, их внешний вид, и подвязывать алгоритм обработки ответов.
Пару слов по поводу доступов – доступ был сделан на основе справочника «Меню».
Если разделить всех возможных пользователей бота, получается примерно следующие категории:
-
Гости – те пользователи, которые нашли бота через поиск или перешли по прямой ссылке.
-
Пользователи, о которых что-то известно в 1С – это могут быть:
-
либо конкретные элементы справочников, например, элементы «Администратор» или «Директор» справочника «Пользователи»;
-
либо типы справочников, к которым мы можем привязывать ID пользователей бота – например, справочники «Контрагенты» или «Пользователи».
-
Как это все организовано? На базе справочника «Меню» мы можем создать различные пункты меню и предоставить для них разные доступы.
-
Например, для новых клиентов, о которых мы ничего не знаем, дать доступ на розничный прайс-лист.
-
Директору и бухгалтеру дать права на финансовые отчеты, выбрав их в доступе.
-
А, например, всем пользователям, которые привязаны к справочнику «Контрагенты» мы дадим возможность запрашивать, например, отчет по дебиторской задолженности, акт сверки или индивидуальный прайс-лист.
В процессе обработки получения нового сообщения мы будем знать, что текущий пользователь бота привязан к справочнику «Контрагенты» и, зная контрагента, к которому он привязан, можем определить для него возможные доступы.
Инлайн vs Обычные кнопки меню
Расскажу про различия между инлайн и обычными кнопками меню:
-
обычные кнопки меню у меня используются для доступа и для выбора режимов взаимодействия;
-
инлайн-кнопки привязываются к конкретному сообщению.
Основное различие инлайн и обычных кнопок заключается в том, что обычная кнопка отправляет в чат текст, который на ней написан.
А инлайн-кнопка отправляет данные, которые не видны пользователю и заданы для этой кнопки программно.
Поэтому инлайн-кнопки подходят для выбора элементов справочников. Если мы для этого будем использовать обычные кнопки, это будет ненадежно, потому что наименования объектов могут совпадать.
Например, я видел реализацию магазина в Telegram, в котором выбирать товар предлагалось через обычные кнопки, но искать по наименованию – это плохая идея. Плюс это неоправданно раздувает историю чата, а ценности никакой не несет.
В данных инлайн-кнопки можно хранить уникальный идентификатор объекта и получать по этому идентификатору однозначно объект в 1С. В итоге в парадигме моей подсистемы обычные кнопки – статичны, их набор задается через справочник, а инлайн-кнопки используются внутри сценариев, их можно динамически менять.
На слайде показано, как это выглядит.
Например, если мы хотим предоставить пользователю возможность выбрать один из складов, мы пишем запрос, в котором получаем нужные данные. После чего создаем конструктором таблицу с этими кнопками.
При создании кнопки обязательно нужно для нее установить:
-
текст – название склада, которое будет на ней написано;
-
и данные, которые будут не видны пользователю – там у меня идет четырехзначный код обработчика события и дальше через нижнее подчеркивание уникальный идентификатор ссылки на склад.
Код обработчика события – это код специального элемента справочника «Действия». Когда мы получим событие с этими данными, мы поищем, есть ли элемент с таким кодом в нужном справочнике. И, если мы его найдем, то выполним алгоритм, который написан в теле этого обработчика.
Вообще для обработки и написания скриптов используется два справочника:
-
в справочнике «Действие» определяются обработчики для обычных кнопок меню,
-
а справочник «Обработка callback» используется для обработки инлайн-событий.
В этих справочниках у меня есть возможность отредактировать запрос через схему СКД. Это очень удобно, потому что позволяет быстро накидать в режиме 1С:Предприятие запрос по извлечению нужных данных. Там же можно указывать какие-то параметры. Например, получить текущего пользователя – например, контрагента, и выбрать заказы, которые принадлежат только ему.
И затем в теле алгоритма мы можем получить эти данные с помощью специального метода.
По инлайн-кнопкам – есть множество возможностей. Основное – это то, что их можно менять динамически.
На скриншоте показан пример, как можно:
-
изменять клавиатуру;
-
изменять одновременно клавиатуру и текст сообщения;
-
или удалять клавиатуру.
Чуть позже мы посмотрим, как это будет выглядеть на реальных кейсах.
По инлайн-клавиатурам также есть ограничения.
-
Во-первых, в параметре data можно хранить только 64 символа.
-
Во-вторых, есть ограничение на количество кнопок в одной клавиатуре. В последний раз я столкнулся с тем, что лимит составлял 40 штук.
Но что делать, если нужно вывести весь справочник? Например, мы хотим предоставить клиенту возможность смотреть список всех своих заказов и скачивать накладные по ним.
Чтобы это сделать, нужно дать возможность листать результаты данных. Для этого был реализован метод «ПолучитьКлавиатуруСтраницы()».
-
В него мы передаем таблицу – те данные, которые мы будем использовать и отображать.
-
Вторым параметром – количество элементов на одной странице.
-
Третий параметр отвечает за номер отображаемой в данный момент страницы.
-
И дальше – коды обработчиков для кнопок «Назад» и «Далее».
Когда мы нажимаем на «Назад» и «Далее», мы снова получаем результат нужного запроса, переключаем нужную страницу – прибавляем или убавляем ее. И отправляем запрос на изменение инлайн-клавиатуры.
Продолжением этого механизма стало отображение каталога товаров.
Здесь все как в обычном справочнике – можно отобразить папки, элементы, прокручивать содержимое текущего каталога и перемещаться по иерархии папок.
Вот так это может выглядеть на реальном боте.
Мы здесь видим папки и конкретные элементы номенклатуры.
Можно перемещаться внутри каталога, проваливаться в папки – при этом мы в тексте сообщения видим, где мы находимся.
Есть отдельные кнопки для пролистывания каталога «Назад» и «Далее» и для перемещения по уровням иерархии «На уровень наверх».
При нажатии на карточку конкретного товара открывается его описание с изображением – вы можете указать количество и положить товар в корзину.
Как быстро создать согласование документа
Теперь посмотрим, как подсистема уведомлений и возможность создавать обработчики событий работают вместе.
Шаг 1. Мы создаем событие с видом «Проведение документа» и указываем тип документа – например, мы хотим согласовать заявку на расход средств.
Шаг 2. На основании этого события создаем шаблон. В нем прописываем текст сообщения и указываем получателя.
Шаг 3. Прикрепляем к шаблону сообщения элемент справочника «Клавиатуры», в котором добавлена одна кнопка «Согласовать» – в поле «Возвращаемое значение» пишем для нее код обработчика события. И устанавливаем здесь флаг «Обработать событие» – он при формировании этой клавиатуры автоматически добавит к обработчику события GUID текущего объекта.
Это позволит нам создать обработчик события с нужным кодом. В нем мы получаем ссылку по GUID-у объекта, производим какие-то действия, и потом можем отправить всплывающее сообщение о статусе операции и удалить клавиатуру, чтобы пользователь не мог ничего лишнего сделать с уже согласованным документом.
За четыре простых шага мы можем создать согласование любого документа – на слайде показано, как это будет выглядеть.
В момент, когда мы провели документ в 1С, в мессенджер автоматически приходит сообщение с одной кнопкой. Если мы на нее нажмем, то отобразится всплывающее сообщение и удалится клавиатура.
Кейсы
Теперь несколько кейсов из реальной практики.
Бот для отеля. Это – один из первых ботов, основанных на этой подсистеме, по запросу от этого клиента как раз-таки и была реализована возможность создавать кнопки.
Здесь мы видим:
-
многоуровневое меню с возможностью запроса различных отчетов;
-
и автоматические уведомления в группу администраторов по бронированию.
B2B-продажи. Бот для компании, которая занимается продажами видеооборудования. Основного смысл этого бота в том, чтобы дать возможность партнерам оформлять заказы и скачивать счета на оплату по различным типам цен.
-
Мы здесь видим пример перемещения по каталогу, получения карточки товара, добавления его в счет.
-
Можем поискать по наименованию, если мы заранее знаем, какой товар нам нужен – выбираем из предложенных найденных вариантов, получаем карточку товара, добавляем его в счет.
-
Запрашиваем корзину – можем ее просмотреть и очистить
-
Также можем сформировать заказ по кнопке «Сформировать отчет». При этом в 1С будет создан документ, и клавиатура изменится на предложенные типы цен, доступные этому клиенту – он сможет по нажатию на нужный тип цен скачать счет на оплату.
Бот для нескольких автосервисов. Здесь используется авторизация по номеру телефона клиента.
Т.е. клиент, по которому есть информация в 1С, может:
-
авторизоваться здесь в боте по номеру телефона, и ему сразу будет доступен остаток его бонусных баллов;
-
запросить штрихкод своей карты лояльности для зачета скидки на кассе;
-
и скачать свою сервисную книжку.
Кейс для сети ювелирных магазинов. Здесь множество кнопок, очень большое меню. Бот сделан как замена мобильному приложению, но я покажу только формирование отчета по остаткам с различными отборами.
Здесь есть различные категории отборов. Мы можем их отмечать и видеть сразу в тексте сообщения, какие категории мы выбрали для отбора. При этом категорий может быть много. Мы можем перемещаться, листать весь список возможных вариантов, отмечать или снимать флажки на разных страницах.
Когда мы отметим все, что нужно, и нажмем кнопку «Сформировать», нам придет отчет в pdf с выставленными отборами.
Работа при блокировке, и производительность при большой нагрузке
В период блокировки Telegram во все клиенты были добавлены настройки прокси-серверов.
Бесплатные прокси показали себя очень плохо, и те, кто хотел продолжать пользоваться ботами, покупали платные – с ними никаких проблем замечено не было.
Что касается нагрузки, самый нагруженный проект – поддержка для консультантов в сети ювелирных магазинов.
Там около 15 пользователей, которые постоянно загружают тяжелые отчеты в pdf и запрашивают карточки товаров с фотографиями – это невероятное количество событий от онлайн-кнопок.
При том, что для консультантов бот – главный источник информации о товарах, 1С успешно справляется с нагрузкой.
Другие мессенджеры
Другие мессенджеры я тоже рассматривал.
-
Пользователи спрашивали, можно ли было сделать интеграцию с чем-то более распространенным, чем Telegram, например, с ВКонтакте. Я сделал интеграцию с ВКонтакте, но по факту оказалось, что она никому не нужна
-
Viber – тоже достаточно распространенный мессенджер, но отличается очень непрозрачной политикой в отношении ботов. Там было много историй, связанных с разделением публичных аккаунтов и ботов. Сейчас они внедряют какие-то лимиты, после которого все сообщения от бота будут платные.
-
Telegram из всех мессенджеров отличается наиболее продвинутым API, поэтому я остановился на нем и другие мессенджеры не стал внедрять в подсистему.
Рекомендации и выводы
Рекомендации простые.
-
Как я уже сказал, если вы используете getUpdates, то делайте это правильно – через long polling.
-
По возможности, уделяйте больше внимания инлайн-кнопкам, чтобы не раздувать историю чата.
Я думаю, что за мессенджерами будущее как за средством коммуникации между клиентом и бизнесом.
И, хотя некоторые изначальные надежды на искусственный интеллект чат-ботов не оправдались (развитие этих технологий пока неточно интерпретирует запросы пользователей), боты в бизнесе приносят много пользы.
Поэтому нужно начинать с понятных кейсов для клиента – например, использовать мессенджер вместо SMS для получения кода скидки. Это позволит бизнесу экономить на SMS, а пользователь сможет получить контролируемый канал коммуникации с бизнесом.
*************
Данная статья написана по итогам доклада (видео), прочитанного на митапе Мессенджеры и 1С.