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

На этом мы завершаем нашу тревогу (!) и узнаем все о выполнении в Dialogflow.

С возвращением и вау - если вы здесь, потому что дочитали Часть 1 и Часть 2 этой серии, я вам аплодирую. Вы обладаете завидной выносливостью или вам действительно трудно просыпаться по утрам.

Но, если вы попали сюда каким-то другим путем, в некотором контексте: это третья часть серии статей, в которых объясняется, как создать говорящий будильник, который будит вас, задавая такие вопросы, как: Что такое 8923 умножить на 2893084? Это также подлый хороший способ узнать кое-что о некоторых продвинутых концепциях Dialogflow (структура Google для создания чат-ботов на базе искусственного интеллекта), таких как выполнение, триггеры событий и сложные логические потоки. Если вы новичок в Dialogflow, обязательно сначала ознакомьтесь с этими более ранними сообщениями.

А теперь займемся постройкой будильника!

В частях 1 и 2 мы узнали, как:

  1. Создайте голосовой пользовательский интерфейс для настройки сигналов тревоги в Dialogflow и
  2. Разверните этот «VUI» на Raspberry Pi (или Macbook, или на настольном компьютере, или на чем-то еще).

Самым сложным из этих двух частей, вероятно, было выяснить, как получить потоковую передачу Dialogflow на компьютере (см. Некоторые дополнительные материалы). Помимо этого более сложного раздела, агент Dialogflow, устанавливающий будильник, который мы создали в Части 1 (предназначенный для распознавания таких фраз, как Установить будильник на 8 утра или Удалить мой будильник), был довольно простым с точки зрения агентов Dialogflow.

Но теперь нам нужно построить настоящую забавную часть этого будильника - пустяковую часть! План состоит в том, чтобы создать второй агент Dialogflow (назовите его что-то вроде TriviaGame), который работает следующим образом:

Агент: «ДОБРОЕ УТРО! ДОБРОЕ УТРО! ПРОСНИСЬ! ПРОСНИСЬ! ПРИШЛО ИГРАТЬ В ПУТЕШЕСТВИЕ! »

Спящий: «Отложить».

Агент: «Извините, я пока не поддерживаю эту функцию, бездельник. Пришло время поиграть в мелочи. Ваш первый вопрос: что такое 9 плюс 11? "

Спящий: «Отложить».

Агент: "ЧТО ТАКОЕ 9 ПЛЮС 11?"

Спящий: «Хорошо. Это 20. "

Агент: «Молодец, верно! Ваш следующий вопрос: сколько 38 умножить на 289? "

Спящий: * вздох *

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

Идея здесь в том, что мы установим время будильника с помощью первого агента Dialogflow (например, «Установить будильник на 8»), а затем, когда оно станет 8, мы запустим потоковую передачу нового агента Dialogflow, запрашивающего викторины.

Итак, давайте продолжим и создадим наш новый агент Dialogflow для мелочей.

Создание агента Dialogflow Trivia

Для начала создайте новый агент Dialogflow Agent с названием что-то вроде TriviaGame. Когда вас спросят, хотите ли вы создать новый проект GCP вместе с этим агентом, ответьте да (в настоящее время проект GCP может поддерживать не более одного агента Dialogflow). Если вам нужно напомнить, как создать новый агент Dialogflow, прочтите Часть 1.

Если вы еще этого не сделали, клонируйте Репозиторий Github Talking to Machines:

git clone [email protected]:dalequark/talking_to_machines.git

Папка trivia_alarm в этом репозитории содержит весь код, который вам понадобится для работы с мелочами. Вот и будет файл TriviaAgent.zip. Этот файл содержит все сущности и намерения, которые вам понадобятся для нашего нового агента Dialogflow. Чтобы импортировать его в свой агент, щелкните значок шестеренки в левой панели диалогового окна, затем щелкните «ИМПОРТ ИЗ ZIP» и выберите файл TriviaAgent.zip.

Как только этот zip-файл будет импортирован, перейдите на вкладку «Намерения» и осмотритесь. Вы должны увидеть шесть намерений:

Вы заметите Default Welcome Intent, который поставляется с каждым агентом Dialogflow, который отвечает на такие фразы, как «Привет» и «Как дела?»

Также существует намерение Ask Question, которое отвечает за то, чтобы задавать пользователям мелкие вопросы. Если вы наберете что-то вроде «Давайте поиграем в мелочи» на правой панели тестовой консоли Dialogflow, вы активируете это намерение:

Обратите внимание, что, хотя ваш агент распознает ваше намерение как намерение «Задать вопрос», на самом деле он еще не задает вам никаких пустяковых вопросов. Это потому, что мы еще не реализовали вопросы!

Вы также можете сказать что-нибудь вроде «Отложить», «Позже» или «Я не хочу играть». Все они будут соответствовать Snooze намерению, которое мы будем использовать, чтобы напомнить пользователю, что ему некогда откладывать сон.

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

Наконец, если вы попытаетесь ввести что-то вроде «Ответ 7» в консоли Dialogflow, вы совпадете с намерением «Ответить на вопрос».

На самом деле, если вы вернетесь и попробуете фразу gobbledy gobbledy goop или Что такое любовь? вы обнаружите, что они также соответствуют намерению Answer Question. Это потому, что Answer Question на самом деле скрытно является запасным намерением! Помните те из части 1? Это намерения с подстановочными знаками, которые сопоставляются, когда Dialogflow не находит альтернативного сопоставления намерений. Вы можете проверить это, щелкнув намерение Answer Question в консоли Dialogflow:

Здесь мы решили сделать Answer Question резервное намерение, потому что мы предполагаем, что все, что говорит пользователь, не соответствует альтернативному намерению (т. Е. Не «Отложить» или «Следующий вопрос»), является попыткой пользователя ответить на вопрос. Это немного похоже на хитрость, но работает!

Пока что, только с этими намерениями, у нас есть скелет викторины. Но чтобы заставить эту вещь работать, нам нужно окунуться в некоторые более «продвинутые» концепции Dialogflow, такие как Выполнения!

Что такое Dialogflow Fulfillations?

Когда пользователь взаимодействует с голосовым помощником или чат-ботом, они обычно ожидают, что он что-то сделает за них. Например, в частях 1 и 2 мы создали голосового помощника, который, когда пользователь говорит: «Установите будильник на 8 часов утра», затем устанавливает будильник на 8 часов утра. В этом случае мы передавали Dialogflow через Raspberry Pi с помощью Node.js и выполнили запрос пользователя на установку будильника в этом коде Node.js, запущенном на устройстве.

Есть еще один способ добавить код в Dialogflow, чтобы он был динамичным и полезным, и он называется Выполнение. Идея заключается в следующем: когда ваш агент DF соответствует намерению, вместо того, чтобы отвечать жестко закодированным ответом (как на изображении, написанном ниже), ваш агент отправляет запрос коду, который выполняется в облаке.

Например: вы можете создать агента, который, когда вы спросите: «Какая сегодня погода?», Будет использовать код выполнения для вызова API погоды и возврата динамического ответа (например, «Сегодня 68º в Остине, штат Техас»). Или, когда вы спросите: «Когда я забронирую ужин?», Ваш агент может запросить базу данных и ответить: «Похоже, у вас забронирован столик на сегодня в 19:00». Возможности безграничны! В нашем случае мы будем использовать Fulfillments для динамической генерации пустяковых вопросов и проверки ответов пользователей.

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

Что такое события Dialogflow?

Обычно мы сопоставляем намерения в Dialogflow, говоря что-то, то есть фраза Я хочу спать соответствует Snooze намерению нашего будильника. Однако намерения также могут быть инициированы с помощью Dialogflow События. Из документации:

Есть два типа событий:

События платформы: эти встроенные события предоставляются интеграциями платформы. Они вызываются, когда происходят события, зависящие от платформы. Например, событие FACEBOOK_LOCATION вызывается интеграцией Facebook, когда конечный пользователь принимает или отклоняет запрос местоположения конечного пользователя.

Пользовательские события: это события, которые вы определяете. Вы можете вызывать эти события, используя выполнение или API. Например, вы можете установить временное оповещение во время разговора, которое вызывает событие в определенное время. Это событие может вызвать намерение, которое о чем-то предупреждает конечного пользователя.

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

Звучит безумно? Это! Не знаете, зачем вам вообще нужно делать что-то подобное? Понятно. Но оказалось, что это именно то, что нам нужно, чтобы наша сигнализация с пустяками заработала.

Готовность к выполнению работ

Если вы посмотрите на любое из намерений нашего проекта в пользовательском интерфейсе Dialogflow, вы заметите внизу заголовок под названием «Выполнение» с активированным ползунком рядом с «Включить вызов веб-перехватчика для этого намерения»:

Это означает, что когда вызывается намерение Ask Question (т. Е. Когда пользователь говорит: «Давайте поиграем в мелочи»), Dialogflow ответит запуском кода выполнения, а не жестко закодированными текстовыми ответами (как вы можете видеть выше, поле «Текстовый ответ» пусто).

Давайте посмотрим, где живет этот код выполнения. В пользовательском интерфейсе Dialogflow щелкните вкладку с надписью «Выполнение» на левой боковой панели:

Здесь вы увидите два заголовка, оба отключены: Веб-перехватчик и Встроенный редактор. Параметр Веб-перехватчик позволяет вам писать код на любом языке, который вам нравится, который запускается где угодно (на вашем собственном сервере, в App Engine, с Облачными функциями Firebase и т. Д.). Вам просто нужно написать код, который может принимать запросы POST от Dialogflow и отвечать на спецификации.

Если вы пишете на Javascript / Node.js, вы можете использовать Библиотеку выполнения диалогового потока, чтобы упростить создание исполнений. Вы также можете использовать Встроенный редактор, который позволяет вставлять код Node.js непосредственно в пользовательский интерфейс Dialogflow и позволяет DF обрабатывать хостинг за вас. По умолчанию встроенный редактор показывает некоторый код, использующий библиотеку Fulfillment, выделенную серым цветом. Если вы отметите Отключено - › Включено рядом с опцией Встроенный редактор , вы сможете просмотреть некоторые базовые и образовательные примеры выполнения.

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

Вы можете найти весь код, который нам понадобится для выполнения викторины, на Github здесь, распределенный по двум основным файлам. trivia.js - небольшая библиотека Javascript для создания простых, средних и сложных математических вопросов. Например, вызов функции getEasyQuestion возвращает ответ json, например:

{        
   "question" : `What is 3 plus 4?`,
   "answer" : 7   
}

Файл index.js содержит весь фактический код выполнения Dialogflow. В этом файле есть функция, соответствующая каждому намерению нашего агента (например, function askQuestion(agent), function snooze(agent)). В самом низу файла мы связываем эти функции с их соответствующими намерениями, используя Map:

// Map Dialogflow intent names to their matching functions  
const intentMap = new Map();  
intentMap.set('Ask Question', askQuestion);  
intentMap.set('Snooze', snooze);  
intentMap.set('Next Question', nextQuestion);  
intentMap.set('Answer Question', answerQuestion);  agent.handleRequest(intentMap);

В типичной веб-разработке это похоже на маршрутизацию.

Если вы хотите понять логику этого файла, взгляните на подробные встроенные комментарии. Работает это так:

  • Ask Question Intent обрабатывается функцией с соответствующим именем askQuestion. Это функция, которая отвечает за вопросы викторины.
  • Answer Question Intent - это резервное намерение, поэтому оно сопоставляется всякий раз, когда не совпадают никакие другие намерения (Snooze, Next Question и т. Д.). Он отвечает за проверку правильности ответа пользователя на простой вопрос. Он хранит эту информацию в переменной с именем lastState, для которой может быть установлено значение «Правильный ответ», «Неверный ответ» или «Нет числа», если пользователь не указал число в своем ответе. Затем он запускает намерение Ask Question, передавая вместе с ним эту информацию.
  • Snooze Намерение соответствует, когда пользователь говорит «Позже» или «Я хочу спать» или что-то подобное в ответ на вопрос. Поскольку мы злые, мы просто вызовем намерение Ask Question от Snooze, которое скажет пользователю: «Нет времени откладывать сон! Ваш вопрос ... »
  • Next Question Намерение также вызовет намерение Ask Question, установив для переменной lastState значение «Следующий вопрос». Это позволяет обработчику Ask Question узнать, что он должен сгенерировать новый вопрос.
  • Наконец, Quiz Done намерение срабатывает, когда пользователь успешно ответил на 3 вопроса, и отвечает, говоря: «Поздравляю, вы, вероятно, уже проснулись. Увидимся завтра!"

Если вы все же решите взглянуть на код, может быть полезно знать некоторые дополнительные концепции Dialogflow:

Контекст, триггеры событий, параметры

Контексты. Контексты в Dialogflow можно использовать для хранения информации в нескольких поворотах разговора. Здесь мы используем контекст, чтобы запомнить, какой вопрос викторины задается в данный момент, ответ на него и на сколько вопросов пользователь уже ответил правильно. В коде это выглядит так:

agent.context.set({
   name: 'quiz_data', // this can be any name you like
   lifespan: 99,     // how long to keep this context alive for
   parameters: {     // where we put the info we want to store
      question: "What's 5 plus 9?"
      answer: 14,
      questions_correct: 1
},});

Триггеры событий. Ранее мы говорили о том, как мы можем вызывать намерения в коде выполнения, чтобы мы могли «связывать» намерения. В нашем будильнике мы используем эти триггеры несколько раз. Например, если пользователь говорит «Следующий вопрос», он вызывает Next Question намерение. В этом случае пользователь хочет, чтобы ему задали новый вопрос. Итак (в коде выполнения) намерение Next Question использует триггер события для вызова Ask Question намерения, которое генерирует новый вопрос и задает его пользователю. В коде это выглядит так:

agent.setFollowupEvent({
   'name': 'ask-question',
   'parameters': {
      'lastState': lastState,
   },
   'languageCode': 'en',
   },
);

В приведенном выше примере вызывается намерение с именем ask-question. Вы также можете увидеть поле parameters, которое позволяет передавать произвольную информацию из вызывающего намерения в целевое намерение. Здесь мы используем это поле, чтобы указать, почему мы инициировали событие (было ли это из-за того, что пользователь неправильно задал вопрос? Верно? Они хотели отложить?).

* Это очень много, чтобы принять во внимание все сразу, поэтому, если вы хотите более подробное объяснение того, что происходит в коде здесь, оставьте примечание ниже в комментариях.

Развертывание исполнений

Следующим и последним шагом к созданию нашего будильника является развертывание нашего кода выполнения. Вы можете сделать это либо во встроенном редакторе кода Dialogflow, либо разместив его самостоятельно. Поскольку мой код распределен по нескольким файлам (index.js и trivia.js), я подумал, что было бы лучше разместить код самостоятельно. Я развернул его с помощью Firebase Cloud Functions. Если вы решили пойти по этому пути, перейдите на вкладку Выполнение и настройте веб-перехватчик следующим образом:

Теперь попробуйте попросить вашего Dialogflow Agent поиграть в мелочи! Он должен задать вам три вопроса, прежде чем позволить вам снова заснуть!

Спасибо за чтение! И если в этом сообщении блога есть еще какие-то подробности, оставьте комментарий ниже, и я их добавлю!