Елизавета Е. Марченко.
Один из подходов в реализации ЕЯ-интерфейсов к реляционной базе данных

Елизавета Е. Марченко.
Один из подходов в реализации ЕЯ-интерфейсов к реляционной базе данных



В данной реализации объекта. При этом требуется основной управляющий блок, координирующий работу и взаимодействие всех объектов.

Диалоговый сервер (DS) – это приложение, которое объединяет все компоненты диалога и управляет работой этих компонентов. Т.е. на вход программы поступают пользовательские фразы, а на выходе – результат работы диалога (дополнительные вопросы и ответы пользователю).

Компоненты диалога:

  1. Парсер грамматик (GP).
  2. Dialogue engine(DE).
  3. HostScript engine (HS)

Теперь по порядку:

Парсер грамматик (GP) – объект, который парсирует пользовательские фразы в соответствии с загруженной в него грамматикой.

Результатом правильного парсирования является “выходная грамматика”.

“Выходная грамматика” - это, в общем случае, набор команд, представленный в виде символьной строки и который понятен какому-либо приложению, а в нашем случае – это набор команд, который понятен DE и может быть выполнен DE с помощью его интерфейсной команды Command(“символьная строка, представляющая команду для DE”) или CommandSequence(“символьная строка, представляющая последовательность команд для DE и разделенных символом точка с запятой”). Т.е. это можно проиллюстрировать следующим C++ кодом для нашего DS.

CString userPhrase(“”);

CString outputGrammar(“”);

// Мы уже имеем указатели на интерфейсы объектов GP и DE,

// которые мы обязаны получить при старте нашего DS.

// Пользователь уже ввел фразу с помощью клавиатуры или фраза уже

// получена как результат голосового распознавания.

// т.е.переменная userPhrase уже заполнена символьной строкой,

// содержащую пользовательскую фразу.

// Парсируем пользовательскую фразу

outputGrammar = GP->parseUserPhrase(userPhrase);

// в случае удачного парсирования, переменная outputGrammar

// будет содержать выходную грамматику или грамматики,

// которые должны быть выполнены в DE.

if(outputGrammar.IsEmpty())

{

//обработка ошибки, или оправить пользователю уведомление,

// что его фраза не понята.

...

}

else

{

// фраза понята,

// меняем текущее состояние логической структуры диалога.

DE->commandSequence(outputGrammar);

//запускаем следующую сессию диалога, но об это чуть позже.

DE->command(“gotonextsession”);

}

Именно таким образом происходит взаимодействие Парсера Грамматики и Dialog Engine в приложении (в нашем случае это приложение Dialog System).

Другими словами, DS получил фразу пользователя (каким-то образом) в символьном виде, затем ее отпарсировал и получил выходную грамматику, которую передал на выполнение в DE. И дальше ждет события, сгенерированного DE.

Dialogue engine(DE) – объект, который работает со структурой диалога (ранее разработанной и загруженной). В этом месте, под структурой диалога мы понимаем не только его логическую структуру (LS), но и таблицу генерации скриптов (SG-table), таблицу генерации ответов (AG-table), таблицу соответствия состояний (SDA-table).

На вход DE поступают выходные грамматики, которые меняют состояние его логической структуры LS. (Смотри описание DE, синтаксис описания диалога и синтаксис выходных грамматик). После изменения текущего состояния LS, DE должен быть запущен на следующую сессию, т.е. произвести пересчет LS с новым состоянием. Это выполняется вызовом команда DE->command(“gotonextsession”) с параметром в виде ключевого слова “ gotonextsession ”.

В результате работы следующей сессии, DE может сгенерировать три типа событий.

Пару слов о событии. Событие – это механизм сообщений (или нотификации клиента), который реализован в каждом COM объекте для передачи результатов работы объекта в клиентскую программу. В нашем случае, такой клиентской программой является DS, а COM объектом - DE.

В физической реализации, для генерации всех своих событий, в COM объекте описываются (точнее объявляются) абстрактные функции, а реализуются (т.е. пишется программный код этих функций) на стороне клиента. В нужный момент, COM объект вызывает эту функцию, поскольку она объявлена внутри него, но выполнение этой функции происходит внутри программы клиента. Нечто, очень похожее на механизм работы функции обратного вызова, или как ее еще называют Callback function, только механизм сообщений COM объекта может работать не только в одном адресном пространстве с приложением, как Callback функция, но и в разных, и даже, если программы клиент и сервер работают на разных компьютерах.

Адресным пространством называется пространство памяти, выделенное операционной системой для работы конкретного приложения. А коль COM объект может запускаться как отдельное приложение (в другом адресном пространстве относительно твоего приложения DS), или даже на другом компьютере, то, и разработан такой механизм обратного взаимодействия COM объекта с программой, которая его вызвала. Это есть одно из наиважнейших свойств COM технологии.

Теперь только на уровне логики работы.

В DE реализованы, как мы говорили, 3 типа событий.

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

И так, расчет новой сессии DE:

На этом работа текущей сессии диалога заканчивается и DE ждет новых команд от DS.

Теперь, что происходит в DS, после его нотификации (или после генерации событий). В DS реализована петля обработки сообщений. Это обычное условие написания программ под Windows. Каждая программа имеет свой обработчик событий, например, если набирается текст на клавиатуре, то события от нажатия клавиш попадают в Word, если эта программа активна в данный момент, или в другую, активную! программу, а не в Excel, например, если он в данный момент не активен. Весь этот механизм передачи различных событий (сообщений) программам реализован в операционной системе. И каждая программа должна иметь свой собственный обработчик событий, причем только тех, которые ей необходимы.

В случае работы с COM объектами, весь этот механизм работает, нужно только подвязать события от COM объекта к твоей петле событий.

Другими словами, у нас в DS реализован код функций-обработчиков OnScript(script), OnAnswer(answer) и OnActiveGrammar(BSTR grammar).

Т.е., когда DE сгенерировал какое-то событие (или попросту говоря, вызвал эту функцию, она же у него объявлена), то эта функция будет выполнена в теле того приложения, которое вызвало DE и имеет обработчик его событий, т.е. DS.

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

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

Другими словами, если поступило событие OnAnswer(answer), то DS знает, что информацию, которая есть в переменной answer, нужно отправить пользователю, как ответ на его вопрос или дополнительный вопрос. Т.е. то, чем ее заполнит DE. Соответственно, реализация данной функции-обработчика может выглядеть так:

DS:: OnAnswer(BSTR answer)

{

//Конвертируем тип BSTR в строку.

CString ourAnswerToChamberlen(answer);

// Передаем эту строку ползователю.

SendToUser(ourAnswerToChamberlen);

}

Естественно, что функция SendToUser(CString str), должна быть реализована в нашей программе, она направляет строку в диалоговое окно для пользователя или в программу TTS (TextToSpeech).

Тоже происходит и с другими событиями. Реализация события на изменение активной грамматики, должна вызвать функцию GP->setActiveGrammar(gramma), a реализация события скрипта, должна передать полученный скрипт на выполнение в соответствующую программу, в нашем случае это HS.

Еще, тип BSTR – это специальный тип для работы с COM объектами. Поскольку нужно было решать задачу передачи данных в межадресном или межкомпьютерном пространстве для нотификации COM объектов, этот тип и стали применять как подходящий.

Итак, круг начинает замыкаться:

Но что делать, если мы получили скрипт-сообщение.

Переходим к описанию следующего компонента.

HostScript engine (HS).

HS – это COM объект (как, впрочем, и все остальные), предназначенный для выполнения скриптов (в том числе и тех, которые сгенерированы DE), а так же для получения данных, с помощью внешних скриптов, из внешних приложений (external application - EA ).

В нашем случае, DE также является внешним приложением для HS, поскольку в технологии DE открывается с помощью функции HS – CreateDialogEngine().

При инициализации DS, нужно выполнить функции COM библиотеки (она является Частью Windows) CreateInstance(…) для запуска указанных в ней COM объектов и получения указателей на их интерфейсы, и мы по идее, это и должны сделать. Но для того, чтобы обеспечить работу HS с DE при выполнении скрипта прямо, минуя DS, и предусмотрена вышесказанная функция HS.

Проще,

При инициализации DS, мы

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