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

Что такое Webhook?

Веб-перехватчики - это определяемые пользователем обратные вызовы HTTP. Веб-перехватчик - это HTTP-запрос, который отправляется автоматически при выполнении определенных критериев. Запрос выполняется как запрос HTTP POST. Веб-перехватчик может быть создан на любом языке программирования на стороне сервера, таком как Python, PHP или Node.js. Подробнее о webhook вы можете прочитать здесь.

Почему Webhook в DialogFlow?

Мы используем веб-перехватчики, когда хотим создать полезного чат-бота со сложными действиями или нам нужны динамические ответы. В Dialoflow веб-перехватчик может использоваться для получения данных с вашего сервера всякий раз, когда вызывается определенное намерение с включенным веб-перехватчиком. Информация из намерения передается службе веб-перехватчика для получения результата. (Подробнее об этом мы узнаем позже в этой статье)

На изображении ниже вы можете увидеть взаимодействие между DialogFlow и Webhook.

Необходимое условие

Прежде чем мы начнем, убедитесь, что вы установили следующие инструменты.

  1. Загрузите и установите python отсюда в соответствии с вашей поддерживаемой ОС.
  2. Убедитесь, что у вас правильная версия python, введя в командной строке приведенные ниже команды.
  3. Установите Flask с помощью следующей команды - pip install Flask
  4. Мы собираемся использовать Ngrok, который можно использовать для проверки веб-перехватчиков с вашего локального сервера. Вы можете скачать его здесь.

Теперь мы можем приступить к написанию кода для нашего проекта.

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

# Create folders
$ mkdir -p travel_assistance && cd travel_assistance && mkdir templates static
# Create files
$ touch index.py static/{custom.js,style.css} templates/index.html requirements.txt .flaskenv .env

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

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

Теперь скопируйте указанные ниже библиотеки в файл requirements.txt и добавьте следующие библиотеки, которые нам нужны.

Flask==1.0.2
requests==2.18.4
dialogflow==0.4.0
python-dotenv==0.8.2

Создание виртуальной среды:

Из командной строки перейдите в корневой каталог вашего проекта (travel_assistanse), а затем выполните следующую команду:

$ python3 -m venv env

or

$ python -m venv env

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

$ source env/bin/activate

Если вы используете Windows, активируйте виртуальную среду с помощью следующей команды:

$ env/Scripts/activate

Теперь давайте настроим среду Flask в .flaskenv, добавив следующие строки.

FLASK_APP=index.py
FLASK_ENV=development

Это даст указание Flask использовать index.py в качестве основного файла ввода и запустить проект в режиме разработки.

Теперь мы готовы написать код для Flask App. Скопируйте приведенный ниже код в файл index.py.

# /index.py
from flask import Flask, request, jsonify, render_template
import os
import dialogflow
import requests
import json
import pusher

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

# run Flask app
if __name__ == "__main__":
    app.run()

В приведенном выше коде мы создали корневой каталог «/», который будет отображать файл index.html, который находится в папке шаблонов.

Создание пользовательского интерфейса для нашего чат-бота Travel Assistance:

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

Теперь перейдите в файл templates / index.html и скопируйте в него приведенный ниже код.

<!doctype html>
<html lang="en">
  <head>
      <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    <title>Travel Assistance</title>
  </head>
  <body>
      <div class="container h-100">
        <div class="row align-items-center h-100">
            <div class="col-md-8 col-sm-12 mx-auto">
                <div class="h-100 justify-content-center">
                    <div class="chat-container" style="overflow: auto; max-height: 80vh">
                        <!-- chat messages -->
                        <div class="chat-message col-md-5 offset-md-7 bot-message">
                          Welcome to Travel portal. How can I help you?
                        </div>
                    </div>
                    <form id="target">
                       <input class="input" type="text" value="" placeholder="Enter message..." id="input_message"/>
                       <input type="submit" hidden>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
    <script src="{{ url_for('static', filename='custom.js')}}"></script>
  </body>
</html>

В приведенном выше HTML-коде мы используем Bootstrap. В приведенном выше коде мы импортировали CDN в стиле Bootstrap, и позже мы используем его при создании файлов jquery и custom.js. При загрузке страницы отображается приветственное сообщение по умолчанию.

Теперь скопируйте следующий код в свой файл static / style.css:

body,html {
  height: 100%;
}

.chat-container {
  /*margin: 0px;*/
  padding: 0px;
  width: 500px;
  /*margin: 35px 0px;*/
  margin-left: 15%;
  margin-right: 15%;
}

.chat-message {
  padding: 6px;
  border-radius: 6px;
  margin-bottom: 3px;
}

.bot-message {
  background: #22b538;
  max-width: 300px;
  color: white;
  margin-left: auto;
}

.human-message {
  background: dodgerblue;
  max-width: 300px;
  color: white;
  margin: 13px 1px;
}

.input {
  width: 500px;
  /*margin: 35px 0px;*/
  margin-left: 15%;
  margin-right: 15%;

Теперь наш пользовательский интерфейс готов.

Теперь установите библиотеки в requirements.txt:

pip install -r requirements.txt

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

 flask run

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

Приложение работает на порту 5000, мы могли видеть наше приложение с приветственным сообщением по адресу http://127.0.0.1:5000/.

DialogFlow-Fulfillment:

Включение веб-перехватчика для намерений:

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

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

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

Сделайте то же самое для Забронировать билет на самолет - никаких дополнительных намерений.

Получение ключей API:

Чтобы использовать библиотеку DialogFlow Python, требуется ключ API. Значит, нам нужно это получить.

  1. Зайдите в Google Cloud Platform.
  2. Выберите название нашего проекта бота - Путешествия (оно совпадает с именем, которое мы дали нашему агенту)

3. Скопируйте свой идентификатор проекта и добавьте его в файл . env, как показано ниже:

DIALOGFLOW_PROJECT_ID = ‹идентификатор вашего проекта›

4. Затем перейдите в API и службы, затем Учетные данные.

5. В разделе Создать учетные данные нажмите Ключ служебного аккаунта.

6. В разделе Создать учетные данные нажмите Ключ служебного аккаунта.

7. Затем выберите JSON в разделе Тип ключа.

8. Наконец, нажмите кнопку Создать, чтобы загрузить свой ключ API.

Ваш ключ API будет загружен автоматически.

Теперь скопируйте загруженный файл JSON (Travel - ****. Json) в корневую папку проекта - travel_assistance.

* Этот файл JSON является вашим закрытым ключом, не фиксируйте его в каких-либо общедоступных репозиториях.

9. Затем добавьте путь к файлу в файл .env:

GOOGLE_APPLICATION_CREDENTIALS=<your JSON file>

Когда пользователь просит нашего бота забронировать билет на самолет, он определяет намерение пользователя и, получив все необходимые параметры, отправляет запрос на наш веб-перехватчик с этими параметрами (город, дата и т. Д.). Используя эти параметры, мы отправим ответ пользователю.

Теперь давайте создадим новый маршрут, который мы будем использовать в качестве нашего веб-перехватчика. Добавьте следующий код в index.py:

@app.route('/webhook', methods=['POST'])
def webhook():
    data = request.get_json(silent=True)
    if data['queryResult']['queryText'] == 'yes':
        reply = {
            "fulfillmentText": "Ok. Tickets booked successfully.",
        }
        return jsonify(reply)

    elif data['queryResult']['queryText'] == 'no':
        reply = {
            "fulfillmentText": "Ok. Booking cancelled.",
        }
        return jsonify(reply)

Ответы Webhook должны быть в правильном формате JSON, чтобы DialogFlow мог понять, что отображать пользователю. Перейдите в консоль DialogFlow, и вы можете проверить, отправив сообщения с правой стороны экрана.

Нажав кнопку ДИАГНОСТИЧЕСКАЯ ИНФОРМАЦИЯ, мы можем просмотреть все сведения о запросе, отправляемом из DialogFlow, и ответе, отправленном с нашего веб-перехватчика. ДИАГНОСТИЧЕСКАЯ ИНФОРМАЦИЯ также может быть очень полезна для отладки вашего веб-перехватчика.

Запустите веб-перехватчик с помощью Ngrok:

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

Почему именно Нгрок?

DialogFlow не поддерживает localhost. Чтобы интегрировать его как веб-перехватчик для DialogFlow, нам нужно сделать его живым.

В моем случае я буду использовать Ngrok, чтобы открыть доступ в Интернет к веб-серверу фляги, работающему на моем локальном компьютере. Я просто говорю Ngrok, какой порт прослушивает веб-сервер (5000).

Чтобы запустить Ngrok, выполните следующую команду в текущем рабочем каталоге:

ngrok http <port_number>

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

Скопируйте ссылку https:, созданную ngrok.

Настройте веб-перехватчик в DialogFlow:

Перейдите в консоль DialogFlow и перейдите на вкладку Выполнение на левой боковой панели. Затем включите веб-перехватчик и введите свою ссылку на ngrok, а затем веб-перехватчик с «/».

<ngrok link>/webhook

Как отправлять сообщения в Dialoflow и отображать ответы?

Когда пользователь отправляет сообщение, мы отправляем его в Diagflow, чтобы определить намерения пользователя. DialogFlow обработает текст, а затем отправит ответ выполнения.

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

Добавьте следующий код в свой файл index.py:

def detect_intent_texts(project_id, session_id, text, language_code):
    session_client = dialogflow.SessionsClient()
    session = session_client.session_path(project_id, session_id)

    if text:
        text_input = dialogflow.types.TextInput(
            text=text, language_code=language_code)
        query_input = dialogflow.types.QueryInput(text=text_input)
        response = session_client.detect_intent(
            session=session, query_input=query_input)
        return response.query_result.fulfillment_text

Наконец, давайте создадим маршрут, по которому будет отправлен этот текст. Добавьте следующий код в index.py:

@app.route('/send_message', methods=['POST'])
def send_message():
    message = request.form['message']
    project_id = os.getenv('DIALOGFLOW_PROJECT_ID')
    fulfillment_text = detect_intent_texts(project_id, "unique", message, 'en')
    response_text = { "message":  fulfillment_text }
    return jsonify(response_text)

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

Теперь давайте напишем код для отображения сообщений в файле static / custom.js.

Добавьте следующий код в файл custom.js:

function submit_message(message) {
        $.post( "/send_message", {message: message}, handle_response);

        function handle_response(data) {
          // append the bot repsonse to the div
          $('.chat-container').append(`
                <div class="chat-message col-md-5 offset-md-7 bot-message">
                    ${data.message}
                </div>
          `)
          // remove the loading indicator
          $( "#loading" ).remove();
        }
    }

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

Затем мы будем использовать jQuery для отправки сообщения на наш маршрут / send_message-, откуда оно будет обработано.

Теперь добавьте следующий код в файл custom.js:

$('#target').on('submit', function(e){
        e.preventDefault();
        const input_message = $('#input_message').val()
        // return if the user does not enter any text
        if (!input_message) {
          return
        }

        $('.chat-container').append(`
            <div class="chat-message col-md-5 human-message">
                ${input_message}
            </div>
        `)

        // loading 
        $('.chat-container').append(`
            <div class="chat-message text-center col-md-2 offset-md-10 bot-message" id="loading">
                <b>...</b>
            </div>
        `)

        // clear the text input 
        $('#input_message').val('')

        // send the message
        submit_message(input_message)
    });

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

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

В webhook вы можете написать свою собственную логику для получения динамических ответов. Например, если пользователь хочет забронировать 100 авиабилетов, а затем нам нужно получить количество билетов в качестве параметра, подтвердить с максимальным лимитом и отобразить что-то вроде «Извините, за раз можно забронировать максимум 7 мест».

Итак, в этом руководстве мы узнали, как создать чат-бота, используя python flask и DialogFlow. Надеюсь, это поможет вам создать собственного чат-бота. Удачи!

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

Автор этой истории Вену Вака. Вену - инженер-программист и энтузиаст машинного обучения.