【问题标题】:I am using Bot framework V4.3, I want to retrieve adaptive card submit values我正在使用 Bot framework V4.3,我想检索自适应卡提交值
【发布时间】:2019-10-04 10:37:27
【问题描述】:

我正在使用 Bot framework V4.3,我一直在瀑布对话框中使用自适应卡,以获取用户信息,一旦用户单击提交按钮,我想获取值,并且我想返回上一步如果用户点击返回按钮。

这是我的自适应卡片的样子

我已经尝试了@mdrichardson 在Stack Overflow 中给出的解决方案 但是自适应卡又重新提示了。

下面的代码帮助我们回到上一步,但是如何实现它到自适应卡片的后退按钮。

stepContext.ActiveDialog.State["stepIndex"] =(int)stepContext.ActiveDialog.State["stepIndex"] - 2;

在对话框中添加自适应卡片。 我什至用过 TextPrompt 而不是 ChoicePrompt

AddDialog(new ChoicePrompt("AdaptiveCardPrompt") { Style = ListStyle.None });

这就是我显示自适应卡片的方式。我的自适应卡是 Json 格式

cardAttachment = CreateAdaptiveCardAttachment();

return await stepContext.PromptAsync("AdaptiveCardPrompt",
    new PromptOptions
    {
        Prompt = (Activity)MessageFactory.Attachment(new Attachment
        {
            ContentType = AdaptiveCard.ContentType,
            Content = cardAttachment.Content
        }),
    }, cancellationToken);

请帮助我解决这个问题。提前谢谢你

从 Botframework 支持编辑:请不要使用下面的代码块。它仅适用于模拟器。相反,使用:

if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
{
    activity.Text = JsonConvert.SerializeObject(activity.Value);
}

编辑 1:@mdrichardson 这是我设置对话框调用的方式

        public static async Task Run(this Dialog dialog, ITurnContext turnContext,IStatePropertyAccessor<DialogState> accessor, CancellationToken cancellationToken = default(CancellationToken))
        {
            var dialogSet = new DialogSet(accessor);
            dialogSet.Add(dialog);

            var dialogContext = await dialogSet.CreateContextAsync(turnContext, cancellationToken);
            // Ensure that message is a postBack (like a submission from Adaptive Cards)
            if (dialogContext.Context.Activity.GetType().GetProperty("ChannelData") != null)
            {
                var channelData = JObject.Parse(dialogContext.Context.Activity.ChannelData.ToString());
                if (channelData.ContainsKey("postBack"))
                {
                    var postbackActivity = dialogContext.Context.Activity;
                    // Convert the user's Adaptive Card input into the input of a Text Prompt
                    // Must be sent as a string
                    postbackActivity.Text = postbackActivity.Value.ToString();
                    await dialogContext.Context.SendActivityAsync(postbackActivity);
                }
            }
            var results = await dialogContext.ContinueDialogAsync(cancellationToken);
            if (results.Status == DialogTurnStatus.Empty)
            {
                await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken);
            }
        }

在OnTurnAsync方法中

 if (turnContext.Activity.Type == ActivityTypes.Message)
 {
      await Dialog.Run(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
 }

编辑 2 :我修改了代码,我能够进入下一个瀑布步骤。但我在这里面临另一个问题。 没有显示下一个提示,但我可以在日志中看到它 这是它在模拟器中的显示方式

Emulator View

一旦用户点击按钮,控件就会进入MoreInfoAsync方法

 private async Task<DialogTurnResult> MoreInfoAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
 {
            var goback = JObject.Parse(stepContext.Result.ToString());
            stepContext.Values["AdaptiveCardDetails"] = stepContext.Result.ToString();

            if (goback.ContainsKey("goBack"))
            {
                return await stepContext.ReplaceDialogAsync(InitialDialogId);
            }
            // stepContext.ActiveDialog.State["stepIndex"] = (int)stepContext.ActiveDialog.State["stepIndex"] - 2;

            else
                return await stepContext.PromptAsync("MoreInfo", new PromptOptions { Prompt = MessageFactory.Text("Tell Me more.") }, cancellationToken);
 }

我想进入初始对话框,所以我使用ReplaceDialogAsync。

MoreInfo 对话框不显示在模拟器中,但显示在日志中

编辑3:这里是瀑布步骤的完整代码

          // This array defines how the Waterfall will execute.
                        var waterfallSteps = new WaterfallStep[]
                        {
                            ChoiceAsync,
                            CardAsync,
                            MoreInfoAsync,
                            ConfirmAsync
                        };
                        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
                        AddDialog(new ChoicePrompt("ChoiceType"));
                        AddDialog(new TextPrompt("AdaptiveCardPrompt"));
                        AddDialog(new TextPrompt("MoreInfo"));
                        InitialDialogId = nameof(WaterfallDialog);

            private async Task<DialogTurnResult> ChoiceAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                options = new PromptOptions()
                {
                    Prompt = MessageFactory.Text("Select the Choice"),
                    RetryPrompt = MessageFactory.Text("That was not a valid choice."),
                    Choices = GetChoices(),
                    Style = ListStyle.HeroCard
                };
                return await stepContext.PromptAsync("ChoiceType", options, cancellationToken);
            }


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

                var cardAttachment = new Attachment();
                stepContext.Values["leaveType"] = stepContext.Result.ToString();
                cardAttachment = CreateAdaptiveCardAttachment();
                return await stepContext.PromptAsync("AdaptiveCardPrompt",
                new PromptOptions
                {
                     Prompt = (Activity)MessageFactory.Attachment(new Attachment
                     {
                         ContentType = AdaptiveCard.ContentType,
                         Content = cardAttachment.Content,
                     }),
                }, cancellationToken);
            }

            private async Task<DialogTurnResult> MoreInfoAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                var goback = JObject.Parse(stepContext.Result.ToString());
                stepContext.Values["AdaptiveCardDetails"] = stepContext.Result.ToString();

                if (goback.ContainsKey("goBack"))
                {
                    return await stepContext.ReplaceDialogAsync(InitialDialogId);
                }
                else return await stepContext.PromptAsync("MoreInfo", new PromptOptions { Prompt = MessageFactory.Text("Tell Me more.") }, cancellationToken);
            }

            private async Task<DialogTurnResult> ConfirmAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                stepContext.Values["MoreInfo"] = stepContext.Result;
                //As of now I wouldn't perform any task here so I'll end
                return await stepContext.EndDialogAsync();
            }

【问题讨论】:

  • 如果卡片再次显示,这可能与您设置对话框的方式有关,而不是卡片的发送方式。您可以包含对话框的代码吗?要返回,在“捕获结果”步骤中,您只需要查看 stepContext.Result 是否具有您的 go back 值(无论您设置卡片在点击返回时发送的任何值)
  • 使用ReplaceDialogAsync 是个好主意,而且您使用正确。很难说为什么它没有被展示。您可以粘贴MoreInfo 对话框的所有代码或指向您的存储库的链接吗?您能否再描述一下您的新问题?只是对话框没有重新启动吗?
  • 我已经粘贴了MoreInfo对话框的完整代码,如果您在提交提交按钮后看到模拟器快照,则控件转到MoreInfo,但在Moreinfo中,我试图返回的提示没有得到显示在模拟器输出屏幕中。但是我可以在模拟器日志中看到“告诉我更多信息”。为什么在输出时向用户显示的不一样。我哪里做错了
  • 很难说。 MoreInfoAsync 看起来不错,所以问题可能出在其他地方。你有类似AddDialog(new TextPrompt("MoreInfo")); 的东西吗?如果您可以链接到所有代码,这将使调试变得更加容易。
  • 我无法复制这个。问题可能出在Run() 中的await dialogContext.Context.SendActivityAsync(postbackActivity);。尝试删除它,因为您实际上并不需要发送它。我已经上传了我的代码to a github repo,所以你可以看看并尝试找出不同之处。同样,使用您的所有代码进行调试会更加容易。

标签: botframework


【解决方案1】:

处理重新提示

问题在于您的 OnTurnAsync() 方法:

 if (turnContext.Activity.Type == ActivityTypes.Message)
 {
      await Dialog.Run(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
 }

每次用户发送消息时,都会运行一个新的对话框实例。由于 Adaptive Card Input 作为 PostBack 消息(仍然是一条消息)发送,它会导致 Dialog 再次运行,重新提示用户。

如果您要从OnTurnAsync() 或OnMessageAsync() 运行对话框,您应该做几件不同的事情:

  1. 使用 if/switch 语句。例如,如果消息包含“帮助”,则运行 HelpDialog,或者

  2. 启动一个对话框,保存用户响应并根据需要跳过步骤。你可以在Core Bot's Booking Dialog 中看到一个例子。请注意它如何在每个步骤中使用bookingDetails.TravelDate = (string)stepContext.Result; 之类的内容保存用户响应,并在使用if (bookingDetails.TravelDate == null) 之类的内容进行提示之前检查它是否存在于上一步中。对于您的,您可能会存储 userProfile.AdaptiveCardDetails 之类的内容。

返回按钮

要让后退按钮正常工作,假设它在您的自适应卡片中看起来像这样:

{
    "type": "Action.Submit",
    "title": "Back",
    "data": {
        "goBack": "true",
    }
},

当用户点击“返回”时,机器人将收到一个活动:

由于用户想要返回并且您不需要数据,您可以执行以下操作:

var activity = turnContext.Activity;

if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value.GetType().GetProperty("goBack"))
{
    dc.Context.Activity.Text = "Back";
}

然后在您的对话步骤中:

if (stepContext.Result == "Back")
{
    stepContext.ActiveDialog.State["stepIndex"] = (int)stepContext.ActiveDialog.State["stepIndex"] - 2;
}

【讨论】:

    猜你喜欢
    • 2020-05-29
    • 2020-11-07
    • 2022-01-08
    • 2020-11-06
    • 2018-03-21
    • 2018-11-15
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多