Яндекс.Диалоги: как я делал навыки для Алисы и инструменты для разработки

14.04.2020, 19:45 - 7 мин читать

История написания навыков для Алисы и тестилок для них.

Яндекс Алиса, Список покупок, Вторая память, Node.js

Предыстория

В chords-viewer была одна фича: голосовой поиск через браузерный API. Так я наступил в голосовые интерфейсы. Начиналось лето 2018.

Я написал простой список, который можно заполнять голосом - voice-list.

Потом написал список, который умеет отвечать на вопросы что где лежит (речь о вкусах жижи для есиг в разноцветных бутыльках) - voice-whatis.

И тут я вспомнил, что Яндекс запустил возможность обучать Алису в марте и решил, что это неплохая идея для навыка.

Yandex Dialogs SDK - фреймворк для Node.js

Писать с нуля я не люблю, первым делом пошёл на Github искать готовые проекты и либы.

Я сразу нашёл yandex-dialogs-sdk, другого тогда ничего не было в нормальном качестве.

Мы с автором пару месяцев сотрудничали: он писал SDK, учитывая мои хотелки. Трудно представить себе нужные в SDK фичи в вакууме, а я имел боевой навык, покрытый автотестами, который быстро выявлял проблемы в SDK и просил обновлений платформы.

Навык “Вторая память”

Про навык есть отдельный пост.

Колонка с Алисой

В декабре я решил, что раз я пишу навыки для Алисы, надо купить соответствующий девайс. Взял Irbis A, в общем понравилось. Я бы и до этого взял, но был только один вариант за 10 000 рублей, меня жаба душила.

Покупка колонки открыла все удобства и недостатки навыка, после этого было много правок с учётом особенности работы на колонке.

Интерфейс навыка - Алиса, то есть у него нет никакого UI, это называется VUI (Voice User Interface). Но для тестирования это не подходит…

Yandex Dialogs Client - инструмент для тестирования навыков

yandex-dialogs-client написал параллельно с разработкой первого навыка, потому что понял, что нужны автотесты, чтобы прогонять разные сценарии.

Настройки

  • Использовать прокси - галочка для отправки запроса с сервера. Плюс: обходит ограничения CORS, если они не обойдены в навыке. Минус: запрос будет отправлен с машины, на которой крутится тестилка, то есть чтобы потестить localhost навык с чужого (или моего) инстанса тестилки, он должен разрешать CORS. Доступно на https://dialogs.home.popstas.ru/ с серверной частью, недоступно на статическом https://dialogs.popstas.ru/
  • Использовать /scenarios.yml - после первого запроса к навыку будет запрошен соответствующий файл с вебхука. Навык должен уметь вернуть yaml по этому запросу, иначе тестилка работать не будет при включенной галочке.
  • Показывать тесты внизу - закрепляет список тестов на экране
  • Показывать JSON в консоли - код запросов и ответов посчитал второстепенным, можно включить его вывод в консоль браузера
  • Макс. кол-во сообщений в чате - установлен разумный предел, при большом кол-ве сообщений тесты начинают тормозить
  • Макс. кол-во сообщений при открытии страницы - история сообщений хранится в Local Storage браузера, но чистится
  • Макс. время ответа - чтобы тестить ограничение на время. Временами я тестил с дебагером и ставил время ответа 60 сек
  • Последние URL навыков - здесь сохраняются все вебхуки, которые вводили через use:

Не выходить в интернет

Я хотел делать всё локально, а стандартная тестилка навыка предполагает, что навык открыт для всех. Поэтому перед написанием навыка я сделал свою тестилку yandex-dialogs-client. Потом я захотел автотесты (сценарии диалогов с проверкой ответов навыка), сделал их, позже они породили yandex-dialogs-tester, который умеет прогонять те же тесты в терминале.

Сейчас для этого я бы взял что-то готовое, тогда тестилок ещё нормальных не написали.
Моя - далеко не единственная.

Прикинуться настоящим

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

Технически это Vue.js с Element UI.

Проверить все сценарии

Этой фичи до сих пор у других не видел.

Идея была в том, чтобы написать все возможные диалоги в файле, который будет автоматически воспроизводиться в навыке и проверять, соответствуют ли ответы ожидаемым.

Тесты можно запускать по одному или все вместе. Для этого внизу чата они выводятся в виде кнопочек.

Тесты прогоняются прямо визуально, просто скрипт пишет в чат сообщения боту.

После прохождения всех тестов будет сводка: сколько тестов прошло, сколько упало, перезапустить все упавшие или один.

Кнопочки раскрашиваются в цвет результата последнего прохождения.

Сообщения от самой тестилки в чате помечаются цветной полосой.

Синтаксис scenarios.yml

Пример одного теста в файле:

"где в конце": # название теста
  - "" # пустая строка в запросе
  - Привет

  - спортзал находится на этаже
  - на этаже находится спортзал, поняла # полное соответствие

  - где спортзал
  - tests: [
      { contains: на этаже }, # содержит строку
      { not_contains: 'на улице' } # не содержит строку
    ]

  - спасибо
  - tests:
      - one_of: # один из вариантов
        - Пожалуйста
        - Всегда пожалуйста
        - Не за что
        - Обращайся!

  - удали банан
  - tests: [ contains: "" ] # пройдёт любой ответ

В итоге в первом навыке получилось 73 диалога. Все сценарии навыка.

На боевом навыке у меня тестирование 73 диалогов (404 реплики) проходит примерно за 30 секунд, на локалке за 15 секунд.

Я покрыл все сценарии тестовыми диалогами, так я мог не боясь рефакторить код и обновлять версию SDK, сразу сообщая автору, в каких местах что сломалось (а ломалось каждый раз в разных).

Вручную тоже

Для ручного тестирования тоже есть пара фич:

  • стрелки вверх-вниз ходят по истории отправленных сообщений, как в терминале
  • у исходящих сообщений есть кнопка повторной отправки

Картинки и карточки я не делал, поэтому в тестилке их нет.

Yandex Dialogs Tester - Continous Integration

Потом захотелось прикрутить Travis CI, чтобы там гонялись те же тесты, что и в WebUI. так появился yandex-dialogs-tester, там та же система тестов, но в виде отдельной либы.

Больше об этом проектике нечего сказать, быстрый, но неудобный.

Навык “Список покупок”

Когда я подавал навык на премию Алисы в феврале, мне посоветовали выделить часть, которая касается списка покупок в отдельный навык. Так появился “Вкусный список".

По сути всё уже было готово, я за вечер выбросил всё лишнее, переписал справку и запустил.

Название было такое, потому что “Список покупок” занял какой-то киберсквоттер, но навык он не сделал, там была просто заглушка.

Через какое-то время мне отдали нормальное название “Список покупок”.

Уменьшившийся упростил жизнь как мне, так и пользователю. Например, стало можно сказать просто “добавь картошку”, а не “добавь картошку в список покупок” и т.п.

Сделал возможность добавлять и удалять помногу, защиту от двойного добавления и прочие мелочи.

В итоге оказалось, что навыком действительно удобно пользоваться. На телефоне список выглядел как список, при нажатии на каждый продукт он удалялся из списка, легко было идти по списку и “вычёркивать”.

Навыком начали пользоваться человек 50 в день, я тоже им пользовался, натурально наговаривал список, глядя в холодильник и смотрел в телефон в магазине.

Были косяки, которые меня не парили, а пользователи жаловались. Список хотелок юзеров в какое-то время превысил мои возможности. Например, я надиктовываю сразу группами: “добавь масло, сгущёнку и сыр”, при этом навык должен определить 3 продукта и действие “добавить”. Самое сложное, что я добавлял - “соевый соус”, его я научился определять как один продукт, определяя прилагательное + существительное.

А пользователь хотел “добавить приправу для плова”, можно было через “для” определить связку, но…

Я устал, я ухожу

Под конец простых регулярок перестало хватать для понимания запроса юзера, я начал прикручивать к навыку Томита-парсер для какого-то понимания смысла услышанного (никакого машинного обучения), но всё остановилось на прототипе tomita-parser-test, т.к. навыком я сам пользовался редко, поднадоело.

Вообще я навыки делал в первую очередь для себя, “Вторая память” оказалась бесполезной даже для меня, списком покупок я пользовался несколько месяцев, пока Яндекс не сделал официальный список покупок, он в чём-то хуже (не продуман механизм быстрого удаления в магазине), но в основном он конечно лучше. А больше я не знаю что писать )

Ещё была неудача с премией: Яндекс проводит ежемесячные премии Алисы, где награждает авторов лучших навыков, я ни с одним из 2 навыков не был удостоен. “Ачивки”, которуе я получил от Яндекса: название “Список покупок” и размещение “Второй памяти на главной странице на несколько дней (это подняло посещаемость с 10 до 500 юзеров в день).

К весне 2019 я наигрался с разработкой навыков, поэтому мои тулзы тоже застыли. Я всего 2 навыка сделал и помогал немного в развитии yandex-dialogs-sdk, автору которого надоело ещё раньше меня.