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

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

Рекомендую к прочтению следующие статьи:

Хакатон по навыкам для Станции

Хакатон по навыкам для Станции

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

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

Донаты в навыках Алисы теперь доступны для всех!

Донаты в навыках Алисы теперь доступны для всех!

Яндекс завершил тестирование, и теперь монетизация голосовых приложений Алисы через донаты доступна всем!

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

Дайджест полезных материалов по разработке навыков Алисы

Дайджест полезных материалов по разработке навыков Алисы

А вот и дайджест в честь двух тысяч подписчиков в сообществе разработчиков Яндекс.Диалогов.

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

Кто такая Алиса? Основные преимущества и назначение Алисы

Кто такая Алиса? Основные преимущества и назначение Алисы

Голосовой помощник Алиса. Что она из себя представляет и для чего она может пригодиться? А также разбор основных преимуществ.

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

В Яндекс.Диалогах появятся донаты для разработчиков навыков Алисы

В Яндекс.Диалогах появятся донаты для разработчиков навыков Алисы

Компания Яндекс начала открытое тестирование монетизации голосовых приложений Алисы через донаты.

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

Комментарии

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

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

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

Телефон:

+7(909) 281 35-20

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

info@maxim-m.ru

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

ВверхВверх 👆