C# MS Bot框架中基于响应的分支对话框/表单

C# MS Bot框架中基于响应的分支对话框/表单,c#,botframework,C#,Botframework,我们正在试验MS Bot框架,但尚未完全解决如何实现此场景: 我们有一个LUIS对话框(类型),它工作正常,并且经过了适当的培训。使用常见的三明治示例,LUIS intent所寻找的基本内容是用户询问订单状态。如果问题中提供了订单号(“1234订单的状态是什么?”),则LUIS对话框将进行查找并直接报告状态(所有状态当前都在工作) 但是,如果用户只是触发意图而没有提供订单号(“我想查找订单状态”),我想启动另一个对话框/表单,询问用户是否想按地址或订单号查找订单,然后根据他们的回答进行相应的DB

我们正在试验MS Bot框架,但尚未完全解决如何实现此场景:

我们有一个LUIS对话框(类型
),它工作正常,并且经过了适当的培训。使用常见的三明治示例,LUIS intent所寻找的基本内容是用户询问订单状态。如果问题中提供了订单号(“1234订单的状态是什么?”),则LUIS对话框将进行查找并直接报告状态(所有状态当前都在工作)

但是,如果用户只是触发意图而没有提供订单号(“我想查找订单状态”),我想启动另一个对话框/表单,询问用户是否想按地址或订单号查找订单,然后根据他们的回答进行相应的DB查找

我只是不知道如何配置表单/对话框(或者在这种情况下哪一个是最好的),根据他们是否选择地址或号码查找来执行不同的查找

以下是迄今为止的意图:

private readonly BuildFormDelegate<OrderStatusDialog> OrderStatusDelegate;

[LuisIntent(nameof(LuisIntents.OrderStatus))]
public async Task OrderStatus(IDialogContext context, LuisResult result)
{
    // Order number(s) were provided
    if (result.Entities.Any(Entity => Entity.Type == nameof(LuisEntityTypes.OrderNumber)))
    {
        // Loop in case they asked about multiple orders
        foreach (var entity in result.Entities.Where(Entity => Entity.Type == nameof(LuisEntityTypes.OrderNumber)))
        {
            var orderNum = entity.Entity;

            // Call webservice to check status
            var request = new RestRequest(Properties.Settings.Default.GetOrderByNum, Method.GET);
            request.AddUrlSegment("num", orderNum);
            var response = await RestHelper.SendRestRequestAsync(request);

            var parsedResponse = JObject.Parse(response);

            if ((bool)parsedResponse["errored"])
            {
                await context.PostAsync((string)parsedResponse["errMsg"]);
                continue;
            }

            // Grab status from returned JSON
            var status = parsedResponse["orderStatus"].ToString();

            await context.PostAsync($"The status of order {orderNum} is {status}");
        }

        context.Wait(MessageReceived);
    }
    // Order number was not provided
    else
    {
        var orderStatusForm = new FormDialog<OrderStatusDialog>(new OrderStatusDialog(), OrderStatusDelegate,
            FormOptions.PromptInStart);
        context.Call<OrderStatusDialog>(orderStatusForm, CallBack);
    }
}

private async Task CallBack(IDialogContext context, IAwaitable<object> result)
{
    context.Wait(MessageReceived);
}
私有只读BuildFormDelegate OrderStatusDelegate;
[LuisIntent(名称(LuisIntents.OrderStatus))]
公共异步任务医嘱状态(IDialogContext上下文,LuisResult结果)
{
//已提供订单号
if(result.Entities.Any(Entity=>Entity.Type==nameof(LuisEntityTypes.OrderNumber)))
{
//循环,以防他们询问多个订单
foreach(result.Entities.Where(entity=>entity.Type==nameof(LuisEntityTypes.OrderNumber))中的var实体)
{
var orderNum=entity.entity;
//调用webservice以检查状态
var request=new RestRequest(Properties.Settings.Default.GetOrderByNum,Method.GET);
AddUrlSegment(“num”,orderNum);
var response=await RestHelper.SendRestRequestAsync(请求);
var parsedResponse=JObject.Parse(响应);
if((bool)parsedResponse[“errored”])
{
wait context.PostAsync((string)parsedResponse[“errMsg”]);
继续;
}
//从返回的JSON获取状态
var status=parsedResponse[“orderStatus”].ToString();
wait context.PostAsync($“订单{orderNum}的状态为{status}”);
}
Wait(MessageReceived);
}
//未提供订单号
其他的
{
var orderStatusForm=new FormDialog(new OrderStatusDialog(),OrderStatusDelegate,
FormOptions.prompinstart);
调用(orderStatusForm,CallBack);
}
}
专用异步任务回调(IDialogContext上下文,IAwaitable结果)
{
Wait(MessageReceived);
}
及表格:

public enum OrderStatusLookupOptions
{
    Address,
    OrderNumber
}

[Serializable]
public class OrderStatusDialog
{
    public OrderStatusLookupOptions? LookupOption;

    public static IForm<OrderStatusDialog> BuildForm()
    {
        return new FormBuilder<OrderStatusDialog>()
            .Message("In order to look up the status of a order, we will first need either the order number or your delivery address.")
            .Build();
    }
}
公共枚举顺序状态查找选项
{
地址:,
订单号
}
[可序列化]
公共类OrderStatus对话框
{
公共订单状态查找选项?查找选项;
公共静态表单BuildForm()
{
返回新的FormBuilder()
.Message(“为了查找订单状态,我们首先需要订单号或您的送货地址。”)
.Build();
}
}

FormFlow路由是一个有效选项。表单流中缺少的是在选择查找选项后询问地址/订单号

在这种情况下,您可以向
OrderStatusDialog
类添加另外两个字段:
OrderNumber
DeliveryAddress

然后,您需要使用所选的
OrderStatusLookupOptions
来激活/停用下一个字段

我脑海中的代码是这样的:

[Serializable]
public class OrderStatusDialog
{
    public OrderStatusLookupOptions? LookupOption;

    public int OrderNumber;

    public string DeliveryAddress

    public static IForm<OrderStatusDialog> BuildForm()
    {
        return new FormBuilder<OrderStatusDialog>()
            .Message("In order to look up the status of a order, we will first need either the order number or your delivery address.")
            .Field(nameof(OrderStatusDialog.LookupOption))
            .Field(new FieldReflector<OrderStatusDialog>(nameof(OrderStatusDialog.OrderNumber))
                .SetActive(state => state.LookupOption == OrderStatusLookupOptions.OrderNumber))
            .Field(new FieldReflector<OrderStatusDialog>(nameof(OrderStatusDialog.DeliveryAddress))
                .SetActive(state => state.LookupOption == OrderStatusLookupOptions.Address))
            .Build();
    }
}
[可序列化]
公共类OrderStatus对话框
{
公共订单状态查找选项?查找选项;
公共int订单号;
公共字符串传递地址
公共静态表单BuildForm()
{
返回新的FormBuilder()
.Message(“为了查找订单状态,我们首先需要订单号或您的送货地址。”)
.Field(名称(OrderStatusDialog.LookupOption))
.Field(新的FieldReflector(名称(OrderStatusDialog.OrderNumber))
.SetActive(state=>state.LookupOption==OrderStatusLookupOptions.OrderNumber))
.Field(新的FieldReflector(名称(OrderStatusDialog.DeliveryAddress))
.SetActive(state=>state.LookupOption==OrderStatusLookupOptions.Address))
.Build();
}
}
然后在回调方法上,您将收到填写的表单,您可以执行DB查找

或者,您可以使用PromptDialogs,引导用户体验相同的体验。查看示例以了解不同的备选方案


我在上面添加了一个工作示例。

谢谢!我敢肯定这只是一个使用内存的问题,但是上面的代码总是要求两者都有(而且,由于某些原因,.Message()没有显示)。嗯,我刚刚尝试了这个,它工作得很好。字段查找选项后缺少一个参数,该参数阻止代码编译。。。但在修复之后(我编辑了这篇文章),一切似乎都正常,包括消息。BotBuilder r u使用的是什么版本?我添加了一个关于谁填写OrderStatusDelegate以及使用什么值的工作示例?为什么不直接使用BuildForm方法?(参见我的代码)实际上,我认为这可能是问题所在。只需删除委托并使用BuildForm方法。。