首页 > 解决方案 > Context.Wait(Function) 未注册并运行先前的 context.Wait 收到消息

问题描述

编辑:这已经解决了。如果有人遇到类似的问题,我的问题是我忘记将对话框中用作实例变量的模型注释为 [Serializable]。

当我使用context.Wait(MyFunction)它时,当我响应机器人时,它不会被调用。我不完全确定这是否是因为对话框被丢弃(完成),所以当新消息进入时它只是再次运行对话框,或者是否导致context.Wait调用以某种方式未注册,因此使用先前发送的context.Wait(func)。Botframework 版本是 3.x 的最新版本,我想要的是自定义QnAMakerDialog.

对话流程看起来像

MessageReceived -> 任务 HandleMessage -> 任务 HandleMessageWhenMoreThanOneAnswer

(这是我使用 Context.Wait(function) 的地方。

关于如何进行调试的任何提示?

如果需要,我可以发布代码!任何帮助表示赞赏!

代码:代码的基础是:https ://github.com/garypretty/botframework/blob/master/QnAMakerDialog/QnAMakerDialog/QnADialog.cs

这是按顺序调用的函数。该对话框是从带有 context.Forward() 的 RootDialog 调用的。

    [Serializable]
public class TestDialog : IDialog<object>
{
    private string _baseUri;
    private string _endpointKey;
    private string _subscriptionKey;
    private string _knowledgeBaseId;
    private int _maxAnswers;
    private List<QnADialog.Models.Metadata> _metadataBoost;
    private List<QnADialog.Models.Metadata> _metadataFilter;
    private QnADialog.Models.QuestionResponse.QnAMakerResult qnaMakerResults;
    //private QnADialog.Models.UserFeedback userFeedback; <--- THIS destroys the flow

    public string BaseUri { get => _baseUri; set => _baseUri = value; }
    public string EndpointKey { get => _endpointKey; set => _endpointKey = value; }
    public string SubscriptionKey { get => _subscriptionKey; set => _subscriptionKey = value; }
    public string KnowledgeBaseId { get => _knowledgeBaseId; set => _knowledgeBaseId = value; }
    public int MaxAnswers { get => _maxAnswers; set => _maxAnswers = value; }



    public List<QnADialog.Models.Metadata> MetadataBoost { get => _metadataBoost; set => _metadataBoost = value; }
    public List<QnADialog.Models.Metadata> MetadataFilter { get => _metadataFilter; set => _metadataFilter = value; }

    public Task StartAsync(IDialogContext context)
    {

        this.BaseUri = "";
        this.EndpointKey = "";
        this.KnowledgeBaseId = "";
        this.SubscriptionKey = "";
        this.MaxAnswers = 5;
        context.Wait(MessageReceived);

        return Task.CompletedTask;
    }

    protected async Task MessageReceived(IDialogContext context, IAwaitable<IMessageActivity> item)
    {
        var message = await item;

        //this.userFeedback = new QnADialog.Models.UserFeedback { userId = message.From.Id, userQuestion = message.Text };
        await context.PostAsync("MessageReceived");

        await this.HandleMessage(context, message.Text);
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as IMessageActivity;

        await context.PostAsync(activity.Text);

        await this.HandleMessage(context, activity.Text);
    }

    private async Task HandleMessage(IDialogContext context, string queryText)
    {
        var response = await GetQnAMakerResponse(queryText, BaseUri, KnowledgeBaseId, EndpointKey);

        //if (HandlerByMaximumScore == null)
        //{
        //    HandlerByMaximumScore =
        //        new Dictionary<QnAMakerResponseHandlerAttribute, QnAMakerResponseHandler>(GetHandlersByMaximumScore());
        //}

        if (response.Answers.Any() && response.Answers.First().QnaId == 0)
        {
            await NoMatchHandler(context, queryText);
        }
        else
        {
            if (response.Answers.Count() == 1)
            {
                await DefaultMatchHandler(context, queryText, response);
            }
            else
            {
                //this.qnaMakerResults = response;
                //var qnaList = qnaMakerResults.Answers;
                //await context.PostAsync(createHeroCard(context, qnaList));
                //context.Wait(HandleQuestionResponse);
                await QnAFeedbackHandler(context, queryText, response);
            }

        }
    }

    private async Task<QnADialog.Models.QuestionResponse.QnAMakerResult> GetQnAMakerResponse(string query, string baseUri, string knowledgeBaseId, string endpointKey)
    {
        string responseString;
        var qnamakerBaseUri = baseUri;
        var knowledgebaseId = knowledgeBaseId; // Use knowledge base id created.
        var qnamakerEndpointKey = endpointKey; //Use endpoint key assigned to you.

        //Build the URI
        var qnamakerUriBase = new Uri(qnamakerBaseUri);
        var builder = new UriBuilder($"{qnamakerUriBase}/knowledgebases/{knowledgebaseId}/generateAnswer");

        //Add the question as part of the body
        var request = new QnADialog.Models.QuestionRequest()
        {
            Question = query,
            Top = MaxAnswers,
            UserId = "QnAMakerDialog"
        };



        var postBody = JsonConvert.SerializeObject(request);

        //Send the POST request
        using (WebClient client = new WebClient())
        {
            //Set the encoding to UTF8
            client.Encoding = System.Text.Encoding.UTF8;

            //Add the subscription key header
            client.Headers.Add("Authorization", $"EndpointKey {qnamakerEndpointKey}");
            client.Headers.Add("Content-Type", "application/json");
            responseString = client.UploadString(builder.Uri, postBody);
        }

        //De-serialize the response
        try
        {
            var response = JsonConvert.DeserializeObject<QnADialog.Models.QuestionResponse.QnAMakerResult>(responseString);
            return response;
        }
        catch
        {
            throw new Exception("Unable to deserialize QnA Maker response string.");
        }
    }

    public virtual async Task DefaultMatchHandler(IDialogContext context, string originalQueryText, QnADialog.Models.QuestionResponse.QnAMakerResult result)
    {
        var messageActivity = ProcessResultAndCreateMessageActivity(context, ref result);
        messageActivity.Text = result.Answers.First().Answer;
        await context.PostAsync(messageActivity);
        await AnswerFeedback(context);
    }

    public virtual async Task NoMatchHandler(IDialogContext context, string originalQueryText)
    {
        await context.PostAsync("No match was found");
        //throw new Exception("Sorry, I cannot find an answer to your question.");
    }

    private async Task AnswerFeedback(IDialogContext context)
    {
        context.PostAsync("HandleMessage");
        var reply = context.MakeMessage();
        reply.Attachments = new List<Attachment>();
        List<CardAction> cardButtons = new List<CardAction>();
        CardAction cardActionYes = new CardAction()
        {
            Type = "imBack",
            Title = "Yes",
            Value = "Yes"
        };
        CardAction cardActionNo = new CardAction()
        {
            Type = "imBack",
            Title = "No",
            Value = "No"
        };
        HeroCard card = new HeroCard()
        {
            Title = "Was the answer helpful?",
            Buttons = cardButtons
        };
        cardButtons.Add(cardActionYes);
        cardButtons.Add(cardActionNo);
        Attachment atch = card.ToAttachment();
        reply.Attachments.Add(atch);
        await context.PostAsync(reply);
        context.Wait(this.HandleHelpfulResponse);
    }

    private async Task HandleHelpfulResponse(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as IMessageActivity;
        if (activity.Text == "Yes")
        {
 //              await context.PostAsync($"{this.userFeedback.kbQuestionId} 
 - {this.userFeedback.userId} - {this.userFeedback.userQuestion}");
        }
        else if (activity.Text == "No")
        {
           await context.PostAsync("NOPNORP");
        }
        context.Done(new Object());
    }

    protected static IMessageActivity ProcessResultAndCreateMessageActivity(IDialogContext context, ref QnADialog.Models.QuestionResponse.QnAMakerResult result)
    {
        var message = context.MakeMessage();

        var attachmentsItemRegex = new Regex("((&lt;attachment){1}((?:\\s+)|(?:(contentType=&quot;[\\w\\/-]+&quot;))(?:\\s+)|(?:(contentUrl=&quot;[\\w:/.=?-]+&quot;))(?:\\s+)|(?:(name=&quot;[\\w\\s&?\\-.@%$!£\\(\\)]+&quot;))(?:\\s+)|(?:(thumbnailUrl=&quot;[\\w:/.=?-]+&quot;))(?:\\s+))+(/&gt;))", RegexOptions.IgnoreCase);
        var matches = attachmentsItemRegex.Matches(result.Answers.First().Answer);

        foreach (var attachmentMatch in matches)
        {
            result.Answers.First().Answer = result.Answers.First().Answer.Replace(attachmentMatch.ToString(), string.Empty);

            var match = attachmentsItemRegex.Match(attachmentMatch.ToString());
            string contentType = string.Empty;
            string name = string.Empty;
            string contentUrl = string.Empty;
            string thumbnailUrl = string.Empty;

            foreach (var group in match.Groups)
            {
                if (group.ToString().ToLower().Contains("contenttype="))
                {
                    contentType = group.ToString().ToLower().Replace(@"contenttype=&quot;", string.Empty).Replace("&quot;", string.Empty);
                }
                if (group.ToString().ToLower().Contains("contenturl="))
                {
                    contentUrl = group.ToString().ToLower().Replace(@"contenturl=&quot;", string.Empty).Replace("&quot;", string.Empty);
                }
                if (group.ToString().ToLower().Contains("name="))
                {
                    name = group.ToString().ToLower().Replace(@"name=&quot;", string.Empty).Replace("&quot;", string.Empty);
                }
                if (group.ToString().ToLower().Contains("thumbnailurl="))
                {
                    thumbnailUrl = group.ToString().ToLower().Replace(@"thumbnailurl=&quot;", string.Empty).Replace("&quot;", string.Empty);
                }
            }

            var attachment = new Attachment(contentType, contentUrl, name: !string.IsNullOrEmpty(name) ? name : null, thumbnailUrl: !string.IsNullOrEmpty(thumbnailUrl) ? thumbnailUrl : null);
            message.Attachments.Add(attachment);
        }

        return message;
    }

    private async Task QnAFeedbackHandler(IDialogContext context, string userQuery, QnADialog.Models.QuestionResponse.QnAMakerResult results)
    {

        //this.feedbackRecord = new UserFeedback() { userQuestion = userQuery };
        this.qnaMakerResults = results;
        var qnaList = results.Answers;
        //var contextTest2 = context;
        await context.PostAsync(createHeroCard(context, qnaList));

        context.Wait(HandleQuestionResponse); // funkar inte....

    }

    protected IMessageActivity createHeroCard(IDialogContext context, QnADialog.Models.QuestionResponse.QnaAnswer[] options)
    {
        var reply = context.MakeMessage();
        reply.Attachments = new List<Attachment>();
        List<CardAction> cardButtons = new List<CardAction>();
        foreach (var ans in options)
        {
            CardAction cardAction = new CardAction()
            {
                Type = "imBack",
                Title = ans.Questions[0],
                Value = ans.Questions[0]
            };
            cardButtons.Add(cardAction);
        }

        CardAction none = new CardAction()
        {
            Type = "imBack",
            Title = Resource.noneOfTheAboveOption,
            Value = Resource.noneOfTheAboveOption
        };
        cardButtons.Add(none);

        HeroCard card = new HeroCard()
        {
            Title = "Did you mean?",
            Buttons = cardButtons
        };
        Attachment atch = card.ToAttachment();
        reply.Attachments.Add(atch);
        return reply;
    }

    protected async Task HandleQuestionResponse(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var selection = await result as IMessageActivity;
        context.PostAsync("LastStep");
        if (this.qnaMakerResults != null)
        {
            bool match = false;
            foreach (var qnaMakerResult in this.qnaMakerResults.Answers)
            {
                if (qnaMakerResult.Questions[0].Equals(selection.Text, StringComparison.OrdinalIgnoreCase))
                {
                    await context.PostAsync(qnaMakerResult.Answer);
                    match = true;

                    //if (userFeedback != null)
                    //{
                    //    userFeedback.kbQuestionId = qnaMakerResult.QnaId;
                    //}
                }
            }
        }
        await this.AnswerFeedback(context);
    }
}

根对话框:

namespace customQnADialog.Dialogs
{
    [Serializable]
    public class RootDialog : IDialog<object>
    {
        public Task StartAsync(IDialogContext context)
        {
            context.Wait(MessageReceivedAsync);

            return Task.CompletedTask;
        }

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
        {
            var activity = await result as Activity;
            await context.Forward(new CustomQnADialog(), ResumeAfterQnADialog, activity, CancellationToken.None);
        }

        private async Task ResumeAfterQnADialog(IDialogContext context, IAwaitable<object> result)
        {
            context.Wait(this.MessageReceivedAsync);
        }
    }
}

控制器:

            if (activity.Type == ActivityTypes.Message)
        {
            await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
        }

标签: c#botframework

解决方案


推荐阅读