- PVSM.RU - https://www.pvsm.ru -
Голосовые помощники — не далёкое будущее, а реальная действительность. Alexa, Siri, Google Now, Алиса встроены в «умные» колонки, часы и телефоны. Они постепенно меняют наш способ взаимодействия с приложениями и устройствами. Через ассистента можно узнать прогноз погоды, купить билеты на самолет, заказать такси, послушать музыку и включить чайник на кухне, лежа на диване в другой комнате.
Siri или Alexa говорят с пользователями в основном по-английски, поэтому в России они не так популярны, как Алиса от Яндекса. Для разработчиков Алиса тоже удобнее: её создатели ведут блог, выкладывают удобные инструменты на GitHub и помогают встраивать ассистента в новые устройства.
Никита Дубко (@dark_mefody в Твиттере) — разработчик интерфейсов в Яндекс, организатор митапов MinskCSS и MinskJS и редактор новостей в Web-стандартах. Никита не работает в Яндекс.Диалогах и никак не связан с Яндекс.Алисой. Но ему было интересно разобраться, как Алиса работает, поэтому он попробовал применить её навыки для Web и подготовил об этом доклад на FrontendConf [1] РИТ++. В расшифровке доклада Никиты рассмотрим, что полезного могут принести голосовые помощники и построим навык прямо в процессе чтения этого материала.
Начнем с истории ботов. В 1966 году появился бот Eliza, который выдавал себя за психотерапевта. С ним можно было пообщаться, и некоторые даже верили, что им отвечает живой человек. В 1995 году вышел бот A.L.I.C.E. — не путать с Алисой. Бот умел выдавать себя за настоящего человека. До наших дней лежит в Open Source и дорабатывается. К сожалению, A.L.I.C.E. не проходит Тест Тьюринга, но вводить в заблуждение людей ему это не мешает.
В 2006 году IBM поместила в бота огромную базу знаний и сложный интеллект — так появился IBM Watson. Это огромный вычислительный кластер, который умеет обрабатывать английскую речь и выдавать какие-то факты.
В 2016 году компания Microsoft провела эксперимент. Она создала бота Tay, которого запустила в Twitter. Там бот обучался вести микроблог на основе того, как с ним общались живые подписчики. В итоге Tay стал расистом и женоненавистником. Теперь это закрытый аккаунт. Мораль: не пускайте детей в Твиттер, он может научить плохому.
Но это все боты, с которыми нельзя пообщаться для своей пользы. В 2015 году в Telegram появились «полезные». Боты существовали и в других программах, но Telegram произвел фурор. Можно было создать полезного бота, который выдавал информацию, генерировал контент, администрировал паблики — возможности большие, а API простой. Ботам добавили картинки, кнопки, подсказки — появился интерфейс взаимодействия.
Постепенно идея распространилась почти во всех мессенджерах: Facebook, Viber, ВКонтакте, WhatsApp и в других приложениях. Теперь боты — это тренд, они везде и всюду. Появились сервисы, которые позволяют писать API сразу под все платформы.
Разработки шли параллельно с ботами, но будем считать, что эра ассистентов наступила позже.
9 августа 2011 появилась Siri. Изначально это был независимый проект, в котором Apple разглядел что-то интересное, поэтому купил его. Это самый старый популярный голосовой ассистент, встроенный в ОС. Годом позже Google достаточно быстро догнал Apple, встроив в свою операционную систему голосового помощника Google Now.
Спустя 2 года Microsoft выпустили Microsoft Cortana. Только непонятно зачем — мобильный рынок голосовых помощников, кажется, они уже упустили. Компания попыталась встроить голосового ассистента в десктопные системы, когда уже шла борьба за рынок разных устройств. Чуть позже в том же году вышла Amazon Alexa.
Ассистенты развивались. Кроме программных комплексов, которые умели работать с голосом, появились колонки с помощниками. По статистике на начало 2019 года в каждой третьей семье в США есть умная колонка. Это огромный рынок, в который можно вкладывать деньги.
Но есть проблема — с русским языком у иностранных ассистентов плохо. Помощники заточены на английский и отлично его понимают, но при общении на русском возникают трудности перевода. Языки разные и требуют разного подхода к обработке естественного языка.
Алиса вышла в открытую бету 10 октября 2017 года. Она заточена под русский язык и это её огромное преимущество. Алиса понимает и английский, но хуже.
Миссия Алисы — помогать русскоязычным пользователям.
Яндекс — большая компания и может позволить себе встроить Алису во все свои приложения, которые могут как-то разговаривать.
Интеграция так хорошо зашла, что сторонние производители тоже решили встроить Алису.
За 2 года развития ассистента её интегрировали во множество сервисов и добавили новые навыки. Она умеет играть музыку, распознавать картинки, искать информацию в Яндексе и работать с умным домом.
Удобно, когда заняты руки. Я готовлю ужин и хочу включить музыку. Подойти к крану, вымыть руки, высушить, открыть приложение, найти нужный трек — долго. Быстрее и проще дать голосовую команду.
Лень. Я лежу на диване под пледиком и мне не хочется вставать, чтобы идти куда-то включать колонки. Если уж лениться, то по полной.
Большой рынок — это приложения для детей. Маленькие дети еще не умеют читать, писать и печатать, но разговаривают и понимают речь. Поэтому дети обожают Алису и любят с ней общаться. Родители тоже довольны — не нужно искать, чем занять ребёнка. Интересно, что Алиса детей понимает благодаря хорошо обученной нейросети.
Доступность. Людям с нарушениями зрения комфортно работать с голосовыми ассистентами — когда не видно интерфейс, его можно слышать и давать ему команды.
Голосом быстрее. Обычный человек, не разработчик, печатает в среднем 30 слов в минуту, а говорит — 120. За минуту голосом передается в 4 раза больше информации.
Будущее. Фантастические фильмы и футуристические прогнозы предполагают, что за голосовыми интерфейсами будущее. Сценаристы задумываются над тем, что, возможно, голосовое управление будет основным способом взаимодействия с интерфейсами, где картинка не так важна.
По статистике в месяц Алисой пользуются 35 000 000 человек. К слову, население Беларуси 9 475 600 человек. То есть примерно 3,5 Беларуси пользуется Алисой каждый месяц.
Голосовые помощники завоевывают рынок. По прогнозам, к 2021 году он вырастет примерно в 2 раза. Сегодняшняя популярность не остановится, а продолжит расти. Все больше разработчиков понимают, что в эту область надо вкладываться.
Здорово, когда компании вкладываются в голосовые ассистенты. Они понимают, как их можно интегрировать со своими сервисами. Но разработчикам тоже хочется в этом как-то поучаствовать, да и самой компании это выгодно.
У Alexa есть Alexa Skills. По задокументированным способам взаимодействия она понимает, что для нее написали разработчики. Google запустил Actions — возможность встроить в голосовой ассистент что-то свое.
У Алисы тоже есть навыки — возможность разработчикам реализовать что-то стороннее.
При этом существует альтернативный каталог навыков, не от Яндекса, который поддерживается сообществом.
Есть хорошие доклады о том, как делать голосовые приложения. Например, Павел Гвай выступил на AppsConf 2018 с темой «Создаем голосовое приложение на примере Google Assistance» [2]. Активно занимаются разработкой голосовых приложений энтузиасты. Один из примеров — визуальная игра на голосовом управлении, которую написал Иван Голубев.
Алиса популярна, хотя по сути всё, что она делает — стоит посередине между голосом и текстом.
Алиса умеет слушать голос и превращать его по своим алгоритмам в текст, создавать ответ и озвучивать. Кажется, что этого мало, но это крайне сложная задача. Множество людей работает над тем, чтобы Алиса звучала естественно, правильно распознавала, понимала акценты и детскую речь. Яндекс предоставляет что-то вроде прокси, который все через себя пропускает. Потрясающие умы работают над тем, чтобы вы могли использовать результаты их работы.
У навыков Алисы — Яндекс.Диалогов — есть одно ограничение. Время, за которое ваш API должен дать ответ, не должен превышать 1,5 секунды. И это логично, ведь если ответ завис — зачем ждать?
Не все ли равно, о чем спрашивать, если ответа все равно не получишь?
Когда мы получаем информацию ушами, паузы воспринимаются
В документации [4] Яндекс.Диалогов все подробно расписано и она всегда актуальна. Не буду повторяться. Расскажу, что было интересно мне и покажу, как быстро создать демо, на которое потратил всего один вечер.
Начнем с идеи. Навыков много, есть каталоги, но я не нашел важного для меня — это календарь событий по фронтенду. Представьте, что просыпаетесь с утра: «Схожу-ка сегодня на митап. Алиса! Есть там что-нибудь интересное?», а Алиса вам отвечает, причём правильно и с учётом вашего местоположения.
Если занимаетесь организациями конференций — присоединяйтесь на GitHub [5]. Можете вносить туда события и встречи, узнавать о многих событиях по фронтенду в мире из одного календаря.
Я взял известные технологии, что были под рукой: Node.js и Express. Еще Heroku, потому что бесплатно. Само приложение простое: это сервер на Node.js, Express-приложение. Просто поднимаете сервер на каком-то порту и слушаете запросы.
import express from 'express';
import { router } from 'routes';
const app = express();
app.use('/', router);
const port = process.env.PORT || 8000;
app.listen(port, () => {
console.log('Server started on :${port}');
});
Я воспользовался тем, что в календаре Web-стандартов уже все настроено, и из огромного количества мелких файлов там собирается один файл ICS, который можно скачать. Зачем мне собирать свой?
// services/vendors/web-standards.js
import axios from 'axios';
const axioslnstance = axios.create({
baseURL: 'https://web-standards.ru/' ,
});
export function getRemoteCal() {
return axioslnstance.get('calendar.ics');
}
Следите, чтобы все работало быстро.
import { Router } from 'express';
import * as wst from 'services/vendors/web-standards';
export const router = Router();
router.get('/', function(req, res, next) {
wst
.getRemoteCal()
.then(vendorResponse => parseCalendar(vendorResponse.data))
.then(events => {
res.json({ events });
})
.catch(next);
});
Для тестов применяйте GET-методы. Навыки работают c POST-методами, поэтому GET-методы можно делать исключительно себе для дебага. Я такой метод и реализовал. Все, что он делает — скачивает тот самый ICS, парсит и выдает в JSON-виде.
Собирал демку быстро, поэтому взял готовую библиотеку node-ical:
import ical from 'node-ical';
function parseCalendar(str) {
return new Promise((resolve, reject) => {
ical.parseICS(str, function(err, data) {
if (err) {
reject(err);
}
resolve(data);
});
});
}
Она умеет парсить формат ICS. На выходе выдает такую простыню:
{
"2018-10-04-f rontendconf@https://web-standards.ru/": {
"type": "VEVENT",
"params": [],
"uid": "2018-10-04-f rontendconf@https://web-standards.ru/",
"sequence": "0",
"dtstamp": "2019-05-25T21:23:50.000Z",
"start": "2018-10-04T00:00:00.000Z",
"datetype": "date",
"end": "2018-10-06T00:00:00.000Z",
"MICROSOFT-CDO-ALLDAYEVENT": "TRUE",
"MICROSOFT-MSNCALENDAR-ALLDAYEVENT": "TRUE",
"summary": "FrontendConf",
"location": "Москва",
"description": "http://frontendconf.ru/moscow/2018"
}
}
Чтобы парсить и выдавать нужную информацию пользователю навыка, достаточно знать время начала и конца мероприятия, его название, ссылку и, что важно, город. Я хочу, чтобы навык искал мероприятия по городу.
Как Яндекс.Диалоги возвращают информацию? Вас слушает колонка или встроенный в мобильное приложение голосовой ассистент, а серверы Яндекса обрабатывают услышанное и присылают в ответ объект:
{
"meta": { … },
"request”: { … },
"session": { … },
"version": "1.0"
}
В объекте содержится метаинформация, информация о запросе, текущей сессии и версия API на случай, если она вдруг обновится — навыки не должны ломаться.
В метаинформации много полезного.
{
"meta": {
"locale": "ru-RU",
"timezone": "Europe/Moscow",
"client_id": "ru.yandex.searchplugin/5.80…”,
"interfaces": {
"screen": {}
}
}
}
«locale» — используется, чтобы понять регион пользователя.
«timezone» можно использовать, чтобы грамотно работать со временем и более точно определять местоположение пользователя.
«Interfaces» — информация о наличии экрана. Если экрана нет, стоит задуматься, как пользователь увидит картинки, если вы их отдаёте в ответе. При наличии экрана выносим информацию на него.
Формат запроса простой:
{
"request": {
"command": "закажи пиццу на улицу льва толстого 16",
"original_utterance": "закажи пиццу на улицу льва толстого, 16",
"type": "SimpleUtterance",
"nlu": {
"tokens": [ "закажи", "пиццу", "на", "льва", "толстого", "16"],
"entities": [...]
}
}
}
Он выдает то, что пользователь сказал, тип запроса и NLU — Natural-language unit. Это как раз та самая магия, которую берет на себя платформа Яндекс.Диалогов. Она разбивает все предложение, которое распознала, на токены — слова. Еще там есть сущности, про которые мы чуть позже поговорим. Использовать токены достаточно для начала.
Получили мы эти слова, а что с ними делать? Пользователь что-то наговорил, но он может сказать слова в другом порядке, использовать частицу «не», которая всё кардинально меняет, или вообще говорить не «утро», а «утречко». Если пользователь еще и на белорусском языке разговаривает, то будет «ранiца», а не утро. В большом проекте потребуется помощь лингвистов для разработки навыка, который все понимает. Но я делал простую задачку, поэтому обошелся без посторонней помощи.
Это философский вопрос, на который пытается ответить тест Тьюринга. Тест позволяет с некоторой вероятностью определить, что искусственный интеллект умеет выдавать себя за человека. Существует премия Лёбнера [6], чтобы получить которую программы соревнуются в прохождении теста Тьюринга. Решение принимает комиссия судей. Для получения премии требуется обмануть 33% судей или больше. Только в 2014 году бот Женя Густман из Санкт-Петербурга наконец-то обманул комиссию.
[15:46:05] Dudge: My favourite music is contemporary Dazz, what do you prefer?
[15:46:14] Eugene: To be short I’ll only say that I HATE Britnie [sic] Spears. All other music is OK compared to her.
[15:47:06] Dudge: do you like to play any musical instruments
[15:47:23] Eugene: I’m tone deaf, but my guinea pig likes to squeal Beethoven’s Ode to Doy every morning. I suspect our neighbors want to cut his throat ... Could you tell me about your job, by the way?
[15:48:02] Dudge: Guinea pig? Are you an animal lover
[15:48:08] Eugene: Yeah. A nice little guinea pig. Not some annoying chatter bot.
В 2019 году ничего особо не поменялось — обмануть человека всё еще сложно. Но мы постепенно к этому идем.
Для хорошего навыка требуется интересный сценарий использования. Советую одну книгу, которая достойна прочтения — «Designing Voice User Interfaces: Principles of Conversational Experiences». В ней потрясающе рассказано о написании сценариев для голосовых интерфейсов и удержании внимания пользователя. Книга на английском, в переводе не видел, но читается довольно легко.
Первое, с чего стоит начать разработку навыка — это приветствие.
«Пока думаешь, что сказать, — делай реверанс! Это экономит время.»
Когда включается навык, необходимо как-то удержать пользователя с первой секунды, а для этого вы должны объяснить, как пользоваться навыком. Представьте, что пользователь запустил навык и наступила тишина. Как понять, работает ли навык вообще? Дайте пользователю инструкцию, например, кнопки на экране.
Признаки легкого диалога. Список придумал Иван Голубев, и мне очень нравится формулировка.
Личностный значит, что у бота должен быть характер. Если вы пообщаетесь с Алисой, то поймете, что характер у нее есть — разработчики об этом заботятся. Поэтому и ваш бот для органичности должен иметь «личность». Выдавать фразы хотя бы одним и тем же голосом, использовать одни и те же словесные конструкции. Это помогает удерживать пользователя.
Естественный. Если пользовательский запрос простой, то и ответ должен быть таким же. Во время общения с ботом пользователь должен понимать, что делать дальше.
Гибкий. Будьте готовы ко всему. В русском языке много синонимов. Пользователь может отвлечься от колонки и перевести разговор на собеседника, а потом вернуться к колонке. Все это сложно обрабатывать. Но если хотите сделать бота хорошо, то придётся. Учтите, что какой-то процент нераспознавания все равно будет. Будьте к этому готовы — предлагайте варианты.
Контекстный — бот, в идеале, должен помнить, что было до этого. Тогда разговор будет живым.
— Алиса, какая сегодня погода?
— Сегодня в Заречье от +11 до +20, облачно, с прояснениями.
— А завтра?
— Завтра в Заречье от +14 до +27, облачно, с прояснениями.
Представьте, что ваш бот не умеет хранить контекст. Что тогда для него значит запрос «а завтра?» Если умеете хранить контекст, как Алиса, то можете использовать предыдущие результаты, чтобы улучшить ответы в навыке.
Инициативный. Если пользователь затупит, бот должен ему подсказать: «Нажми вот эту кнопку!», «Смотри, у меня картинка для тебя есть!», «Перейди по ссылке». Бот должен подсказывать, как с ним работать.
Бот должен быть кратким. Когда человек долго говорит, ему сложно удержать внимание слушателей. С ботом еще сложнее — его не жалко, он неживой. Чтобы удержать внимание, надо строить разговор интересно или кратко и ёмко. В этом поможет «Пиши. Сокращай». Когда начнёте разрабатывать ботов — почитайте эту книгу.
При разработке сложного бота без базы данных не обойтись. Мое демо не использует БД, оно простое. Но если прикрутить какие-то базы, можно использовать информацию о сессии пользователя, хотя бы для хранения контекста.
Есть нюанс: Яндекс.Диалоги не отдают приватную информацию пользователя, например, имя, местоположение. Но эту информацию можно спросить у пользователя, сохранить и привязать к конкретному ID сессии, который Яндекс.Диалоги присылают в запросе.
Упомянув сложные сценарии, нельзя не вспомнить state machine. Этот механизм давно и отлично используется для программирования микроконтроллеров, а иногда и фронтенда. State machine удобен для сценария: есть состояния, из которых по определенным фразам переходим в другие состояния.
Не перестарайтесь. Можно увлечься и создать огромную state machine, в которой будет сложно разобраться — поддерживать такой код тяжело. Проще написать один сценарий, который состоит из маленьких подсценариев.
Никогда не говорите: «Повторите, пожалуйста». Что делает человек, когда его просят повторить? Говорит громче. Если пользователь наорёт на ваш навык, распознавание не улучшится. Задайте уточняющий вопрос. Если распознали одну часть диалога пользователя и чего-то не хватает — уточните недостающий блок.
Распознавание текста — самая сложная задача в разработке бота, поэтому иногда уточнение не помогает. В любой непонятной ситуации лучшее решение — собирать всё в одном месте, логировать, а потом анализировать и использовать в будущем. Например, если пользователь говорит откровенно странные и непонятные вещи.
«Варкалось. Хливкие шорьки
Пырялись по наве.
И хрюкотали зелюки.
Как мюмзики в мове».
Пользователи могут неожиданно использовать некий неологизм, который что-то означает, и его нужно как-то обработать. Как следствие — процент распознавания падает. Не огорчайтесь — логируйте, изучайте и улучшайте своего бота.
Должно быть что-то, что остановит навык, когда захочется из него выйти. Алиса умеет останавливаться после фраз: «Алиса, хватит!» или «Алиса, стоп!» Но пользователи обычно не читают инструкции. Поэтому реагируйте хотя бы на слово «Стоп» и возвращайте управление Алисе.
Теперь давайте посмотрим код.
Я хочу реализовать следующие фразы.
Для «ближайших событий» подойдет любая фраза. Я создал ленивого бота, и когда он не понимает, что ему говорят, выдает информацию о трёх ближайших событиях.
{
"request": {
"nlu": {
"entities": [
{
"tokens": { "start": 2, "end": 6 },
"type": "YANDEX.GEO",
"value": {
"house_number": "16",
"street": "льва толстого",
"city": "москва"
}
}
]
}
}
}
Яндекс постепенно улучшает платформу Яндекс.Диалоги и выдает сущности, которые он сумел распознать. Например, он умеет доставать адреса из текста, разбирая его по частям: город, страна, улица, дом. Также он умеет распознавать числа и даты, как абсолютные, так и относительные. Он поймет, что слово «Завтра» — это сегодняшняя дата, к которой прибавлена единичка.
Вам нужно как-то ответить вашему пользователю. Весь навык — это 209 строчек [7] с последней пустой строкой. Ничего сложного — работы на вечер.
Всё, что вы делаете — это обрабатываете POST-запрос и получаете «request».
router.post(‘/’, (req/ res, next) ⇒ {
const request = req.body;
Дальше я не сильно усложнял state machine, а шел по приоритетам. Если пользователь хочет узнать, как пользоваться ботом, значит это первый запуск или просьба о помощи. Поэтому просто готовим ему «EmptyResponse» — у меня это так называется.
if (needHelp(request.request)) {
res.json(prepareEmptyResponse(request));
return;
}
Функция «needHelp» простая.
function needHelp(req) {
if (req.nlu.token.length ≤ 2 && req.nlu.tokens.includes(‘помоги’)) {
return true;
}
if (req.nlu.token.length = 0 && req.type ≠ ‘ButtonPressed’) {
return true;
}
return false;
}
Когда у нас ноль токенов, значит мы находимся в начале запроса. Пользователь только запустил навык или ничего не спросил. Нужно проверить, что токенов ноль и это не кнопка — когда вы нажимаете кнопку, пользователь тоже ничего не говорит. Когда пользователь просит помощи, мы ходим по токенам и ищем слово «Помоги». Логика простая.
Если пользователь хочет остановиться.
if (needToStop(request.request)) {
res.json(prepareStopResponse(request));
return;
}
Значит мы ищем какое-то стоп-слово внутри.
function needStop(req) {
const stopWords = [‘хватит’, ‘стоп’, ‘спасибо’ ];
return req.nlu.token.length ≤ 2 &&
stopWords.some(w ⇒ return req.nlu.token.includes(w));
}
Во всех ответах вы должны вернуть ту информацию, которую Яндекс.Диалоги прислал о сессии. Ему нужно как-то сопоставить ваш ответ и запрос пользователя.
function prepare StopResponse(req) {
const { session, version } = req;
return {
response: {
text: ‘Приходи еще. Хорошего дня!’,
end_session: true,
},
session,
version,
};
}
Поэтому то, что вы получили в переменных «session» и «version», возвращайте обратно, и всё будет хорошо. Уже в ответе вы можете дать какой-то текст, чтобы Алиса его озвучила, и передать «end session: true». Это значит, что мы заканчиваем сессию работы с навыком и передаем управление Алисе.
Когда вы вызываете навык — Алиса выключается. Все, что она слушает — это свои стоп-слова, а вы полностью контролируете процесс работы с навыком. Поэтому нужно вернуть управление.
С пустым запросом интереснее.
return {
"response": {
"text": ‘Привет! Со мной ты можешь узнать о ближайших фронтенд-событиях в России.’,
"tts": ‘Привет! Со мной ты можешь узнать о ближайших фронтенд-событиях в России.’,
buttons: [
{
title: ‘Ближайшие события’,
payload: {}
hide: false,
},
{
title: ‘События в Москве’,
payload: {
city: ‘москва’,
}
hide: false,
},
],
end_session: false,
},
session,
version,
};
Здесь есть поле TTS (Text To Speech) — управление озвучиванием. Это несложный формат, который позволяет по-разному озвучивать текст. Например, у слова «многопрофильный» два ударения в русском языке — одно основное, второе побочное. Задача в том, чтобы Алиса смогла это слово произнести правильно. Можно разбить его пробелом:
мн+ого пр+офильный
Она будет его понимать, как два. Плюсом выделяется ударение.
В речи бывают паузы — вы ставите знак препинания, который отделен пробелами. Так можно создавать драматические паузы:
Смелость — - - - - - - - - город+а берет
Про кнопки я уже говорил. Они важны, если вы общаетесь не с колонкой, а с мобильным приложением Яндекса, например.
{
"response": {
"buttons": [
{
"title": "Frontend Conf",
"payload": {},
"url": "https://frontendconf.ru/moscow-rit/2019" ,
"hide": false
}
]
}
}
Кнопки — это еще и подсказки по фразам, которые вы воспринимаете в своем навыке. Навыки работают в приложениях Яндекса — вы общаетесь с интерфейсом. Если хотите выдать какую-то информацию — даете ссылку, пользователь переходит по ней. Для этого также можно добавлять кнопки.
Здесь есть поле «payload», в которое можно добавлять данные. Они потом обратно придут с «request» — вы будете знать, например, как пометить эту кнопку.
Можно выбрать голоса, которым будет говорить ваш навык.
Чтобы завершить навык, достаточно вернуть «end_session: true».
{
"response": {
"end_session": true
}
}
Для начала я фильтрую по дате.
function filterByDate(events) {
return events.filter(event ⇒ {
const current = new Date().getTime();
const start = new Date(event.start).getTime();
return (start > current) ||
(event.end && new Date(event.end).getTime() > current && start ≤ current);
});
}
Логика простая: во всех событиях, которые я распарсил из календаря, беру те, что пройдут в будущем, либо идут сейчас. Спрашивать о прошлых событиях, наверное, странно — навык не про это.
Дальше фильтрация по месту — то, ради чего всё и затевалось.
function filterByPlace(events, req) {
const cities = new Set();
const geoEntities = req.nlu.entities.filter(e ⇒ e.type = ‘YANDEX.GEO’);
if (req.payload && req.payload.city) cities.add(req.payload.city);
geoEntities.forEach(e ⇒ {
const city = e.value.city && e.value.city.toLowerCase();
if (city && !cities.has(city)) {
cities.add(city);
}
});
В «entities» вы можете найти сущность YANDEX.GEO, которая уточняет место. Если у сущности есть город, добавляем в наш набор. Дальше логика тоже простая. В токенах ищем этот город, и если он там есть — ищем то, что хочет пользователь. Если нет — ищем во всех «locations» и «events», которые у нас есть.
Допустим, Яндекс не распознал, что это YANDEX.GEO, но пользователь назвал город — он уверен, что там что-то проходит. Мы перебираем все города в «events» и ищем то же в токенах. Получается перекрестное сравнение массивов. Не самый производительный способ, конечно, но какой есть. Вот и весь навык!
Пожалуйста, не ругайте меня за код — я писал его быстро. Там все примитивно, но попробуйте использовать или просто поиграться.
Переходите на страницу Яндекс.Диалогов.
Выбираете навык в Алисе. Жмете кнопку «Создать диалог» и попадаете в форму, которую нужно заполнить вашими данными.
Готово — отправляете навык на модерацию, и можете тестировать.
Я написал банальный Express-сервер. Это простой API, который покрывается обычными тестами. Есть специализированные утилиты, например, «alice-tester» — умеет работать именно с тем форматом, который предоставляет Алиса.
const assert = require('assert');
const User = require('alice-tester');
it('should show help', async () => {
const user = new User('http://localhost:3000');
await user.enter();
await user.say('Что ты умеешь?');
assert.equal(user.response.text, 'Я умею играть в города.');
assert.equal(user.response.tts, 'Я умею играть в город+а.');
assert.deepEqual(user.response.buttons, [{title: 'Понятно', hide: true}]);
}]);
Также можно тестировать прямо в платформе Яндекс.Диалоги, в которой есть вкладка «Тестирование».
Удобно тем, что вы видите, как все будет работать в приложении. Навык не озвучивается, но вы видите визуальный ряд: кнопки, ответ, который приходит с вашего сервера. Что важно вам, как разработчику — видно тот самый запрос, который будет отправлен вам. Копируете оттуда в Postman — и поехали.
Есть симулятор Яндекс.Станции [8]. Его разрабатывает Just AI. Это сторонняя разработка, а не Яндекса, поэтому протоколы могут не соответствовать и симулятор иногда не работает.
Возможно тестировать локально. На странице dialogs.home.popstas.ru [9] указываете URL, например, ваш localhost. На странице работает интерфейс, похожий на тот самый debug. Это тоже сторонняя разработка, но бывает удобна для тестирования localhost.
Есть навык Тест прокси [10]. Сложноват — я не смог завести. В навык передается URL через приложение, а он выдает какой-то номер и можно тестировать прямо на колонке.
Лучшее тестирование из всех — говорить с приватным навыком ртом.
Да, разговаривайте с навыком напрямую, например, через колонку.
Напоследок — не забывайте про коридорное тестирование. Среди тех, кто будет пользоваться навыком, будут люди с акцентом, с дефектами речи, или те, кто строит интонации иначе. Из-за каких-то сложных для распознавания слов ваш навык будет плохо воспринимать их речь.
Навыки можно разрабатывать вообще без кода на платформе Dialogflow, которая изначально создана для Google Now. Все, что она выдает — это интерфейс, который позволяет склеивать интенты — намерения.
Вы задаете набор фраз, который сопоставляется с конкретным намерением пользователя. Уже по этому намерению добавляете ответы. Прелесть в том, что платформа умеет хранить контекст и использовать прошлые запросы. Не нужно подключать базу данных, и вообще писать код.
Чтобы подключить Google Dialogflow к Яндекс.Алисе, применяем Dialogflower. При этом можно одновременно поддерживать своего ассистента и для Alexa, и для Google Now, и для Яндекс.Алисы — написать один API, и его будут понимать все платформы.
Есть еще инструменты, которые работают с русским языком. Aimyloqic [11] — подходит для русского языка. Еще есть Zenbot [12], Tortu [13] и Alfa.Bot [14] — импортная вещь, разработано в Беларуси. Рекомендую!
Добавить интерактивности разделу F.A.Q. Добавляем на сайт виджет, который будет отправлять на навык. Пользователь проговорит голосом вопрос, в своей базе вы найдете ответ, Алиса озвучит.
Техподдержка. Пока идет дозвон, вместо того, чтобы пользователю включать музыку Моцарта, предварительно отправим его в навык. Вы получите информацию — кто этот человек, какая у него проблема. В момент соединения с оператором, он уже будет видеть дополнительную информацию. Голосом это делать интереснее, чем заполнять текстовые формы.
Можно подключить сервис IFTTT, который соединяет огромное количество всего — от умного дома до Trello. Но есть нюанс — у них медлительная API. Если за полторы секунды вы не успеете все прогнать, есть риск, что навык будет работать плохо. Если не готовы взять на себя этот риск, IFTT — это портал к невероятным возможностям.
Голосовые помощники применяются для умного дома. Уже давно сторонние разработчики создают навыки, подключив Яндекс.Диалоги к своим устройствам.
Например, сервис «Альфред» умеет подключать различные умные устройства.
Но с недавнего времени Яндекс и сам этому научилась. Алиса нативно работает с Xiaomi и прочими умными девайсами. В Яндекс.Диалогах появилась возможность создавать навыки для умного дома. Например, вы написали на Arduino что-то супер-мега-ультра-пупер крутое, и хотите, чтобы запускалось голосом: «Алиса, запусти Мега-Уничтожитель Вселенной 2000!» Теперь можно сделать для этого адаптер — круто!
Недавно я был приятно ошарашен, когда пришел домой и сказал: «Алиса, включи свет!» — и она включила! Если бы еще у нас в Беларуси Яндекс.Еда работала, я бы вообще с дивана не вставал.
Используйте максимум информации. Например, используйте время суток пользователя, чтобы правильно поздороваться: доброе утро, день или вечер. Изучайте Блог Яндекс.Диалогов [15]. Полезных материалов много и будет еще больше. Также посмотрите библиотеки и ресурсы для Яндекс.Диалогов [16]. В GitHub-репозитории [16] гораздо больше всего о Яндекс.Диалогах, чем я описал. Разработчики обещают наращивать функциональность — следите за ними.
Рекомендую вступить в Telegram-чат Яндекс.Диалогов [17]. Если заинтересуетесь Диалогами — подключайтесь и предлагайте идеи. Я был приятно удивлен, когда общался с разработчиками Диалогов по поводу доклада. Мне сразу собрали обратную связь по моему материалу. Команда горит своей работой.
Думайте о приватности. Обычно во время разработки мы не думаем, в каких условиях будет использоваться навык. Пользователь что-то наговорил, навык его не понял и решил уточнить информацию. А пользователь в это время едет без наушников в автобусе, например. Перебить Алису тяжело. Если она захочет, то скажет всё и громко. Возможно, это будет приватная информация: пароль, пин-код, ответ на вопрос пользователя, о котором он не хочет рассказывать всем вокруг. Я утрирую, разумеется, но думайте о сценариях приватного и неприватного использования. Спросите у пользователя: «Ты уверен, что хочешь это услышать?» Например, при запросе включить музыку группировки Ленинград, Алиса предупреждает, что надо увести детей подальше от колонки.
Креативьте — так повышается вероятность того, что ваш навык попадет в топ каталога. Пользователям интереснее пользоваться креативным навыком.
Подытожим. Голосовое управление — это удобно. Оно не вытеснит все остальное, но я считаю, что оно будет развиваться и расширяться. Возможно, скоро фронтенд будет вплотную работать с голосом.
Нужно бежать со всех ног, чтобы только оставаться на месте, а чтобы куда-то попасть, надо бежать как минимум вдвое быстрее!
Из приятных полезностей оставлю Школу Алисы [18] — информативные видео о разработке навыков, и Премию Алисы [19] — заработок на навыках. Лучшие навыки месяца получают деньги. Написал навык — получил деньги — круто!
На FrontendConf 2019 [20] Никита будет выступать с докладом «CSS — язык программирования [21]». Доклад Никиты курирует Сергей Попов — участник ПК конференции и постоянный спикер. Он рассказал, как проходит подготовка к FrontendConf 2019 в отдельном интервью [22]. Подробнее, как проходит подготовка к выступлению, а также о синдроме самозванца, влиянии выступлений на жизнь и карьеру, Никита рассказал в интервью [23] Андрею Смирнову.
До конференции уже меньше двух недель. Изучайте расписание [24], бронируйте билеты [25] и подписывайтесь на рассылку [26], чтобы следить за анонсами и новыми статьями.
Автор: Глеб Михеев
Источник [27]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/331712
Ссылки в тексте:
[1] FrontendConf: https://frontendconf.ru/
[2] «Создаем голосовое приложение на примере Google Assistance»: https://habr.com/ru/company/oleg-bunin/blog/437586/
[3] мозгом: http://www.braintools.ru
[4] документации: https://dialogs.yandex.ru/development
[5] присоединяйтесь на GitHub: https://github.com/web-standards-ru/calendar
[6] Лёбнера: https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%BC%D0%B8%D1%8F_%D0%9B%D1%91%D0%B1%D0%BD%D0%B5%D1%80%D0%B0
[7] 209 строчек: https://github.com/MeFoDy/web-standards-calendar-alice
[8] симулятор Яндекс.Станции: https://station.aimylogic.com/
[9] dialogs.home.popstas.ru: https://dialogs.home.popstas.ru/
[10] Тест прокси: https://aliceskill.ru/skill/test-proksi/
[11] Aimyloqic: https://aimylogic.com/
[12] Zenbot: https://zenbot.org/index.html
[13] Tortu: https://tortu.io/
[14] Alfa.Bot: https://alfa.bot/ru/
[15] Блог Яндекс.Диалогов: https://yandex.ru/blog/dialogs
[16] библиотеки и ресурсы для Яндекс.Диалогов: https://github.com/sameoldmadness/awesome-alice
[17] Telegram-чат Яндекс.Диалогов: https://t.me/yadialogschat
[18] Школу Алисы: https://events.yandex.ru/events/webinars/alisa-school/
[19] Премию Алисы: https://dialogs.yandex.ru/prize
[20] FrontendConf 2019: https://frontendconf.ru/moscow/2019
[21] CSS — язык программирования: https://frontendconf.ru/moscow/2019/abstracts/5659
[22] отдельном интервью: https://habr.com/ru/company/oleg-bunin/blog/468543/
[23] рассказал в интервью: https://habr.com/ru/company/oleg-bunin/blog/450830/
[24] расписание: https://frontendconf.ru/moscow/2019/schedule
[25] билеты: https://conf.ontico.ru/conference/join/fc2019-moscow.html
[26] на рассылку: http://eepurl.com/bb99tn
[27] Источник: https://habr.com/ru/post/468545/?utm_source=habrahabr&utm_medium=rss&utm_campaign=468545
Нажмите здесь для печати.