Создание навыка я никогда не
Создание навыка я никогда не с использованием движка u_bot, позволяющего создавать приложения на разных платформах.
Создание навыка я никогда не
6 Января, 2021 Автор: Максим МСоздание навыка я никогда не
С чего начать
Как и с любым другим навыком для Алисы, нужно продумать механику навыка, а также подготовить контент.
Так как мы разрабатываем навык "Я никогда не", то основной сценарий следующий:
- Приветствие, где навык приветствует пользователя, и рассказывает о своих возможностях.
- Выбор режима игра. Для более интересно игры, добавим несколько режимов, чтобы в навык могли играть как взрослые, так и дети.
- Сама игра, где навык будет задавать вопрос, и по необходимости давать подсказки.
В приветствии нужно кратко рассказать о чем навык, а также предложить пользователю начать игру. При этом, не стоит забывать о том, что пользователю может понадобиться помощь, а значит нужно подготовить текст помощи, где будет рассказано как играть в игру, а также, как пользоваться навыком. Помимо этого, нужно позаботиться о разнообразии, а именно навык должен говорить что-либо по разному, чтобы игрок не заскучал. Сравните сами:
Пример 1
- Следующий вопрос: Я никогда не пил молоко
- Следующий вопрос: Я никогда не дрался с крапивой
- Следующий вопрос: Я никогда не смотрел аниме
- Следующий вопрос: Я никогда не играл в прятки
Пример 2
- Следующий вопрос: Я никогда не пил молоко
- А вот это было? Я никогда не дрался с крапивой
- Вот это ты точно делал: Я никогда не смотрел аниме
- Попробуем вот это: Я никогда не играл в прятки
Какой из примеров выглядит интереснее? Конечно 2, так как игрок не слышит одно и тоже раз за разом, а значит вероятность того, что он заскучает мала.
Предположим что мы написали или нашли контент для навыка, а также нашли базу с интересными вопросами, и раскидали их по категориям. Остается написать навык. Для этого воспользуемся u#_bot. U#_bot - это движок, позволяющий легко создавать навыки для Алисы, при этом вы пишите только логику навыка. Но ведь я могу сам изучить протокол работы Алисы, и возвращать ответ в нужном формате, скажете Вы. Все верно, Вы действительно можете все изучить и возвращать нужный ответ, но я рекомендую воспользоваться u#_bot, так как:
- В движок, попадают все самые последние нововведения. Что говорит о том, что не нужно следить за протоколом работы Алисы. Единственное за что нужно отвечать это логика навыка.
- Скорость разработки. Так как Вы пишите только логику навыка, вы существенно увеличиваете скорость своей разработки, при этом нет необходимости отвлекаться на посторонние вещи.
- В движок встроены готовые компоненты, которые упростят разработку. На данный момент есть компоненты для работы с текстом и навигацией.
- И самое главное - кроссботовость. Вы пишите логику для Алисы, и при этом, есть возможность без каких либо изменений, сразу создать навык в Марусе или Сбер SmartApp, помимо этого, можно создать бота для vk, telegram и viber. Звучит заманчиво, не правда ли? Вы пишите только логику, а использовать можете на нескольких платформах.
Что ж с контентом навыка разобрались, а также выбрали движок для навыка. Можно приступить к разработке.
Разработка навыка.
Для начала необходимо скачать движок. Он доступен по следующей ссылке: universal#_bot.А документация к нему доступна тут: Документация
К слову, навык будет разрабатываться на php, но это не значит что движок написан только для php. Существует версия и для typeScript.universal#_bot-ts ядро, документация.
Давайте создадим файл с настройками навыка. Для этого создадим файл, который будет возвращать объект с нужными настройками. В документации можно посмотреть значение каждого элемента подробнее:
return [
'yandex#_token' => '',
'intents' => [
[
'name' => 'by',
'slots' => [
'пока',
'выйти'
]
],
[
'name' => 'hint',
'slots'=>[
'подсказ',
'подскаж',
'помог',
]
],
[
'name' => 'm#_help',
'slots' => [
'инструкци',
'что за игра',
'как играт',
]
],
[
'name' => 'start',
'slots' => [
'начат',
'игра'
]
],
[
'name' => 'mode',
'slots' => [
'режим'
]
],
[
'name' => 'next',
'slots' => [
'дальш',
'еще'
]
],
[
'name' => 'replay',
'slots' => [
'повтори',
'не понял'
]
],
[
'name' => 'never',
'slots' => [
'я никогда не',
]
],
]
];
yandex#_token - Вы устанавливаете токен, полученный от Яндекс. Он необходим для того, чтобы иметь возможность для загрузки аудиофайлов и изображений в навык. Но можно загрузить все изображения в консоли разработчика, и оставить значение пустым.
intents - Сюда необходимо передавать массив, на которые будет реагировать навык. Проще говоря, это поле отвечает за поиск вхождений в пользовательском запросе. Где name - уникальное имя команды, а slots - активационные фразы, на которые будет реагировать приложение. Если было найдено вхождение из slots, то в метод логики actions, передастся name.
Так как мы пишем навык только для Алисы, то можно воспользоваться локальным хранилищем, для этого просто в конфигурации установим isLocalStorage в значение true. Также рекомендуется установить путь для сохранения логов(ошибок при выполнении программы), а также путь для сохранения json файлов. Если не указать эти пути, то по умолчанию, все ошибки и сохраненные данные будут сохраняться в директории расположения проекта. При использовании локального хранилища, json файл с сохраненными данными не создается, так как в этом нет необходимости. Конечная настройка будет выглядеть следующим образом:
[
'json' => #_#_DIR#_#_ . '/json',
'error#_log' => #_#_DIR#_#_ . '/errors',
'isLocalStorage' => true
]
Сейчас навык настроен так, что мы не используем базу данных, вместо этого, все данные будут сохраняться в json файл. Сейчас бд нам совершенно не нужна, но если она вам потребуется, то необходимо заполнить конфигурацию следующим образом:
$config = [
'error#_log' => #_#_DIR#_#_ . '/../../logs',
'json' => #_#_DIR#_#_ . '/../../json',
'db' => [
'host' => null, // Адрес расположения базы данных (localhost, https://example.com)
'user' => null, // Имя пользователя
'pass' => null, // Пароль пользователя
'database' => null, // Название базы данных
]
];
По умолчанию все данные записываются в файл. Для использования базы данных, необходимо установить переменную `mmApp::$isSaveDb` в `true`, а также, создайте необходимые таблицы.
mmApp::setIsSaveDb(true);
Создать базу данных можно одним из способов:
- Создать таблицы вручную;
- Использовать консольный скрипт;
Рассмотрим каждый способ подробнее.
Создание таблиц вручную
Необходимо создать 3 таблицы:
- UsersData - Таблица, в которой будут храниться данные, введенные пользователем.
- ImageTokens - Таблица с загруженными изображениями.
- SoundTokens - Таблица с загруженными звуками.
Со следующей структурой:
UsersData
CREATE TABLE IF NOT EXISTS `usersData` (
`userId` VARCHAR(250) COLLATE utf8#_unicode#_ci NOT NULL,
`meta` TEXT COLLATE utf8#_unicode#_ci DEFAULT NULL,
`data` TEXT COLLATE utf8#_unicode#_ci DEFAULT NULL,
`type` INT(3) DEFAULT 0,
PRIMARY KEY (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8#_unicode#_ci;
ImageTokens
CREATE TABLE IF NOT EXISTS `ImageTokens` (
`imageToken` VARCHAR(150) COLLATE utf8#_unicode#_ci NOT NULL,
`path` VARCHAR(150) COLLATE utf8#_unicode#_ci DEFAULT NULL,
`type` INT(3) NOT NULL,
PRIMARY KEY (`imageToken`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8#_unicode#_ci;
SoundTokens
CREATE TABLE IF NOT EXISTS `SoundTokens` (
`soundToken` VARCHAR(150) COLLATE utf8#_unicode#_ci NOT NULL,
`path` VARCHAR(150) COLLATE utf8#_unicode#_ci DEFAULT NULL,
`type` INT(3) NOT NULL,
PRIMARY KEY (`soundToken`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8#_unicode#_ci;
Создание таблицы через консольный скрипт
Перед использованием, необходимо создать json файл, в котором будет расположена конфигурация для подключения к бд. Содержимое файла:
{
"config":{
"db": {
"host": "Расположение базы данных",
"user": "Логин пользователя, для подключения к бд",
"pass": "Пароль пользователя",
"database": "Название базы"
}
}
}
После в корне проекта вызвать скрипт и указать в качестве 1 аргумента `init-db`, а в качестве 2 путь к json файлу.
php ./MM/console/cApp init-db config.json
Теперь создадим файлы, в которых будут храниться вопросы для игры, назовем их 0.json, 1.json и 3.json, в дальнейшем по коду будет понятно почему такое именование. Также создадим index файл со следующим содержимым:
/// 0.json - Детский режим
[
"пользовалась Алисой",
"читала книгу",
"играла в игры на телефоне весь день",
"ела песок",
...
]
/// 1.json - Стандартный режим
/// 3.json - 18+ режим
/// index.php
require#_once #_#_DIR#_#_ . '/../universal#_bot/src/MM/bot/init.php'; // Подключаем ядро приложения
require#_once #_#_DIR#_#_ . '/controller/NeverController.php'; // Подключаем файл с логикой навыка
$bot = new MM#\bot#\core#\Bot(); // Создаем объект с ядром приложения
$configs = [
'json' => #_#_DIR#_#_ . '/json',
'error#_log' => #_#_DIR#_#_ . '/errors',
'isLocalStorage' => true,
]; // Конфигурация приложения
$bot->initConfig($configs); // Инициализируем конфигурацию приложения
$bot->initParams(include #_#_DIR#_#_ . '/config/params.php'); // Инициализируем параметры приложения
$logic = new NeverController(); // Создаем объект с логикой приложений
$bot->initBotController($logic); // Подключаем логику приложения к ядру
echo $bot->run(); // Запуск навыка
//$bot->test(); // Тестирование навыка в терминале
Думаю что стало понятно, что имя файла с вопросами соответствует режиму игры. Тогда не понятно почему отсутствует файл с именем 2. Тут все просто файл с именем 2 соответствует сложному режимы, а в нем мы просто объединим вопросы из детского и стандартного режимы.
Основные моменты настроены, теперь можно приступить к написанию логики навыка. Для этого создадим новый файл, в котором будет находиться класс, отвечающий за логику. Важно учесть, что класс должен быть унаследован от класса BotController ядра. Минимальный код выглядит следующим образом:
use #\MM#\bot#\controller#\BotController;
class NeverController extends BotController
{
public function action($intentName): void
{
...
}
}
Основной метод, который отвечает за обработку пользовательских запросов, это - action, в параметр которого, передается имя интента, который мы указали в параметрах приложения. Если не удалось найти никаких вхождений, то передастся null. Так мы сможем определить моменты, которые не смогли обработать, и в случае чего вернуть пользователю подсказку, или выполнить любое другое действие.
Основные переменные класса BotController:
- $buttons: Кнопки отображаемые в приложении
- $card: Карточка отображаемая в приложении
- $text: Текст, который увидит пользователь
- $tts: Текст, который услышит пользователь
- $nlu: Обработанный nlu в приложении
- $sound: Класс звуков в приложении
- $userId: Идентификатор пользователя
- $userToken: Пользовательский токен. Инициализируется тогда, когда пользователь авторизован (Актуально для Алисы)
- $userMeta: Meta данные пользователя
- $messageId: Id сообщения (Порядковый номер сообщения), необходим для того, чтобы понять в 1 раз пишет пользователь или нет.
- $userCommand: Запрос пользователь в нижнем регистре
- $originalUserCommand: Оригинальный запрос пользователя
- $payload: Дополнительные параметры запроса. Передается в том случае, если нажата кнопка в которой установлен payload
- $userData: Пользовательские данные (Хранятся в бд либо в файле. Зависит от значения переменной mmApp::$isSaveDb)
- $isAuth: Запросить авторизацию пользователя или нет (Актуально для Алисы)
- $isAuthSuccess: Проверка что авторизация пользователя прошла успешно (Актуально для Алисы)
- $state: Пользовательское хранилище (Актуально для Алисы)
- $isScreen: Если ли экран
- $isEnd: Завершение сессии (Актуально для Алисы)
- $isSend: Отправлять в конце запрос или нет. (Актуально для Vk и Telegram) False тогда, когда все запросы отправлены внутри логики приложения, и больше ничего отправлять не нужно
- $oldIntentName: Идентификатор предыдущего действия пользователя.
- $thisIntentName: Идентификатор текущего действия пользователя.
Давайте подробнее рассмотрим те переменные, которые могут нам пригодиться.
isScreen
Переменная, которая может ввести в заблуждение, так как в зависимости от наличия экрана, мы либо отображаем карточки и кнопки в навыке или нет. Можно предположить, что в зависимости от переменной Вы сами должны следить за тем, отображать что-либо или нет, но это не так, движок сам смотрит на переменную, и в зависимости от значения, отображает карточки и кнопки. Эта переменная больше предназначения для разработчиков, чтобы понимать, на чем играет пользователь, и в зависимости от наличия/отсутствия экрана, отображать тот или иной контент.
userData
Сюда попадают значения из бд или локального хранилища. Любые данные в переменной запишутся в бд или локальное хранилище.
oldIntentName/thisIntentName
Эту переменную вы заполняете самостоятельно. Она необходима для того, чтобы понимать в каком контексте пользователь общается в навыке. Используйте thisIntentName, чтобы задать текущий идентификатор, этот идентификатор вы получите в oldIntentName при следующем запросе пользователя.
text/tts
Переменные для отображения/воспроизведение ответа пользователю. Тут все понятно.
buttons
Массив с кнопками, которые увидит пользователь. Существует 2 вида кнопок в Алисе, в виде кнопки и в виде ссылки, и оба этих вида можно использовать одновременно. Сказать движку об использовании кнопок можно 2 способами.
1 способ
Можно задать кнопки через переменные. Для этого у объекта есть 2 переменные:
- links - Массив с кнопками, которые отобразятся как ссылка
- btns - Массив с кнопками, которые отобразятся как кнопка
Обе переменные имеют одинаковый тип данных. Можно передать простую строку, тогда при нажатии на кнопку, в навык придет содержимое кнопки(строка, которую передали). Или можно передать массив вида:
[
'title' => '', // Заголовок для кнопки
'url' => '', // Ссылка, по которой перейдет пользователь после нажатия на кнопку
'payload' => [], // Произвольные данные, которые передадутся в навык после нажатия на кнопку
'options' => null // Дополнительные параметры для кнопки. Не актуально для Алисы.
]
При передаче массива нужно обязательно передавать title, иначе кнопка не отобразится. Остальные параметры не обязательны и их можно пропустить.
2 способ
Можно создавать кнопки через методы объекта. Для этого существует 2 метода:
- addLink - Кнопка которая отобразятся как ссылка
- addBtn - Кнопка, которая отобразятся как кнопка
Методы принимают 4 параметра, 1 из которых является обязательным. В случае успешного создания кнопки вернется true. Описание методов:
/**
* @param string $title Текст на кнопке.
* @param string|null $url Ссылка для перехода при нажатии на кнопку.
* @param string|array|null $payload Произвольные данные, отправляемые при нажатии кнопки.
* @param array $options Дополнительные параметры для кнопки
* @see Button::options Описание опции options
* @return bool
*/
card
Переменная, отвечающая за отображение карточки пользователю. Создать карточку крайне просто, для этого необходимо добавить хотя бы 1 элемент в нее. Сделать это можно с помощью метода add. Который принимает 4 параметра:
- $image Идентификатор или расположение изображения
- $title Заголовок для изображения
- $desc Описание для изображения
- $button Кнопки, обрабатывающие команды при нажатии на элемент карточки
В $button передается массив такого же типа что и для объекта buttons, а именно для переменных links и btns.
Также можно явно указать движку, что пользователю в любом случае нужно отобразить карточку с большой картинкой, для этого нужно установить переменную $isOne в true. Также можно указать заголовок и описание для карточки, для этого есть переменные $title и $desc, а также можно указать footer, для этого, нужно добавить кнопки в переменную $button.
С основными моментами разобрались, можно продолжить разработку навыка, но давайте рассмотрим еще статический класс Text, который упрощает работу с текстом. Данный класс обладает множеством полезных методов, о которых подробнее можно посмотреть в документации, но мы рассмотрим 2, которые пригодятся в проекте:
- getText - Метод, который возвращает строку. В метод можно передать как строку, так и массив строк, в результате вернется случайная строка если это массив, или переданная строка, если передали строку. Проще говоря, метод является эквивалентом записи $str[rand(0, count($str) - 1)].
- isSayText - Метод, который возвращает true в том случае, если в тексте присутствует строка для поиска. Он
принимает 3 параметра:
- $find Текст который ищем. Может быть строка или массив строк
- $text Исходный текст, в котором осуществляется поиск.
- $isPattern Если true, тогда используется пользовательское регулярное выражение.
Логика навыка
Теперь, когда все изучено, можно писать логику навыка, с этим не должно быть никаких проблем. Ссылка на навык и исходники с подробными комментариями:
Класс с логикой навыка выглядит следующим образом:
use #\MM#\bot#\controller#\BotController;
use #\MM#\bot#\components#\standard#\Text;
class NeverController extends BotController
{
protected const CHILDREN#_MODE = 0; // Детский режим
protected const NORMAL#_MODE = 1; // Нормальный режим
protected const HARD#_MODE = 2; // Режим, в котором объединены детский и нормальный режим
protected const SEX#_MODE = 3; // Режим 18+
protected const DEFAULT#_MODE = 0; // Стандартный режим
/**
* Доступные режимы
*/
protected const MODES = [
self::CHILDREN#_MODE => [
'name' => 'Детский режим', // Название режима
'img' => '937455/038af42397fb33d3a91a', // Токен изображения
'desc' => 'Вопросы и действия, предназначенные для детей', // Описание режима
'actions' => ['дете', 'детски', 'легки'] // Фразы, по которым происходит понимание того, что выбран этот режим
],
self::NORMAL#_MODE => [
'name' => 'Стандартный режим',
'img' => '1030494/5f1705d1c43609428bda',
'desc' => 'Вопросы и действия, предназначенные для взрослых',
'actions' => ['просто', 'стандарт', 'норм']
],
self::HARD#_MODE => [
'name' => 'Сложный
Рекомендую к прочтению следующие статьи:
Продажи умных колонок с Алисой достигли 1,3 миллиона устройств
Продажи умных колонок с Алисой достигли 1,3 миллиона устройств
Читать статью
Курс по проектированию и разработке навыков Алисы теперь доступен на YouTube
Яндекс переработали записи лекций и семинаров с хатакотна по «городским» навыкам Алисы и выложили в отдельный плейлист на своем YouTube без технических блоков мероприятия
Читать статью
Проверка SSL-сертификата для навыков
Яндекс добавили дополнительную проверку на валидность SSL-сертификата для навыков, размещенных через webhook.
Читать статью
Новый формат контента в утреннем шоу Алисы: истории от навыков
Теперь навыки смогут отправлять короткий регулярный контент в утреннее шоу Алисы
Читать статью
Оплаты в навыках Алисы: успешный кейс и продолжение тестирования
Недавно на платформе Яндекс произошел важный запуск: в навыке «Аудиокниги ЛитРес» появилась возможность не только прослушивать, но и оплачивать аудиокниги.
Читать статью
Комментарии
Оставить комментарий
Как со мной связаться находясь в Ростове
Я работаю по всей России, поэтому вы можете спокойно связаться со мной находясь в Ростове!
Задавайте свои вопросы в форме обратной связи, и я с радостью отвечу на все вопросы!
Телефон:
+7(909) 281 35-20Почта:
maximco36895@yandex.ruДополнительная почта:
info@maxim-m.ruЯ в социальных сетях: