Как вы обнаруживаете активный диалог в On MessageActivityAsync - PullRequest
1 голос
/ 23 декабря 2019

Я создал DispatchBot с использованием Luis и QnA, и я хочу дополнительно использовать несколько диалогов (по одному для каждого намерения.

Все работает, кроме случаев, когда диалоговое окно должно запрашивать вопрос. Если вы получаетевсе сущности в первом высказывании, на которые вы можете ответить, и все в порядке, однако, если вам нужно запросить дополнительную информацию, когда происходит сбой. Когда пользователь отвечает, он возвращается к OnMessageActivityAsync и затем забывает о диалоге.

Я понимаю, что мне нужно запустить RunAsync (..), чтобы снова открыть диалоговое окно, однако я не могу получить правильный контекст. Все, что я пробовал, либо открывает диалоговое окно с нулевыми Accessors / DialogState, либо не может открыть диалоговое окно.

Я очень новичок в Azure Bot Framework, и я потратил дни на поиски в Google, но каждый пример не делает всего, что мне нужно.

Мой бот выглядит следующим образом:

   public class DispatchBot : ActivityHandler
    {
        private readonly ILogger<DispatchBot> _logger;
        private readonly IBotServices _botServices;
        private readonly DialogSet _dialogSet;
        private readonly MilaAccessors _milaAccessors;
        private readonly BotState _userState;

        public DispatchBot(IBotServices botServices, ILogger<DispatchBot> logger, MilaAccessors accessors)
        {
            _logger = logger;
            _botServices = botServices;
            _dialogSet = new DialogSet(accessors.ConversationDialogState);
            _milaAccessors = accessors;
            _userState = accessors.UserState;

        }

        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            await base.OnMessageActivityAsync(turnContext, cancellationToken);
            await _milaAccessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

            List<Dialog> dialogs = _dialogSet.GetDialogs().ToList();


            if (dialogs.Any()) //This is always false
            {
                //If count is greater than zero, then you can continue dialog conversation.  
                await dialogs.First().RunAsync(turnContext, _milaAccessors.ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
            }
            else
            {
                // First, we use the dispatch model to determine which cognitive service (LUIS or QnA) to use.
                var recognizerResult = await _botServices.Dispatch.RecognizeAsync(turnContext, cancellationToken);

                // Top intent tell us which cognitive service to use.
                var topIntent = recognizerResult.GetTopScoringIntent();

                // Next, we call the dispatcher with the top intent.
                if (topIntent.score > 0.5)
                {
                    await DispatchToTopIntentAsync(turnContext, topIntent.intent, recognizerResult, cancellationToken);
                }
                else
                {
                    await ProcessQnAAsync(turnContext, cancellationToken);
                }
            }



        }

        private async Task DispatchToTopIntentAsync(ITurnContext<IMessageActivity> turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken)
        {
            switch (intent)
            {
                case "Form15":
                    await Form15IntentAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
                    break;
                case "Layouts":
                    await ProcessLayoutsAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
                    break;
                case "Weather":
                    await ProcessWeatherAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
                    break;
                default:
                    await ProcessQnAAsync(turnContext, cancellationToken);
                    break;
            }
        }
}

И диалоги имеют вид:

public class Form15Dialog : ComponentDialog
{
    private const string UserInfo = "form15-userInfo";
    private readonly MilaAccessors _milaAccessors;
    private readonly string DlgAddressId = "AddressDlg";
    private readonly string Form15Id = "Form15DialogName";
    private readonly BotState _userState;
    private readonly BotState _conversationState;


    public Form15Dialog(MilaAccessors milaAccessors) : base(nameof(Form15Dialog))
    {
        _milaAccessors = milaAccessors;
        _userState = milaAccessors.UserState;
        _conversationState = milaAccessors.ConversationState;


        AddDialog(new TextPrompt(DlgAddressId, AddressValidation));
        AddDialog(new WaterfallDialog(nameof(Form15Id), new WaterfallStep[]
        {
            InitialiseStepAsync,
            GetAddressStepAsync,
            DisplayForm15StepAsync
        }));

        InitialDialogId = nameof(Form15Id);

    }

    private async Task<DialogTurnResult> InitialiseStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        stepContext.Values["MilaAccessors"] = _milaAccessors;
        UserProfile userProfile = _milaAccessors.UserProfile.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken).Result;

        Form15DialogValues userInfo = new Form15DialogValues {Name = userProfile.Name, MilaSessionId = userProfile.SessionId};

        IList<EntityModel> options = (IList<EntityModel>)stepContext.Options;
        foreach (EntityModel model in options)
        {
            switch (model.Type)
            {
                case "JobNumber":
                    userInfo.JobNumber = model.Entity;
                    break;
                case "Sections":
                    userInfo.Sections = model.Entity;
                    break;
                case "StreetAddress":
                    userInfo.StreetAddress = model.Entity;
                    break;
                case "Suburb":
                    userInfo.Suburb = model.Entity;
                    break;
                case "PostCode":
                    userInfo.PostCode = model.Entity;
                    break;
            }

        }

        // Create an object in which to collect the user's information within the dialog.
        stepContext.Values[UserInfo] = userInfo;

        if (UpdateUserInfoFromWebService(userInfo))
        {
            stepContext.Values[UserInfo] = userInfo;
            return await stepContext.NextAsync(new List<string>(), cancellationToken);
        }


        await _userState.SaveChangesAsync(stepContext.Context, false, cancellationToken);
        await _conversationState.SaveChangesAsync(stepContext.Context, false, cancellationToken);


        PromptOptions promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Could you give me the full Job Address?") };
        return await stepContext.PromptAsync(DlgAddressId, promptOptions, cancellationToken);
    }


    private async Task<DialogTurnResult> GetAddressStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {

        Form15DialogValues userInfo = (Form15DialogValues)stepContext.Values[UserInfo];

        if (!(stepContext.Result is string[] results) || results.Length == 0)
        {
            return await stepContext.NextAsync(new List<string>(), cancellationToken);
        }

        userInfo.JobNumber = null;
        userInfo.StreetAddress = results[0];
        userInfo.Suburb = null;

        if (UpdateUserInfoFromWebService(userInfo))
        {
            stepContext.Values[UserInfo] = userInfo;
            return await stepContext.NextAsync(new List<string>(), cancellationToken);
        }


        await _userState.SaveChangesAsync(stepContext.Context, false, cancellationToken);
        await _conversationState.SaveChangesAsync(stepContext.Context, false, cancellationToken);

        var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("I'm unable to find that address.  Could you please enter the job number?") };
        return await stepContext.PromptAsync(nameof(TextPrompt), promptOptions, cancellationToken);

    }

Я следил за информацией в https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-dialog-manage-conversation-flow?view=azure-bot-service-4.0&tabs=csharp однако я не могу получить "Dialog.RunAsync ".

Любая помощь / ссылки / указатели, которые вы могли бы дать мне, была бы очень признательна.

1 Ответ

0 голосов
/ 23 декабря 2019

Если вы никогда не позвоните stepContext.EndDialogAsync WaterfallStep всегда заканчивается концом Водопада. В вашем коде это DisplayForm15StepAsync, и ваш диалог будет завершен и вернется к OnMessageActivityAsync

Так что нет необходимости повторно открывать активное диалоговое окно, вы должны повторно запросить на WaterfallStep, когда он не работает и не 'не позволяйте этому закончиться, пока вы не получите правильный контекст

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...