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 вытаскивает из запроса ту его часть, которая относится к дате. И если она есть, то получает из нее нужные составляющие (день, месяц, год), которые уже подготовил Агрегат, когда увидел, что это дата в запросе пользователя. А далее модуль просто сгенерировал дату в нужном формате и вернул ее в ответ на событие. Если модуль просто возвращает строку текста, то Агрегат просто ее озвучивает, посылая событие одному из синтезаторов. Этим данный модуль и пользуется.

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

Структура кода модуля

Метод start

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

Существует два вида этого метода - синхронный и асинхронный. Подробнее о них читайте здесь.

Sorry, there was an error rendering this page.

Clone this wiki locally