I want change Default Answer in Q&A Maker Azure Framework Bot, but I cant find field that respond this value. I'm reading documentation (but it looks like it uses an older interface), and I'm trying to find this field but with result.
Here's my current configuration screen:
I'm assuming that you're referring to these docs: QnaMaker - Change Default Answer
They're a little confusing, but they key part is:
You can override this default response in the bot or application code
calling the endpoint.
Where the docs have this image:
What they actually mean is that in the QnAMaker Test Console, you can edit the default answer from your Application Settings. Be sure to Save, Train, and Publish your app or the setting may not show.
There's also kind of a way that you can use this setting for your default answer in a bot:
In Node/JS, your bot will not receive that DefaultAnswer at all. It receives nothing if there isn't a match, so you have to hard code it with something like:
const qnaResults = await this.qnaMaker.getAnswers(context);
// If an answer was received from QnA Maker, send the answer back to the user.
if (qnaResults[0]) {
await context.sendActivity(qnaResults[0].answer);
// If no answers were returned from QnA Maker, show this reply.
// Note: .getAnswers() does NOT return the default answer from the App Service's Application Settings
} else {
const defaultAnswer = 'No QnA Maker answers were found. This example uses a QnA Maker Knowledge Base that focuses on smart light bulbs. To see QnA Maker in action, ask the bot questions like "Why won\'t it turn on?" or "I need help."'
await context.sendActivity(defaultAnswer);
}
When creating an Azure Web Bot, one of the default Web Chat clients is a fork of microsoft's BotBuilder-Samples project, specifically 49 - QnAMaker All Features
The source code for Dialog/QnAMakerBaseDialog.cs defines the constant DefaultNoAnswer:
public const string DefaultNoAnswer = "No QnAMaker answers found.";
And then uses that value when returning a response from GetQnAResponseOptionsAsync:
protected async override Task<QnADialogResponseOptions> GetQnAResponseOptionsAsync(DialogContext dc)
{
var noAnswer = (Activity)Activity.CreateMessageActivity();
noAnswer.Text = DefaultNoAnswer; // <- used right here
var cardNoMatchResponse = (Activity)MessageFactory.Text(DefaultCardNoMatchResponse);
var responseOptions = new QnADialogResponseOptions
{
ActiveLearningCardTitle = DefaultCardTitle,
CardNoMatchText = DefaultCardNoMatchText,
NoAnswer = noAnswer,
CardNoMatchResponse = cardNoMatchResponse,
};
return responseOptions;
}
This particular sample repo doesn't appear to leverage the DefaultAnswer configuration key anywhere.
You can opt to include it when available by updating the noAnswer.Text like this:
- noAnswer.Text = DefaultNoAnswer;
+ noAnswer.Text = this._configuration["DefaultAnswer"] ?? DefaultNoAnswer;
You'll also have to pass in the configuration object through the dependency management system. See this commit for a full example.
Change the line in qamakerBaseDialog.js as below
var noAnswer = ActivityFactory.DefaultNoAnswer;
Remove ActivityFactory. and rebuild the code.
constructor(knowledgebaseId, authkey, host) {
//ActivityFactory.
var noAnswer = DefaultNoAnswer;
var filters = [];
super(knowledgebaseId, authkey, host, noAnswer, DefaultThreshold, DefaultCardTitle, DefaultCardNoMatchText,
DefaultTopN, ActivityFactory.cardNoMatchResponse, filters, QNAMAKER_BASE_DIALOG);
this.id = QNAMAKER_BASE_DIALOG;
}
Related
I need to send QnA users questions and answers to my Azure bot insights using telemetry. Already tried this tutorial :
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=javascript
And this SO posts:
How to get the Qna Maker "Q" from Analytics Application Insights?
How can I save some custom qna maker data in azure app insights?
Thing is, first it's done for LUIS and gives no additional info to Insights, also nothing for QnA...second ones are written for C#...
I need to send question and answer to customEvents logs on Azure insights using NodeJS but I can't find how, any help ?
Thanks in advance.
///// EDIT:
Here's what I got so far (only posted the code related to the telemetry and QnA that's already working fine):
Index.js
const { ApplicationInsightsTelemetryClient, TelemetryInitializerMiddleware } = require('botbuilder-applicationinsights');
const { TelemetryLoggerMiddleware } = require('botbuilder-core');
function getTelemetryClient(instrumentationKey) {
if (instrumentationKey) {
return new ApplicationInsightsTelemetryClient(instrumentationKey);
}
return new NullTelemetryClient();
}
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
var telemetryClient = getTelemetryClient(process.env.InstrumentationKey);
var telemetryLoggerMiddleware = new TelemetryLoggerMiddleware(telemetryClient);
var initializerMiddleware = new TelemetryInitializerMiddleware(telemetryLoggerMiddleware);
adapter.use(initializerMiddleware);
const mybot = new MYBOT(conversationState,userState, telemetryClient);
mybot.js
class MYBOT extends ActivityHandler {
constructor(conversationState,userState,telemetryClient) {
super();
this.conversationState = conversationState;
this.userState = userState;
this.telemetryClient = telemetryClient;
}
}
//This is how I get my qna result:
console.log(this.telemetryClient);
var result = await this.qnaMaker.getAnswers(context);
As You can see, I pass the telemetryClient to the bot file, and if I console log that item I get the complete telemetry object, but how I pass it the user question and answer so its save on insights customevents ??
Found a way to it, in case people that's looking for one of the possible solutions for Node may need it :
Basically, We use the same telemetry code process described in oficial documentation for instancing telemetry on index.js :
const { ApplicationInsightsTelemetryClient, TelemetryInitializerMiddleware } = require('botbuilder-applicationinsights');
const { TelemetryLoggerMiddleware } = require('botbuilder-core');
function getTelemetryClient(instrumentationKey) {
if (instrumentationKey) {
return new ApplicationInsightsTelemetryClient(instrumentationKey);
}
return new NullTelemetryClient();
}
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
var telemetryClient = getTelemetryClient(process.env.InstrumentationKey);
var telemetryLoggerMiddleware = new TelemetryLoggerMiddleware(telemetryClient);
var initializerMiddleware = new TelemetryInitializerMiddleware(telemetryLoggerMiddleware);
adapter.use(initializerMiddleware);
const mybot = new MYBOT(conversationState,userState, telemetryClient);
Then, we pass it to the bot file (bot.js or the one you´re using):
class MYBOT extends ActivityHandler {
constructor(conversationState,userState,telemetryClient) {
super();
this.conversationState = conversationState;
this.userState = userState;
this.telemetryClient = telemetryClient;
}
}
And later in code, You can use telemetry.trackEvent method (Official docs are only in C#), but basically, it allows you to create a custom event you want to track in specifics events in your code, like when You're bot has an error or doesn´t found an answer to user. Code according to previous lines would be like this:
this.telemetryClient.trackEvent(
{name: "myEvent",
properties: {my_user_question: 'Context activity text here or your captured question',
my_bot_answer: 'bot reply or whatever'}
}
); // name and properties are part of the sintaxys, values inside properties object as you may need.
That way, on Azure insights customEvents model You will see records captured with the event name you used, also, with the properties objects as a dict in customdimensions field.
I've created QnA bot on Azure and integrated it with Teams. I'm built a knowledge base and it's able to return answers based on the knowledge base.
For training, I would like the bot to turn the top 5 answers regardless if there's a match. It will help me train the model if I can select which one is actually the best match.
I've updated the default responses to return the top 5 if there's no response, but I don't see where to always return the top 5 responses and invoke feedback from the user.
From the qnamakerBaseDialog.js in App Server Editor:
const {
QnAMakerDialog
} = require('botbuilder-ai');
const {
ActivityFactory
} = require('botbuilder-core');
// Default parameters
const DefaultThreshold = 0.0;
const DefaultTopN = 5;
const DefaultNoAnswer = 'No answers found. Please rephrase the question.';
I have choosen Nodejs in Azure Webapp bot with Qnamaker and Default No answer modified in online code editor itself, but still it is not reflecting in chat. Even I tried changing the Default answer in app service configuration its not working
You can edit the nodeJs code and change the text.
in "dialogs/qnamakerBaseDialog.js"
You can do:
class QnAMakerBaseDialog extends QnAMakerDialog {
/**
* Core logic of QnA Maker dialog.
* #param {QnAMaker} qnaService A QnAMaker service object.
*/
constructor(knowledgebaseId, authkey, host) {
var noAnswer = DefaultNoAnswer;
var filters = [];
super(knowledgebaseId, authkey, host, noAnswer, DefaultThreshold, DefaultCardTitle, DefaultCardNoMatchText,
DefaultTopN, ActivityFactory.cardNoMatchResponse, filters, QNAMAKER_BASE_DIALOG);
this.id = QNAMAKER_BASE_DIALOG;
}
}
Take note that:
var noAnswer = DefaultNoAnswer;
And / OR you can change the default message in line 15 (or so)
const DefaultNoAnswer = 'Your custom message';
I've developed a chatbot that communicates with SharePoint on Premise,
When I run the chatbot in Emulator its work.
But When I run at Web that hosted outside of SharePoint, it does not work.
Herewith my screenshot of Error On Azure, From the result of Error is starting from XMLReader and SyndicationFeed
Success in Local Emulator
Herewith my Souce Code.
private async Task ProcessRSSAsync(ITurnContext<IMessageActivity> turnContext, LuisResult luisResult, string intent, CancellationToken cancellationToken)
{
var questionluis = turnContext.Activity.Text;
await turnContext.SendActivityAsync("intent recognize" + intent);
var intentresut = intent;
await turnContext.SendActivityAsync("Get LUIS Entity");
await turnContext.SendActivityAsync(string.Join("\t", luisResult.Entities.Select((entityObj) => entityObj.Entity)));
var entityfound = string.Join("\t", luisResult.Entities.Select((entityObj) => entityObj.Entity));
string spxurl = #"https://intra.aspac.com/sites/sg/daw/_layouts/15/srchrss.aspx?k=*%20ListId:7BC0F2C3-6366-48B8-B88A-8738BE1F9C31";
await turnContext.SendActivityAsync("Intent: " + intent.ToString() + " Entity: " + entityfound.ToString());
////---------------------------------------------------------------------------------------------
//22112019
try
{
//#ES09122019
var credentials = new NetworkCredential("email#example.com", "Pa$$w0rd", "sg.kworld.com");
var handler = new HttpClientHandler { Credentials = credentials, UseDefaultCredentials = false };
var client = new HttpClient(handler);
client.BaseAddress = new Uri("https://intra.aspac.com/sites/sg/daw/");
HttpResponseMessage resp = client.GetAsync("_layouts/15/srchrss.aspx?k=" + entityfound + "*%20ListId:7BC0F2C3-6366-48B8-B88A-8738BE1F9C31").Result;
string respString = resp.Content.ReadAsStringAsync().Result;
if (resp.StatusCode == HttpStatusCode.OK)
{
await turnContext.SendActivityAsync("Connected");
//Success 06122019 .
try
{
string spurl = #"https://intra.aspac.com/sites/sg/daw/_layouts/15/srchrss.aspx?k=*%20ListId:7BC0F2C3-6366-48B8-B88A-8738BE1F9C31";
XmlSecureResolver resolver = new XmlSecureResolver(new XmlUrlResolver(), spurl);
resolver.Credentials = new NetworkCredential("email#example.com.sg", "Pa$$w0rd", "sg.kworld.com");
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.ValidationType = ValidationType.DTD;
settings.XmlResolver = resolver;
XmlReader reader = XmlReader.Create(spurl, settings);
SyndicationFeed feed = SyndicationFeed.Load(reader);
reader.Close();
var attachments = new List<Attachment>();
foreach (SyndicationItem item in feed.Items)
{
//Get Title,Description,URL
String title = item.Title.Text;
String description = item.Summary.Text;
String link = item.Links.FirstOrDefault().Uri.ToString();
//Hero Card
var heroCard = new HeroCard(
title: item.Title.Text,
// subtitle: description,
buttons: new CardAction[]
{
new CardAction(ActionTypes.OpenUrl,"Learn More",value:link)
}
).ToAttachment();
attachments.Add(heroCard);
}
var reply = MessageFactory.Carousel(attachments);
await turnContext.SendActivityAsync(reply);
await ProcessCosmoDBStorageLUISAsync(turnContext, questionluis, intent, entityfound, respString, cancellationToken);
}
catch (Exception ex)
{
await turnContext.SendActivityAsync(ex.ToString());
}
}
}
catch (Exception ex)
{
await turnContext.SendActivityAsync("Sorry,Currently Server Under Maintenace");
await turnContext.SendActivityAsync(ex.ToString());
}
}
any solution for this and suggestion?
ok, I think I finally understand this better, so hopefully can put a useful reply together. Would be much easier if we had a shared whiteboard :-)
Basically, in terms of hosting a bot on the Microsoft Bot Framework Services, you need to have a registration in Azure. However, there are two different options, and both are VERY different in terms of hosting. When you "create" the resource in Azure, and search for "Bot", you'll see two options - "Web App Bot" and "Bot Channels Registration":
"Bot Channels Registration" means JUST registering your bot in Azure, but HOSTING it elsewhere.
"Web App Bot" - INCLUDES the "Bot Channels Registration" but ALSO adds hosting using an Azure Web Application (so it's a Bot registration PLUS hosting)
From the screenshot you posted, I can see you've selected (2) above, and so your bot is running inside Azure, and therefore can't connect to your on premises resource (SharePoint).
As a result, I'd suggest one of two options:
Create an Azure Application Proxy - this is basically a small gateway so that your bot HOSTED in Azure can securely talk to your on-premises SharePoint. There is in fact a specific use case for SharePoint in particular.
Delete and re-create your Azure Bot entry to instead be just a "Bot Channels Registration", and then in the "Settings" screen you can call a bot hosted at any "https" endpoint. You can then have your bot run on the local network, but it will need a live "https" address (not -that- hard to do, but you have to involve your IT team to get a live web address, like "whatever.aspac.com", and you'll need an SSL/TLS certificate so that it can run httpS instead of just http.
Which option you choose might depend on the skills and resources on your team, as well as in the organisation. For instance, the company might have Azure Application Proxy configured already, in which case that saves a lot of work. It might have a wildcard certificate, which would make option (2) easier, etc.
Either way, I hope that helped, but feel free to ask more if anything is still unclear.
i had a similar problem using a on premise database. as you are deploying your bot externally, the bot needs resources that are available on the internet, and not contained internally. It will work fine using the bot emulator because it has access to what your machine has.
Saying that, azure has developed some actions which you can use to help this problem. If you look at application proxys, that may be able to help you out.
i think thats what you mean... anyway!
I’ve got a WinRT app that I’m using the Windows Azure Toolkit for Windows 8 with. I’ve got a setup where I’d like clients subscribed to ignore messages posted to a ServiceBus Topic if they’re the originator or if the message is older than when their subscription started.
In the Properties of my BrokeredMessage, I’ve added 2 items to cover these scenarios:
message.Properties["Timestamp"] = DateTime.UtcNow.ToFileTime();
message.Properties["OriginatorId"] = clientId.ToString();
clientId is a Guid.
The subscriber side looks like this:
// ti is a class that contains a Topic, Subscription and a bool as a cancel flag.
string FilterName = "NotMineNewOnly";
// Find or create the topic.
if (await Topic.ExistsAsync(DocumentId.ToString(), TokenProvider))
{
ti.Topic = await Topic.GetAsync(DocumentId.ToString(), TokenProvider);
}
else
{
ti.Topic = await Topic.CreateAsync(DocumentId.ToString(), TokenProvider);
}
// Find or create this client's subscription to the board.
if (await ti.Topic.Subscriptions.ExistsAsync(ClientSettings.Id.ToString()))
{
ti.Subscription = await ti.Topic.Subscriptions.GetAsync(ClientSettings.Id.ToString());
}
else
{
ti.Subscription = await ti.Topic.Subscriptions.AddAsync(ClientSettings.Id.ToString());
}
// Find or create the subscription filter.
if (!await ti.Subscription.Rules.ExistsAsync(FilterName))
{
// Want to ignore messages generated by this client and ignore any that are older than Timestamp.
await ti.Subscription.Rules.AddAsync(FilterName, sqlFilterExpression: string.Format("(OriginatorId != '{0}') AND (Timestamp > {1})", ClientSettings.Id, DateTime.UtcNow.ToFileTime()));
}
ti.CancelFlag = false;
Topics[boardId] = ti;
while (!ti.CancelFlag)
{
BrokeredMessage message = await ti.Subscription.ReceiveAndDeleteAsync(TimeSpan.FromSeconds(30));
if (!ti.CancelFlag && message != null)
{
// Everything gets here! :(
}
I get back everything – so I’m not sure what I’m doing wrong. What’s the easiest way to troubleshoot problems with subscription filters?
When you create a Subscription then by default you get a "MatchAll" filter. In the code above you are just adding your filter so it is applied in addition to the "MatchAll" filter and thus all messages are recieved. Just delete the $Default filter once the Subscription is created and that should resolve the issue.
Best way to troubleshoot is using the Service Bus Explorer from Paolo Salvatori
http://code.msdn.microsoft.com/windowsazure/Service-Bus-Explorer-f2abca5a
He has done a good few blog posts on it e.g. http://windowsazurecat.com/2011/07/exploring-topics-and-queues-by-building-a-service-bus-explorer-toolpart-1/
Windows Azure SDK 1.7 does have built in capability but the Service Bus Explorer Standalone version is still better, see comparison here.
http://soa-thoughts.blogspot.com.au/2012/06/visual-studio-service-bus-explorer.html
HTH your debugging...