- PVSM.RU - https://www.pvsm.ru -

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

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

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

Играть с реальным человеком может быть интереснее, чем с виртуальным персонажем, поэтому в качестве примера разрабатывать будем многопользовательскую игру для Алисы.

Раз! Диалог

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

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

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

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

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

В каждом запросе, согласно протоколу [1], Алиса передаёт идентификатор пользователя. Этого достаточно для сохранения и последующего восстановления его контекста.

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

Создав таблицу с нужными заголовками, можно перейти к редактору скриптов:

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

Логику игры можно описать в проекте на Apps Script, организовав её в виде набора gs-файлов, и перейти к публикации:

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

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

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

На выходе вы получите URL опубликованного веб-приложения. Функции doGet() и doPost() в скрипте будут обрабатывать запросы соответствующих типов, чтобы получать и сохранять контексты пользователей.

Ниже схема работы с API таблиц для оперирования данными:

    //получение листа
    var sheet = SpreadsheetApp.openById("<id таблицы>").getSheetByName("<название вкладки>");
   //получение диапазона
    var range = sheet.getRange(<нужные ячейки>);
   //извлечение данных диапазона
    var values = range.getValues();
   //сохранение данных в диапазон
    range.setValues(<нужные данные>);

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

В общем случае корректная интерпретация текстовых запросов требует использования интеллектуальных NLU-алгоритмов. И хотя такие алгоритмы доступны в несложных инструментах вроде описанного мной Aimylogic [2], в этом случае от обработки естественного языка я решил отказаться в пользу простоты.

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

Сценарий в этом случае сводится к следующему коду на Apps Script:

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

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

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

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

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

Недавно я сформулировал концепцию ЛЁГКОГО диалога [3], описывающую принципы проектирования разговорного интерфейса в том числе для Алисы. Формат ответа Алисы позволяет реализовать эти принципы.

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

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

Итак, у нас есть Google Таблица с данными пользователей, которые сохраняются и получаются через URL веб-приложения. Приложение написано на Apps Script, оно интерпретирует действие пользователя в соответствии с его контекстом и формирует данные для ответного сообщения.

Осталось подключиться к Алисе…

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

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

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

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

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

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

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

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

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

Веб-приложение, созданное на Apps Script, по умолчанию возвращает ответ в виде html-странички, но с помощью ContentService его можно заставить возвращать и JSON:

return ContentService.createTextOutput(JSON.stringify(<JSON ответа>))
  .setMimeType(ContentService.MimeType.JSON);

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

Существуют бесплатные сервисы, которые предлагают подходящий для Алисы веб-хук, например Zenbot [5]. В 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 [6] позволяет на одной веб-странице писать код сервера и деплоить его на нужный 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 Таблицы на примере PvP-игры для Алисы - 6
В многопользовательской игре для Алисы должны быть решены задачи синхронизации как между серверами игры и Яндекса, так и между игроками. Если игрок хочет играть против другого пользователя, игра сама подбирает соперника — из тех, кто хотел играть в последнее время. Пользователи должны подтвердить готовность играть друг с другом, чтобы игра началась.

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

Заключение

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

Надеюсь, данная статья поможет энтузиастам и разработчикам быстрее создавать полезные навыки для Алисы или других каналов. Предложенная игра доступна в магазине навыков Яндекс.Диалогов под названием “Раз, Два, Три! Многопользовательская игра [7]”.

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

Автор: IvanGolubev

Источник [8]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/diy-ili-sdelaj-sam/283053

Ссылки в тексте:

[1] согласно протоколу: https://tech.yandex.ru/dialogs/alice/doc/protocol-docpage/

[2] описанного мной Aimylogic: https://habr.com/company/just_ai/blog/412557/

[3] концепцию ЛЁГКОГО диалога: https://medium.com/@igolubev/%D0%BB%D1%91%D0%B3%D0%BA%D0%B8%D0%B9-%D0%B4%D0%B8%D0%B0%D0%BB%D0%BE%D0%B3-%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D1%83%D0%B5%D0%BC-%D0%BD%D0%B0%D0%B2%D1%8B%D0%BA-%D0%B4%D0%BB%D1%8F-%D0%B3%D0%BE%D0%BB%D0%BE%D1%81%D0%BE%D0%B3%D0%BE-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D0%BD%D0%B8%D0%BA%D0%B0-4a795a366d20

[4] формальным требованиям: https://tech.yandex.ru/dialogs/alice/doc/requirements-docpage/#specific__key-phrase

[5] например Zenbot: https://blog.dusi.mobi/2018/03/18/zenbot-alice/

[6] Cloud Shell: https://console.cloud.google.com/cloudshell/

[7] Раз, Два, Три! Многопользовательская игра: https://dialogs.yandex.ru/store/skills/f30eb7ff-raz-dva-tri-mnogopol-zovatel-skaya-igr

[8] Источник: https://habr.com/post/414213/?utm_campaign=414213