Распознавание речи (CLU) — это обновленная версия LUIS.
Дополнительные сведения о поддержке распознавания речи в пакете SDK Bot Framework см. в разделе "Распознавание естественного языка".
Возможность понимать, что пользователь хочет сказать и какой вкладывает контекст, может быть сложной задачей, но также может способствовать более естественной беседе с ботом. API распознавания речи — это облачная служба API, которая позволяет сделать так, чтобы бот мог распознавать намерения пользовательских сообщений, использовать более естественный язык пользователя и лучше направлять поток общения.
В этом разделе рассматривается добавление LUIS в приложение для бронирования авиабилетов, чтобы распознавать намерения и сущности в введенных пользователем данных.
Примечание.
Пакеты SDK для JavaScript, C# и Python для Bot Framework по-прежнему будут поддерживаться, однако пакет SDK java отменяется с окончательной долгосрочной поддержкой, заканчивающейся в ноябре 2023 года.
Существующие боты, созданные с помощью пакета SDK для Java, будут продолжать функционировать.
Знания об основах бота и обработке естественного языка.
Об этом примере
Этот пример основного бота реализует логику приложения для бронирования авиабилетов. С помощью службы LUIS он распознает пользовательский ввод и возвращает наиболее вероятное из обнаруженных LUIS намерений.
Языковая модель содержит три намерения: Book Flight, Cancel и None. Служба LUIS будет использовать эти намерения для распознавания желаний пользователя в полученном от него сообщении. Языковая модель также определяет сущности, которые LUIS может извлекать из входных данных пользователя, таких как аэропорты вылета или назначения.
После каждой обработки введенных пользователем данных DialogBot сохраняет текущее состояние UserState и ConversationState. После сбора всех необходимых сведений пример кода создает демонстрационное резервирование для бронирования рейсов. В этой статье мы рассмотрим аспекты LUIS этого примера. Однако общий поток примера состоит в следующем:
Когда подключается новый пользователь, вызывается OnMembersAddedAsync и отображается приветственная карточка.
OnMessageActivityAsync вызывается для каждого полученного блока данных, введенных пользователем.
Модуль OnMessageActivityAsync запускает соответствующий диалог с помощью метода расширения диалога Run. Затем главный диалог вызывает вспомогательного метода LUIS для поиска самого вероятного намерения пользователя. Если таким намерением является BookFlight (бронирование авиабилетов), вспомогательный метод сохраняет полученные от LUIS данные пользователя. Затем главный диалог запускает BookingDialog для сбора требуемых дополнительных сведений от пользователя, например:
Origin — город вылета;
TravelDate — дата для бронирования авиабилетов;
Destination — город прилета;
После каждой обработки введенных пользователем данных dialogBot сохраняет текущее состояние userState и conversationState. После сбора всех необходимых сведений пример кода создает демонстрационное резервирование для бронирования рейсов. В этой статье мы рассмотрим аспекты LUIS этого примера. Однако общий поток примера состоит в следующем:
Когда подключается новый пользователь, вызывается onMembersAdded и отображается приветственная карточка.
OnMessage вызывается для каждого полученного блока данных, введенных пользователем.
Модуль onMessage запускает mainDialogмодуль, который собирает входные данные пользователя.
Затем главный диалог вызывает FlightBookingRecognizer вспомогательного метода LUIS для поиска самого вероятного намерения пользователя. Если таким намерением является BookFlight (бронирование авиабилетов), вспомогательный метод сохраняет полученные от LUIS данные пользователя.
Получив ответ, mainDialog сохраняет для пользователя информацию, полученную от LUIS, и запускает bookingDialog. bookingDialog получает от пользователя дополнительные сведения по мере необходимости, например:
destination — город прилета;
origin — город вылета;
travelDate — дата для бронирования авиабилетов;
После каждой обработки введенных пользователем данных DialogBot сохраняет текущее состояние UserState и ConversationState.
После сбора всех необходимых сведений пример кода создает демонстрационное резервирование для бронирования рейсов.
В этой статье мы рассмотрим аспекты LUIS этого примера. Однако общий поток примера состоит в следующем:
Когда подключается новый пользователь, вызывается onMembersAdded и отображается приветственная карточка.
onMessageActivity вызывается для каждого полученного блока данных, введенных пользователем.
Модуль onMessageActivity запускает соответствующий диалог с помощью метода расширения диалога run. Затем главный диалог вызывает вспомогательного метода LUIS для поиска самого вероятного намерения пользователя. Если таким намерением является BookFlight (бронирование авиабилетов), вспомогательный метод сохраняет полученные от LUIS данные пользователя. Затем главный диалог запускает BookingDialog для сбора требуемых дополнительных сведений от пользователя, например:
Origin — город вылета;
TravelDate — дата для бронирования авиабилетов;
Destination — город прилета;
После каждой обработки введенных пользователем данных DialogBot сохраняет текущее состояние user_state и conversation_state. После сбора всех необходимых сведений пример кода создает демонстрационное резервирование для бронирования рейсов. В этой статье мы рассмотрим аспекты LUIS этого примера. Однако общий поток примера состоит в следующем:
Когда подключается новый пользователь, вызывается on_members_added_activity и отображается приветственная карточка.
on_message_activity вызывается для каждого полученного блока данных, введенных пользователем.
Модуль on_message_activity запускает соответствующий диалог с помощью метода расширения диалога run_dialog. Затем основное диалоговое окно вызывает LuisHelper поиск намерения пользователя в верхней оценке. Если таким намерением является BookFlight (бронирование авиабилетов), вспомогательная функция сохраняет полученные от LUIS данные пользователя. Затем главный диалог запускает BookingDialog для сбора требуемых дополнительных сведений от пользователя, например:
На странице "Приложения беседы" в LUIS выберите "Импорт", а затем импорт в формате JSON.
В диалоговом окне импорта нового приложения :
Выберите файл FlightBooking.json в папке CognitiveModels примера.
Введите FlightBooking необязательное имя приложения и нажмите кнопку "Готово".
Сайт может отобразить , как создать эффективное приложение LUIS и обновить диалоговые окна составных сущностей . Эти диалоги можно закрыть и продолжить.
Обучите свое приложение, а затем опубликуйте приложение в рабочей среде.
Дополнительные сведения см. в документации LUIS по обучению и публикации приложения.
Для чего нужны сущности
Сущности LUIS позволяют боту понимать события за пределами стандартных намерений. Это позволяет собирать дополнительные сведения от пользователей, чтобы бот мог задавать вопросы и отвечать более интеллектуально. Наряду с определениями для трех намерений LUIS "Book Flight", "Отмена" и "Нет", файл FlightBooking.json также содержит набор сущностей, таких как From.Airport и To.Airport. Эти сущности позволяют LUIS обнаруживать и возвращать дополнительные сведения из данных, которые пользователь предоставляет при запросе нового бронирования.
Получение значений для подключения к приложению LUIS
После публикации приложения LUIS ваш бот сможет обратиться к нему. Необходимо записать несколько значений, чтобы получить доступ к приложению LUIS из бота. Нужные сведения можно получить с помощью портала LUIS.
Получение сведений о приложении на портале LUIS.ai
Файл параметров (appsettings.json, .env или config.py) используется, чтобы собрать в одном расположении ссылки на все службы. Полученные данные будут добавлены в этот файл в следующем разделе.
Выберите опубликованное приложение LUIS на сайте luis.ai.
Открыв опубликованное приложение LUIS, выберите в нем вкладку MANAGE (Управление).
Перейдите на вкладку "Параметры" слева и запишите значение, отображаемое для идентификатора приложения как YOUR_APP_ID.><
Выберите ресурсы Azure, а затем ресурс прогнозирования. Запишите значение, отображаемое для расположения как YOUR_REGION> и первичный ключ, как <<YOUR_AUTHORING_KEY>.
Кроме того, можно использовать регион и первичный ключ для ресурса разработки.
Добавьте сведения, необходимые для доступа к приложению LUIS, включая идентификатор приложения, ключ разработки и регион в appsettings.json файл. На предыдущем шаге вы получили эти значения из опубликованного приложения LUIS. Имя узла API должно быть в формате <your region>.api.cognitive.microsoft.com.
Добавьте сведения, необходимые для доступа к приложению LUIS, включая идентификатор приложения, ключ разработки и регион в .env файл. На предыдущем шаге вы получили эти значения из опубликованного приложения LUIS. Имя узла API должно быть в формате <your region>.api.cognitive.microsoft.com.
Добавьте сведения, необходимые для доступа к приложению LUIS, включая идентификатор приложения, ключ разработки и регион в application.properties файл. На предыдущем шаге вы получили эти значения из опубликованного приложения LUIS. Имя узла API должно быть в формате <your region>.api.cognitive.microsoft.com.
Добавьте сведения, необходимые для доступа к приложению LUIS, включая идентификатор приложения, ключ разработки и регион в config.py файл. На предыдущем шаге вы получили эти значения из опубликованного приложения LUIS. Имя узла API должно быть в формате <your region>.api.cognitive.microsoft.com.
Убедитесь, что для вашего проекта установлен пакет NuGet Microsoft.Bot.Builder.AI.Luis.
Чтобы подключиться к службе LUIS, бот извлекает сведения, добавленные в файл appsetting.json. Класс FlightBookingRecognizer содержит код с параметрами из файла appsetting.json и отправляет запрос к службе LUIS, вызывая метод RecognizeAsync.
FlightBookingRecognizer.cs
public class FlightBookingRecognizer : IRecognizer
{
private readonly LuisRecognizer _recognizer;
public FlightBookingRecognizer(IConfiguration configuration)
{
var luisIsConfigured = !string.IsNullOrEmpty(configuration["LuisAppId"]) && !string.IsNullOrEmpty(configuration["LuisAPIKey"]) && !string.IsNullOrEmpty(configuration["LuisAPIHostName"]);
if (luisIsConfigured)
{
var luisApplication = new LuisApplication(
configuration["LuisAppId"],
configuration["LuisAPIKey"],
"https://" + configuration["LuisAPIHostName"]);
// Set the recognizer options depending on which endpoint version you want to use.
// More details can be found in https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
var recognizerOptions = new LuisRecognizerOptionsV3(luisApplication)
{
PredictionOptions = new Bot.Builder.AI.LuisV3.LuisPredictionOptions
{
IncludeInstanceData = true,
}
};
_recognizer = new LuisRecognizer(recognizerOptions);
}
}
// Returns true if luis is configured in the appsettings.json and initialized.
public virtual bool IsConfigured => _recognizer != null;
public virtual async Task<RecognizerResult> RecognizeAsync(ITurnContext turnContext, CancellationToken cancellationToken)
=> await _recognizer.RecognizeAsync(turnContext, cancellationToken);
public virtual async Task<T> RecognizeAsync<T>(ITurnContext turnContext, CancellationToken cancellationToken)
where T : IRecognizerConvert, new()
=> await _recognizer.RecognizeAsync<T>(turnContext, cancellationToken);
}
FlightBookingEx.cs содержит логику для извлечения From, To и TravelDate. Это расширение разделяемого класса FlightBooking.cs, используемого для хранения результатов LUIS при вызове FlightBookingRecognizer.RecognizeAsync<FlightBooking> из MainDialog.cs.
CognitiveModels\FlightBookingEx.cs
// Extends the partial FlightBooking class with methods and properties that simplify accessing entities in the luis results
public partial class FlightBooking
{
public (string From, string Airport) FromEntities
{
get
{
var fromValue = Entities?._instance?.From?.FirstOrDefault()?.Text;
var fromAirportValue = Entities?.From?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault();
return (fromValue, fromAirportValue);
}
}
public (string To, string Airport) ToEntities
{
get
{
var toValue = Entities?._instance?.To?.FirstOrDefault()?.Text;
var toAirportValue = Entities?.To?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault();
return (toValue, toAirportValue);
}
}
// This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
// TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
public string TravelDate
=> Entities.datetime?.FirstOrDefault()?.Expressions.FirstOrDefault()?.Split('T')[0];
}
Чтобы использовать LUIS, в проект следует установить пакет npm botbuilder-ai.
Чтобы подключиться к службе LUIS, бот использует сведения, добавленные в .env файл. Класс flightBookingRecognizer.js содержит код, который импортирует параметры из файла .env и отправляет запрос к службе LUIS, вызывая метод recognize().
dialogs/flightBookingRecognizer.js
class FlightBookingRecognizer {
constructor(config) {
const luisIsConfigured = config && config.applicationId && config.endpointKey && config.endpoint;
if (luisIsConfigured) {
// Set the recognizer options depending on which endpoint version you want to use e.g v2 or v3.
// More details can be found in https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
const recognizerOptions = {
apiVersion: 'v3'
};
this.recognizer = new LuisRecognizer(config, recognizerOptions);
}
}
get isConfigured() {
return (this.recognizer !== undefined);
}
/**
* Returns an object with preformatted LUIS results for the bot's dialogs to consume.
* @param {TurnContext} context
*/
async executeLuisQuery(context) {
return await this.recognizer.recognize(context);
}
getFromEntities(result) {
let fromValue, fromAirportValue;
if (result.entities.$instance.From) {
fromValue = result.entities.$instance.From[0].text;
}
if (fromValue && result.entities.From[0].Airport) {
fromAirportValue = result.entities.From[0].Airport[0][0];
}
return { from: fromValue, airport: fromAirportValue };
}
getToEntities(result) {
let toValue, toAirportValue;
if (result.entities.$instance.To) {
toValue = result.entities.$instance.To[0].text;
}
if (toValue && result.entities.To[0].Airport) {
toAirportValue = result.entities.To[0].Airport[0][0];
}
return { to: toValue, airport: toAirportValue };
}
/**
* This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
* TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
*/
getTravelDate(result) {
const datetimeEntity = result.entities.datetime;
if (!datetimeEntity || !datetimeEntity[0]) return undefined;
const timex = datetimeEntity[0].timex;
if (!timex || !timex[0]) return undefined;
const datetime = timex[0].split('T')[0];
return datetime;
}
}
Логика извлечения From, To и TravelDate реализуется в виде вспомогательных методов в flightBookingRecognizer.js. Эти методы используются после вызова flightBookingRecognizer.executeLuisQuery() из mainDialog.js
Убедитесь, что пакет com.microsoft.bot-ai-luis-v3 добавляется в файл pom.xml.
Чтобы подключиться к службе LUIS, бот извлекает сведения, добавленные в файл application.properties. Класс FlightBookingRecognizer содержит код с параметрами из файла application.properties и запрашивает службу LUIS путем вызова recognize метода.
FlightBookingRecognizer.java
/**
* The constructor of the FlightBookingRecognizer class.
*
* @param configuration The Configuration object to use.
*/
public FlightBookingRecognizer(Configuration configuration) {
Boolean luisIsConfigured = StringUtils.isNotBlank(configuration.getProperty("LuisAppId"))
&& StringUtils.isNotBlank(configuration.getProperty("LuisAPIKey"))
&& StringUtils.isNotBlank(configuration.getProperty("LuisAPIHostName"));
if (luisIsConfigured) {
LuisApplication luisApplication = new LuisApplication(
configuration.getProperty("LuisAppId"),
configuration.getProperty("LuisAPIKey"),
String.format("https://%s", configuration.getProperty("LuisAPIHostName"))
);
// Set the recognizer options depending on which endpoint version you want to use.
// More details can be found in
// https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
LuisRecognizerOptionsV3 recognizerOptions = new LuisRecognizerOptionsV3(luisApplication);
recognizerOptions.setIncludeInstanceData(true);
this.recognizer = new LuisRecognizer(recognizerOptions);
}
}
/**
* Runs an utterance through a recognizer and returns a generic recognizer result.
*
* @param turnContext Turn context.
* @return Analysis of utterance.
*/
@Override
public CompletableFuture<RecognizerResult> recognize(TurnContext turnContext) {
return this.recognizer.recognize(turnContext);
}
Содержит FlightBookingRecognizer.cs логику извлечения из, to to and TravelDate; и вызывается из MainDialog.java декодирования результатов результата запроса Luis.
FlightBookingRecognizer.java
/**
* Gets the From data from the entities which is part of the result.
*
* @param result The recognizer result.
* @return The object node representing the From data.
*/
public ObjectNode getFromEntities(RecognizerResult result) {
String fromValue = "", fromAirportValue = "";
if (result.getEntities().get("$instance").get("From") != null) {
fromValue = result.getEntities().get("$instance").get("From").get(0).get("text")
.asText();
}
if (!fromValue.isEmpty()
&& result.getEntities().get("From").get(0).get("Airport") != null) {
fromAirportValue = result.getEntities().get("From").get(0).get("Airport").get(0).get(0)
.asText();
}
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
ObjectNode entitiesNode = mapper.createObjectNode();
entitiesNode.put("from", fromValue);
entitiesNode.put("airport", fromAirportValue);
return entitiesNode;
}
/**
* Gets the To data from the entities which is part of the result.
*
* @param result The recognizer result.
* @return The object node representing the To data.
*/
public ObjectNode getToEntities(RecognizerResult result) {
String toValue = "", toAirportValue = "";
if (result.getEntities().get("$instance").get("To") != null) {
toValue = result.getEntities().get("$instance").get("To").get(0).get("text").asText();
}
if (!toValue.isEmpty() && result.getEntities().get("To").get(0).get("Airport") != null) {
toAirportValue = result.getEntities().get("To").get(0).get("Airport").get(0).get(0)
.asText();
}
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
ObjectNode entitiesNode = mapper.createObjectNode();
entitiesNode.put("to", toValue);
entitiesNode.put("airport", toAirportValue);
return entitiesNode;
}
/**
* This value will be a TIMEX. And we are only interested in a Date so grab the first result and
* drop the Time part. TIMEX is a format that represents DateTime expressions that include some
* ambiguity. e.g. missing a Year.
*
* @param result A {link RecognizerResult}
* @return The Timex value without the Time model
*/
public String getTravelDate(RecognizerResult result) {
JsonNode datetimeEntity = result.getEntities().get("datetime");
if (datetimeEntity == null || datetimeEntity.get(0) == null) {
return null;
}
JsonNode timex = datetimeEntity.get(0).get("timex");
if (timex == null || timex.get(0) == null) {
return null;
}
String datetime = timex.get(0).asText().split("T")[0];
return datetime;
}
Убедитесь, что для проекта установлен пакет PyPI botbuilder-ai.
Чтобы подключиться к службе LUIS, бот использует сведения, добавленные в config.py файл. Класс FlightBookingRecognizer содержит код, который импортирует параметры из файла config.py и отправляет запрос к службе LUIS, вызывая метод recognize().
flight_booking_recognizer.py
class FlightBookingRecognizer(Recognizer):
def __init__(self, configuration: DefaultConfig):
self._recognizer = None
luis_is_configured = (
configuration.LUIS_APP_ID
and configuration.LUIS_API_KEY
and configuration.LUIS_API_HOST_NAME
)
if luis_is_configured:
# Set the recognizer options depending on which endpoint version you want to use e.g v2 or v3.
# More details can be found in https://docs.microsoft.com/azure/cognitive-services/luis/luis-migration-api-v3
luis_application = LuisApplication(
configuration.LUIS_APP_ID,
configuration.LUIS_API_KEY,
"https://" + configuration.LUIS_API_HOST_NAME,
)
self._recognizer = LuisRecognizer(luis_application)
@property
def is_configured(self) -> bool:
# Returns true if luis is configured in the config.py and initialized.
return self._recognizer is not None
async def recognize(self, turn_context: TurnContext) -> RecognizerResult:
return await self._recognizer.recognize(turn_context)
Логика извлечения From, To и travel_date реализуется в виде вспомогательных методов из класс LuisHelper в luis_helper.py. Эти методы используются после вызова LuisHelper.execute_luis_query() из main_dialog.py
helpers/luis_helper.py
class LuisHelper:
@staticmethod
async def execute_luis_query(
luis_recognizer: LuisRecognizer, turn_context: TurnContext
) -> (Intent, object):
"""
Returns an object with preformatted LUIS results for the bot's dialogs to consume.
"""
result = None
intent = None
try:
recognizer_result = await luis_recognizer.recognize(turn_context)
intent = (
sorted(
recognizer_result.intents,
key=recognizer_result.intents.get,
reverse=True,
)[:1][0]
if recognizer_result.intents
else None
)
if intent == Intent.BOOK_FLIGHT.value:
result = BookingDetails()
# We need to get the result from the LUIS JSON which at every level returns an array.
to_entities = recognizer_result.entities.get("$instance", {}).get(
"To", []
)
if len(to_entities) > 0:
if recognizer_result.entities.get("To", [{"$instance": {}}])[0][
"$instance"
]:
result.destination = to_entities[0]["text"].capitalize()
else:
result.unsupported_airports.append(
to_entities[0]["text"].capitalize()
)
from_entities = recognizer_result.entities.get("$instance", {}).get(
"From", []
)
if len(from_entities) > 0:
if recognizer_result.entities.get("From", [{"$instance": {}}])[0][
"$instance"
]:
result.origin = from_entities[0]["text"].capitalize()
else:
result.unsupported_airports.append(
from_entities[0]["text"].capitalize()
)
# This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop
# the Time part. TIMEX is a format that represents DateTime expressions that include some ambiguity.
# e.g. missing a Year.
date_entities = recognizer_result.entities.get("datetime", [])
if date_entities:
timex = date_entities[0]["timex"]
if timex:
datetime = timex[0].split("T")[0]
result.travel_date = datetime
else:
result.travel_date = None
except Exception as exception:
print(exception)
return intent, result
Теперь служба LUIS для бота полностью настроена и подключена.
Выполните этот пример на локальном компьютере. Если вам нужны инструкции, ознакомьтесь с файлом README для примера C#, примера JS или Python.
В эмуляторе введите сообщение, например "путешествие в Париж" или "переход из Парижа в Берлин". Используйте все речевые фрагменты, включенные в файл FlightBooking.json, для обучения намерения Book flight (Бронирование авиабилетов).
Если первое намерение, возвращенное из LUIS, разрешает "Бронировать рейс", бот будет задавать дополнительные вопросы, пока не будет достаточно информации, сохраненной для создания резервирования путешествий. После этого он возвращает всю собранную информацию о бронировании пользователю.
На этом этапе логика бота кода сбрасывается, и вы можете продолжать создавать дополнительные резервирования.
Дополнительная информация:
Дополнительные сведения о LUIS см. в документации по LUIS: