C# 多个LUIS对话框及其实体的问题

C# 多个LUIS对话框及其实体的问题,c#,botframework,azure-language-understanding,azure-bot-service,C#,Botframework,Azure Language Understanding,Azure Bot Service,我正在尝试创建一个具有多个Luis意图的机器人,它自然意味着多个对话。我已经安装了默认的CoreBot模板(从Azure下载)。设定意图和实体后; 创建了第二个名为“WeatherDialog”的对话框, 创建了“WeatherDetails”,其中包括我的LUIS weather实体的getter和setter, 实现了一些代码,用于访问已在BookingDialog项目中的分部类的实体结果 然后在主对话框中,我尝试添加对话框 主对话框: // Copyright (c) Microsoft

我正在尝试创建一个具有多个Luis意图的机器人,它自然意味着多个对话。我已经安装了默认的CoreBot模板(从Azure下载)。设定意图和实体后; 创建了第二个名为“WeatherDialog”的对话框, 创建了“WeatherDetails”,其中包括我的LUIS weather实体的getter和setter, 实现了一些代码,用于访问已在BookingDialog项目中的分部类的实体结果

然后在主对话框中,我尝试添加对话框

主对话框:

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
using CoreBot;

namespace Microsoft.BotBuilderSamples.Dialogs
{
    public class MainDialog : ComponentDialog
    {
        private readonly FlightBookingRecognizer _luisRecognizer;
        protected readonly ILogger Logger;

        // Dependency injection uses this constructor to instantiate MainDialog
        public MainDialog(FlightBookingRecognizer luisRecognizer, BookingDialog bookingDialog, CoreBot.Dialogs.WeatherDialog weatherDialog, ILogger<MainDialog> logger)
            : base(nameof(MainDialog))
        {
            _luisRecognizer = luisRecognizer;
            Logger = logger;

            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(bookingDialog);
            AddDialog(weatherDialog);
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                IntroStepAsync,
                ActStepAsync,
                FinalStepAsync,
            }));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }



        private async Task<DialogTurnResult> IntroStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            if (!_luisRecognizer.IsConfigured)
            {
                await stepContext.Context.SendActivityAsync(
                    MessageFactory.Text("NOTE: LUIS is not configured. To enable all capabilities, add 'LuisAppId', 'LuisAPIKey' and 'LuisAPIHostName' to the appsettings.json file.", inputHint: InputHints.IgnoringInput), cancellationToken);

                return await stepContext.NextAsync(null, cancellationToken);
            }

            // Use the text provided in FinalStepAsync or the default if it is the first time.
            var messageText = stepContext.Options?.ToString() ?? "How can I help you?";
            var promptMessage = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput);
            return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = promptMessage }, cancellationToken);
        }

        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<CoreBot.WeatherModel>(stepContext.Context, cancellationToken);
            switch (luisResult.TopIntent().intent)
            {
                case CoreBot.WeatherModel.Intent.BookFlight:
                    //await ShowWarningForUnsupportedCities(stepContext.Context, luisResult, cancellationToken);
                    Console.WriteLine("This is bookflight");
                    // 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 CoreBot.WeatherModel.Intent.GetWeather:
                    Console.WriteLine("This is getweather");
                    var weatherDetails = new CoreBot.WeatherDetails()
                    {
                        Location = luisResult.Location,
                        TravelDate = luisResult.TravelDate,
                    };
                    return await stepContext.BeginDialogAsync(nameof(CoreBot.Dialogs.WeatherDialog), weatherDetails, cancellationToken);

                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);
        }

        // Shows a warning if the requested From or To cities are recognized as entities but they are not in the Airport entity list.
        // In some cases LUIS will recognize the From and To composite entities as a valid cities but the From and To Airport values
        // will be empty if those entity values can't be mapped to a canonical item in the Airport.
        private static async Task ShowWarningForUnsupportedCities(ITurnContext context, FlightBooking luisResult, CancellationToken cancellationToken)
        {
            var unsupportedCities = new List<string>();

            var fromEntities = luisResult.FromEntities;
            if (!string.IsNullOrEmpty(fromEntities.From) && string.IsNullOrEmpty(fromEntities.Airport))
            {
                unsupportedCities.Add(fromEntities.From);
            }

            var toEntities = luisResult.ToEntities;
            if (!string.IsNullOrEmpty(toEntities.To) && string.IsNullOrEmpty(toEntities.Airport))
            {
                unsupportedCities.Add(toEntities.To);
            }

            if (unsupportedCities.Any())
            {
                var messageText = $"Sorry but the following airports are not supported: {string.Join(',', unsupportedCities)}";
                var message = MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput);
                await context.SendActivityAsync(message, cancellationToken);
            }
        }

        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);
            }
            else if (stepContext.Result is CoreBot.WeatherDetails sonuc)
            {
                var timeProperty = new TimexProperty(sonuc.TravelDate);
                var weatherDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
                var messageText = $"Thats your weather result for {weatherDateMsg} at {sonuc.Location}: 00 F";
                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);
        }
    }
}
//版权所有(c)微软公司。版权所有。
//根据麻省理工学院许可证授权。
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统线程;
使用System.Threading.Tasks;
使用Microsoft.Bot.Builder;
使用Microsoft.Bot.Builder.Dialogs;
使用Microsoft.Bot.Schema;
使用Microsoft.Extensions.Logging;
使用Microsoft.Recognizers.Text.DataTypes.TimexExpression;
使用CoreBot;
命名空间Microsoft.BotBuilderSamples.Dialogs
{
公共类MainDialog:ComponentDialog
{
私人只读FlightBookingRecognitor\u LuisRecogniter;
受保护的只读ILogger记录器;
//依赖项注入使用此构造函数实例化MainDialog
公共主对话框(FlightBookingRecognitor LuisRecogniter、BookingDialog BookingDialog、CoreBot.Dialogs.WeatherDialog WeatherDialog、ILogger记录器)
:base(名称(主对话框))
{
_路易斯认知者=路易斯认知者;
记录器=记录器;
AddDialog(新建文本提示(名称)(文本提示));
AddDialog(bookingDialog);
AddDialog(weatherDialog);
AddDialog(新建WaterWallDialog)(名称(WaterWallDialog),新建WaterWallStep[]
{
异步的,
ActStepAsync,
最后阶段同步,
}));
//要运行的初始子对话框。
InitialDialogId=nameof(WaterWallDialog);
}
专用异步任务IntroStepAsync(WaterWallStepContext stepContext,CancellationToken CancellationToken)
{
如果(!\u luisrecogner.IsConfigured)
{
等待stepContext.Context.SendActivityAsync(
MessageFactory.Text(“注意:未配置LUIS。若要启用所有功能,请将'luisapid'、'LuisAPIKey'和'LuisAPIHostName'添加到appsettings.json文件中。”,inputHint:InputHints.IgnoringInput),cancellationToken);
返回Wait-stepContext.NextAsync(null,cancellationToken);
}
//使用FinalStepSync中提供的文本,如果是第一次,则使用默认文本。
var messageText=stepContext.Options?.ToString()??“我能为您做些什么?”;
var promptMessage=MessageFactory.Text(messageText,messageText,InputHints.ExpectingInput);
返回wait wait stepContext.PromptAsync(nameof(TextPrompt),newpromptoptions{Prompt=promptMessage},cancellationToken);
}
专用异步任务ActStepAsync(WaterWallStepContext stepContext,CancellationToken CancellationToken)
{
如果(!\u luisrecogner.IsConfigured)
{
//没有配置LUIS,我们只是使用空的BookingDetails状态运行BookingDialog路径。
return wait stepContext.BeginDialogAsync(name of(BookingDialog),new BookingDetails(),cancellationToken);
}
//打电话给LUIS,收集任何可能的预订详细信息。(注意TurnContext对提示有响应。)
var luisResult=await _luisRecognizer.RecognizeAsync(stepContext.Context,cancellationToken);
开关(luisResult.TopIntent().intent)
{
案例CoreBot.WeatherModel.Intent.BookFlight:
//等待显示不支持活动的警告(stepContext.Context、luisResult、cancellationToken);
Console.WriteLine(“这是bookflight”);
//使用我们可能在响应中找到的任何实体初始化BookingDetails。
var bookingdestails=新bookingdestails()
{
//从复合实体数组中获取目标和原点。
目的地=luisResult.ToEntities.Airport,
原点=luisResult.FromEntities.Airport,
TravelDate=luisResult.TravelDate,
};
//运行BookingDialog,给出我们从LUIS通话中获得的任何详细信息,它将填充剩余部分。
return wait stepContext.BeginDialogAsync(名称(BookingDialog)、bookingDetails、cancellationToken);
案例CoreBot.WeatherModel.Intent.GetWeather:
Console.WriteLine(“这是getweather”);
var weatherDetails=new CoreBot.weatherDetails()
{
位置=luisResult.位置,
TravelDate=luisResult.TravelDate,
};
return wait-stepContext.BeginDialogAsync(nameof(CoreBot.Dialogs.WeatherDialog)、weatherDetails、cancellationToken);
违约:
//抓住所有未处理的意图
var didntUnderstandMessageText=$“对不起,我没听清楚。请尝试用另一种方式提问(intent是{luisResult.TopIntent().intent})”;
var didntUnderstandMessage=MessageFactory.Text(didntUnderstandMessageText,didntUnderstandMessageText,inputInts.IgnoringInput);
Wait stepContext.Context.SendActivityAsync(didntUnderstandMessage,cancellationToken);
打破
}
返回Wait-stepContext.NextAsync(null,cancellationToken);
}
//如果请求的从城市或到城市被识别为实体,但它们是实体,则显示警告
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Dialogs;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;

namespace CoreBot.Dialogs
{
    public class WeatherDialog : CancelAndHelpDialog
    {
        private const string DestinationStepMsgText = "Type the location.";


        public WeatherDialog()
            : base(nameof(WeatherDialog))
        {
            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
            AddDialog(new DateResolverDialog());
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                LocationStepAsync,
                TravelDateStepAsync,
                ConfirmStepAsync,
                FinalStepAsync,
            }));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }

        private async Task<DialogTurnResult> LocationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var weatherDetails = (WeatherDetails)stepContext.Options;

            if (weatherDetails.Location == null)
            {
                var promptMessage = MessageFactory.Text(DestinationStepMsgText, DestinationStepMsgText, InputHints.ExpectingInput);
                return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = promptMessage }, cancellationToken);
            }

            return await stepContext.NextAsync(weatherDetails.Location, cancellationToken);
        }


        private async Task<DialogTurnResult> TravelDateStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var weatherDetails = (WeatherDetails)stepContext.Options;

            weatherDetails.Location = (string)stepContext.Result;

            if (weatherDetails.TravelDate == null || IsAmbiguous(weatherDetails.TravelDate))
            {
                return await stepContext.BeginDialogAsync(nameof(DateResolverDialog), weatherDetails.TravelDate, cancellationToken);
            }

            return await stepContext.NextAsync(weatherDetails.TravelDate, cancellationToken);
        }

        private async Task<DialogTurnResult> ConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var weatherDetails = (WeatherDetails)stepContext.Options;

            weatherDetails.TravelDate = (string)stepContext.Result;

            var messageText = $"You want to know weather status at {weatherDetails.Location} for {weatherDetails.TravelDate}. Is this correct?";
            var promptMessage = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput);

            return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = promptMessage }, cancellationToken);
        }

        private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            if ((bool)stepContext.Result)
            {
                var weatherDetails = (WeatherDetails)stepContext.Options;

                return await stepContext.EndDialogAsync(weatherDetails, cancellationToken);
            }

            return await stepContext.EndDialogAsync(null, cancellationToken);
        }

        private static bool IsAmbiguous(string timex)
        {
            var timexProperty = new TimexProperty(timex);
            return !timexProperty.Types.Contains(Constants.TimexTypes.Definite);
        }
    }
}