Context.Wait (Function) не регистрирует и запускает предыдущий context.Wait для полученного сообщения. - PullRequest
0 голосов
/ 21 мая 2018

РЕДАКТИРОВАТЬ: Это было решено.Если кто-то сталкивался с подобной проблемой, моя проблема заключалась в том, что я забыл аннотировать модели, используемые в качестве переменных экземпляра в диалоге, как [Сериализуемый].

Когда я использую context.Wait(MyFunction), он не вызывается какЯ отвечаю боту.Я не совсем уверен, так ли это, потому что диалог удаляется (делается), поэтому, когда приходит новое сообщение, он просто снова запускает диалог, или это потому, что вызов context.Wait каким-то образом не зарегистрирован и, таким образом, ранее отправлен в context.Wait(func) используется.Версия Botframework является самой последней из 3.x, и я пытаюсь создать пользовательский QnAMakerDialog.

Диалоговое окно выглядит как

MessageReceived -> Task HandleMessage-> Task HandleMessageWhenMoreThanOneAnswer

(Здесь я использую Context.Wait (функция).

Любые советы о том, как можно отладить это?

Я могу опубликовать код в случае необходимости! Любая помощь приветствуется!

Код: Основа кода: https://github.com/garypretty/botframework/blob/master/QnAMakerDialog/QnAMakerDialog/QnADialog.cs

А вот функции, вызываемые по порядку. Диалог вызывается изRootDialog с контекстом. Forward ().

    [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);
    }
}

RootDialog:

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());
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...