Kesintileri işleme, güçlü bir botun önemli bir yönüdür. Kullanıcılar her zaman tanımlı konuşma akışınızı adım adım izlemez. İşlemin ortasında bir soru sormayı deneyebilir veya yalnızca tamamlamak yerine iptal etmek isteyebilirler. Bu makalede, botunuzda kullanıcı kesintilerini işlemenin bazı yaygın yolları açıklanmaktadır.
Çekirdek bot örneği, kullanıcı amaçlarını tanımlamak için Language Understanding (LUIS) kullanır; ancak bu makalenin odak noktası kullanıcı amacını belirlemek değildir.
Kullanıcı amaçlarını belirleme hakkında bilgi için bkz . Doğal dil anlama ve Botunuza doğal dil anlama ekleme.
Bu makalede kullanılan örnek, kullanıcıdan uçuş bilgilerini almak için iletişim kutularını kullanan bir uçuş rezervasyon botunu modellemektedir. Kullanıcı, botla konuşma sırasında herhangi bir zamanda kesintiye neden olmak için yardım verebilir veya komutları iptal edebilir. İşlenen iki tür kesinti vardır:
İletişim kutularını kullanmak için Microsoft.Bot.Builder.Dialogs NuGet paketini yükleyin.
İletişim Kutuları\CancelAndHelpDialog.cs
Kullanıcı kesintilerini işlemek için sınıfını CancelAndHelpDialog
uygulayın. İptal edilebilir iletişim kutuları BookingDialog
ve DateResolverDialog
bu sınıftan türetilir.
public class CancelAndHelpDialog : ComponentDialog
CancelAndHelpDialog
sınıfında yöntemi, OnContinueDialogAsync
kullanıcının normal akışı kesintiye uğratıp kesintiye uğratmadığını denetlemek için yöntemini çağırırInterruptAsync
. Akış kesintiye uğrarsa temel sınıf yöntemleri çağrılır; aksi takdirde değerinden InterruptAsync
döndürülen değer döndürülür.
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
{
var result = await InterruptAsync(innerDc, cancellationToken);
if (result != null)
{
return result;
}
return await base.OnContinueDialogAsync(innerDc, cancellationToken);
}
Kullanıcı "help" (yardım) InterruptAsync
yazın, yöntemi bir ileti gönderir ve ardından üstteki iletişim kutusunun kullanıcıdan yanıt beklediğini belirtmek için çağrısında DialogTurnResult (DialogTurnStatus.Waiting)
bulunur. Bu şekilde, konuşma akışı yalnızca bir dönüş için kesilir ve bir sonraki dönüş konuşmanın kaldığı yerden devam eder.
Kullanıcı "iptal" oluşturursa, iletişim kutusu yığınını temizleyen ve iptal edilmiş bir durumla ve sonuç değeri olmadan çıkmasına neden olan iç iletişim kutusu bağlamını çağırır CancelAllDialogsAsync
. MainDialog
(daha sonra gösterilen) için, rezervasyon iletişim kutusunun sona erdiği ve kullanıcı rezervasyonunu onaylamamayı seçtiğinde olduğu gibi null döndürdüğünü göreceksiniz.
private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken)
{
if (innerDc.Context.Activity.Type == ActivityTypes.Message)
{
var text = innerDc.Context.Activity.Text.ToLowerInvariant();
switch (text)
{
case "help":
case "?":
var helpMessage = MessageFactory.Text(HelpMsgText, HelpMsgText, InputHints.ExpectingInput);
await innerDc.Context.SendActivityAsync(helpMessage, cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
case "cancel":
case "quit":
var cancelMessage = MessageFactory.Text(CancelMsgText, CancelMsgText, InputHints.IgnoringInput);
await innerDc.Context.SendActivityAsync(cancelMessage, cancellationToken);
return await innerDc.CancelAllDialogsAsync(cancellationToken);
}
}
return null;
}
İletişim kutularını kullanmak için botbuilder-dialogs npm paketini yükleyin.
iletişim kutuları/cancelAndHelpDialog.js
Kullanıcı kesintilerini işlemek için sınıfını CancelAndHelpDialog
uygulayın. İptal edilebilir iletişim kutuları BookingDialog
ve DateResolverDialog
bu sınıfı genişletin.
class CancelAndHelpDialog extends ComponentDialog {
CancelAndHelpDialog
sınıfında yöntemi, onContinueDialog
kullanıcının normal akışı kesintiye uğratıp kesintiye uğratmadığını denetlemek için yöntemini çağırırinterrupt
. Akış kesintiye uğrarsa temel sınıf yöntemleri çağrılır; aksi takdirde değerinden interrupt
döndürülen değer döndürülür.
async onContinueDialog(innerDc) {
const result = await this.interrupt(innerDc);
if (result) {
return result;
}
return await super.onContinueDialog(innerDc);
}
Kullanıcı "help" (yardım) interrupt
yazın, yöntemi bir ileti gönderir ve ardından üstteki iletişim kutusunun kullanıcıdan yanıt beklediğini belirten bir { status: DialogTurnStatus.waiting }
nesne döndürür. Bu şekilde, konuşma akışı yalnızca bir dönüş için kesilir ve bir sonraki dönüş konuşmanın kaldığı yerden devam eder.
Kullanıcı "iptal" oluşturursa, iletişim kutusu yığınını temizleyen ve iptal edilmiş bir durumla ve sonuç değeri olmadan çıkmasına neden olan iç iletişim kutusu bağlamını çağırır cancelAllDialogs
. MainDialog
(daha sonra gösterilen) için, rezervasyon iletişim kutusunun sona erdiği ve kullanıcı rezervasyonunu onaylamamayı seçtiğinde olduğu gibi null döndürdüğünü göreceksiniz.
async interrupt(innerDc) {
if (innerDc.context.activity.text) {
const text = innerDc.context.activity.text.toLowerCase();
switch (text) {
case 'help':
case '?': {
const helpMessageText = 'Show help here';
await innerDc.context.sendActivity(helpMessageText, helpMessageText, InputHints.ExpectingInput);
return { status: DialogTurnStatus.waiting };
}
case 'cancel':
case 'quit': {
const cancelMessageText = 'Cancelling...';
await innerDc.context.sendActivity(cancelMessageText, cancelMessageText, InputHints.IgnoringInput);
return await innerDc.cancelAllDialogs();
}
}
}
}
CancelAndHelpDialog.java
Kullanıcı kesintilerini işlemek için sınıfını CancelAndHelpDialog
uygulayın. İptal edilebilir iletişim kutuları BookingDialog
ve DateResolverDialog
bu sınıftan türetilir.
public class CancelAndHelpDialog extends ComponentDialog {
CancelAndHelpDialog
sınıfında yöntemi, onContinueDialog
kullanıcının normal akışı kesintiye uğratıp kesintiye uğratmadığını denetlemek için yöntemini çağırırinterrupt
. Akış kesintiye uğrarsa temel sınıf yöntemleri çağrılır; aksi takdirde değerinden interrupt
döndürülen değer döndürülür.
@Override
protected CompletableFuture<DialogTurnResult> onContinueDialog(DialogContext innerDc) {
return interrupt(innerDc).thenCompose(result -> {
if (result != null) {
return CompletableFuture.completedFuture(result);
}
return super.onContinueDialog(innerDc);
});
}
Kullanıcı "help" (yardım) interrupt
yazın, yöntemi bir ileti gönderir ve ardından üstteki iletişim kutusunun kullanıcıdan yanıt beklediğini belirtmek için çağrısında DialogTurnResult(DialogTurnStatus.WAITING)
bulunur. Bu şekilde, konuşma akışı yalnızca bir dönüş için kesilir ve bir sonraki dönüş konuşmanın kaldığı yerden devam eder.
Kullanıcı "iptal" oluşturursa, iletişim kutusu yığınını temizleyen ve iptal edilmiş bir durumla ve sonuç değeri olmadan çıkmasına neden olan iç iletişim kutusu bağlamını çağırır cancelAllDialogs
. MainDialog
(daha sonra gösterilen) için, rezervasyon iletişim kutusunun sona erdiği ve kullanıcı rezervasyonunu onaylamamayı seçtiğinde olduğu gibi null döndürdüğünü göreceksiniz.
private CompletableFuture<DialogTurnResult> interrupt(DialogContext innerDc) {
if (innerDc.getContext().getActivity().isType(ActivityTypes.MESSAGE)) {
String text = innerDc.getContext().getActivity().getText().toLowerCase();
switch (text) {
case "help":
case "?":
Activity helpMessage = MessageFactory
.text(helpMsgText, helpMsgText, InputHints.EXPECTING_INPUT);
return innerDc.getContext().sendActivity(helpMessage)
.thenCompose(sendResult ->
CompletableFuture
.completedFuture(new DialogTurnResult(DialogTurnStatus.WAITING)));
case "cancel":
case "quit":
Activity cancelMessage = MessageFactory
.text(cancelMsgText, cancelMsgText, InputHints.IGNORING_INPUT);
return innerDc.getContext()
.sendActivity(cancelMessage)
.thenCompose(sendResult -> innerDc.cancelAllDialogs());
default:
break;
}
}
return CompletableFuture.completedFuture(null);
}
İletişim kutularını kullanmak için paketi yükleyin botbuilder-dialogs
ve örnek requirements.txt
dosyanın gibi botbuilder-dialogs>=4.5.0
uygun başvuruyu içerdiğinden emin olun.
Paketleri yükleme hakkında daha fazla bilgi için örnek deposu BENİOKU dosyasına bakın.
Not
Komutunu çalıştırdığınızda pip install botbuilder-dialogs
, botbuilder-connector
ve botbuilder-schema
de yüklenirbotbuilder-core
.
iletişim kutuları/cancel-and-help-dialog.py
Kullanıcı kesintilerini işlemek için sınıfını CancelAndHelpDialog
uygulayın. İptal edilebilir iletişim kutuları BookingDialog
ve DateResolverDialog
bu sınıftan türetilir.
class CancelAndHelpDialog(ComponentDialog):
CancelAndHelpDialog
sınıfında yöntemi, on_continue_dialog
kullanıcının normal akışı kesintiye uğratıp kesintiye uğratmadığını denetlemek için yöntemini çağırırinterrupt
. Akış kesintiye uğrarsa temel sınıf yöntemleri çağrılır; aksi takdirde değerinden interrupt
döndürülen değer döndürülür.
async def on_continue_dialog(self, inner_dc: DialogContext) -> DialogTurnResult:
result = await self.interrupt(inner_dc)
if result is not None:
return result
return await super(CancelAndHelpDialog, self).on_continue_dialog(inner_dc)
Kullanıcı "help" veya "?" yazarsa, interrupt
yöntem bir ileti gönderir ve ardından yığının üstündeki iletişim kutusunun kullanıcıdan yanıt beklediğini belirtmek için çağrısında DialogTurnResult(DialogTurnStatus.Waiting)
bulunur. Bu şekilde, konuşma akışı yalnızca bir dönüş için kesilir ve bir sonraki dönüş konuşmanın kaldığı yerden devam eder.
Kullanıcı "iptal" veya "çık" yazarsa, iletişim kutusu yığınını temizleyen ve iptal edilmiş bir durumla ve sonuç değeri olmadan çıkmasına neden olan iç iletişim kutusu bağlamını çağırır cancel_all_dialogs()
. MainDialog
Daha sonra gösterilen öğesine, kullanıcı rezervasyonunu onaylamamayı seçtiğinde olduğu gibi, rezervasyon iletişim kutusunun sona erdiği ve null döndürdüğünü gösterir.
async def interrupt(self, inner_dc: DialogContext) -> DialogTurnResult:
if inner_dc.context.activity.type == ActivityTypes.message:
text = inner_dc.context.activity.text.lower()
help_message_text = "Show Help..."
help_message = MessageFactory.text(
help_message_text, help_message_text, InputHints.expecting_input
)
if text in ("help", "?"):
await inner_dc.context.send_activity(help_message)
return DialogTurnResult(DialogTurnStatus.Waiting)
cancel_message_text = "Cancelling"
cancel_message = MessageFactory.text(
cancel_message_text, cancel_message_text, InputHints.ignoring_input
)
if text in ("cancel", "quit"):
await inner_dc.context.send_activity(cancel_message)
return await inner_dc.cancel_all_dialogs()
return None
Kesme işleme sınıfı uygulandıktan sonra, bu bot kullanıcıdan yeni bir ileti aldığında ne olduğunu gözden geçirin.
İletişim Kutuları\MainDialog.cs
Yeni ileti etkinliği geldikçe bot çalıştırır MainDialog
. Kullanıcıdan MainDialog
yardımcı olabileceği şeyleri ister. Ardından yönteminde MainDialog.ActStepAsync
öğesini aşağıda gösterildiği gibi çağrısıyla BeginDialogAsync
başlatırBookingDialog
.
private async Task<DialogTurnResult> ActStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
if (!_luisRecognizer.IsConfigured)
{
// LUIS is not configured, we just run the BookingDialog path with an empty BookingDetailsInstance.
return await stepContext.BeginDialogAsync(nameof(BookingDialog), new BookingDetails(), cancellationToken);
}
// Call LUIS and gather any potential booking details. (Note the TurnContext has the response to the prompt.)
var luisResult = await _luisRecognizer.RecognizeAsync<FlightBooking>(stepContext.Context, cancellationToken);
switch (luisResult.TopIntent().intent)
{
case FlightBooking.Intent.BookFlight:
await ShowWarningForUnsupportedCities(stepContext.Context, luisResult, cancellationToken);
// Initialize BookingDetails with any entities we may have found in the response.
var bookingDetails = new BookingDetails()
{
// Get destination and origin from the composite entities arrays.
Destination = luisResult.ToEntities.Airport,
Origin = luisResult.FromEntities.Airport,
TravelDate = luisResult.TravelDate,
};
// Run the BookingDialog giving it whatever details we have from the LUIS call, it will fill out the remainder.
return await stepContext.BeginDialogAsync(nameof(BookingDialog), bookingDetails, cancellationToken);
case FlightBooking.Intent.GetWeather:
// We haven't implemented the GetWeatherDialog so we just display a TODO message.
var getWeatherMessageText = "TODO: get weather flow here";
var getWeatherMessage = MessageFactory.Text(getWeatherMessageText, getWeatherMessageText, InputHints.IgnoringInput);
await stepContext.Context.SendActivityAsync(getWeatherMessage, cancellationToken);
break;
default:
// Catch all for unhandled intents
var didntUnderstandMessageText = $"Sorry, I didn't get that. Please try asking in a different way (intent was {luisResult.TopIntent().intent})";
var didntUnderstandMessage = MessageFactory.Text(didntUnderstandMessageText, didntUnderstandMessageText, InputHints.IgnoringInput);
await stepContext.Context.SendActivityAsync(didntUnderstandMessage, cancellationToken);
break;
}
return await stepContext.NextAsync(null, cancellationToken);
}
Ardından, sınıfın FinalStepAsync
yönteminde MainDialog
rezervasyon iletişim kutusu sona erdi ve rezervasyon tamamlanmış veya iptal edilmiş olarak kabul edilir.
private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// If the child dialog ("BookingDialog") was cancelled, the user failed to confirm or if the intent wasn't BookFlight
// the Result here will be null.
if (stepContext.Result is BookingDetails result)
{
// Now we have all the booking details call the booking service.
// If the call to the booking service was successful tell the user.
var timeProperty = new TimexProperty(result.TravelDate);
var travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
var messageText = $"I have you booked to {result.Destination} from {result.Origin} on {travelDateMsg}";
var message = MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput);
await stepContext.Context.SendActivityAsync(message, cancellationToken);
}
// Restart the main dialog with a different message the second time around
var promptMessage = "What else can I do for you?";
return await stepContext.ReplaceDialogAsync(InitialDialogId, promptMessage, cancellationToken);
}
'deki BookingDialog
kod, kesinti işlemeyle doğrudan ilgili olmadığından burada gösterilmez. Kullanıcılardan rezervasyon ayrıntılarını istemesi için kullanılır. Bu kodu Dialogs\BookingDialogs.cs içinde bulabilirsiniz.
iletişim kutuları/mainDialog.js
Yeni ileti etkinliği geldikçe bot çalıştırır MainDialog
. Kullanıcıdan MainDialog
yardımcı olabileceği şeyleri ister. Ardından yönteminde MainDialog.actStep
öğesini aşağıda gösterildiği gibi çağrısıyla beginDialog
başlatırbookingDialog
.
async actStep(stepContext) {
const bookingDetails = {};
if (!this.luisRecognizer.isConfigured) {
// LUIS is not configured, we just run the BookingDialog path.
return await stepContext.beginDialog('bookingDialog', bookingDetails);
}
// Call LUIS and gather any potential booking details. (Note the TurnContext has the response to the prompt)
const luisResult = await this.luisRecognizer.executeLuisQuery(stepContext.context);
switch (LuisRecognizer.topIntent(luisResult)) {
case 'BookFlight': {
// Extract the values for the composite entities from the LUIS result.
const fromEntities = this.luisRecognizer.getFromEntities(luisResult);
const toEntities = this.luisRecognizer.getToEntities(luisResult);
// Show a warning for Origin and Destination if we can't resolve them.
await this.showWarningForUnsupportedCities(stepContext.context, fromEntities, toEntities);
// Initialize BookingDetails with any entities we may have found in the response.
bookingDetails.destination = toEntities.airport;
bookingDetails.origin = fromEntities.airport;
bookingDetails.travelDate = this.luisRecognizer.getTravelDate(luisResult);
console.log('LUIS extracted these booking details:', JSON.stringify(bookingDetails));
// Run the BookingDialog passing in whatever details we have from the LUIS call, it will fill out the remainder.
return await stepContext.beginDialog('bookingDialog', bookingDetails);
}
case 'GetWeather': {
// We haven't implemented the GetWeatherDialog so we just display a TODO message.
const getWeatherMessageText = 'TODO: get weather flow here';
await stepContext.context.sendActivity(getWeatherMessageText, getWeatherMessageText, InputHints.IgnoringInput);
break;
}
default: {
// Catch all for unhandled intents
const didntUnderstandMessageText = `Sorry, I didn't get that. Please try asking in a different way (intent was ${ LuisRecognizer.topIntent(luisResult) })`;
await stepContext.context.sendActivity(didntUnderstandMessageText, didntUnderstandMessageText, InputHints.IgnoringInput);
}
}
return await stepContext.next();
}
Ardından, sınıfın finalStep
yönteminde MainDialog
rezervasyon iletişim kutusu sona erdi ve rezervasyon tamamlanmış veya iptal edilmiş olarak kabul edilir.
async finalStep(stepContext) {
// If the child dialog ("bookingDialog") was cancelled or the user failed to confirm, the Result here will be null.
if (stepContext.result) {
const result = stepContext.result;
// Now we have all the booking details.
// This is where calls to the booking AOU service or database would go.
// If the call to the booking service was successful tell the user.
const timeProperty = new TimexProperty(result.travelDate);
const travelDateMsg = timeProperty.toNaturalLanguage(new Date(Date.now()));
const msg = `I have you booked to ${ result.destination } from ${ result.origin } on ${ travelDateMsg }.`;
await stepContext.context.sendActivity(msg, msg, InputHints.IgnoringInput);
}
// Restart the main dialog with a different message the second time around
return await stepContext.replaceDialog(this.initialDialogId, { restartMsg: 'What else can I do for you?' });
}
'deki BookingDialog
kod, kesinti işlemeyle doğrudan ilgili olmadığından burada gösterilmez. Kullanıcılardan rezervasyon ayrıntılarını istemesi için kullanılır. Bu kodu iletişim kutusunda /bookingDialogs.js bulabilirsiniz.
MainDialog.java
Yeni ileti etkinliği geldikçe bot çalıştırır MainDialog
. Kullanıcıdan MainDialog
yardımcı olabileceği şeyleri ister. Ardından yönteminde MainDialog.actStep
öğesini aşağıda gösterildiği gibi çağrısıyla beginDialog
başlatırBookingDialog
.
private CompletableFuture<DialogTurnResult> actStep(WaterfallStepContext stepContext) {
if (!luisRecognizer.isConfigured()) {
// LUIS is not configured, we just run the BookingDialog path with an empty BookingDetailsInstance.
return stepContext.beginDialog("BookingDialog", new BookingDetails());
}
// Call LUIS and gather any potential booking details. (Note the TurnContext has the response to the prompt.)
return luisRecognizer.recognize(stepContext.getContext()).thenCompose(luisResult -> {
switch (luisResult.getTopScoringIntent().intent) {
case "BookFlight":
// Extract the values for the composite entities from the LUIS result.
ObjectNode fromEntities = luisRecognizer.getFromEntities(luisResult);
ObjectNode toEntities = luisRecognizer.getToEntities(luisResult);
// Show a warning for Origin and Destination if we can't resolve them.
return showWarningForUnsupportedCities(
stepContext.getContext(), fromEntities, toEntities)
.thenCompose(showResult -> {
// Initialize BookingDetails with any entities we may have found in the response.
BookingDetails bookingDetails = new BookingDetails();
bookingDetails.setDestination(toEntities.get("airport").asText());
bookingDetails.setOrigin(fromEntities.get("airport").asText());
bookingDetails.setTravelDate(luisRecognizer.getTravelDate(luisResult));
// Run the BookingDialog giving it whatever details we have from the LUIS call,
// it will fill out the remainder.
return stepContext.beginDialog("BookingDialog", bookingDetails);
}
);
case "GetWeather":
// We haven't implemented the GetWeatherDialog so we just display a TODO message.
String getWeatherMessageText = "TODO: get weather flow here";
Activity getWeatherMessage = MessageFactory
.text(
getWeatherMessageText, getWeatherMessageText,
InputHints.IGNORING_INPUT
);
return stepContext.getContext().sendActivity(getWeatherMessage)
.thenCompose(resourceResponse -> stepContext.next(null));
default:
// Catch all for unhandled intents
String didntUnderstandMessageText = String.format(
"Sorry, I didn't get that. Please "
+ " try asking in a different way (intent was %s)",
luisResult.getTopScoringIntent().intent
);
Activity didntUnderstandMessage = MessageFactory
.text(
didntUnderstandMessageText, didntUnderstandMessageText,
InputHints.IGNORING_INPUT
);
return stepContext.getContext().sendActivity(didntUnderstandMessage)
.thenCompose(resourceResponse -> stepContext.next(null));
}
});
}
Ardından, sınıfın finalStep
yönteminde MainDialog
rezervasyon iletişim kutusu sona erdi ve rezervasyon tamamlanmış veya iptal edilmiş olarak kabul edilir.
private CompletableFuture<DialogTurnResult> finalStep(WaterfallStepContext stepContext) {
CompletableFuture<Void> stepResult = CompletableFuture.completedFuture(null);
// If the child dialog ("BookingDialog") was cancelled,
// the user failed to confirm or if the intent wasn't BookFlight
// the Result here will be null.
if (stepContext.getResult() instanceof BookingDetails) {
// Now we have all the booking details call the booking service.
// If the call to the booking service was successful tell the user.
BookingDetails result = (BookingDetails) stepContext.getResult();
TimexProperty timeProperty = new TimexProperty(result.getTravelDate());
String travelDateMsg = timeProperty.toNaturalLanguage(LocalDateTime.now());
String messageText = String.format("I have you booked to %s from %s on %s",
result.getDestination(), result.getOrigin(), travelDateMsg
);
Activity message = MessageFactory
.text(messageText, messageText, InputHints.IGNORING_INPUT);
stepResult = stepContext.getContext().sendActivity(message).thenApply(sendResult -> null);
}
// Restart the main dialog with a different message the second time around
String promptMessage = "What else can I do for you?";
return stepResult
.thenCompose(result -> stepContext.replaceDialog(getInitialDialogId(), promptMessage));
}
'deki BookingDialog
kod, kesinti işlemeyle doğrudan ilgili olmadığından burada gösterilmez. Kullanıcılardan rezervasyon ayrıntılarını istemesi için kullanılır. Bu kodu BookingDialogs.java bulabilirsiniz.
iletişim kutuları/main_dialog.py
Yeni ileti etkinliği geldikçe bot çalıştırır MainDialog
. Kullanıcıdan MainDialog
yardımcı olabileceği şeyleri ister. Ardından yönteminde act_step
öğesini aşağıda gösterildiği gibi çağrısıyla begin_dialog
başlatırbookingDialog
.
async def act_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
if not self._luis_recognizer.is_configured:
# LUIS is not configured, we just run the BookingDialog path with an empty BookingDetailsInstance.
return await step_context.begin_dialog(
self._booking_dialog_id, BookingDetails()
)
# Call LUIS and gather any potential booking details. (Note the TurnContext has the response to the prompt.)
intent, luis_result = await LuisHelper.execute_luis_query(
self._luis_recognizer, step_context.context
)
if intent == Intent.BOOK_FLIGHT.value and luis_result:
# Show a warning for Origin and Destination if we can't resolve them.
await MainDialog._show_warning_for_unsupported_cities(
step_context.context, luis_result
)
# Run the BookingDialog giving it whatever details we have from the LUIS call.
return await step_context.begin_dialog(self._booking_dialog_id, luis_result)
if intent == Intent.GET_WEATHER.value:
get_weather_text = "TODO: get weather flow here"
get_weather_message = MessageFactory.text(
get_weather_text, get_weather_text, InputHints.ignoring_input
)
await step_context.context.send_activity(get_weather_message)
else:
didnt_understand_text = (
"Sorry, I didn't get that. Please try asking in a different way"
)
didnt_understand_message = MessageFactory.text(
didnt_understand_text, didnt_understand_text, InputHints.ignoring_input
)
await step_context.context.send_activity(didnt_understand_message)
return await step_context.next(None)
Ardından, sınıfın final_step
yönteminde MainDialog
rezervasyon iletişim kutusu sona erdi ve rezervasyon tamamlanmış veya iptal edilmiş olarak kabul edilir.
async def final_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
# If the child dialog ("BookingDialog") was cancelled or the user failed to confirm,
# the Result here will be null.
if step_context.result is not None:
result = step_context.result
# Now we have all the booking details call the booking service.
# If the call to the booking service was successful tell the user.
# time_property = Timex(result.travel_date)
# travel_date_msg = time_property.to_natural_language(datetime.now())
msg_txt = f"I have you booked to {result.destination} from {result.origin} on {result.travel_date}"
message = MessageFactory.text(msg_txt, msg_txt, InputHints.ignoring_input)
await step_context.context.send_activity(message)
prompt_message = "What else can I do for you?"
return await step_context.replace_dialog(self.id, prompt_message)
Bağdaştırıcının hata işleyicisi, botta yakalanmamış özel durumları işler.
AdapterWithErrorHandler.cs
Örnekte, bağdaştırıcının OnTurnError
işleyicisi botunuzun dönüş mantığı tarafından oluşan özel durumları alır. Bir özel durum oluşursa, işleyici botunun hatalı durumda olmasından kaynaklanan bir hata döngüsünde takılmasını önlemek için geçerli konuşmanın konuşma durumunu siler.
{
// Log any leaked exception from the application.
// NOTE: In production environment, you should consider logging this to
// Azure Application Insights. Visit https://aka.ms/bottelemetry to see how
// to add telemetry capture to your bot.
logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
// Send a message to the user
var errorMessageText = "The bot encountered an error or bug.";
var errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.IgnoringInput);
await turnContext.SendActivityAsync(errorMessage);
errorMessageText = "To continue to run this bot, please fix the bot source code.";
errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.ExpectingInput);
await turnContext.SendActivityAsync(errorMessage);
if (conversationState != null)
{
try
{
// Delete the conversationState for the current conversation to prevent the
// bot from getting stuck in a error-loop caused by being in a bad state.
// ConversationState should be thought of as similar to "cookie-state" in a Web pages.
await conversationState.DeleteAsync(turnContext);
}
catch (Exception e)
{
logger.LogError(e, $"Exception caught on attempting to Delete ConversationState : {e.Message}");
}
}
// Send a trace activity, which will be displayed in the Bot Framework Emulator
await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError");
};
}
index.js
Örnekte, bağdaştırıcının onTurnError
işleyicisi botunuzun dönüş mantığı tarafından oluşan özel durumları alır. Bir özel durum oluşursa, işleyici botunun hatalı durumda olmasından kaynaklanan bir hata döngüsünde takılmasını önlemek için geçerli konuşmanın konuşma durumunu siler.
// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity(
'OnTurnError Trace',
`${ error }`,
'https://www.botframework.com/schemas/error',
'TurnError'
);
// Send a message to the user
let onTurnErrorMessage = 'The bot encountered an error or bug.';
await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
onTurnErrorMessage = 'To continue to run this bot, please fix the bot source code.';
await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
// Clear out state
await conversationState.delete(context);
};
// Set the onTurnError for the singleton CloudAdapter.
adapter.onTurnError = onTurnErrorHandler;
// Define a state store for your bot. See https://aka.ms/about-bot-state to learn more about using MemoryStorage.
// A bot requires a state store to persist the dialog and user state between messages.
// For local development, in-memory storage is used.
Bu örnekteki için BotFrameworkHttpAdapter
Application.java spring çerçevesine bir AdapterWithErrorHandler
kaydederek, bağdaştırıcının onTurnError
işleyicisi botunuzun dönüş mantığı tarafından oluşan özel durumları alır. Bir özel durum oluşursa, işleyici botunun hatalı durumda olmasından kaynaklanan bir hata döngüsünde takılmasını önlemek için geçerli konuşmanın konuşma durumunu siler. Java SDK'sında, AdapterWithErrorHandler
SDK'nın bir parçası olarak uygulanır ve com.microsoft.bot.integration paketine dahil edilir. Bu bağdaştırıcının uygulanmasıyla ilgili ayrıntılar için bkz. Java SDK kaynak kodu.
adapter_with_error_handler.py
Örnekte, bağdaştırıcının on_error
işleyicisi botunuzun dönüş mantığı tarafından oluşan özel durumları alır. Bir özel durum oluşursa, işleyici botunun hatalı durumda olmasından kaynaklanan bir hata döngüsünde takılmasını önlemek için geçerli konuşmanın konuşma durumunu siler.
def __init__(
self,
settings: ConfigurationBotFrameworkAuthentication,
conversation_state: ConversationState,
):
super().__init__(settings)
self._conversation_state = conversation_state
# Catch-all for errors.
async def on_error(context: TurnContext, error: Exception):
# This check writes out errors to console log
# NOTE: In production environment, you should consider logging this to Azure
# application insights.
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
traceback.print_exc()
# Send a message to the user
await context.send_activity("The bot encountered an error or bug.")
await context.send_activity(
"To continue to run this bot, please fix the bot source code."
)
# Send a trace activity if we're talking to the Bot Framework Emulator
if context.activity.channel_id == "emulator":
# Create a trace activity that contains the error object
trace_activity = Activity(
label="TurnError",
name="on_turn_error Trace",
timestamp=datetime.utcnow(),
type=ActivityTypes.trace,
value=f"{error}",
value_type="https://www.botframework.com/schemas/error",
)
# Send a trace activity, which will be displayed in Bot Framework Emulator
await context.send_activity(trace_activity)
# Clear out state
nonlocal self
await self._conversation_state.delete(context)
self.on_turn_error = on_error
Startup.cs
Son olarak, içinde Startup.cs
bot geçici olarak oluşturulur ve her dönüşte botun yeni bir örneği oluşturulur.
// Register the BookingDialog.
Başvuru için, yukarıdaki botu oluşturmak için çağrıda kullanılan sınıf tanımları aşağıdadır.
public class DialogAndWelcomeBot<T> : DialogBot<T>
public class DialogBot<T> : ActivityHandler
where T : Dialog
public class MainDialog : ComponentDialog
index.js
Son olarak, içinde index.js
bot oluşturulur.
const dialog = new MainDialog(luisRecognizer, bookingDialog);
const bot = new DialogAndWelcomeBot(conversationState, userState, dialog);
// Create HTTP server
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator');
Başvuru için, yukarıdaki botu oluşturmak için çağrıda kullanılan sınıf tanımları aşağıdadır.
class MainDialog extends ComponentDialog {
class DialogAndWelcomeBot extends DialogBot {
class DialogBot extends ActivityHandler {
Application.java
Son olarak, içinde Application.java
bot oluşturulur.
@Bean
public Bot getBot(
Configuration configuration,
UserState userState,
ConversationState conversationState
) {
FlightBookingRecognizer recognizer = new FlightBookingRecognizer(configuration);
MainDialog dialog = new MainDialog(recognizer, new BookingDialog());
return new DialogAndWelcomeBot<>(conversationState, userState, dialog);
}
Başvuru için, yukarıdaki botu oluşturmak için çağrıda kullanılan sınıf tanımları aşağıdadır.
public class DialogAndWelcomeBot<T extends Dialog> extends DialogBot {
public class DialogBot<T extends Dialog> extends ActivityHandler {
public class MainDialog extends ComponentDialog {
app.py Son olarak, içinde app.py
bot oluşturulur.
# Create dialogs and Bot
RECOGNIZER = FlightBookingRecognizer(CONFIG)
BOOKING_DIALOG = BookingDialog()
DIALOG = MainDialog(RECOGNIZER, BOOKING_DIALOG)
BOT = DialogAndWelcomeBot(CONVERSATION_STATE, USER_STATE, DIALOG)
Başvuru için, botu oluşturmak için çağrıda kullanılan sınıf tanımları aşağıdadır.
class MainDialog(ComponentDialog):
class DialogAndWelcomeBot(DialogBot):
class DialogBot(ActivityHandler):