Раз, Два, Три! Чат-бот из Google Таблицы на примере PvP-игры для Алисы

МЕНЮ


Искусственный интеллект
Поиск
Регистрация на сайте
Помощь проекту

ТЕМЫ


Новости ИИРазработка ИИВнедрение ИИРабота разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика

Авторизация



RSS


RSS новости


Появившись, Алиса увлекла пользователей неожиданно качественными синтезом речи и чат-ботом. Сегодня от неё ждут полезных навыков и интересных игр с бекендом, способным учитывать контекст пользователя и реализовывать широкий спектр сценариев. В этой статье рассматривается создание навыка на базе Google Таблицы, хорошо знакомого многим инструмента с большим потенциалом для небольших чат-ботов.
Играть с реальным человеком может быть интереснее, чем с виртуальным персонажем, поэтому в качестве примера разрабатывать будем многопользовательскую игру для Алисы.

Раз! Диалог

Игра начинается с правил. Я придумал такие: каждый из двух игроков сперва размещает за тремя дверями сокровище и ловушку, а затем открывает любую из дверей соперника. Открываете сокровище — получаете монеты соперника, открываете ловушку — отдаёте монеты ему. Количество монет, от 1 до 3, определяет сам игрок. За оставшейся дверью находится ящик Пандоры, открыв который можно найти/потерять случайное количество монет. Играть можно как с Алисой, так и против других пользователей.

Интерфейс Алисы решён в виде диалога, и всё игровое взаимодействие должно быть реализовано через обмен сообщениями. Обработка каждого сообщения сервером игры представляется следующими шагами:

  1. восстановление контекста пользователя;
  2. интерпретация запроса в восстановленном контексте;
  3. формирование ответного сообщения;
  4. сохранение изменившегося контекста пользователя.

Восстановление и сохранение контекста пользователя

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

В каждом запросе, согласно протоколу, Алиса передаёт идентификатор пользователя. Этого достаточно для сохранения и последующего восстановления его контекста. В качестве хранилища данных возьмём Google Таблицы. К объективным преимуществам этого решения относятся бесплатное использование, наглядность и простота эксплуатации. Встроенный редактор скриптов позволяет описывать логику игры на Apps Script (базирующемся на JavaScript), обращаясь к API таблиц, и публиковать её в виде web-приложения. Создав таблицу с нужными заголовками, можно перейти к редактору скриптов:

Логику игры можно описать в проекте на Apps Script, организовав её в виде набора gs-файлов, и перейти к публикации:
При публикации нужно указать доступность приложения анонимным пользователям:
На выходе вы получите URL опубликованного веб-приложения. Функции doGet() и doPost() в скрипте будут обрабатывать запросы соответствующих типов, чтобы получать и сохранять контексты пользователей. Ниже схема работы с API таблиц для оперирования данными:
    //получение листа     var sheet = SpreadsheetApp.openById("<id таблицы>").getSheetByName("<название вкладки>");    //получение диапазона     var range = sheet.getRange(<нужные ячейки>);    //извлечение данных диапазона     var values = range.getValues();    //сохранение данных в диапазон     range.setValues(<нужные данные>); 

Интерпретация запроса в восстановленном контексте

В общем случае корректная интерпретация текстовых запросов требует использования интеллектуальных NLU-алгоритмов. И хотя такие алгоритмы доступны в несложных инструментах вроде описанного мной Aimylogic, в этом случае от обработки естественного языка я решил отказаться в пользу простоты. В предложенной игре взаимодействие игрока с Алисой ограничивается десятком возможных состояний и может быть сведено к небольшому набору намерений. Для простоты я всегда предлагаю игроку три возможных действия: отправить “Раз”, “Два” или “Три”. На любой другой запрос Алиса просит уточнить действие. Сценарий в этом случае сводится к следующему коду на Apps Script:

//для каждого состояния в игре switch(user.state){     case "start":       //прописываем реакцию на каждое из возможных действий       switch(utterance){         case “1?? Раз”:         case “2?? Два”:         case “3?? Три”:           //формируем ответ на ожидаемые действия         default:           //формируем ответ на неожиданное действие       }       break;    //здесь все другие состояния     default:      //формируем ответ на случай непредвиденного состояния } 

Для пользователя решённое таким образом взаимодействие представляется как выбор одного из трёх вариантов, смысл которых явно определён в каждом ответе Алисы. Сами варианты представлены кнопками “Раз”, “Два”, “Три”, которые существенно ускоряют игровой процесс.

Формирование ответного сообщения

Ответ Алисы состоит из нескольких частей, каждую из которых нужно сформировать, в том числе:

  • текст для отображения на экране;
  • текст для синтеза речи;
  • набор кнопок-подсказок.

Недавно я сформулировал концепцию ЛЁГКОГО диалога, описывающую принципы проектирования разговорного интерфейса в том числе для Алисы. Формат ответа Алисы позволяет реализовать эти принципы. Так разделение отображаемого и проговариваемого текста позволяет сделать ответы более краткими и естественными. Можно не заставлять Алису синтезировать длинный текст, с которым пользователь уже знаком, а также использовать emoji в тексте сообщения и названии кнопок. Кнопки-подсказки реализуют принцип инициативы: Алиса всегда обозначает и предлагает возможные действия для продолжения диалога. В сценарии предложенной игры список кнопок не зависит от контекста и добавляется к каждому сообщению. Итак, у нас есть Google Таблица с данными пользователей, которые сохраняются и получаются через URL веб-приложения. Приложение написано на Apps Script, оно интерпретирует действие пользователя в соответствии с его контекстом и формирует данные для ответного сообщения. Осталось подключиться к Алисе…

Два! Интеграция

Яндекс.Диалоги позволяют разработчикам добавлять в Алису свои навыки. Подключение навыка сводится к трём основным вещам:

  • активация;
  • оформление;
  • веб-хук.

Активация и оформление

Для активации важно выбрать хорошо распознаваемую Алисой фразу, соответствующую формальным требованиям Яндекса. Если в активационном имени присутствуют числа, отдельно проверяйте активацию при вводе с клавиатуры и голосом. В оформление навыка входят название, описание, иконка, категория и т.п. Стоит учесть, что в списке навыков в каталоге отображаются только иконка и активационная фраза, а поиск в каталоге осуществляется преимущественно по описанию.

Получение веб-хука

Веб-хук — это адрес, по которому Алиса будет отправлять сообщения к вашему навыку и ждать JSON-ответ в описанном формате.

Веб-приложение, созданное на Apps Script, по умолчанию возвращает ответ в виде html-странички, но с помощью ContentService его можно заставить возвращать и JSON:
return ContentService.createTextOutput(JSON.stringify(<JSON ответа>))   .setMimeType(ContentService.MimeType.JSON);

Однако Google при использовании ContentService перенаправляет запрос пользователя на временный URL, к чему Яндекс.Диалоги не готовы. Поэтому адрес веб-приложения в качестве веб-хука не подходит.

Существуют бесплатные сервисы, которые предлагают подходящий для Алисы веб-хук, например Zenbot. В Zenbot для предложенной игры можно написать короткий скрипт, обращающийся к гугловому веб-приложению и возвращающий ответ вместе с кнопками. Кстати, таким образом игру можно интегрировать не только с Алисой, но и с другими каналами. Ниже пример скрипта, который обеспечивает работу игры “Раз, Два, Три!” в Telegram-боте @RazDvaTriBot:
<context>      <input pattern="$Text">         <var name="Utterance" value="$Text" scope="input"/>         <get url="https://script.google.com/macros/s/<id веб-приложения>/exec" var="Result">             <param name="userId" value="$req_telegram_chat"/>             <param name="utterance" value="$Utterance"/>             <param name="channel" value="telegram"/>                           </get>           <var name="Answer" value='javascript: $Result.text'/>         <output value="$Answer"/>         <sample>             <item value="Раз"/>             <item value="Два"/>             <item value="Три"/>         </sample>           </input>  </context> 

Для большей гибкости в обработке запросов можно написать свой сервер, используя для этого, например, Google App Engine. Этим инструментом тоже можно пользоваться бесплатно.

После создания проекта в Google App Engine интерфейс Cloud Shell позволяет на одной веб-странице писать код сервера и деплоить его на нужный URL вида https://<id проекта>.appspot.com, который и будет адресом веб-хука. Работа сервера состоит из следующих этапов:
  1. получение данных запроса из Алисы;
  2. взаимодействие с веб-приложением игры;
  3. отправка ответа в формате Алисы.

Получение/отправка данных Алисы

От Алисы важно получить идентификаторы сессии, пользователя, сообщения, а также текст запроса. Ниже пример на PHP:

	$data = json_decode(file_get_contents("php://input"));  	$session_id = $data->session->session_id; 	$user_id = $data->session->user_id; 	$utterance = $data->request->original_utterance; 	$messageId = $data->session->message_id; 

В качестве ответа в игру возвращаются кнопки-подсказки и тексты для отображения и проговаривания:

	$button1 = array('title' => '1?? Раз', 'hide' => true); 	$button2 = array('title' => '2?? Два', 'hide' => true); 	$button3 = array('title' => '3?? Три', 'hide' => true); 	$yaButtons = array($button1, $button2, $button3); 	$yaResponse = array('text' => $text, 'tts' => $tts, 'buttons' => $yaButtons, 'end_session' => false); 	$yaSession = array('session_id' => $session_id, 'message_id' => $messageId + 1, 'user_id' => $user_id); 	$yaResult = array('response' => $yaResponse, 'session' => $yaSession, 'version' => '1.0'); 	 	echo json_encode($yaResult); 

Три! Синхронизация

Отправка/получение данных от веб-приложения занимает время, а Алисе не терпится дать ответ пользователю, поэтому в дело вмешиваются вопросы синхронизации.

Естественно, для больших проектов в качестве бекенда навыка Алисы Google Таблицы не подходят: время ответа увеличивается при большом количестве параллельных запросов. Тем не менее существуют рекомендации по оптимизации чат-бота, которые позволяют сделать небольшой проект жизнеспособным в условиях диалоговой системы реального времени.

Таймаут синхронного протокола Алисы — 1,5 секунды на ответ. Если сервер не успевает выдать ответ за это время, пользователь видит грустное сообщение в духе “Извините, <имя диалога> не отвечает”. Никаких подсказок, что делать дальше, система не предлагает.

Чтобы избежать такой ситуации, можно и нужно ускорять сервис, а также отслеживать и обрабатывать таймауты. Наиболее длительные операции при работе скрипта игры — чтение и запись данных таблицы. Поэтому, во-первых, количество эти операций нужно минимизировать, а во-вторых, желательно их распараллелить.

Зачитать данные таблицы достаточно один раз. После исполнения логики скрипт готов выдать пользователю ответ сразу, до окончания записи результатов.

На получение ответа следует отвести ограниченное время — например, 1100 мс:

	$request_params = array( 	  'userId' => $user_id,  	  'utterance' => $utterance, 	  'channel' => 'alice' 	);  	 	$get_params = http_build_query($request_params); 	 	$ctx = stream_context_create(array('http'=> 	    array( 	        'timeout' => 1.1 	    ) 	)); 	 	$answer = file_get_contents('https://script.google.com/macros/s/<id веб-приложения>/exec?'. $get_params, false, $ctx); 

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

	if($answer === FALSE) { 		$text = ' Помедленнее, я не успеваю.'; 		$tts = 'Помедленнее, я не успеваю.'; 	} else { 		 	    $answer = json_decode($answer);             $text = $answer->text; 	    $tts = $answer->tts; 	 	    //сохранение в таблице 	    $data2store = $answer->data;             $postdata = json_encode(array( 	          'data' => $data2store 	      )); 	   $opts = array('http' => 	      array( 	          'method'  => 'POST', 	          'header'  => 'Content-Type: application/json', 	          'content' => $postdata, 	          'timeout' => 0.1 	      ) 	  ); 	           $context  = stream_context_create($opts); 	  file_get_contents("https://script.google.com/macros/s/<id веб-приложения>/exec", false, $context); 	} 

В многопользовательской игре для Алисы должны быть решены задачи синхронизации как между серверами игры и Яндекса, так и между игроками. Если игрок хочет играть против другого пользователя, игра сама подбирает соперника — из тех, кто хотел играть в последнее время. Пользователи должны подтвердить готовность играть друг с другом, чтобы игра началась. На текущий момент навык не может инициировать отправку сообщения пользователю Алисы. Поэтому в скрипте игры предусмотрена проверка готовности соперника и отведённой под раунд игры минуты. Если соперник задерживает игру, пользователю предлагается подождать его: “Подождём соперника ещё чуть-чуть?” Соглашаясь подождать, пользователь запускает очередную проверку. Если минута игры заканчивается, игра завершается.

Заключение

К плюсам Google Таблицы как бекенда для чат-бота, кроме бесплатности, можно отнести то, что при разработке она является инструментом отладки, а после — становится консолью администратора навыка со всеми прелестями совместного редактирования с любого устройства. К минусам — задержки при одновременной работе большого количества пользователей.

Надеюсь, данная статья поможет энтузиастам и разработчикам быстрее создавать полезные навыки для Алисы или других каналов. Предложенная игра доступна в магазине навыков Яндекс.Диалогов под названием “Раз, Два, Три! Многопользовательская игра”. Наряду с инструментами общего назначения существуют и специализированные решения для разработки чат-ботов. Предлагаю читателям принять участие в небольшом опросе по известным мне в этой области сервисам. В список попали далеко не все существующие продукты — буду благодарен за комментарии с названиями и краткими отзывами, если вы использовали другие инструменты.


Источник: habr.com

Комментарии: