如何在C#[Bot Framework v4]中从QnaBot(qna maker api)调用瀑布对话框?

如何在C#[Bot Framework v4]中从QnaBot(qna maker api)调用瀑布对话框?,c#,botframework,qnamaker,C#,Botframework,Qnamaker,我已经使用c#在bot Framework v4中创建了一个qna maker机器人,现在当在qna知识库中找不到答案时,我必须调用瀑布式对话框向用户提问 我该怎么做 protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) { var httpClie

我已经使用c#在bot Framework v4中创建了一个qna maker机器人,现在当在qna知识库中找不到答案时,我必须调用瀑布式对话框向用户提问

我该怎么做

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
    {
        var httpClient = _httpClientFactory.CreateClient();

        var qnaMaker = new QnAMaker(new QnAMakerEndpoint
        {
            KnowledgeBaseId = _configuration["QnAKnowledgebaseId"],
            EndpointKey = _configuration["QnAAuthKey"],
            Host = GetHostname()
        },
        null,
        httpClient);

        _logger.LogInformation("Calling QnA Maker");

        // The actual call to the QnA Maker service.
        var response = await qnaMaker.GetAnswersAsync(turnContext);
        if (response != null && response.Length > 0)
        {
            string message = GetMessage(response[0].Answer);
            Attachment attachment = GetHeroCard(response[0].Answer);
            await turnContext.SendActivityAsync(MessageFactory.Text(message), cancellationToken);
            if (attachment != null)
                await turnContext.SendActivityAsync(MessageFactory.Attachment(attachment), cancellationToken);
        }
        else
        {  
            //HERE I WANT TO CALL WATERFALL DIALOG
            //await turnContext.SendActivityAsync(MessageFactory.Text("No QnA Maker answers were found."), cancellationToken);
        }
    }
messageActivityAsync上的受保护覆盖异步任务(iTurContext turnContext,CancellationToken CancellationToken)
{
var httpClient=_httpClientFactory.CreateClient();
var qnaMaker=新qnaMaker(新qnaMaker点
{
KnowledgeBaseId=_配置[“QnAKnowledgebaseId”],
EndpointKey=_配置[“QnAAuthKey”],
Host=GetHostname()
},
无效的
httpClient);
_logger.LogInformation(“调用QnA Maker”);
//对QnA Maker服务的实际调用。
var response=wait qnaMaker.GetAnswersAsync(turnContext);
if(response!=null&&response.Length>0)
{
字符串消息=GetMessage(响应[0]。应答);
附件附件=GetHeroCard(响应[0]。应答);
Wait turnContext.SendActivityAsync(MessageFactory.Text(message),cancellationToken);
如果(附件!=null)
Wait turnContext.SendActivityAsync(MessageFactory.Attachment(Attachment),cancellationToken);
}
其他的
{  
//这里我想调用瀑布对话框
//Wait turnContext.SendActivityAsync(MessageFactory.Text(“未找到QnA生成器答案”)、cancellationToken);
}
}

您可以使用多回合提示,它使用瀑布式对话框、一些提示和组件对话框创建一个简单的交互,向用户询问一系列问题。机器人通过UserProfileDialog与用户交互。当我们创建bot的DialogBot类时,我们将UserProfileDialog设置为它的主对话框。然后,bot使用Run helper方法访问该对话框

要使用提示,请从对话框中的一个步骤调用它,并在下面的步骤中使用stepContext.result检索提示结果。您应该始终从瀑布式步骤返回非空的DialogTurnResult

询问用户姓名的示例如下:

 public class UserProfileDialog : ComponentDialog
    {
        private readonly IStatePropertyAccessor<UserProfile> _userProfileAccessor;

        public UserProfileDialog(UserState userState)
            : base(nameof(UserProfileDialog))
        {
            _userProfileAccessor = userState.CreateProperty<UserProfile>("UserProfile");

            // This array defines how the Waterfall will execute.
            var waterfallSteps = new WaterfallStep[]
            {
                NameStepAsync,
                NameConfirmStepAsync,
                SummaryStepAsync,
            };

            // Add named dialogs to the DialogSet. These names are saved in the dialog state.
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }

        private static async Task<DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;

            return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") }, cancellationToken);
        }

        private async Task<DialogTurnResult> NameConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            stepContext.Values["name"] = (string)stepContext.Result;

            // We can send messages to the user at any point in the WaterfallStep.
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Thanks {stepContext.Result}."), cancellationToken);

            // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
            return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text("Would you like to give your age?") }, cancellationToken);
        }


        private async Task<DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            if ((bool)stepContext.Result)
            {
                // Get the current profile object from user state.
                var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken);

                userProfile.Name = (string)stepContext.Values["name"];

            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("Thanks. Your profile will not be kept."), cancellationToken);
            }

            // WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is the end.
            return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
        }      
    }
公共类UserProfileDialog:ComponentDialog { 专用只读IStatePropertyAccessor\u userProfileAccessor; 公共用户档案对话框(UserState UserState) :base(nameof(UserProfileDialog)) { _userProfileAccessor=userState.CreateProperty(“UserProfile”); //此数组定义瀑布将如何执行。 var waterwallsteps=新的waterwallstep[] { 名称步异步, NameConfirmStepAsync, SummaryStepAsync, }; //将命名对话框添加到对话框集中。这些名称保存在对话框状态中。 AddDialog(新建WaterWallDialog(名称(WaterWallDialog),WaterWallSteps)); AddDialog(新建文本提示(名称)(文本提示)); AddDialog(新建确认提示)(名称(确认提示)); //要运行的初始子对话框。 InitialDialogId=nameof(WaterWallDialog); } 专用静态异步任务名称StepAsync(WaterCallStepContext stepContext,CancellationToken CancellationToken) { stepContext.Values[“transport”]=((FoundChoice)stepContext.Result).Value; return wait-stepContext.PromptAsync(nameof(TextPrompt),newpromptoptions{Prompt=MessageFactory.Text(“请输入您的姓名”)},cancellationToken); } 专用异步任务名称ConfirmStepAsync(WaterWallStepContext stepContext,CancellationToken CancellationToken) { stepContext.Values[“name”]=(string)stepContext.Result; //我们可以在Waterwall步骤中的任意点向用户发送消息。 等待stepContext.Context.SendActivityAsync(MessageFactory.Text($“Thank{stepContext.Result}”)、cancellationToken; //瀑布步骤总是在瀑布的结尾或另一个对话框中结束;这里是一个提示对话框。 return wait-stepContext.PromptAsync(nameof(confirmport),new-PromptOptions{Prompt=MessageFactory.Text(“您想给出您的年龄吗?”)},cancellationToken); } 专用异步任务摘要StepAsync(WaterWallStepContext stepContext,CancellationToken CancellationToken) { if((bool)stepContext.Result) { //从用户状态获取当前配置文件对象。 var userProfile=await _userProfileAccessor.GetAsync(stepContext.Context,()=>newuserprofile(),cancellationToken); userProfile.Name=(字符串)stepContext.Values[“Name”]; } 其他的 { Wait stepContext.Context.SendActivityAsync(MessageFactory.Text(“谢谢,您的个人资料将不会保留”)、cancellationToken); } //瀑布步骤总是在瀑布的末尾或另一个对话框中结束,这里就是终点。 return wait stepContext.EndDialogAsync(cancellationToken:cancellationToken); } } 文档将帮助您更好地理解多提示对话框


希望这能有所帮助。

谢谢您的回答,但是我如何才能从那里调用UserProfileDialog?@MarianoBejo您可以查看答案中链接的文档,以获得更详细的解释。