A compreensão da linguagem coloquial (CLU), um recurso da Linguagem de IA do Azure, é a versão atualizada do LUIS.
Para obter mais informações sobre o suporte ao reconhecimento de linguagem no SDK do Bot Framework, confira Reconhecimento de linguagem natural.
A capacidade de entender o que seu usuário quer dizer contextualmente e em conversas pode ser uma tarefa difícil, mas pode dar ao seu bot uma sensação de conversa mais natural. O LUIS (Reconhecimento vocal) é um serviço de API baseado em nuvem que permite que você faça exatamente isso, para que o seu bot possa reconhecer a intenção das mensagens do usuário, permitir uma linguagem mais natural do seu usuário e direcionar melhor o fluxo de conversação.
Este tópico explica como adicionar LUIS a um aplicativo de reservas de voo para reconhecer intenções e entidades diferentes contidas na entrada do usuário.
Observação
Os SDKs JavaScript, C# e Python do Bot Framework continuarão a ser compatíveis. No entanto, o SDK Java está sendo desativado, com o suporte final de longo prazo terminando em novembro de 2023.
Os bots existentes criados com o SDK para Java continuarão a funcionar.
Essa amostra de bot básico mostra um exemplo de um aplicativo de reservas de voo em aeroportos. Ele usa um serviço do LUIS para reconhecer a entrada do usuário e retornar a melhor intenção reconhecida pelo LUIS.
O modelo de linguagem contém três intenções: Book Flight, Cancel e None. O LUIS usará essas intenções para entender o que o usuário pretendia ao enviar uma mensagem ao bot. O modelo de linguagem também define as entidades que o LUIS pode extrair da entrada do usuário, como o aeroporto de origem ou de destino.
Após cada processamento da entrada do usuário, DialogBot salva o estado atual de UserState e ConversationState. Depois que todas as informações necessárias forem coletadas, o exemplo de código cria uma reserva “Reservar voo” de demonstração. Neste artigo, abordaremos os aspectos do LUIS para esta amostra. No entanto, o fluxo geral da amostra é:
OnMembersAddedAsync é chamado quando um novo usuário é conectado e exibe um cartão de boas-vindas.
OnMessageActivityAsync é chamado em cada entrada de usuário recebida.
O módulo OnMessageActivityAsync executa o diálogo apropriado por meio do método de extensão de diálogo Run. Em seguida, a caixa de diálogo principal chama o auxiliar do LUIS para localizar a intenção do usuário com melhor pontuação. Se a intenção principal para a entrada do usuário retornar "BookFlight", o auxiliar preencherá as informações do usuário retornadas pelo LUIS. Depois disso, a caixa de diálogo principal inicia o BookingDialog, que adquire informações adicionais do usuário conforme necessário, tais como:
Origin a cidade de origem
TravelDate a data da reserva do voo
Destination a cidade de destino
Após cada processamento da entrada do usuário, dialogBot salva o estado atual de userState e conversationState. Depois que todas as informações necessárias forem coletadas, o exemplo de código cria uma reserva “Reservar voo” de demonstração. Neste artigo, abordaremos os aspectos do LUIS para esta amostra. No entanto, o fluxo geral da amostra é:
onMembersAdded é chamado quando um novo usuário é conectado e exibe um cartão de boas-vindas.
OnMessage é chamado em cada entrada de usuário recebida.
O módulo onMessage executa mainDialog, que coleta a entrada de usuário.
Em seguida, a caixa de diálogo principal chama o auxiliar do LUIS FlightBookingRecognizer para localizar a intenção do usuário com melhor pontuação. Se a intenção principal para a entrada do usuário retornar "BookFlight", o auxiliar preencherá as informações do usuário retornadas pelo LUIS.
Quando recebe uma resposta de volta, mainDialog preserva as informações do usuário retornadas pelo LUIS e inicia bookingDialog. bookingDialog obtém informações adicionais conforme a necessidade do usuário, como
destination A cidade de destino.
origin A cidade de origem.
travelDate A data da reserva do voo.
Após cada processamento da entrada do usuário, DialogBot salva o estado atual de UserState e ConversationState.
Depois que todas as informações necessárias forem coletadas, o exemplo de código cria uma reserva “Reservar voo” de demonstração.
Neste artigo, abordaremos os aspectos do LUIS para esta amostra. No entanto, o fluxo geral da amostra é:
onMembersAdded é chamado quando um novo usuário é conectado e exibe um cartão de boas-vindas.
onMessageActivity é chamado em cada entrada de usuário recebida.
O módulo onMessageActivity executa o diálogo apropriado por meio do método de extensão de diálogo run. Em seguida, a caixa de diálogo principal chama o auxiliar do LUIS para localizar a intenção do usuário com melhor pontuação. Se a intenção principal para a entrada do usuário retornar "BookFlight", o auxiliar preencherá as informações do usuário retornadas pelo LUIS. Depois disso, a caixa de diálogo principal inicia o BookingDialog, que adquire informações adicionais do usuário conforme necessário, tais como:
Origin a cidade de origem
TravelDate a data da reserva do voo
Destination a cidade de destino
Após cada processamento da entrada do usuário, DialogBot salva o estado atual de user_state e conversation_state. Depois que todas as informações necessárias forem coletadas, o exemplo de código cria uma reserva “Reservar voo” de demonstração. Neste artigo, abordaremos os aspectos do LUIS para esta amostra. No entanto, o fluxo geral da amostra é:
on_members_added_activity é chamado quando um novo usuário é conectado e exibe um cartão de boas-vindas.
on_message_activity é chamado em cada entrada de usuário recebida.
O módulo on_message_activity executa o diálogo apropriado por meio do método de extensão de diálogo run_dialog. Em seguida, o diálogo principal chama LuisHelper para localizar a intenção do usuário com maior pontuação. Se a intenção principal para a entrada do usuário retornar "BookFlight", a função auxiliar preencherá as informações do usuário retornadas pelo LUIS. Depois disso, a caixa de diálogo principal inicia o BookingDialog, que adquire informações adicionais do usuário conforme necessário, tais como:
Na página Aplicativos de conversação no LUIS, escolha Importar e, em seguida, Importar como JSON.
No diálogo Importar novo aplicativo:
Escolha o arquivo FlightBooking.json na pasta CognitiveModels da amostra.
Insira FlightBooking como o nome opcional do aplicativo e escolha Concluído.
O site pode exibir os diálogos Como criar um aplicativo do LUIS efetivo e Atualizar as entidades de composição. Você pode ignorar esses diálogos e continuar.
Treine o aplicativo e, em seguida, publique-o no ambiente de produção.
Para obter mais informações, confira a documentação do LUIS sobre como treinar e publicar um aplicativo.
Por que usar entidades?
As entidades do LUIS possibilitam que o seu bot tenha reconhecimento de eventos além das intenções padrão. Isso permite que você colete informações adicionais dos usuários, para que seu bot possa fazer perguntas e responder de forma mais inteligente. Em conjunto com as definições para as três intenções do LUIS “Reservar voo”, “Cancelar” e “Nenhum”, o arquivo FlightBooking.json também contém um conjunto de entidades, como “From.Airport” e “To.Airport”. Essas entidades permitem que o LUIS detecte e retorne informações adicionais contidas na entrada original do usuário, quando ele solicitar uma nova reserva de viagem.
Obter valores para conectar ao seu aplicativo LUIS
Após a publicação de seu aplicativo LUIS, acesse-o no bot. Será necessário registrar vários valores para acessar o aplicativo do LUIS no bot. Você pode recuperar essas informações usando o portal do LUIS.
Recuperar informações do aplicativo do portal LUIS.ai
O arquivo de configurações (appsettings.json, .env ou config.py) age como um único local para reunir todas as referências de serviço. As informações que você recupera serão adicionadas a esse arquivo na próxima seção.
Com o aplicativo LUIS publicado aberto, escolha a guia GERENCIAR.
Selecione a guia Configurações no lado esquerdo e registre o valor mostrado para ID do Aplicativo como <YOUR_APP_ID>.
Selecione Recursos do Azure e, em seguida, Recurso de Previsão. Registre o valor mostrado para Localização como <YOUR_REGION> e Chave Primária como <YOUR_AUTHORING_KEY>.
Como alternativa, é possível usar a região e a chave primária para seu recurso de criação.
Adicione as informações necessárias para acessar o aplicativo do LUIS, incluindo a ID do aplicativo, a chave de criação e a região, no arquivo appsettings.json. Na etapa anterior, esses valores foram recuperados do aplicativo do LUIS publicado. O nome do host da API deve estar no formato <your region>.api.cognitive.microsoft.com.
Adicione as informações necessárias para acessar o aplicativo do LUIS, incluindo a ID do aplicativo, a chave de criação e a região, no arquivo .env. Na etapa anterior, esses valores foram recuperados do aplicativo do LUIS publicado. O nome do host da API deve estar no formato <your region>.api.cognitive.microsoft.com.
Adicione as informações necessárias para acessar o aplicativo do LUIS, incluindo a ID do aplicativo, a chave de criação e a região, no arquivo application.properties. Na etapa anterior, esses valores foram recuperados do aplicativo do LUIS publicado. O nome do host da API deve estar no formato <your region>.api.cognitive.microsoft.com.
Adicione as informações necessárias para acessar o aplicativo do LUIS, incluindo a ID do aplicativo, a chave de criação e a região, no arquivo config.py. Na etapa anterior, esses valores foram recuperados do aplicativo do LUIS publicado. O nome do host da API deve estar no formato <your region>.api.cognitive.microsoft.com.
Verifique se o pacote do NuGet Microsoft.Bot.Builder.AI.Luis está instalado para o seu projeto.
Para se conectar ao serviço do LUIS, o bot transfere as informações que você adicionou ao arquivo appsetting.json. A classe FlightBookingRecognizer contém código com as configurações do arquivo appsetting.json e consulta o serviço do LUIS chamando o método 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);
}
O FlightBookingEx.cs contém a lógica para extrair From, To e TravelDate; ela estende a classe parcial FlightBooking.cs usada para armazenar os resultados do LUIS ao chamar FlightBookingRecognizer.RecognizeAsync<FlightBooking> do 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];
}
Para usar o LUIS, seu projeto precisa instalar o pacote do npm botbuilder-ai.
Para se conectar ao serviço do LUIS, o bot usa as informações que você adicionou ao arquivo .env. A classe flightBookingRecognizer.js contém o código que importa as configurações do arquivo .env e consulta o serviço do LUIS chamando o método 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;
}
}
A lógica para extrair From, To e TravelDate é implementada como métodos auxiliares dentro de flightBookingRecognizer.js. Esses métodos são usados após chamar flightBookingRecognizer.executeLuisQuery() de mainDialog.js
Certifique-se de que o pacote com.microsoft.bot.bot-ai-luis-v3 esteja adicionado ao arquivo pom.xml.
Para se conectar ao serviço do LUIS, o bot transfere as informações que você adicionou ao arquivo application.properties. A classe FlightBookingRecognizer contém código com as configurações do arquivo application.properties e consulta o serviço do LUIS ao chamar o método 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);
}
O FlightBookingRecognizer.cs contém a lógica para extrair From, To e TravelDate; e é chamado de MainDialog.java para decodificar os resultados da consulta do 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;
}
Certifique-se de que o pacote PyPI botbuilder-ai esteja instalado para seu projeto.
Para se conectar ao serviço do LUIS, o bot usa as informações que você adicionou ao arquivo config.py. A classe FlightBookingRecognizer contém o código que importa as configurações do arquivo config.py e consulta o serviço do LUIS chamando o método 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)
A lógica para extrair From, To e travel_date é implementada como métodos auxiliares da classe LuisHelper dentro de luis_helper.py. Esses métodos são usados após chamar LuisHelper.execute_luis_query() de 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
Agora, o LUIS está configurado e conectado ao seu bot.
No Emulator, digite uma mensagem, como “viagem para Paris” ou “viajar de Paris para Berlim”. Use qualquer enunciado encontrado no arquivo FlightBooking.json para treinar a intenção "Reservar voo".
Se a intenção principal retornada do LUIS for “Reservar voo”, o bot fará mais perguntas até ter informações suficientes armazenadas para criar uma reserva de viagem. Nesse ponto, ele retornará essas informações de reserva para o usuário.
Neste ponto, a lógica do bot de código será restaurada e você poderá continuar a criar mais reservas.
Informações adicionais
Para obter mais informações sobre o LUIS, consulte a documentação dele: