1

我使用 BotFramework、Adaptive Cards、LUIS 和 FormFlow 在 C# 中制作了一个机器人。它/他负责管理团队中的会议。

return new FormBuilder<MeetingRequestInput>()

    ...

    .Field(
        nameof(MeetingRequestInput.RequestedDate),
        "What date would you like to meet?"
    )

    ...

    .Build();

在测试期间,我们注意到用户应该输入所需的会议日期/时间时出现问题(人们会输入dd/mm/yy, mm/dd/yy, dd-mm-yy, onlydd等),因此我们希望使用某种带有格式化输入的“表单”来避免解析问题和保留可用性。

我认为我们无法更改所需的键盘类型(有点像在移动设备中,有时键盘只显示数字或显示日期时间选择器),也不能应用模式自动完成,至少使用 BotFramework。

为了解决这个问题,我想在我的 FormFlow 提示中使用带有日期和时间选择器的 AdaptiveCard,至少在要求用户键入请求的日期时,如下所示:

使用自适应卡片的输入示例

在此示例中,用户将填写 AdaptiveDateInput 和 AdaptiveTimeInput,然后按下确认按钮。这样做,它将获取输入中的值,然后在特定模板中为用户“键入并发送”所需的 DateTime,避免之前的解析问题。

问题是,我不能用整个自适应卡替换“正常”的 FormFlow 卡(他们期望一个简单的字符串作为提示参数)。我该如何解决这个问题?AdaptiveCards 是最佳答案还是有替代方案?

现在我正在手动显示卡片,如下所示:

AdaptiveCard card = new AdaptiveCard();
    card.Body = new List<AdaptiveElement>()
    {
        new AdaptiveTextBlock()
        {
            Text = "What date would you like to meet?"
        },
        new AdaptiveDateInput()
        {
            Value = DateTime.Now.ToShortDateString(),
            Id = "dateInp"
        },
        new AdaptiveTimeInput()
        {
            Value = DateTime.Now.ToShortTimeString(),
            Id = "timeInp"
        }
    };
    card.Actions = new List<AdaptiveAction>()
    {
        new AdaptiveSubmitAction()
        {
            Type = "Action.Submit",
            Title = "Confirm"
        }
    };
    var msg = context.MakeMessage();
    msg.Attachments.Add(
        new Attachment()
        {
            Content = card,
            ContentType = "application/vnd.microsoft.card.adaptive",
            Name = "Requested Date Adaptive Card"
        }
    );
    await context.PostAsync(msg);

我读过这个问题,但我不知道我们是否有完全相同的问题。他们的解决方案不适用于我:即使我用英语制作了上面的示例,机器人实际上也会期望其他语言的输入,所以是的,我们可以使用识别器解析“2 月 2 日”,但我们没有相同的“2 de Fevereiro”或“2 Fevralya”的运气。

4

1 回答 1

0

使用FormBuilder.Prompter,您可以以任何您喜欢的方式自定义FormFlow消息。但是,由于AdaptiveCard在 .Value 中发送响应,因此代码需要在验证之前将 .Value 传输到 .Text 属性。

以下是为 RequestedDate 字段发送 AdaptiveCard 的 FormFlow 表单示例:

[Serializable]
public class AdaptiveCardsFormFlow
{
    public string Name { get; set; }
    public DateTime? RequestedDate { get; set; }

    public static IForm<AdaptiveCardsFormFlow> BuildForm()
    {
        IFormBuilder<AdaptiveCardsFormFlow> formBuilder = GetFormbuilder();

        var built = formBuilder
            .Field(nameof(Name), "What is your name?")
            .Field(nameof(RequestedDate))
            .Confirm("Is this information correct? {*}")
            .Build();

        return built;
    }

    private static AdaptiveCard GetDateCard()
    {
        AdaptiveCard card = new AdaptiveCard();
        card.Body = new List<AdaptiveElement>()
        {
            new AdaptiveTextBlock()
            {
                Text = "What date would you like to meet?"
            },
            new AdaptiveDateInput()
            {
                Value = DateTime.Now.ToShortDateString(),
                Id = "dateInp"
            },
            new AdaptiveTimeInput()
            {
                Value = DateTime.Now.ToShortTimeString(),
                Id = "timeInp"
            }
        };
        card.Actions = new List<AdaptiveAction>()
        {
            new AdaptiveSubmitAction()
            {
                Type = "Action.Submit",
                Title = "Confirm"
            }
        };
        return card;
    }

    private static IFormBuilder<AdaptiveCardsFormFlow> GetFormbuilder()
    {

        IFormBuilder<AdaptiveCardsFormFlow> formBuilder = new FormBuilder<AdaptiveCardsFormFlow>()
            .Prompter(async (context, prompt, state, field) =>
            {
                var preamble = context.MakeMessage();
                var promptMessage = context.MakeMessage();
                if (prompt.GenerateMessages(preamble, promptMessage))
                {
                    await context.PostAsync(preamble);
                }

                if (field != null && field.Name == nameof(AdaptiveCardsFormFlow.RequestedDate))
                {
                    var attachment = new Attachment()
                    {
                        Content = GetDateCard(),
                        ContentType = AdaptiveCard.ContentType,
                        Name = "Requested Date Adaptive Card"
                    };

                    promptMessage.Attachments.Add(attachment);
                }

                await context.PostAsync(promptMessage);

                return prompt;
            }).Message("Please enter your information to schedule a callback.");

        return formBuilder;
    }
}

使用这个类:

 private class DateTimeInp
    {
        public string dateInp { get; set; }
        public string timeInp { get; set; }

        public DateTime? ToDateTime()
        {
            string fullDateTime = dateInp + " " + timeInp;
            DateTime toDateTime;
            if(DateTime.TryParse(fullDateTime, out toDateTime))
            {
                return toDateTime;
            }
            return null;
        }
    }

然后,在 Messages Controller 中,将 Adaptive Card 的返回值添加到 Activity 的 .Text 属性中:

if(activity.Value != null)
{
    DateTimeInp input = JsonConvert.DeserializeObject<DateTimeInp>(activity.Value.ToString());
    var toDateTime = input.ToDateTime();
    if(toDateTime != null)
    {
        activity.Text = toDateTime.ToString();
    }
}
于 2018-09-25T21:26:11.977 回答