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

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, автору которого надоело ещё раньше меня.