c# - 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("((<attachment){1}((?:\\s+)|(?:(contentType="[\\w\\/-]+"))(?:\\s+)|(?:(contentUrl="[\\w:/.=?-]+"))(?:\\s+)|(?:(name="[\\w\\s&?\\-.@%$!£\\(\\)]+"))(?:\\s+)|(?:(thumbnailUrl="[\\w:/.=?-]+"))(?:\\s+))+(/>))", 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="", string.Empty).Replace(""", string.Empty);
}
if (group.ToString().ToLower().Contains("contenturl="))
{
contentUrl = group.ToString().ToLower().Replace(@"contenturl="", string.Empty).Replace(""", string.Empty);
}
if (group.ToString().ToLower().Contains("name="))
{
name = group.ToString().ToLower().Replace(@"name="", string.Empty).Replace(""", string.Empty);
}
if (group.ToString().ToLower().Contains("thumbnailurl="))
{
thumbnailUrl = group.ToString().ToLower().Replace(@"thumbnailurl="", string.Empty).Replace(""", 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++ - 没有初始化的 OMP for 循环
- amazon-web-services - AWS Cloudformation 容器覆盖
- c# - 使用 .Net Core 开发跨平台“低级”软件
- ms-access - MsAccess QueryDef.SQL 与实际查询 sql 不同
- perl - 如何禁用 Perl Tk::Text 小部件的键盘绑定?
- ios - react-native - 在没有 Apple 开发者帐户的情况下部署到 iOS
- machine-learning - Softmax 层和最后一层神经网络
- google-apps-script - 如何制作一个谷歌表格脚本,从另一张表格返回单元格上的注释
- javascript - 流星笔预处理器在每个 text-laign:center 中添加 `j-`
- html - 圆形按钮在悬停时随文本展开