C# Botframework v4:如何简化这个瀑布式对话框?
我有这个代码,但我认为它过于复杂,可以简化。 如果用户键入“back”而不重新启动整个对话框,是否有方法返回到spefici瀑布步骤?我是新手,很难找到关于BotFrameworkV4的指南或在线课程,因为它是新的。任何帮助都将不胜感激,谢谢C# Botframework v4:如何简化这个瀑布式对话框?,c#,botframework,C#,Botframework,我有这个代码,但我认为它过于复杂,可以简化。 如果用户键入“back”而不重新启动整个对话框,是否有方法返回到spefici瀑布步骤?我是新手,很难找到关于BotFrameworkV4的指南或在线课程,因为它是新的。任何帮助都将不胜感激,谢谢 public GetNameAndAgeDialog(string dialogId, IEnumerable<WaterfallStep> steps = null) : base(dialogId, steps) {
public GetNameAndAgeDialog(string dialogId, IEnumerable<WaterfallStep> steps = null) : base(dialogId, steps)
{
var name = "";
var age = "";
AddStep(async (stepContext, cancellationToken) =>
{
return await stepContext.PromptAsync("textPrompt",
new PromptOptions
{
Prompt = stepContext.Context.Activity.CreateReply("What's your name?")
});
});
AddStep(async (stepContext, cancellationToken) =>
{
name = stepContext.Result.ToString();
return await stepContext.PromptAsync("numberPrompt",
new PromptOptions
{
Prompt = stepContext.Context.Activity.CreateReply($"Hi {name}, How old are you ?")
});
});
AddStep(async (stepContext, cancellationToken) =>
{
age= stepContext.Result.ToString();
return await stepContext.PromptAsync("confirmPrompt",
new PromptOptions
{
Prompt = stepContext.Context.Activity.CreateReply($"Got it you're {name}, age {age}. {Environment.NewLine}Is this correct?"),
Choices = new[] {new Choice {Value = "Yes"},
new Choice {Value = "No"},
}.ToList()
});
});
AddStep(async (stepContext, cancellationToken) =>
{
var result = (stepContext.Result as FoundChoice).Value;
if(result == "Yes" || result == "yes" || result == "Yeah" || result == "Correct" || result == "correct")
{
var state = await (stepContext.Context.TurnState["FPBotAccessors"] as FPBotAccessors).FPBotStateAccessor.GetAsync(stepContext.Context);
state.Name = name;
state.Age = int.Parse(age);
return await stepContext.BeginDialogAsync(MainDialog.Id, cancellationToken);
}
else
{
//restart the dialog
return await stepContext.ReplaceDialogAsync(GetNameAndAgeDialog.Id);
}
});
}
public static string Id => "GetNameAndAgeDialog";
public static GetNameAndAgeDialog Instance { get; } = new GetNameAndAgeDialog(Id);
}
public GetNameAndAgeDialog(string dialogId,IEnumerable steps=null):base(dialogId,steps)
{
var name=“”;
var age=“”;
AddStep(异步(stepContext,cancellationToken)=>
{
返回wait wait stepContext.PromptAsync(“textPrompt”,
新提示
{
Prompt=stepContext.Context.Activity.CreateReply(“您叫什么名字?”)
});
});
AddStep(异步(stepContext,cancellationToken)=>
{
name=stepContext.Result.ToString();
返回wait wait stepContext.PromptAsync(“numbercompt”,
新提示
{
Prompt=stepContext.Context.Activity.CreateReply($“你好{name},你多大了?”)
});
});
AddStep(异步(stepContext,cancellationToken)=>
{
age=stepContext.Result.ToString();
返回wait wait stepContext.PromptAsync(“confirmport”,
新提示
{
Prompt=stepContext.Context.Activity.CreateReply($“明白了,您是{name},age{age}.{Environment.NewLine}这对吗?”),
Choices=new[]{new Choice{Value=“Yes”},
新选项{Value=“No”},
}托利斯先生()
});
});
AddStep(异步(stepContext,cancellationToken)=>
{
var result=(stepContext.result作为FoundChoice).Value;
如果(结果==“是”| |结果==“是”| |结果==“是”| |结果==“正确”| |结果==“正确”)
{
var state=await(stepContext.Context.TurnState[“FPBotAccessors”]作为FPBotAccessors)。FPBotStateAccessor.GetAsync(stepContext.Context);
state.Name=名称;
state.Age=int.Parse(Age);
返回wait wait stepContext.BeginDialogAsync(MainDialog.Id,cancellationToken);
}
其他的
{
//重新启动对话框
返回wait-stepContext.ReplaceDialogAsync(GetNameAndAgeDialog.Id);
}
});
}
公共静态字符串Id=>“GetNameAndAgeDialog”;
公共静态GetNameAndAgeDialog实例{get;}=new GetNameAndAgeDialog(Id);
}
这是我的访问者代码:
public class FPBotAccessors
{
public FPBotAccessors(ConversationState conversationState)
{
ConversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
}
public static string FPBotAccessorName { get; } = $"{nameof(FPBotAccessors)}.FPBotState";
public IStatePropertyAccessor<FPBotState> FPBotStateAccessor { get; internal set; }
public static string DialogStateAccessorName { get; } = $"{nameof(FPBotAccessors)}.DialogState";
public IStatePropertyAccessor<DialogState> DialogStateAccessor { get; internal set; }
public ConversationState ConversationState { get; }
//
public static string ConversationFlowName { get; } = "ConversationFlow";
public IStatePropertyAccessor<ConversationFlow> ConversationFlowAccessor { get; set; }
}
公共类访问器
{
公共FPBOT访问器(会话状态会话状态)
{
ConversationState=ConversationState??抛出新的ArgumentNullException(nameof(ConversationState));
}
公共静态字符串FPBotAccessorName{get;}=$“{nameof(FPBotAccessors)}.FPBotState”;
公共IStatePropertyAccessor FPBotStateAccessor{get;internal set;}
公共静态字符串DialogStateAccessorName{get;}=$“{nameof(FPBotAccessors)}.DialogState”;
公共IStatePropertyAccessor对话框StateAccessor{get;internal set;}
公共会话状态会话状态{get;}
//
公共静态字符串ConversationFlowName{get;}=“ConversationFlow”;
公共IStatePropertyAccessor会话流访问器{get;set;}
}
因此,您的代码存在一些问题,您可以采取一些措施来改进代码
对话框中的状态
首先,让我们从这样一个事实开始:在构造函数中关闭局部变量,并从表示步骤的闭包中访问这些变量。这种方法现在“有效”,但最终是有缺陷的。初始缺陷是不同的,这取决于您在实例化GetNameAndAgeDialog
对话框时采用的方法
如果您将其作为单例使用,这意味着用户和您的bot之间的所有活动对话都将通过该实例进行,并且您将遇到并发问题,即两个用户同时与bot对话时,将其值存储到同一内存(这些变量)中,并踩在彼此的数据上
也有可能,根据您所遵循的示例,您会在每一轮中实例化GetNameAndAgeDialog
。这意味着在每次对话中,这些变量都会被初始化为空字符串,这样您就无法跟踪原始值
最终,无论使用何种实例,无论何时扩展,这种方法最终都是有缺陷的,因为充其量您的状态将被绑定到单个服务器实例,并且如果一轮对话发生在ServerA
上,而下一轮对话发生在ServerM
上,那么ServerM
将没有上一轮
很明显,你需要用某种适当的状态管理机制来存储它们。您显然对使用BotState
(无论是对话还是用户范围)有些熟悉,因为您已经在使用状态属性访问器,但是在收集过程结束之前,将在多回合提示中收集的值存储到更永久的地方可能还为时过早。幸运的是,对话框本身存储在状态中,当您为DialogState
设置状态属性访问器时,您可能已经找到了状态,因此提供了一种临时持久性机制,该机制与对话框堆栈上每个对话框的生存期相关联。使用这种状态并不明显,也没有很好的文档记录,但是waterwalldialog
实际上更进一步,通过
public GetNameAndAgeDialog(string dialogId, IEnumerable<WaterfallStep> steps = null) : base(dialogId, steps)
{
AddStep(async (stepContext, cancellationToken) =>
{
return await stepContext.PromptAsync("textPrompt",
new PromptOptions
{
Prompt = MessageFactory.Text("What's your name?"),
},
cancellationToken: cancellationToken);
});
AddStep(async (stepContext, cancellationToken) =>
{
var name = (string)stepContext.Result;
stepContext.Values["name"] = name;
return await stepContext.PromptAsync("numberPrompt",
new PromptOptions
{
Prompt = MessageFactory.Text($"Hi {name}, How old are you ?"),
},
cancellationToken: cancellationToken);
});
AddStep(async (stepContext, cancellationToken) =>
{
var age = (int)stepContext.Result;
stepContext.Values["age"] = age;
return await stepContext.PromptAsync("confirmPrompt",
new PromptOptions
{
Prompt = MessageFactory.Text($"Got it you're {name}, age {age}.{Environment.NewLine}Is this correct?"),
},
cancellationToken: cancellationToken);
});
AddStep(async (stepContext, cancellationToken) =>
{
var result = (bool)stepContext.Result;
if(result)
{
var state = await (stepContext.Context.TurnState["FPBotAccessors"] as FPBotAccessors).FPBotStateAccessor.GetAsync(stepContext.Context);
state.Name = stepContext.Values["name"] as string;
state.Age = stepContext.Values["age"] as int;
return await stepContext.ReplaceDialogAsync(MainDialog.Id, cancellationToken: cancellationToken);
}
else
{
//restart the dialog
return await stepContext.ReplaceDialogAsync(GetNameAndAgeDialog.Id, cancellationToken: cancellationToken);
}
});
}