Создание бота для Viber

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

Существует два типа ботов:

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

Рассмотрим создание бота для получения списка вакансий нашей компании. Для работы с ботом будем использовать кнопки ответов, чтобы упростить взаимодействие с ботом.

Работу начнем с изучения официальной документации Viber, она находится тут:

https://developers.viber.com/docs/.

В компании Viber позаботились о разработчиках, которые захотят создать новых viber-ботов, и создали для популярных языков программирования уже готовые библиотеки, в которые инкапсулированы сложные операции по работе с сервисом Viber, что значительно упрощает разработку ботов.

В данный момент имеются библиотеки для Python и Node.JS.

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

Процесс создания бота разделим на несколько шагов:

  1. Создание бота в сервисе Viber.
  2. Создание каркаса бота на Python.
  3. Настройка бота под конкретные сообщения.
  4. Использование ngrok для локальной разработки.
  5. Пример работы.

Создание бота в сервисе Viber

Для это требуется перейти по ссылке: https://partners.viber.com/account/create-bot-account и заполнить все необходимые поля формы. После успешного заполнения данных, будет создан бот и автоматически сгенерируется токен (обязательно сохраните его - он будет использоваться для аутентификации).

Создание каркаса бота на Python

Установим библиотеку для бота от viber:

pip install viberbot

Версия python для этой библиотеки должна быть выше 2.7.

В качестве фреймворка для python возьмем легковесный Flask:

pip install Flask

Создадим и сконфигурируем нашего бота:

viber = Api(BotConfiguration(
    name='Smyt Career\'s Bot',
    avatar='',
    auth_token='your auth token'
))

Создадим каркас для обработки сообщений пользователя:

    if not viber.verify_signature(request.get_data(), request.headers.get('X-Viber-Content-Signature')):

        return Response(status=403)

    # this library supplies a simple way to receive a request object

    viber_request = viber.parse_request(request.get_data())

    if isinstance(viber_request, ViberMessageRequest):
        message = viber_request.message 
        viber.send_messages(viber_request.sender.id, [
            message
        ])

    elif isinstance(viber_request, ViberSubscribedRequest):
        viber.send_messages(viber_request.user.id, [
            TextMessage(text="thanks for subscribing!")
        ])

    elif isinstance(viber_request, ViberFailedRequest):
        logger.warn("client failed receiving message. failure: {0}".format(viber_request))

    return Response(status=200)

Для каждого сообщения пользователя выполняется проверка на подлинность с помощью токена. Также определяется тип сообщения пользователя:

  • простое сообщение пользователя;
  • запрос на подписку;
  • ошибка в запросе.

В зависимости от типа сообщения система реагирует.

В нашем примере пользователю, в ответ на его сообщение, отправляется то же самое сообщение.

Создание http-сервера

Для работы бота ваш http-сервер обязательно должен быть защищен ssl-шифрованием.

Так выглядит запуск сервиса у меня:

from flask import Flask, request, Response

app = Flask(__name__)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8443, debug=True)

Обращаю внимание, что это только ознакомительный пример и бота я запускал на локальном компьютере, поэтому не заполнил данные для ssl. Имеется возможность указать ssl-сертификат через параметр ssl_context.

Установим веб-хуку

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

Первый - через python:

viber.set_webhook('https://mybot.com/')

Второй - отправить запрос на установку веб-хука вручную; например, используя программу Postman.

Установим заголовки:

где X-Viber-Auth-Token – токен, полученный ранее.

Текст сообщения:

В переменной event_types мы можем указать на какие типы событий наш бот будет реагировать.

После этого бот уже будет рабочим и вы сможете отправлять сообщения через приложение viber, а он будет вам отвечать.

Настройка бота под конкретные сообщения

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

Например, у нас должна быть кнопка поиска вакансий, для этого добавим следующий код:

{
            "DefaultHeight": True,
            "BgColor": "#FFFFFF",
            "Type": "keyboard",
            "Buttons": [
                {
                    "Columns": 6,
                    "Rows": 1,
                    "BgColor": "#e6f5ff",
                    "BgLoop": True,
                    "ActionType": "reply",
                    "ActionBody": "search_vacancies",
                    "ReplyType": "message",
                    "Text": "Поиск вакансий"
                }
            ]
        }

Если нужно добавить несколько кнопок, то их нужно перечислить в списке Buttons.

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

  • она будет занимать 6 колонок и 1 строку;
  • иметь определенный цвет фона;
  • какой вид действия используется при нажатии;
  • задано сообщение, которое будет посылаться на сервер при нажатии;
  • задан тип сообщения;
  • указан заголовок кнопки.

Так как в ActionBody указывается сообщение, которое будет отправлено на сервер при нажатии пользователем соответствующей кнопки, я решил использовать ActionBody для определения типа ответа от пользователя и самого ответа. Для этого использовал такую структуру:

ActionBody: action_type|value или просто action_type.

Рабочие примеры: 

ActionBody: select_country|Russia
ActionBody: search_vacancies
ActionBody: select_level|’’

Также хочу отметить, что нам необходимо запоминать ответы, которые дает пользователь. Это можно сделать несколькими способами. Я решил эти данные сохранять в параметр сообщения tracking_data.

Это поле может содержать только строковые значения, поэтому сохраним данные в json, а передавать их пользователю будем через параметр tracking_data в виде строки, путем преобразования json.dumps() и обратно через json.loads().

Вот пример работы с сообщениями пользователя:

        keyboard = {
            "DefaultHeight": True,
            "BgColor": "#FFFFFF",
            "Type": "keyboard",
            "Buttons": [
                {
                    "Columns": 6,
                    "Rows": 1,
                    "BgColor": "#e6f5ff",
                    "BgLoop": True,
                    "ActionType": "reply",
                    "ActionBody": "search_vacancies",
                    "ReplyType": "message",
                    "Text": "Поиск вакансий"
                }
            ]
        }
        is_finished = False
        buttons = {}

        if text_type == 'search_vacancies':
            tracking_data = {}
            countries = [country[1] for country in COUNTRIES]
            text_message = 'Доступны вакансии в следующих странах: {countries}. Пожалуйста, выберите одну из них.'\
                .format(countries=', '.join(countries))
            buttons = get_buttons('select_country', COUNTRIES)

        elif text_type == 'select_country':
            tracking_data['country'] = text[1]
            items = [item[1] for item in PROFILES]
            text_message = 'Доступны вакансии по следующим профилям: {profiles}. Пожалуйста, выберите один из них.'\
                .format(profiles=', '.join(items))
            buttons = get_buttons('select_profile', PROFILES)

        elif text_type == 'select_profile':
            tracking_data['profile'] = text[1]
            items = [item[1] for item in LEVELS]
            text_message = 'Укажите пожалуйста какой у вас опыт в этой области: {items}. Пожалуйста, выберите один из них.'\
                .format(
                items=', '.join(items))
            buttons = get_buttons('select_level', LEVELS)

        elif text_type == 'select_level':
            is_finished = True
            tracking_data['level'] = text[1]

        else:
            text_message = "Выберите опцию"

        messages = []

        if is_finished:
            response = requests.get(VACANCIES_URL, params=tracking_data)
            json_response = response.json()
            items = json_response.get('results', [])
            for item in items:
                messages.append(URLMessage(media=item.get('url'),
                                           keyboard=keyboard,
                                           tracking_data={}))

            if not messages:
                messages.append(TextMessage(text='Извините, по выбранным критериям, вакансий не найдено.',
                                            keyboard=keyboard,
                                            tracking_data={}))

        else:
            keyboard_buttons = keyboard.get('Buttons', [])
            keyboard_buttons.extend(buttons)
            keyboard['Buttons'] = keyboard_buttons
            keyboard = keyboard if keyboard.get('Buttons') else None
            tracking_data = json.dumps(tracking_data)
            messages.append(TextMessage(text=text_message,
                                        keyboard=keyboard,
                                        tracking_data=tracking_data))

        viber.send_messages(viber_request.sender.id, messages)

В вышеприведенном фрагменте кода происходит следующее: определяется тип отправленного сообщения пользователем, к примеру 'search_vacancies' - значит запустить процедуру выбора параметров для поиска вакансий; следующим шагом нужно показать выбор страны в виде кнопок и таким же способом далее выбирается профиль и опыт, как только все параметры выбраны, то посылается запрос на сервер и результаты с вакансиями отображаются ботом.

Также, хочется отметить, что Бот может отправлять следующие сообщения:

  1. Обычное текстовое – TextMessage(text=’some text’).
  2. Сообщение-ссылка – URLMessage(media=’http://mysite.com’).
  3. Контактное сообщение – ContactMessage(contact=contact), где contact объект вида Contact c параметрами name, phone_number, avatar.
  4. Сообщение-картинка – PictureMessage(media=’http://picture.url.com’).
  5. Видео сообщение – VideoMessage(media=’http://video.url.com’, size=1234).
  6. Сообщение о местоположении – LocationMessage(location=location), где location – объект вида Location с указанием координат широты и долготы.
  7. Стикер – StickerMessage(sticker_id=123), где sticker_id это ид конкретного стикера.
  8. Файл – FileMessage(media=’http://path/to/file’, size=123, file_name=’file name’).
  9. Сложное медиа-сообщение – RichMediaMessage(rich_media=json_object), более подробно можно посмотреть в документации, можно вывести несколько объектов вида: картинку с текстом и ссылкой, таким образом организовать некую «карусель» объектов.
  10. Hotkeys для пользователя – KeyboardMessage – это такие кнопки которые мы делали для ответа пользователям.

Использование ngrok для локальной разработки

Как я отмечал выше, чтобы ваш сервис работал с Viber, он должен быть запущен через ssl (самоподписанные сертификаты работать не будут, нужен хотя бы let’s encrypt).

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

Установка ее очень простая: достаточно посетить сайт https://ngrok.com/.

С помощью нее вы можете пробросить свой локальный порт наружу даже с защищенным туннелем. Мой сервис локально был развернут на 8443 порту, поэтому я запустил ngrok cо следующими параметрами:

./ngrok http 8443

После это получаем такую информацию:

Тут видно что по адресу https://4c4b93d5.ngrok.io доступен мой сервис с ботом.

Этот адрес сервера нужно отправлять при установке хука инициализации бота.

Пример работы

После нажатия кнопки (Поиск вакансий):

создать чат-бот смит компания

После выбора страны (Россия):

создать чат-бот smyt компания

После выбора профиля деятельности (Разработка):

создание чат-бота смит компания

После указания опыта работы(Неважно) получаем такие результаты:

создание чат-бота smyt компания

По нашему запросу нашлась одна вакансия.

К сожалению, мы самостоятельно не можем добавить нашего бота в общий список всех доступных ботов и даже не можем дать на него прямую ссылку, а все потому, что у компании Viber строгие требования к чат-ботам и нужно обращаться в компанию Viber с просьбой о подтверждении (судя по статьям в интернете, такое подтверждение удается получить только крупным компаниям).

 

Полный код бота доступен по адресу:

https://github.com/akapitonov/simple-viber-bot

  python, viber

  Смотреть все посты