Создание навыка я никогда не

Создание навыка я никогда не с использованием движка 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);
    

Создать базу данных можно одним из способов:

  1. Создать таблицы вручную;
  2. Использовать консольный скрипт;

Рассмотрим каждый способ подробнее.

Создание таблиц вручную

Необходимо создать 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 миллиона устройств

Продажи умных колонок с Алисой достигли 1,3 миллиона устройств

Читать статью

Курс по проектированию и разработке навыков Алисы теперь доступен на YouTube

Курс по проектированию и разработке навыков Алисы теперь доступен на YouTube

Яндекс переработали записи лекций и семинаров с хатакотна по «городским» навыкам Алисы и выложили в отдельный плейлист на своем YouTube без технических блоков мероприятия

Читать статью

Проверка SSL-сертификата для навыков

Проверка SSL-сертификата для навыков

Яндекс добавили дополнительную проверку на валидность SSL-сертификата для навыков, размещенных через webhook.

Читать статью

Новый формат контента в утреннем шоу Алисы: истории от навыков

Новый формат контента в утреннем шоу Алисы: истории от навыков

Теперь навыки смогут отправлять короткий регулярный контент в утреннее шоу Алисы

Читать статью

Оплаты в навыках Алисы: успешный кейс и продолжение тестирования

Оплаты в навыках Алисы: успешный кейс и продолжение тестирования

Недавно на платформе Яндекс произошел важный запуск: в навыке «Аудиокниги ЛитРес» появилась возможность не только прослушивать, но и оплачивать аудиокниги.

Читать статью

Комментарии

Оставить комментарий

Как со мной связаться?

Свяжитесь со мной по любому поводу!
Я с радостью отвечу на все вопросы!

Телефон:

+7(909) 281 35-20

Дополнительная почта:

info@maxim-m.ru

Я в социальных сетях:

ВверхВверх 👆