Барух Садогурский рассказывает, как с помощью сервиса голосовых команд Alexa можно добавить голосовой интерфейс к совершенно неожиданным вещам, таким как IntelliJ IDEA и Jenkins, а также, откинувшись в кресле с бокалом любимого напитка, управлять всем, чем угодно.
В основе статьи – выступление Баруха на конференции JPoint 2017 в Москве.
Барух занимается Developer Relations в компании JFrog. Кроме этого, он энтузиаст Groovy, DevOps, IOT и Home Automation.
В этой статье я буду разговаривать с Alexa. Это – продукт компании Amazon – голосовой помощник, такой же, как Siri, Cortana (ни дай Бог, если кто не сумел удалить), Google Home и т.д. Alexa – это сегодня лидер рынка, и мы поговорим, почему, хотя причина очевидна.
Есть три вида Alexa-устройств.
Я буду разговаривать с Amazon Tap. Раньше она не умела откликаться на имя, поэтому приходилось нажимать на кнопочку, отсюда в названии Tap. Сейчас она уже реагирует на имя, но название осталось. Полноценная Alexa большая, с хорошим динамиком. Есть еще «финтифлюшка» со слабым динамиком, которая предназначена для того, чтобы подключаться к другим ресиверам, динамикам и т.д. Все они вполне доступны, стоят 170, 130 и 50 долларов. У меня дома их в общей сложности девять. Зачем мне все это надо, мы сейчас поговорим.
Я упомянул о том, что Alexa сейчас — безусловный лидер рынка. Лидером она является благодаря открытому API для написания сценариев Alexa Skills. Как раз недавно говорилось о том, что количество скилов в основной базе достигло 10 тысяч. Большинство из них бестолковые, но благодаря многим полезным скиллам ничего похожего на Alexa по полезности и популярности нет. Как они накрутили 10 тысяч, вполне понятно. Там есть шаблон, по которому можно сделать скилл, поменяв пару строк. Затем опубликовать его, получить футболочку — и вот у них их 10 тысяч. Но сегодня мы научимся писать несколько более интересных скилов — и вы поймете, что это достаточно просто.
Почему я этим заинтересовался и как я пользуюсь армией «Алекс», которая у меня дома?
Я встаю и первым делом прошу ее выключить будильник («Alexa, turn off the alarm»). После чего как-то добираюсь до кухни и прошу включить свет («Alexa, turn on morning lights»). Здороваюсь с ней («Alexa, good morning»). Кстати, на «Good morning» она отвечает интересные вещи, например, сообщает, что в Малайзии в прошлом году нашли большую змею. Полезная информация с утра, под кофе.
Затем я спрашиваю о новостях («Alexa, what’s my news flash?»), и она зачитывает мне новости с разных ресурсов. После этого спрашиваю, что у меня в календаре? («Alexa, what’s on my agenda?»). Благодаря этому я знаю, как выглядит мой день. И дальше я спрашиваю, как я еду на работу, есть ли по дороге пробки и так далее («Alexa, how’s my commute?»). Это – домашнее-ориентированное использование, тут вообще нет никаких custom skills, все это встроено.
Но есть еще много крутых вариантов применения.
Но вы сюда пришли, конечно же, не для того, чтобы послушать консьюмерский спич про Алексу — вы пришли услышать про голосовые интерфейсы будущего. Нынче это хайп, и, в общем-то, достаточно неожиданный. Но этот хайп очень по делу, потому что голосовые интерфейсы – это то, чего мы ждем. Мы выросли на ожидании голосовых интерфейсов, которые будут работать. И вот это сейчас происходит на наших глазах.
Аналитики утверждают, что за последние 30 месяцев в области голосовых интерфейсов произошел прогресс, которого не было в течение последних 30 лет. Суть в том, что голосовой интерфейс в какой-то момент заменил графический. Это логично, потому что графический интерфейс – это был костыль, который существовал только потому, что голосовой был недостаточно развит.
Безусловно, есть вещи, которые лучше показывать, но, тем не менее, очень многое, что мы делаем с экрана, можно было бы, да и нужно было бы, делать голосом.
Вот этот API, который лежит поверх распознавания голоса и определенного Artificial Intelligence, который есть в Алексе, – это то, что гарантирует взрывное развитие в этой индустрии и возможность для многих людей писать много полезных скиллов.
Сегодня мы посмотрим два скилла. Первый открывает приложение, мою IntelliJ IDEA, и он, конечно, прикольный, но не очень полезный (так как открывать приложение голосом, а затем писать код ручками не имеет особого смысла). Второй будет про Jenkins, и он должен быть намного полезнее.
Написание скилла – простая штука и состоит из трех этапов:
В основе лежит очень простая идея:
Мы можем вычленять переменные из текста и передавать в обработчик (к примеру, я прошу открыть IDEA, которая является слотом, но я точно так же мог попросить открыть Rider или Sea Lion).
JSON-ом я называю команды, а дальше даю текстом, как эти команды могут звучать. И вот тут происходит волшебство, потому что одно и то же можно сказать разными способами. И этот Artificial Intelligence (Voice Recognition, который предоставляет Alexa) умеет подбирать по смыслу не только ту команду, которую я прописал, но и все похожие. Кроме этого, есть набор встроенных команд, таких как Stop, Start, Help, Yes, No и так далее, для которых не надо писать никаких примеров.
Вот JSON IntentSchema, в которой прописано, какие примеры я хочу. Этот наш пример, который открывает тулзы из JetBrains Toolbox.
Вы видите, что у меня есть интент, который называется OpenIntent, и есть один слот Tool. Его параметр – это какой-то список тулзов. Кроме того, там еще хелп.
Вот какие бывают типы слотов:
Обязательно нужно помнить, что они не являются enum. То есть этот список служит только приоритетом. Если Alexa узнает какое-то другое слово, оно будет передано в мой скилл.
Вот тот самый List of Tools – те варианты, которые я ей дал.
Написание тут отличается от написания продуктов компании JetBrains просто потому, что Alexa работает с натуральными словами. Соответственно, если я напишу IntelliJ IDEA в одно слово, она не сможет распознать, что это такое.
Вот примеры того, как люди могут обращаться, чтобы затребовать открытие этого инструмента:
Есть и другие варианты. Когда Alexa видит этот набор, она знает, что синонимы этих слов тоже попадают под этот интент.
Мы описали голосовой интерфейс, и дальше у нас идет обработчик команд. Он работает очень просто: Alexa превращает голос, которым мы с ним говорим, в REST-запрос в формате JSON.
Запрос может идти или в AWS Lambda Function или на произвольный HTTP-сервер. Преимущество Lambda Function в том, что для них не нужен произвольный HTTP-сервер. У нас есть platform as a service, где мы можем писать наш обработчик без необходимости поднимать какие-то сервисы.
Преимущества AWS Lambda Function:
С Java 8 все гораздо сложнее. В Java у нас нет каких-то top-level-функций, которые мы можем написать и вызывать, — все это должно быть завернуто в классы. Наш друг Сергей Егоров на короткой ноге с ребятами, которые пилят Lambda, и сейчас работает над тем, чтобы Groovy можно было использовать в Lambda не так, как сейчас (когда мы делаем jar-файл и работаем с ним так же), а напрямую через Groovy-скрипты, когда можно будет писать скрипты с колбеками, которые будут вызываться.
Класс, который обрабатывает запросы Alexa к Java, называется Speechlet. Когда вы видите спичлеты, вы вспоминаете про апплеты, про мидлеты и про сервлеты. И вы уже знаете, чего ожидать – контролируемого цикла исполнения, то есть, грубо говоря, какой-то интерфейс, который нам, как разработчикам, нужно будет имплементировать с разными фазами жизни нашего «лета», в данном случае – спичлета.
И вы не ошиблись, потому что вот у вас интерфейс Speechlet, где есть четыре метода, которые нам нужно имплементировать:
В начале
В общем-то очень похоже на любой другой «лет», и сейчас мы посмотрим, как все выглядит в коде.
Существует два места в Амазоне, с которыми нам нужно работать:
У нас есть юзер, который говорит: «Alexa, ask Jenkins how’s my build?». Это приходит в устройство, в данном случае – в Amazon Tap. Дальше все идет в тот самый скилл, который превращает голос в JSON, обращается в Lambda Functions и дергает Jenkins API.
Теперь самое время посмотреть на код
(https://github.com/jbaruch/jb-toolbox-alexa-skill/blob/master/src/main/groovy/ru/jug/jpoint2017/alexa/jbtoolboxactivator/JbToolBoxActivatorSpeechlet.groovy)
Вот наш спичлет. Мы вынесли в константы Help Test, Default Question и так далее. У нас есть HTTP BUILDER, напомню, это сервис, который бежит к Amazon Lambda. Соответственно, он должен дергать что-то по интернету. На самом деле это Groovy, но добавьте boilerplate, и будет вам Java.
На
Из
Cамое интересное происходит в
И вот самое интересное –
Соответственно, потом мы возвращаем ответ. Ответ у нас может быть или
Хелп работает хелпом, стоп и кансел делает
Все предельно просто, я специально написал его таким простым, чтобы вы увидели, как это просто.
Давайте осмотрим на другой skill. И в этот раз пойдем наоборот: от кода к скиллу и в конце попробуем его запустить. Вот Jenkins speechlet – обработчик скилла, который управляет Дженкинсом (https://github.com/jbaruch/jenkins-alexa-skill/blob/master/src/main/groovy/ru/jug/jpoint2017/alexa/jenkins/JenkinsSpeechlet.groovy).
Все начинается очень похоже:
Тут у нас, соответственно, побольше интентов, имеет смысл посмотреть нашу модель — https://github.com/jbaruch/jenkins-alexa-skill/blob/master/src/main/resources/speechAssets/IntentSchema.json
У нас есть
Начнем. Вот к нам пришел интент, и мы берем у него данные по имени. Если у нас попросили last build, то мы пойдем в Jenkins API и возьмем оттуда список билдов с их именем и цветом (цвет красный или синий – прошел или не прошел). Возьмем last, билд с таким-то названием, прошел он или не прошел.
И дальше у нас есть то самое yes-no. Если мы ответили да, то нужно проверить, был ли вопрос или, может, мы просто так сказали «да». И если вопрос был, то опять же, мы создадим какой-то post request, в этот раз в наш Jenkins API, и завалим job. И если действительно job стал красненьким, мы скажем, что мы завалили job, а если нет – ничего не получилось. Ну и stop – мы говорим Goodbye и выходим.
Такая интересная функциональность, и кода тут на одну страницу. Я пытался усложнить код, но там нечего усложнять, потому что это на самом деле так просто.
После этого мы собираем все это грейдлом, причем Gradle тут простейший. У меня тут есть куча зависимостей: groovy, который мне, естественно, нужен, плюс три зависимости вот этого API, логгер, commons-io, commons-lang. Все! testCompile – естественно, у меня тесты под это дело. И дальше я строю ZIP, в котором в главной директории лежит мой jar. Кроме того, есть директория lib со всеми зависимостями. Реально проще некуда.
Теперь посмотрим, что мы делаем с этим билдом. У нас есть два места, куда мы реально обращаемся. Первое – Alexa Skill Kit, в нем есть все скиллы, которые я написал. Давайте посмотрим на Jenkins Skill.
Как я уже сказал, тут у нас есть metadata: название и invocation name — то самое слово (Дженкинс), когда я говорю: «Alexa, попроси у Дженкинса сделать то-то».
Далее можно указать, нужен ли мне аудиоплеер (если я, к примеру, хочу стримить звук, например, играть музыку, проигрывать новости и так далее)
Дальше у нас есть наша интерактивная модель – тот самый JSON, который описывает интенты.
Тут нет никакого слота, но в JetBrains у нас был бы custom slot и у этого слота были бы values и примеры, которые работают на мои интенты.
Вкладка конфигурации – что я вызываю: Lambda или HTTPS.
Тут же есть тот самый Account Linking – даем ли мы возможность залогиниться при настройке скилла (и по идее, в Jenkins было бы неплохо это сделать).
И дальше Permissions для всяких покупок, но это нас уже не очень интересует.
Вкладка тестирования – тут я могу писать то, что она будет делать, если я буду говорить.
Дальше вкладка Publishing Information. Скилл проходит всякие проверки у Амазона. Я должен им рассказать, какая от него польза, как это тестируется и так далее.
Вторая часть работы со скиллом – это моя AWS Lambda. Там у меня нет ничего, кроме этих трех скиллов.
Давайте посмотрим на Jenkins. Сюда я заливаю тот самый jar, который построил Gradle. Еще здесь есть variables (host, password и user).
В конфигурации я пишу, какой мне нужен runtime. Как я уже говорил, поддерживается Node, Python, Java. И недавно стал поддерживаться С#. Дальше – handler. Это – где внутри находится мой спичлет. Role у меня называется lambda_basic_execution. И у меня есть description. Все.
Триггер приходит из Алексы. Есть специальный вид триггеров, который называется Alexa Kit. Это значит, что вызов будет оттуда.
И тут тоже можно потестировать, если известно, какой JSON Алекса посылает Лямбде. А я знаю, какой, ведь когда я это буду тестировать здесь, я увижу этот Jenkins. И сейчас давайте посмотрим на этот Jenkins. Я послал запрос: how is my build.
Я послал intent, intent называется last build, и Alexa сообразила, что я хочу.
Это все обернуто в JSON, который я могу протестировать в Лямбде. Я могу сказать: я посылаю вот этот JSON. И когда я это скажу, я могу протестировать только этот кусок.
Да, у меня есть тестирование end to end вот с этой штукой распознавания голоса (текст в JSON, в Лямбду и потом обратно) или я могу этот тестировать только на уровне Лямбды, если я знаю тот JSON, который нужен.
В общем, пора бы уже запустить все. У нас есть Jenkins, и у меня есть билд предыдущего скилла.
Дальше у меня происходит вот такой диалог с системой:
Барух: Alexa, open Jenkins
Alexa: With this skill you can control your build server
Барух: Alexa, ask Jenkins, how is my build?
Alexa: You last build jb-toolbox-alexa-skill is passing. What do you want to do next?
Барух: What’s the code coverage?
Alexa: The code coverage for the last jb-toolbox-alexa-skill build is 30%. What do you want to do next?
Барух: Fail the build.
Alexa: I understand you want to fail the latest successful build. Are you sure?
Барух: Yes
Alexa: Successfully changed the build status to failed. Thank you and goodbye.
Это очень круто и очень просто, даже стыдно за такой легкий уровень.
Кроме голосового интерфейса, у Alexa есть визуальный компаньон. Это приложение, в котором кроме настройки всех девайсов, интернета и прочего, есть еще карточки. Это такой стрим из информации, которая является вспомогательной для голосового интерфейса. В общем-то, это здравая мысль, потому что не все можно сказать голосом. Если я, например, сейчас запросил
Давайте теперь поговорим про два вида недостатков: мнимые и реальные. Первый — мнимый — связан с распознаванием речи. Пользователь может говорить с акцентом или не очень внятно произносить слова. Я не знаю, как они это делают, но Alexa прекрасно понимает даже моего маленького сына, хотя мы с женой понимаем его далеко не всегда.
Второй мнимый недостаток показан на иллюстрации ниже.
На самом деле эта проблема решается очень просто при помощи средств безопасности: Alexa никогда не сделает заказ в магазине или не откроет дверь, пока вы не произнесете заранее предустановленный пин-код.
Еще существует такой аспект: «Ой-ой-ой, нас постоянно слушают». Это все давным-давно уже реверс-инжинирнули, всем прекрасно понятно, что слушают. Единственное, что слушают постоянно, — это триггер-слова. То есть когда я ее зову. Иногда триггер-слова произносятся случайно, после этого в течение десяти секунд записывается, что мы говорим, и запись отсылается на главный интент, на главный скилл. Если там она не распознается, то выкидывается в мусор. Поэтому вся эта паранойя неоправданна.
А теперь мы с вами поговорим про реальные недостатки. Их можно разбить на несколько категорий.
Есть недостатки voice user interface. Они связаны с тем, что некоторые называют вещи одинаковыми словами. Попробуйте попросить музыку группы Helloween и не получить музыку к празднику Halloween. Думаю, что, учитывая прогресс, контекст должен эту проблему решить, потому что Alexa уже должна знать, что между музыкой к празднику Halloween и группой Helloween я предпочитаю группу. К этому все идет, но пока что это еще не так, особенно – если контекст непонятен.
И еще одна проблема. Связана она с отсутствием поддержки нестандартных названий и имен. Если Alexa не знает какое-то имя или название, то она не сможет его произнести.
Кроме того, у самой Alexa как у консьюмерского девайса, тоже есть недостатки:
Самые большие и мерзкие недостатки вылезают при попытке написать Alexa Skill, например тот, который мы сейчас делали. Java API – это кошмар, голосовую модель нужно вручную копировать на страничку, и это указано даже в документации. Кроме того, нет никакого бутстрапа: ни Maven Archetype, ни Lazybones Template.
Нет никакой локальной тестовой инфраструктуры, то есть если я поменял единственную строчку в коде, мне нужно пойти на сайт скилла и поменять ручками в text area json, a потом пойти на Лямбду и загрузить там новый jar (ну, на Lambda, допустим, есть Rest API, потому что она все-таки написала для разработчиков, туда можно сделать continuous deployment, там все нормально). Но на стороне skill kit при любом изменении мне нужно пойти и все это загрузить и потестировать только на сервере. Локально никакой инфраструктуры нет, и это, естественно, тоже очень большой минус.
Вот и все. Скиллы, о которых шла речь, можно взять с моего Github – jb-toolbox-alexa-skill и jenkins-alexa-skill. У меня к вам есть большая просьба: давайте придумывать и писать полезные скиллы, тогда мы сможем вернуться к этой теме на следующих конференциях.
Надеемся, вам пригодится опыт Баруха. А если вы любите смаковать все детали разработки на Java так же, как и мы, наверняка вам будут интересны вот эти доклады на нашей апрельской конференции JPoint 2018:
В основе статьи – выступление Баруха на конференции JPoint 2017 в Москве.
Барух занимается Developer Relations в компании JFrog. Кроме этого, он энтузиаст Groovy, DevOps, IOT и Home Automation.
Что такое Alexa и зачем она в нашей жизни?
В этой статье я буду разговаривать с Alexa. Это – продукт компании Amazon – голосовой помощник, такой же, как Siri, Cortana (ни дай Бог, если кто не сумел удалить), Google Home и т.д. Alexa – это сегодня лидер рынка, и мы поговорим, почему, хотя причина очевидна.
Есть три вида Alexa-устройств.
Я буду разговаривать с Amazon Tap. Раньше она не умела откликаться на имя, поэтому приходилось нажимать на кнопочку, отсюда в названии Tap. Сейчас она уже реагирует на имя, но название осталось. Полноценная Alexa большая, с хорошим динамиком. Есть еще «финтифлюшка» со слабым динамиком, которая предназначена для того, чтобы подключаться к другим ресиверам, динамикам и т.д. Все они вполне доступны, стоят 170, 130 и 50 долларов. У меня дома их в общей сложности девять. Зачем мне все это надо, мы сейчас поговорим.
Я упомянул о том, что Alexa сейчас — безусловный лидер рынка. Лидером она является благодаря открытому API для написания сценариев Alexa Skills. Как раз недавно говорилось о том, что количество скилов в основной базе достигло 10 тысяч. Большинство из них бестолковые, но благодаря многим полезным скиллам ничего похожего на Alexa по полезности и популярности нет. Как они накрутили 10 тысяч, вполне понятно. Там есть шаблон, по которому можно сделать скилл, поменяв пару строк. Затем опубликовать его, получить футболочку — и вот у них их 10 тысяч. Но сегодня мы научимся писать несколько более интересных скилов — и вы поймете, что это достаточно просто.
Почему я этим заинтересовался и как я пользуюсь армией «Алекс», которая у меня дома?
Я встаю и первым делом прошу ее выключить будильник («Alexa, turn off the alarm»). После чего как-то добираюсь до кухни и прошу включить свет («Alexa, turn on morning lights»). Здороваюсь с ней («Alexa, good morning»). Кстати, на «Good morning» она отвечает интересные вещи, например, сообщает, что в Малайзии в прошлом году нашли большую змею. Полезная информация с утра, под кофе.
Затем я спрашиваю о новостях («Alexa, what’s my news flash?»), и она зачитывает мне новости с разных ресурсов. После этого спрашиваю, что у меня в календаре? («Alexa, what’s on my agenda?»). Благодаря этому я знаю, как выглядит мой день. И дальше я спрашиваю, как я еду на работу, есть ли по дороге пробки и так далее («Alexa, how’s my commute?»). Это – домашнее-ориентированное использование, тут вообще нет никаких custom skills, все это встроено.
Но есть еще много крутых вариантов применения.
- Умный дом – это самый крутой вариант. Как вы уже, наверное, видели, свет я включал через Алексу. Но это может быть не только свет: замки, камеры, охранная сигнализация, всякие сенсоры – все, что подключается к умному дому.
- Музыка. Alexa может проигрывать музыку, которую я люблю. Сюда же — аудиокниги. У взрослых на них обычно нет времени, но мой сын слушает сказки через Алексу.
- Вопросы/ответы. То есть то, что обычно ищут в Википедии.
- Новости/погода – об этом я уже говорил.
- Заказ еды – конечно же, очень важно, чтобы можно было, не вставая с дивана, заказать пиццу, суши и т.д.
Но вы сюда пришли, конечно же, не для того, чтобы послушать консьюмерский спич про Алексу — вы пришли услышать про голосовые интерфейсы будущего. Нынче это хайп, и, в общем-то, достаточно неожиданный. Но этот хайп очень по делу, потому что голосовые интерфейсы – это то, чего мы ждем. Мы выросли на ожидании голосовых интерфейсов, которые будут работать. И вот это сейчас происходит на наших глазах.
Аналитики утверждают, что за последние 30 месяцев в области голосовых интерфейсов произошел прогресс, которого не было в течение последних 30 лет. Суть в том, что голосовой интерфейс в какой-то момент заменил графический. Это логично, потому что графический интерфейс – это был костыль, который существовал только потому, что голосовой был недостаточно развит.
Безусловно, есть вещи, которые лучше показывать, но, тем не менее, очень многое, что мы делаем с экрана, можно было бы, да и нужно было бы, делать голосом.
Вот этот API, который лежит поверх распознавания голоса и определенного Artificial Intelligence, который есть в Алексе, – это то, что гарантирует взрывное развитие в этой индустрии и возможность для многих людей писать много полезных скиллов.
Сегодня мы посмотрим два скилла. Первый открывает приложение, мою IntelliJ IDEA, и он, конечно, прикольный, но не очень полезный (так как открывать приложение голосом, а затем писать код ручками не имеет особого смысла). Второй будет про Jenkins, и он должен быть намного полезнее.
Написание скилла для Alexa
Написание скилла – простая штука и состоит из трех этапов:
- Определить интерактивную модель – тот самый голосовой API;
- Написать обработчик команд, которые к нам приходят;
- Пройти ревью в Амазоне (этот этап мы рассматривать не будем).
Интерактивная голосовая модель: что это, зачем это?
В основе лежит очень простая идея:
Мы можем вычленять переменные из текста и передавать в обработчик (к примеру, я прошу открыть IDEA, которая является слотом, но я точно так же мог попросить открыть Rider или Sea Lion).
JSON-ом я называю команды, а дальше даю текстом, как эти команды могут звучать. И вот тут происходит волшебство, потому что одно и то же можно сказать разными способами. И этот Artificial Intelligence (Voice Recognition, который предоставляет Alexa) умеет подбирать по смыслу не только ту команду, которую я прописал, но и все похожие. Кроме этого, есть набор встроенных команд, таких как Stop, Start, Help, Yes, No и так далее, для которых не надо писать никаких примеров.
Вот JSON IntentSchema, в которой прописано, какие примеры я хочу. Этот наш пример, который открывает тулзы из JetBrains Toolbox.
{
"intents": [
{
"intent": "OpenIntent",
"slots" : [
{
"name" : "Tool",
"type" : "LIST_OF_TOOLS"
}
]
},
{
"intent": "AMAZON.HelpIntent"
}
]
}
Вы видите, что у меня есть интент, который называется OpenIntent, и есть один слот Tool. Его параметр – это какой-то список тулзов. Кроме того, там еще хелп.
Типы слотов
Вот какие бывают типы слотов:
- Встроенные, такие как AMAZON.DATE, DURATION, FOUR_DIGIT_NUMBER, NUMBER, TIME;
- Масса всякой информации, которую Alexa уже знает и вокруг которой мы можем написать скиллы, например, список актеров, рейтинги, список городов в Европе и США, список известных людей, фильмов, напитки и т.д. (AMAZON.ACTOR, AGREATERATING, AIRLINE, EUROPE_CITY, US_CITY, PERSON, MOVIE, DRINK). Информация о них и все возможные варианты уже заложены и хранятся в Alexa.
- Custom Types.
Обязательно нужно помнить, что они не являются enum. То есть этот список служит только приоритетом. Если Alexa узнает какое-то другое слово, оно будет передано в мой скилл.
Вот тот самый List of Tools – те варианты, которые я ей дал.
Написание тут отличается от написания продуктов компании JetBrains просто потому, что Alexa работает с натуральными словами. Соответственно, если я напишу IntelliJ IDEA в одно слово, она не сможет распознать, что это такое.
Примеры фраз для команд
Вот примеры того, как люди могут обращаться, чтобы затребовать открытие этого инструмента:
OpenIntent open {Tool}
OpenIntent start {Tool}
OpenIntent startup {Tool}
OpenIntent {Tool}
Есть и другие варианты. Когда Alexa видит этот набор, она знает, что синонимы этих слов тоже попадают под этот интент.
Обработчик команд
Мы описали голосовой интерфейс, и дальше у нас идет обработчик команд. Он работает очень просто: Alexa превращает голос, которым мы с ним говорим, в REST-запрос в формате JSON.
Запрос может идти или в AWS Lambda Function или на произвольный HTTP-сервер. Преимущество Lambda Function в том, что для них не нужен произвольный HTTP-сервер. У нас есть platform as a service, где мы можем писать наш обработчик без необходимости поднимать какие-то сервисы.
Преимущества AWS Lambda Function:
- Serverless cumpute server – он работает сам по себе
- No-ops!
- Node.js – это самая элегантная из имплементаций. Мы пишем Javascript-функции, и когда мы дергаем этот сервис, там они отрабатываются.
- Поддержка Python (мы пишем скрипт с какими-то функциями, и это все прекрасно работает)
- Java 8.
С Java 8 все гораздо сложнее. В Java у нас нет каких-то top-level-функций, которые мы можем написать и вызывать, — все это должно быть завернуто в классы. Наш друг Сергей Егоров на короткой ноге с ребятами, которые пилят Lambda, и сейчас работает над тем, чтобы Groovy можно было использовать в Lambda не так, как сейчас (когда мы делаем jar-файл и работаем с ним так же), а напрямую через Groovy-скрипты, когда можно будет писать скрипты с колбеками, которые будут вызываться.
Speechlet
Класс, который обрабатывает запросы Alexa к Java, называется Speechlet. Когда вы видите спичлеты, вы вспоминаете про апплеты, про мидлеты и про сервлеты. И вы уже знаете, чего ожидать – контролируемого цикла исполнения, то есть, грубо говоря, какой-то интерфейс, который нам, как разработчикам, нужно будет имплементировать с разными фазами жизни нашего «лета», в данном случае – спичлета.
И вы не ошиблись, потому что вот у вас интерфейс Speechlet, где есть четыре метода, которые нам нужно имплементировать:
public interface Speechlet {
void onSessionStarted(SessionStartedRequest request, Session session);
SpeechletResponse onLaunch(LaunchRequest request, Session session);
SpeechletResponse onIntent(IntentRequest request, Session session);
void onSessionEnded(SessionEndedRequest request, Session session);
}
В начале
оnSessionStarted
– это когда Alexa поднимается и осознает, что у нее есть спичлет. onLaunch
– это когда мы вызываем команду с названием нашего скилла. onIntent
– когда с нами поговорил человек, и мы получили то, что он сказал, в виде Json и команду, которую он назвал. onSessionEnded
– это когда мы делаем обычный клинап.В общем-то очень похоже на любой другой «лет», и сейчас мы посмотрим, как все выглядит в коде.
Где писать Speechlet
Существует два места в Амазоне, с которыми нам нужно работать:
- Alexa Skill Kit, где мы описываем новый скилл (интерактивную модель, метаданные, название, куда обращаться, когда идет запрос).
- Lambda или любой другой сервис, где у нас живет speechlet, который является обработчиком запросов. То есть, грубо говоря, у нас получается примерно так:
У нас есть юзер, который говорит: «Alexa, ask Jenkins how’s my build?». Это приходит в устройство, в данном случае – в Amazon Tap. Дальше все идет в тот самый скилл, который превращает голос в JSON, обращается в Lambda Functions и дергает Jenkins API.
Пример кода: JbToolBoxActivator Speechlet
Теперь самое время посмотреть на код
(https://github.com/jbaruch/jb-toolbox-alexa-skill/blob/master/src/main/groovy/ru/jug/jpoint2017/alexa/jbtoolboxactivator/JbToolBoxActivatorSpeechlet.groovy)
Вот наш спичлет. Мы вынесли в константы Help Test, Default Question и так далее. У нас есть HTTP BUILDER, напомню, это сервис, который бежит к Amazon Lambda. Соответственно, он должен дергать что-то по интернету. На самом деле это Groovy, но добавьте boilerplate, и будет вам Java.
На
оnSessionStarted
мы конфигурируем наш HTTP клиент, говорим, что будем стучаться в тулбокс по такому-то хосту и такому-то порту. Дальше мы считываем из файла список поддерживаемым тулзов, который вы тоже уже видели (List of tools.txt).Из
onLaunch
мы выдаем HelpResponse
. Этот тот самый, о котором вы слышали, – я могу открывать такие же тулзы.Cамое интересное происходит в
onIntent
. Мы делаем switch по названию интента. То есть из всех команд, которые у нас были, что к нам пришло. В данном случае, если вы помните, у нас было два интента. Один – это open, который наш кастомер, а другой – это help. Еще могут быть stop, cancel и любые другие.И вот самое интересное –
openIntent
. Мы из него вынимаем тот самый слот, тул (у нас это были IDEA и так далее), и дальше обращаемся по HTTP-билдеру в наш URI плюс вот этот тул. То есть мы обращаемся к API JetBrains Toolbox, который понимает этот формат.Соответственно, потом мы возвращаем ответ. Ответ у нас может быть или
Opening $toolName
, или, если тул не в списке: Sorry, I can’t find a tool named $toolName in the toolbox. Goodbye.Хелп работает хелпом, стоп и кансел делает
Goodbye
. Если пришел интент, которого у нас не существует, мы кидаем invalid Intent.Все предельно просто, я специально написал его таким простым, чтобы вы увидели, как это просто.
onSessionEnded
у меня ничего нет. Тут у меня есть метод newAskResponse
, который в чистейшем виде boilerplate в течение десяти строчек кода создает три объекта: один объект, в который в конструкторе теоретически нужно перевести два других, в которых нужно перевести какие-то тексты. В общем все, что он делает, – создает объект SpeechletResponse
, в котором у нас есть OutputSpeech text и repromptText. Почему это занимает десять строчек кода? Ну, так исторически сложилось, мы об этом немного поговорим. Надеюсь, все остальное, кроме этого бойлерплейта, понятно и просто.Пример кода: Jenkins Speechlet
Давайте осмотрим на другой skill. И в этот раз пойдем наоборот: от кода к скиллу и в конце попробуем его запустить. Вот Jenkins speechlet – обработчик скилла, который управляет Дженкинсом (https://github.com/jbaruch/jenkins-alexa-skill/blob/master/src/main/groovy/ru/jug/jpoint2017/alexa/jenkins/JenkinsSpeechlet.groovy).
Все начинается очень похоже:
оnSessionStarted
мы инициализируем HTTPBuilder, который будет обращаться к Дженкинсу через Rest API в JENKINS_HOST и авторизоваться с определенным username и password. Вот это, конечно, через environment variables не очень правильно. У Alexa есть целая система, которая позволяет регистрироваться с username и password в скилл, то есть когда мы инсталлируем этот скилл на нашей локальной Alexa, открывается окно, в котором мы можем залогиниться. Но для простоты здесь мы берем username и password у environment variables.onLaunch
мы отбарабаним тот же текст: «Приветствуем вас, гигантские морды, мы управляем Дженкинсом», — и тут начинается наш интересный onIntent
.Тут у нас, соответственно, побольше интентов, имеет смысл посмотреть нашу модель — https://github.com/jbaruch/jenkins-alexa-skill/blob/master/src/main/resources/speechAssets/IntentSchema.json
У нас есть
LastBuild
, который, очевидно, вернет нам информацию про наш последний билд, GetCodeCoverage
, который вернет нам информацию о покрытии кода, и FailBuildIntent
, который завалит билд. Кроме того, есть еще куча встроенных, таких как help, stop, cancel и даже yes, no. Посмотрим, что мы, собственно говоря, делаем с этими yes и no.Начнем. Вот к нам пришел интент, и мы берем у него данные по имени. Если у нас попросили last build, то мы пойдем в Jenkins API и возьмем оттуда список билдов с их именем и цветом (цвет красный или синий – прошел или не прошел). Возьмем last, билд с таким-то названием, прошел он или не прошел.
GetCodeCoverage
– опять же, мы обратимся к Jenkins API, к плагину, который называется jacoco. В нем, как и в любом хорошем плагине, есть масса параметров. Мы возьмем один – lineCoverage — и получим какую-то информацию.FailBuild
– это запрос на превращение приходящего билда в фейловый. Не хотелось бы сразу на это соглашаться. Alexa часто отзывается впустую, поэтому есть вероятность случайно зафейлить билд. И мы у нее попросим подтверждения. Мы пошлем еще один запрос и скажем: «вот я хочу завалить билд» «Действительно ли это то, что ты имел в виду?». Мы положим в sessions. Это как раз то, что держится через разные invokations, и мы положим какой-то флаг в fail requested.И дальше у нас есть то самое yes-no. Если мы ответили да, то нужно проверить, был ли вопрос или, может, мы просто так сказали «да». И если вопрос был, то опять же, мы создадим какой-то post request, в этот раз в наш Jenkins API, и завалим job. И если действительно job стал красненьким, мы скажем, что мы завалили job, а если нет – ничего не получилось. Ну и stop – мы говорим Goodbye и выходим.
Такая интересная функциональность, и кода тут на одну страницу. Я пытался усложнить код, но там нечего усложнять, потому что это на самом деле так просто.
После этого мы собираем все это грейдлом, причем Gradle тут простейший. У меня тут есть куча зависимостей: groovy, который мне, естественно, нужен, плюс три зависимости вот этого API, логгер, commons-io, commons-lang. Все! testCompile – естественно, у меня тесты под это дело. И дальше я строю ZIP, в котором в главной директории лежит мой jar. Кроме того, есть директория lib со всеми зависимостями. Реально проще некуда.
Использование Alexa Skill Kit
Теперь посмотрим, что мы делаем с этим билдом. У нас есть два места, куда мы реально обращаемся. Первое – Alexa Skill Kit, в нем есть все скиллы, которые я написал. Давайте посмотрим на Jenkins Skill.
Как я уже сказал, тут у нас есть metadata: название и invocation name — то самое слово (Дженкинс), когда я говорю: «Alexa, попроси у Дженкинса сделать то-то».
Далее можно указать, нужен ли мне аудиоплеер (если я, к примеру, хочу стримить звук, например, играть музыку, проигрывать новости и так далее)
Дальше у нас есть наша интерактивная модель – тот самый JSON, который описывает интенты.
Тут нет никакого слота, но в JetBrains у нас был бы custom slot и у этого слота были бы values и примеры, которые работают на мои интенты.
Вкладка конфигурации – что я вызываю: Lambda или HTTPS.
Тут же есть тот самый Account Linking – даем ли мы возможность залогиниться при настройке скилла (и по идее, в Jenkins было бы неплохо это сделать).
И дальше Permissions для всяких покупок, но это нас уже не очень интересует.
Вкладка тестирования – тут я могу писать то, что она будет делать, если я буду говорить.
Дальше вкладка Publishing Information. Скилл проходит всякие проверки у Амазона. Я должен им рассказать, какая от него польза, как это тестируется и так далее.
Использование AWS Lambda
Вторая часть работы со скиллом – это моя AWS Lambda. Там у меня нет ничего, кроме этих трех скиллов.
Давайте посмотрим на Jenkins. Сюда я заливаю тот самый jar, который построил Gradle. Еще здесь есть variables (host, password и user).
В конфигурации я пишу, какой мне нужен runtime. Как я уже говорил, поддерживается Node, Python, Java. И недавно стал поддерживаться С#. Дальше – handler. Это – где внутри находится мой спичлет. Role у меня называется lambda_basic_execution. И у меня есть description. Все.
Триггер приходит из Алексы. Есть специальный вид триггеров, который называется Alexa Kit. Это значит, что вызов будет оттуда.
И тут тоже можно потестировать, если известно, какой JSON Алекса посылает Лямбде. А я знаю, какой, ведь когда я это буду тестировать здесь, я увижу этот Jenkins. И сейчас давайте посмотрим на этот Jenkins. Я послал запрос: how is my build.
Я послал intent, intent называется last build, и Alexa сообразила, что я хочу.
Это все обернуто в JSON, который я могу протестировать в Лямбде. Я могу сказать: я посылаю вот этот JSON. И когда я это скажу, я могу протестировать только этот кусок.
Да, у меня есть тестирование end to end вот с этой штукой распознавания голоса (текст в JSON, в Лямбду и потом обратно) или я могу этот тестировать только на уровне Лямбды, если я знаю тот JSON, который нужен.
Демонстрация работы Jenkins Speechlet
В общем, пора бы уже запустить все. У нас есть Jenkins, и у меня есть билд предыдущего скилла.
Дальше у меня происходит вот такой диалог с системой:
Барух: Alexa, open Jenkins
Alexa: With this skill you can control your build server
Барух: Alexa, ask Jenkins, how is my build?
Alexa: You last build jb-toolbox-alexa-skill is passing. What do you want to do next?
Барух: What’s the code coverage?
Alexa: The code coverage for the last jb-toolbox-alexa-skill build is 30%. What do you want to do next?
Барух: Fail the build.
Alexa: I understand you want to fail the latest successful build. Are you sure?
Барух: Yes
Alexa: Successfully changed the build status to failed. Thank you and goodbye.
Это очень круто и очень просто, даже стыдно за такой легкий уровень.
Визуальный компаньон Alexa
Кроме голосового интерфейса, у Alexa есть визуальный компаньон. Это приложение, в котором кроме настройки всех девайсов, интернета и прочего, есть еще карточки. Это такой стрим из информации, которая является вспомогательной для голосового интерфейса. В общем-то, это здравая мысль, потому что не все можно сказать голосом. Если я, например, сейчас запросил
code coverage
, и она мне дала какую-то метрику — на самом деле jacoco возвращает шесть метрик: покрытие по branch execution, по методам, по линиям кода и т.д. Естественно, имеет смысл отобразить это визуально в приложении. Это можно сделать одной строчкой – есть команда «пошли текст в приложение». И дальше туда можно посылать простой текст, картинку или html, которые будут там отображаться. Например, если спросить о погоде, помощник даст краткий ответ. В приложении же можно увидеть погоду на всю неделю. Также я сейчас проверил, что у меня дома заперт замок, и что мой сын в данный момент включил себе сказку о Красной Шапочке. Вот как это выглядит:Недостатки Alexa: мнимые и реальные
Давайте теперь поговорим про два вида недостатков: мнимые и реальные. Первый — мнимый — связан с распознаванием речи. Пользователь может говорить с акцентом или не очень внятно произносить слова. Я не знаю, как они это делают, но Alexa прекрасно понимает даже моего маленького сына, хотя мы с женой понимаем его далеко не всегда.
Второй мнимый недостаток показан на иллюстрации ниже.
На самом деле эта проблема решается очень просто при помощи средств безопасности: Alexa никогда не сделает заказ в магазине или не откроет дверь, пока вы не произнесете заранее предустановленный пин-код.
Еще существует такой аспект: «Ой-ой-ой, нас постоянно слушают». Это все давным-давно уже реверс-инжинирнули, всем прекрасно понятно, что слушают. Единственное, что слушают постоянно, — это триггер-слова. То есть когда я ее зову. Иногда триггер-слова произносятся случайно, после этого в течение десяти секунд записывается, что мы говорим, и запись отсылается на главный интент, на главный скилл. Если там она не распознается, то выкидывается в мусор. Поэтому вся эта паранойя неоправданна.
А теперь мы с вами поговорим про реальные недостатки. Их можно разбить на несколько категорий.
Есть недостатки voice user interface. Они связаны с тем, что некоторые называют вещи одинаковыми словами. Попробуйте попросить музыку группы Helloween и не получить музыку к празднику Halloween. Думаю, что, учитывая прогресс, контекст должен эту проблему решить, потому что Alexa уже должна знать, что между музыкой к празднику Halloween и группой Helloween я предпочитаю группу. К этому все идет, но пока что это еще не так, особенно – если контекст непонятен.
И еще одна проблема. Связана она с отсутствием поддержки нестандартных названий и имен. Если Alexa не знает какое-то имя или название, то она не сможет его произнести.
Кроме того, у самой Alexa как у консьюмерского девайса, тоже есть недостатки:
- Не понимает множественные команды. Я могу построить интерактивную модель, как мы сделали с Jenkins, когда я не произносил каждый раз ее имя для передачи следующей команды. Но, например, выполнить команду «Alexa, turn on TV and set living room lights to 20%» на данный момент она не может. И если команд много и ты ими пользуешься постоянно, это надоедает.
- Не работает в кластере. Несмотря на то, что у меня дома семь таких девайсов, каждый из них считает себя единственным. И поэтому если я стою в месте, где их три, то все три мне отвечают. Кроме того, я не могу с помощью одной включить музыку у другой, потому что они не знают, что их больше, чем одна. Эта проблема известна, над ней работают и, надеюсь, скоро это будет решено.
- Не знает, где она находится и где нахожусь я. Из-за этого Alexa не может среагировать на команду «Turn on the lights». Я должен сказать «Turn on the lights in the bedroom», и это глупо.
- Само приложение сделано на html5, оно медленное, кривое, но это тоже чинится.
- Понимает только три языка: британский английский, американский английский и немецкий. Соответственно, по-русски ее еще пока не научили.
Самые большие и мерзкие недостатки вылезают при попытке написать Alexa Skill, например тот, который мы сейчас делали. Java API – это кошмар, голосовую модель нужно вручную копировать на страничку, и это указано даже в документации. Кроме того, нет никакого бутстрапа: ни Maven Archetype, ни Lazybones Template.
Нет никакой локальной тестовой инфраструктуры, то есть если я поменял единственную строчку в коде, мне нужно пойти на сайт скилла и поменять ручками в text area json, a потом пойти на Лямбду и загрузить там новый jar (ну, на Lambda, допустим, есть Rest API, потому что она все-таки написала для разработчиков, туда можно сделать continuous deployment, там все нормально). Но на стороне skill kit при любом изменении мне нужно пойти и все это загрузить и потестировать только на сервере. Локально никакой инфраструктуры нет, и это, естественно, тоже очень большой минус.
Заключение
Вот и все. Скиллы, о которых шла речь, можно взять с моего Github – jb-toolbox-alexa-skill и jenkins-alexa-skill. У меня к вам есть большая просьба: давайте придумывать и писать полезные скиллы, тогда мы сможем вернуться к этой теме на следующих конференциях.
Чтобы вы не пропустили ни одной детали, под спойлером мы оставили для вас ответы на вопросы из зала
Вопрос о безопасности. Есть ли вероятность брутфорса, когда пин-код может быть подобран (например, чтобы открыть дверь)?
Поскольку пин-код вводится голосом, а Alexa должна реагировать на каждый запрос, на перебор значений может уйти целый месяц (если, конечно, я не появлюсь дома до этого времени).
Смартфон, ноутбук при включении могут требовать аутентификацию. Как обстоят дела с Alexa?
У Alexa нет никакого пин-кода на включение, ты можешь его украсть и включать и выключать свет у меня дома. А все опасные штуки по идее должны быть защищены пин-кодом. На данный момент нет никакого voice recognition, хотя над этим работают, и это будет прикручено к аутентификации.
Что вы можете сказать об Alexa в сравнении с Google Home?
Google Home намного моложе Alexa, и у него пока что много проблем. Самая главная – это то, что писать скиллы для Google Home намного сложнее. Это требует намного большего уровня вхождения, что не очень хорошо для адаптации этой технологии. Однако у Google Home есть большое преимущество – собственный поисковик. У Alexa его нет, поэтому без кастомного поискового скилла Гугла обойтись невозможно.
Ты показывал большие и маленькие устройства Alexa. Есть ли смысл ставить много больших устройств?
Единственная разница между большими и маленькими устройствами — в качестве встроенного динамика. В самом маленьком динамик предназначен только для общения, но не для музыки. То есть везде можно поставить маленькие, а там, где ты хочешь слушать музыку – большой.
Вопрос о безопасности. Есть ли вероятность брутфорса, когда пин-код может быть подобран (например, чтобы открыть дверь)?
Поскольку пин-код вводится голосом, а Alexa должна реагировать на каждый запрос, на перебор значений может уйти целый месяц (если, конечно, я не появлюсь дома до этого времени).
Смартфон, ноутбук при включении могут требовать аутентификацию. Как обстоят дела с Alexa?
У Alexa нет никакого пин-кода на включение, ты можешь его украсть и включать и выключать свет у меня дома. А все опасные штуки по идее должны быть защищены пин-кодом. На данный момент нет никакого voice recognition, хотя над этим работают, и это будет прикручено к аутентификации.
Что вы можете сказать об Alexa в сравнении с Google Home?
Google Home намного моложе Alexa, и у него пока что много проблем. Самая главная – это то, что писать скиллы для Google Home намного сложнее. Это требует намного большего уровня вхождения, что не очень хорошо для адаптации этой технологии. Однако у Google Home есть большое преимущество – собственный поисковик. У Alexa его нет, поэтому без кастомного поискового скилла Гугла обойтись невозможно.
Ты показывал большие и маленькие устройства Alexa. Есть ли смысл ставить много больших устройств?
Единственная разница между большими и маленькими устройствами — в качестве встроенного динамика. В самом маленьком динамик предназначен только для общения, но не для музыки. То есть везде можно поставить маленькие, а там, где ты хочешь слушать музыку – большой.
Надеемся, вам пригодится опыт Баруха. А если вы любите смаковать все детали разработки на Java так же, как и мы, наверняка вам будут интересны вот эти доклады на нашей апрельской конференции JPoint 2018:
- Анализ программ: как понять, что ты хороший программист (Алексей Кудрявцев, JetBrains)
- Приключения Сеньора Холмса и Джуниора Ватсона в мире разработки ПО (Барух Садогурский, JFrog и Евгений Борисов, Naya Technologies)
- Extreme scaling with Alibaba JDK (Sanhong Li, Alibaba)