В этом цикле статей мы реализуем службу поддержки для онлайн-чатов. Система должна уведомлять команду операторов о новом сообщении, делить нагрузку на команду любого размера, делегировать сообщения в зависимости от приоритета. Звучит жутко. Но без паники, я поделюсь нашим опытом построения такой системы, которая уместилась всего в пару сотен строк кода. Да, мы будем использовать Telegram-бота. Но не потому, что это модно, а потому что супер удобно.


Всё началось с того, как мы захотели делать мобильное приложение, где люди могут писать любой вопрос в чаты заведений вокруг и получить быстрый ответ. Сделать чат — не проблема. Но что если мы хотим получать уведомления о новых сообщениях в real-time, для мгновенного ответа пользователю?

В первой части статьи я покажу на тестовом примере, как можно управлять системой службы поддержки через чат-бота, почему это очень простой и удобный способ. А во второй части статьи мы реализуем этот пример на Python.

Проблема и решение



Любая команда операторов службы поддержки должна отвечать на запросы оперативно, для этого её нужно оперативно уведомлять. Нет нужды придумывать что-то своё — любой современный мессенджер справится с этой задачей на ура. Я выбрал Telegram. Он удобен, работает на всех основных платформах, а функционал ботов опережает даже титанов рынка мессенджеров как минимум на год. К чему это я про ботов?

В нашем случае, бот представляет собой информационный канал, к которому легко можно подключать людей, с которым можно взаимодествовать текстовыми командами. После того, как мы создали бота, подключить к нему людей легко, достаточно кинуть им ссылку. Однако, наш бот исключительно для внутреннего использования. Нельзя допустить, чтобы кто угодно мог получить доступ по этой ссылке. Ссылку мы прятать надёжно не можем, а вот включать функционал специальной командой с подтверждением пароля — запросто.



Telegram бот позволяет задавать для бота свои текстовые команды. Делаем так: создадим команду "/on" которая «включает» функционал бота для пользователя. Но только после подтверждения паролем! Ну и на всякий случай можно предусмотреть команду "/off", которая отключает функционал.



Теперь наш бот знает группу людей — операторов службы поддержки. Пока что представим, что группа операторов у нас всего одна, каждый вопрос от клиента очень важен, поэтому будем рассылать уведомления всей группе. В этом нет никакой магии, конечно Telegram имеет апи для рассылки сообщений людям, подключившимся к нашему боту.



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

Система, которую мы разработали, работает корректно, когда оператор службы поддержки один. Безусловно, мы можем рассылать уведомления любому количеству людей. Но как понять, что кто-то уже отвечает на запрос клиента? Как распределять нагрузку, чтобы не возникло путаницы? Это мы будем делать в следующей статье с помощью… кнопок в чате. Не так давно Telegram опубликовал Bot Api 2.0. Теперь стало возможным добавлять кнопки к сообщениям и отслеживать нажатия на них пользователей. Чем мы и займёмся в следующей статье. Ну и скриншот для превью того, что мы будем делать.



Реализация



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

@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
    bot.reply_to(message, "Welcome to Support_Bot!")

Так выглядит код, который реагирует на команды "/start", "/help", а так же приветствует новых пользователей бота (при первом открытии бота автоматически посылается команда "/start").

@bot.message_handler(commands=['on'])
def subscribe_chat(message):
    if message.chat.id in team_users:
        bot.reply_to(message, "You are already an operator")
    else:
        user_step[message.chat.id] = TEAM_USER_LOGGING
        bot.reply_to(message, "Enter team secret phrase:")

Это уже обработка не стандартных команд ("/start" и "/help" есть по умолчанию у всех ботов). Мы создали обработчик команды "/on". После обработки мы просим ввести пароль.

@bot.message_handler(func=lambda message: user_step.get(message.chat.id) == TEAM_USER_LOGGING)
def team_user_login(message):
    if message.text == 'password1':
        team_users.add(TeamUser(message.chat.id))
        user_step[message.chat.id] = TEAM_USER_ACCEPTED
        bot.reply_to(message, "You`ve started receiving messages")
    else:
        bot.reply_to(message, "Wrong secrete phrase, try again")

Эта функция проверяет пароль на валидность. Но как понять, что последнее сообщение было паролем? В обработчике "/on" мы сохраняем статус диалога в глобальной переменной. Декораторы обработчиков сообщений могут принимать lambda-функции, в которые попадют входящие сообщения и если lambda-функция вернула True — идём в обработчик. На самом деле, в нашем случае текст сообщения не так важен, но мы проверяем статус глобальной переменной. Если пользователь до этого вызывал команду "/on" — значит нужно интерпретировать его сообщение, как пароль. Если пароль проходит проверку — сохраним так называемый chat id куда-нибудь, например в файл. С помощью этого id мы позже будем отправлять сообщения в чат оператору.

@bot.message_handler(commands=['off'])
def team_user_logout(message):
    if message.chat.id not in team_users:
        bot.reply_to(message, "You are not an operator anyway")
    else:
        team_users.remove_by_chat_id(message.chat.id)
        bot.reply_to(message, "You`ve stopped receiving messages")

Аналогично реализуем команду отключения оператора, который больше не хочет получать уведомления.

def process(message):
    text = '%s\n%s writes to %s\nReply: %s' %           (message, 'Vasya', 'Super Support Team', '*reply_url*')
    for user in team_users:
        bot.send_message(user.chat_id, text, disable_web_page_preview=True)

Ну и рассылка сообщений делается ещё проще. Так как в сообщениях мы можем передавать разную необходимую информацию, включая ссылки, не будем заставлять приложение Telegram пытаться распарсить их, это будет только мешать. С помощью флага disable_web_page_preview = True Telegram не будет пытаться проходить по нашим ссылкам и выдавать картинку превью в чате.

threading.Thread(target=bot.polling).start()

Запускаем бота одной строчкой (метод polling, ещё доступны webhook-и, но для начала этого хватит с головой).

В этой статье мы сделали бота, научили его добавлять операторов только после ввода пароля, так же научили его рассылать всем в группе операторов уведомления. Я буду продолжать цикл и расскажу, как убрать возможную путаницу «кто на какой запрос отвечает», как на основе бота сделать разбиение операторов на группы, делегирование сообщений определённой группе, а так же как отвечать на вопросы клиентов не выходя из Telegram чата. Подобную систему мы используем в работе нашего приложения (Android и iOS). Ну и, конечно, будем изучать новые классные фишки Telegram Bot API 2.0. Надеюсь, наш опыт будет полезен.
Поделиться с друзьями
-->

Комментарии (10)


  1. Tujh
    21.06.2016 13:14
    +2

    Картинки должны быть бОльших размеров, такие маленькие не все смогут рассмотреть на своих устаревших 4К мониторах.


  1. govorov
    21.06.2016 13:24

    Все с этим телеграмом нормально, но вот невозможность автоматического интеграционного тестирования ставит под сомнение нормальную разработку ботов на нем. Нельзя никак сделать так, чтобы для конкретного аккаунта (номера телефона) был заранее известный проверочный код. В данный момент его можно получить только в СМС. Когда они это допилят, если вообще собираются, тогда и про что-то серьезное можно будет на телеграме пилить.


    1. 12sd
      21.06.2016 14:08

      Можно его получить один раз и использовать всё время, не вижу причин не делать именно так на тестовом аккаунте/клиенте.


      1. govorov
        22.06.2016 12:16

        У меня есть билд-сервер, который гоняет интеграционные тесты для написанного мной бота. Суть каждого теста — с нуля создается бот с произвольным именем, тестовый пользователь заходит в инстаграмм и общается с этим ботом, мы проверяем, что бот корректно отвечает пользователю. Даже если как-то исхитриться и сделать так, чтобы тестового пользователя залогинить один раз и не убивать после каждого теста, а использовать снова и снова (что в общем-то противоречит духу тестирования, т.к. тесты не должны зависеть от результатов предыдущих тестов), то кейс, когда нужно проверить реакцию бота на то, что пользователь вышел, оказывается невозможно реализовать.


    1. Fedcomp
      21.06.2016 18:51

      Вы считаете что сервера телеграма не покрыты тестами?


      1. govorov
        22.06.2016 12:17

        Я про интеграционное тестирование своих ботов


  1. Natoriys
    22.06.2016 12:29

    Недавно реализовали интеграцию Telegram и 1C, авторизацию делали по телефону и сверяли в справочнике Пользователей (Телеграм шлет нам номер телефона мы его ищем в 1С и в зависимости от результата активируем или пользователя для работы с ботом).
    Интеграция реализована через промежуточную бд на mysql и скриптом на питоне.


    1. govorov
      23.06.2016 11:31

      Не совсем понял. У телеграмма есть API; для того, чтобы там авторизоваться нужен номер телефона. Процесс авторизации выглядит так: мы первым методом стучимся в API, он нам возвращает некий hash-ключ, потом мы вторым методом говорим, что хотим получить проверочный код через СМС, после получения СМС мы вызываем третий метод, передаем в него hash-ключ и проверочный код из СМС и получаем токен авторизации. После этого мы можем общаться с API телеграмма без ограничений. Как вы автоматизировали процесс получения проверочного кода?


      1. Natoriys
        23.06.2016 12:04

        Вы описали процесс авторизации в самом Телеграмме как я понял.
        Я же описал как мы авторизуем пользователей у себя в системе (уже установивших Телеграмм) для работы с нашим ботом. Для работы используем библиотеку TeleBot.

        Так же пробывали средствами 1С (регали бота и потом из 1С посредством HTTPЗапроса на api.telegram.org отсылали токен бота + ПараметрыЗапроса). Первый вариант показался наиболее удобным и быстрым по срокам для внедрения.
        Бота регали руками.


  1. evnik
    23.06.2016 11:15

    Под заголовком «бот для службы поддержки» ожидал прочитать об опыте создания бота заменяющего операторов-людей.
    Схема с паролем, сохраняющимся в истории, не выглядит надежной. Лучше уж присылать пользователю ссылку с токеном и аутентифицировать его в браузере, после чего сообщать боту, что пользователь доверенный.