Skip to content

Создание функционального модуля

Dmitry Che edited this page Mar 4, 2016 · 8 revisions

Перед началом

Перед тем как приступать к созданию своего функционального модуля, внимательно ознакомьтесь с разделом Как создать модуль.

Что такое функциональный модуль

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

Что нужно для его создания

Кроем самого модуля вам необходимо написать грамматику запросов для вашего модуля. Чтобы Агрегат понимал, какие команды относятся именно к вашему модулю и передавал ему управление каждый раз, когда фраза пользователя в текущем контексте подходит под одну из указанных вами команд. Файл грамматики содержит шаблоны команд и их контексты. Этот файл должен иметь имя в формате <имя модуля>.xml и находиться в корне архива модуля.

Подробнее о грамматике и синтаксисе читайте здесь.

API

Для создания функционального модуля может пригодиться библиотека API Агрегата. Это необязательно, но она содержит абстракции, которые могут упростить написание модуля, чтобы вам не пришлось работать с данными на "низком" уровне.

Для Java можно использовать API для Java.

Как работает функциональный модуль

Функциональный модуль получает управление от Агрегата всякий раз, когда пользователь в текущем контексте произнес фразу, подходящую под одну из команд вашего модуля. Агрегат выбирает лучшее совпадение, если таких модулей несколько, и передает управление только одному из них.

В файле грамматики запросов каждая команда имеет идентификатор. Этот идентификатор является именем события, которое должен слушать модуль, чтобы получить управление от Агрегата, когда сработала эта команда.

Например

Если в файле грамматики написано следующее:

<module>
    <command id="cmd.datetime.time">
        <pattern value="* который * час *"/>
        <pattern value="* скольк* * врем* *"/>
        <pattern value="время"/>
    </command>
</module>

Это значит, что Агрегат сгенерирует событие с названием cmd.datetime.time в тот момент, когда пользователь произнесет одну из фраз типа "Который сейчас час" или "Скажи сколько времени". Слушая такое событие, модуль получит управление, когда оно произойдет. Вместе с событием Агрегат передаст и сообщение, которое будет содержать дополнительную информацию о пользовательском запросе.

Формат запроса

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

Например

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

Посмотрим на другой пример:

<command id="cmd.datetime.date">
  <pattern value="[* как*] {(день [недели] | дата) [* $Date]}"/>
</command>

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

Вот как может выглядеть код обработчика такого события в модуле на Java:

@Override
public void start() throws Exception {
  vertx.eventBus().consumer("cmd.datetime.date", m -> {
    m.reply(getDate(Request.fromMessage(m)));
  });

private String getDate(Request request) {
  Markup date = request.markup.get(Pattern.DATE);
  Date d;
  if (date != null) {
    Calendar calendar = GregorianCalendar.getInstance();
    calendar.set(Calendar.DATE, (Integer) date.data.get("day"));
    calendar.set(Calendar.MONTH, (Integer) date.data.get("month"));
    calendar.set(Calendar.YEAR, (Integer) date.data.get("year"));
    d = calendar.getTime();
  } else {
    d = new Date();
  }
  return new SimpleDateFormat("dd MMMM, EEEE").format(d);
}

Как видно из этого простого кода, модуль реагирует на событие cmd.datetime.date и синхронно возвращает в ответе дату (он мог бы сделать это и асинхронно, но в данном случае операция простая и быстрая). Классы Request, Pattern и Markup - это абстракции API для Java, которые упрощают работу с данными запроса.

Как видно, модуль в методе getDate вытаскивает из запроса ту его часть, которая относится к дате. И если она есть, то получает из нее нужные составляющие (день, месяц, год), которые уже подготовил Агрегат, когда увидел, что это дата в запросе пользователя. А далее модуль просто сгенерировал дату в нужном формате и вернул ее в ответ на событие. Если модуль просто возвращает строку текста, то Агрегат просто ее озвучивает, посылая событие одному из синтезаторов. Этим данный модуль и пользуется.

Полный код данного модуля можно найти в исходниках здесь.

Sorry, there was an error rendering this page.

Clone this wiki locally