Blog. Just Blog

Пишем навыки для умной колонки Алиса на PHP

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Пишем навыки для умной колонки Алиса на PHP
Пишем навыки для умной колонки Алиса на PHP

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

Технологии Алисы позволяют перевести взаимодействие с внешними сервисами на голосовой диалог. Для этого используются так называемые "навыки". Это внешние приложения, которые можно запускать голосом, а затем запрашивать и получать от них нужную информацию. Есть два типа навыков - публичные и приватные. Публичные навыки, как правило, разрабатываются крупными компаниями, они доступны для всех устройств. Но для добавления в каталог навык проходит строгую модерацию и должен быть полезен широкому кругу пользователей. А вот приватные навыки можно использовать для решения личных задач.

Создаем новый навык
Создаем новый навык

Для создания навыка надо сперва авторизоваться под тем аккаунтом, к которому привязаны устройства умного дома, в частности, колонки Алиса. Запускать навык можно будет только с них. После авторизации открываем страницу добавления навыка. Тип диалога - "Научить Алису чему-нибудь новому". Гусары, молчать.

Настройки навыка
Настройки навыка

На странице настроек надо заполнить обязательные поля, из которых наиболее важными являются "Название" и "Backend". Название будет использоваться для голосовой команды типа "Алиса, включи навык Управление", а в Backend указывается ссылка на скрипт-приемник, который находится на вашем сервере. Тип доступа меняем на "Приватный", а в разделе "Публикация в каталоге" можно написать всякую херню, все равно в этот самый публичный каталог навык попадать не будет.

Переходим к скрипту. На каждую голосовую команду пользователя, в том числе и на запуск навыка, скрипту отправляется запрос в формате JSON. Вот так примерно выглядит декодированный запрос за активацию:

Array (
  [meta] => Array (
    [locale] => ru-RU
    [timezone] => Europe/Moscow
    [client_id] => aliced/1.0 (Yandex yandexmini; Linux 1.0)
    [interfaces] => Array (
      [payments] => Array ()
      [account_linking] => Array ()
    )
  )
  [session] => Array (
    [message_id] => 0
    [session_id] => 00000000-1111-2222-3333-444444444444
    [skill_id] => aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
    [user] => Array (
      [user_id] => AAAAAAAAAAAAAA...AAAAAAA
    )
    [application] => Array (
      [application_id] => BBBBBBBBBBBB...BBBBBBBB
    )
    [new] => 1
    [user_id] => BBBBBBBBBBBB...BBBBBBBB
  )
  [request] => Array (
    [command] =>
    [original_utterance] =>
    [nlu] => Array (
      [tokens] => Array ()
      [entities] => Array ()
      [intents] => Array ()
    )
    [markup] => Array (
      [dangerous_context] =>
    )
    [type] => SimpleUtterance
  )
  [version] => 1.0
)

Важными полями тут являются skill_id, в котором передается уникальный идентификатор вашего навыка, и command, в котором указывается команда. В данном случае команда пустая и поле new равно 1, значит просто выполнен запуск навыка. Проверять значение skill_id надо обязательно, чтобы исключить возможность подмены данных. Поля session_id и message_id отвечают, соответственно, за сессию и номер сообщения в сессии. Их можно использовать, если диалог представляет собой многоходовочку из нескольких последовательных команд, основанных на предыдущем выборе пользователя.

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

Array (
  [meta] => Array (
    [locale] => ru-RU
    [timezone] => Europe/Moscow
    [client_id] => aliced/1.0 (Yandex yandexmini; Linux 1.0)
    [interfaces] => Array (
      [payments] => Array ()
      [account_linking] => Array ()
    )
  )
  [session] => Array (
    [message_id] => 1
    [session_id] => 00000000-1111-2222-3333-444444444444
    [skill_id] => aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
    [user] => Array (
      [user_id] => AAAAAAAAAAAAAA...AAAAAAA
    )
    [application] => Array (
      [application_id] => BBBBBBBBBBBB...BBBBBBBB
    )
    [new] =>
    [user_id] => BBBBBBBBBBBB...BBBBBBBB
  )
  [request] => Array (
    [command] => включи плеер
    [original_utterance] => включи плеер
    [nlu] => Array (
      [tokens] => Array (
        [0] => включи
        [1] => плеер
      )
      [entities] => Array ()
      [intents] => Array ()
    )
    [markup] => Array (
      [dangerous_context] =>
    )
    [type] => SimpleUtterance
  )
  [version] => 1.0
)

В поле command приходит распознанный текст команды, которую произнес пользователь, а в массиве tokens он же, но с разбивкой по отдельным словам. Анализируя вхождение тех или иных команд в массиве, можно понять, что хотел пользователь. Например, для команд "выключи плеер", "да выключи ты уже плеер задолбала", из массива tokens достаточно проверить наличие слов "выключи" и "плеер", чтобы понять, какое действие и с каким устройством надо выполнить. Более подробно о взаимодействии можно почитать в официальной документации.

Теперь к обратной связи от скрипта к колонке. На каждый запрос скрипт должен передавать ответ в формате JSON в юникоде. Ответ может содержать достаточно большой объем информации, но минимально необходимый включает в себя следующие поля:

Array (
  [response] => Array (
    [text] => Команда "выйди в окно" не распознана
    [tts] => Команда выйди в окно не распознана
    [end_session] =>
  )
  [version] => 1.0
)

Поле text содержит человекопонятный оформленный текст, который появится в качестве ответа пользователю на устройствах с экраном. В поле tts передается текст для озвучивания голосовым помощником. Тут может понадобится более точная настройка произношения в виде простановки ударений, пауз между словами и даже звуковых эффектов. Поле end_session указывает, следует ли продолжать диалог и ожидать от пользователя какую-то очередную команду в контексте текущей сессии, или же колонка прекращает общение после передачи этой информации. Проверить взаимодействие навыка со скриптом-приемником можно в кабинете разработчика на вкладке "Тестирование".

Простейший скрипт на PHP для обработки навыка выглядит примерно так:
  1. // Получить данные
  2. $data=file_get_contents('php://input');
  3. $json=json_decode($data,true);
  4.  
  5. // Это наш навык?
  6. if (isset($json['session'], $json['session']['skill_id'])) {
  7.     if ($json['session']['skill_id']!='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee') {
  8.         exit;
  9.     }
  10. }
  11. else {
  12.     exit;
  13. }
  14.  
  15. // Обработать команду
  16. if (isset($json['request'], $json['request']['command'])) {
  17.   $command=$json['request']['command'];
  18.  
  19.   // Запуск навыка
  20.   if ($command=='') {
  21.     $text='Система управления активирована';
  22.     $tts='Система управления активирована';
  23.   }
  24.   else {
  25.     // Команда касается плеера
  26.     if (in_array('плеер',$json['request']['nlu']['tokens'])) {
  27.       if (in_array('включи',$json['request']['nlu']['tokens'])) {
  28.         $text='Запускаю плеер';
  29.         $tts='Запускаю плеер';
  30.       }
  31.       elseif (in_array('выключи',$json['request']['nlu']['tokens'])) {
  32.         $text='Выключаю плеер';
  33.         $tts='Выключаю плеер';
  34.       }
  35.       else {
  36.         $text='Команда управления плеером не распознана';
  37.         $tts='Команда управления плеером не распознана';
  38.       }
  39.     }
  40.     // Неизвестная команда
  41.     else {
  42.       $text='Команда "'.$command.'" не распознана';
  43.       $tts='Команда '.$command.' не распознана';
  44.     }
  45.   }
  46. }
  47. else {
  48.   exit;
  49. }
  50.  
  51. // Отправить ответ
  52. $response=array(
  53.   'response'=>array(
  54.     'text'=>$text,
  55.     'tts'=>$tts,
  56.     'end_session'=>false,
  57.   ),
  58.   'version'=>'1.0'
  59. );
  60.  
  61. echo json_encode($response);
Проверки минимальные, как и выполняемые действия. Тут скрипт будет обрабатывать запуск навыка и команды, касающиеся устройства "плеер", причем команды могут быть только "включи" или "выключи", другие не принимаются.

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

Поделиться ссылкой ВКонтакте
Просмотров: 560 | Комментариев: 2

Комментарии

Отзывы посетителей сайта о статье
ManHunter (20.03.2024 в 10:31):
Нет. Или "Алиса", или "Яндекс".
master-ufa (20.03.2024 в 10:30):
А можно через "навыки" изменить имя "Алиса" на "Оксана" для одной колонки?

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0026 сек.) / Память: 4.5 Mb
Наверх