我一直在尝试使用带有QnAMaker
API 的 Microsoft Cognitive 和 AI 工具包,以创建一个简单的聊天机器人。
虽然我的普通 qnaMakerAi 聊天机器人工作正常,但在我尝试增强它的功能并将机器人反馈包含在响应中时出现了问题。
我一直在关注这里提到的确切代码示例。
我遇到的问题是:
Exception: Object reference not set to an instance of an object.
[File of type 'text/plain'].
调试器在代码部分给出错误 - (在文件 WebApiConfig.cs 中)
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
};
我还在https://github.com/Microsoft/BotBuilder/issues/4267中提出了对该问题的详细描述。
请检查并提出建议。
根据用户评论,这里是 MessagesController 的代码 -
using System;
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Builder.Dialogs;
using System.Web.Http.Description;
using System.Net.Http;
using QnABot.Dialogs;
namespace Microsoft.Bot.Sample.QnABot
{
[BotAuthentication]
public class MessagesController : ApiController
{
/// <summary>
/// POST: api/Messages
/// receive a message from a user and send replies
/// </summary>
/// <param name="activity"></param>
[ResponseType(typeof(void))]
public virtual async Task<HttpResponseMessage> Post([FromBody] Activity activity)
{
// check if activity is of type message
if (activity.GetActivityType() == ActivityTypes.Message)
{
//await Conversation.SendAsync(activity, () => new RootDialog());
await Conversation.SendAsync(activity, () => new QnaDialog());
}
else
{
HandleSystemMessage(activity);
}
return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
}
private Activity HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.DeleteUserData)
{
// Implement user deletion here
// If we handle user deletion, return a real message
}
else if (message.Type == ActivityTypes.ConversationUpdate)
{
// Handle conversation state changes, like members being added and removed
// Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
// Not available in all channels
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
// Handle add/remove from contact lists
// Activity.From + Activity.Action represent what happened
}
else if (message.Type == ActivityTypes.Typing)
{
// Handle knowing tha the user is typing
}
else if (message.Type == ActivityTypes.Ping)
{
}
return null;
}
}
}
对于 QnADialog -
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.CognitiveServices.QnAMaker;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
namespace QnABot.Dialogs
{
[Serializable]
public class QnaDialog : QnAMakerDialog
{
public QnaDialog() : base(new QnAMakerService(new QnAMakerAttribute("b372e477-0a2f-4a5a-88d5-3a664d16a4c3", "4ee02ead3xxxxxx", "Sorry, I couldn't find an answer for that", 0.5)))
{
}
protected override async Task RespondFromQnAMakerResultAsync(IDialogContext context, IMessageActivity message, QnAMakerResults result)
{
// answer is a string
var answer = result.Answers.First().Answer;
Activity reply = ((Activity)context.Activity).CreateReply();
string[] qnaAnswerData = answer.Split(';');
int dataSize = qnaAnswerData.Length;
string title = qnaAnswerData[0];
string description = qnaAnswerData[1];
string url = qnaAnswerData[2];
string imageURL = qnaAnswerData[3];
HeroCard card = new HeroCard
{
Title = title,
Subtitle = description,
};
card.Buttons = new List<CardAction>
{
new CardAction(ActionTypes.OpenUrl, "Learn More", value: url)
};
card.Images = new List<CardImage>
{
new CardImage( url = imageURL)
};
reply.Attachments.Add(card.ToAttachment());
await context.PostAsync(reply);
}
protected override async Task DefaultWaitNextMessageAsync(IDialogContext context, IMessageActivity message, QnAMakerResults result)
{
// get the URL
var answer = result.Answers.First().Answer;
string[] qnaAnswerData = answer.Split(';');
string qnaURL = qnaAnswerData[2];
// pass user's question
var userQuestion = (context.Activity as Activity).Text;
context.Call(new FeedbackDialog(qnaURL, userQuestion), ResumeAfterFeedback);
}
private async Task ResumeAfterFeedback(IDialogContext context, IAwaitable<IMessageActivity> result)
{
if (await result != null)
{
await MessageReceivedAsync(context, result);
}
else
{
context.Done<IMessageActivity>(null);
}
}
}
}
对于反馈对话框 -
using Microsoft.ApplicationInsights;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
namespace QnABot.Dialogs
{
[Serializable]
public class FeedbackDialog : IDialog<IMessageActivity>
{
private string qnaURL;
private string userQuestion;
public FeedbackDialog(string url, string question)
{
// keep track of data associated with feedback
qnaURL = url;
userQuestion = question;
}
public async Task StartAsync(IDialogContext context)
{
var feedback = ((Activity)context.Activity).CreateReply("Did you find what you need?");
feedback.SuggestedActions = new SuggestedActions()
{
Actions = new List<CardAction>()
{
new CardAction(){ Title = "", Type=ActionTypes.PostBack, Value=$"yes-positive-feedback" },
new CardAction(){ Title = "", Type=ActionTypes.PostBack, Value=$"no-negative-feedback" }
}
};
await context.PostAsync(feedback);
context.Wait(this.MessageReceivedAsync);
}
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var userFeedback = await result;
if (userFeedback.Text.Contains("yes-positive-feedback") || userFeedback.Text.Contains("no-negative-feedback"))
{
// create telemetry client to post to Application Insights
TelemetryClient telemetry = new TelemetryClient();
if (userFeedback.Text.Contains("yes-positive-feedback"))
{
// post feedback to App Insights
var properties = new Dictionary<string, string>
{
{"Question", userQuestion },
{"URL", qnaURL },
{"Vote", "Yes" }
// add properties relevant to your bot
};
telemetry.TrackEvent("Yes-Vote", properties);
}
else if (userFeedback.Text.Contains("no-negative-feedback"))
{
// post feedback to App Insights
}
await context.PostAsync("Thanks for your feedback!");
context.Done<IMessageActivity>(null);
}
else
{
// no feedback, return to QnA dialog
context.Done<IMessageActivity>(userFeedback);
}
}
}
}