disable qna recognizer when inside a dialog - node.js

I am using Luis and QnA maker, qna maker is now interupting a waterfall prompt. I have disabled the Luis prompt with code below, how can I to do same for the qna recognizer?
var recognizer = new
builder.LuisRecognizer(LuisModelUrl).onEnabled(function (context,
callback) {
var enabled = context.dialogStack().length == 0;
callback(null, enabled);
});
bot.recognizer(recognizer);
bot.recognizer(qnaRecognizer);
console.log(recognizer);
eg: What part of the toilet is broken? (1. Cistern, 2. Pipe, or 3. Seat)
Anything except an exact match gets picked up by qna sentiment which replaces the dialog stack
Thanks

You shouldn't have to disable either one for the code to work. I suspect the problem is in your dialog flow. Below is an example of how to construct the dialog portion of your bot. When I ran this, the logger middleware shows QnA is matching on the inputs I feed, but the bot is dictating the conversation because of the code.
var luisrecognizer = new builder.LuisRecognizer(LuisModelUrl);
var qnarecognizer = new cognitiveservices.QnAMakerRecognizer({
knowledgeBaseId: process.env.QnAKnowledgebaseId,
authKey: process.env.QnAAuthKey || process.env.QnASubscriptionKey,
endpointHostName: process.env.QnAEndpointHostName
});
var basicQnAMakerDialog = new cognitiveservices.QnAMakerDialog({
recognizers: [qnarecognizer],
defaultMessage: 'No match! Try changing the query terms!',
qnaThreshold: 0.3
});
bot.recognizer(luisrecognizer);
bot.recognizer(basicQnAMakerDialog);
bot.dialog('/', basicQnAMakerDialog);
bot.dialog('GreetingDialog',[
(session) => {
session.send('You reached the Greeting intent. You said \'%s\'.',
session.message.text);
builder.Prompts.text(session, "What is your name?");
},
(session, results) => {
session.userData.name = results.response;
session.send("Glad you could make it, " + session.userData.name);
builder.Prompts.text(session, "Ask me something!");
},
(session, results) => {
session.conversationData.question = results.response;
session.send(session.conversationData.question + " is an interesting topic!")
session.endDialog();
}
]).triggerAction({
matches: 'Greeting'
})
In the following image, LUIS brings me to the Greeting intent when I type "I'm happy [to be here]" which I have trained in the LUIS app. The bot dialog takes over asking me questions and storing the answers. Even though I'm making statements that QnA or LUIS should respond to neither is doing so. The conversation follows the code.
Had Qna taken over it would have responded to "What are you" with some text about QnA Maker. Similarly, "help" would have produced responses from either QnA or LUIS as I have topics/intents for both, respectively.

Related

How do I handle "cancel" intent when already in a dialog?

In Microsoft Bot Framework, I already started a conversation and have some intent running, let's say "login", but then while I ask the user for username or password, he might say "cancel that" or "cancel login", how do I get this intent: "cancel" and how do I handle it by cancelling out of the current dialog?
// Login Dialog
bot.dialog('login', [
(session:Builder.Session) => {
Builder.Prompts.text(session, 'What\'s your account email?');
},
(session:Builder.Session, results: any) => {
session.dialogData.email = results.response;
Builder.Prompts.text(session, 'What\'s your password?');
},
(session:Builder.Session, results: any) => {
session.dialogData.passWord = results.response;
CheckAccountLogin(session, session.dialogData.email,session.dialogData.passWord)
.then((result:boolean)=>{
if(result === true){
session.send('Login Successful');
session.userData.loginSuccessful = true;
session.userData.email = session.dialogData.email;
}else{
session.userData.loginSuccessful = false;
}
session.endDialog();
});
},
]);
Refer to this article: https://learn.microsoft.com/en-us/azure/bot-service/nodejs/bot-builder-nodejs-recognize-intent-messages?view=azure-bot-service-3.0
You can basically register a CancelIntent recognizer that will cause the conversation to forwarded the dialog you want then triggered. For example:
bot.recognizer(new builder.RegExpRecognizer(
"CancelIntent",
{ en_us: /^(cancel|nevermind)/i, ja_jp: /^(キャンセル)/ })
);
This uses a regular expression to detect when the user wants to cancel, and one way to cancel the current dialog would be just to end the conversation:
bot.dialog('CancelDialog', function (session) {
session.endConversation("Ok, cancelling loggin.");
}).triggerAction({ matches: 'CancelIntent' });
Notice that the code above tells the bot framework to end the conversation, so the login dialog will end thus cancelling the action.
Here are some useful samples too: https://github.com/Microsoft/BotBuilder-Samples/blob/master/Node/intelligence-LUIS/app.js
Edit
To set up a Luis intent recognizer you first need to remove the previously registered RegexRecognizer and then create a new instance of the LuisRecognizer by doing:
// Make sure you add code to validate these fields
var luisAppId = process.env.LuisAppId;
var luisAPIKey = process.env.LuisAPIKey;
var luisAPIHostName = process.env.LuisAPIHostName || 'westus.api.cognitive.microsoft.com';
const LuisModelUrl = 'https://' + luisAPIHostName + '/luis/v2.0/apps/' + luisAppId + '?subscription-key=' + luisAPIKey;
// Create a recognizer that gets intents from LUIS, and add it to the bot
var recognizer = new builder.LuisRecognizer(LuisModelUrl);
And then register the Luis recognizer with:
bot.recognizer(recognizer);
Your CancelDialog should look the same, it will match the intent with the triggerAction.matches:
bot.dialog('CancelDialog', function (session) {
session.endConversation("Ok, cancelling loggin.");
}).triggerAction({ matches: 'CancelIntent' });
Once you have that setup create the CancelIntent in your Luis App, add some sample utterances to it (at least three) and the conversation should automatically forward to the CancelDialog once the CancelIntent is detected.
There's more info about that here: https://learn.microsoft.com/en-us/azure/bot-service/nodejs/bot-builder-nodejs-recognize-intent-luis?view=azure-bot-service-3.0
Another way to do it is to use the built in cancel event. Luis would still work. This is based on Javier's answer:
// Setup Luis Recognizer first:
const LuisModelUrl = 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/' + LuisID + '?subscription-key=' + LuisKey;
var recognizer = new Builder.LuisRecognizer(LuisModelUrl);
bot.recognizer(recognizer);
// Dialog definition
bot.dialog('login', [
(session:Builder.Session) => {
// Your dialog stuff here
}
]).cancelAction(
"Cancel", "What would you like to do next?",
{
matches: "Cancel",
confirmPrompt: "This will cancel your dialog. Are you ure?"
}
);

How to integrate LUIS and QnA Maker services in single Node.js bot?

I'm developing a chatbot using Microsoft Bot Framework with Node.js SDK. I've integrated LUIS and QnA maker but I want to create this scenario if it's possible. Taking in example the following link and in particular this section:
There are a few ways that a bot may implement a hybrid of LUIS and QnA Maker:
Call LUIS first, and if no intent meets a specific threshold score, i.e., "None" intent is triggered, then call QnA Maker. Alternatively, create a LUIS intent for QnA Maker, feeding your LUIS model with example QnA questions that map to "QnAIntent."
Just an example:
I have my QnA KB in which I have a pair : " who are you?" / "Hi I'm your bot! " . Then I have my Luis app that recognize this intent called "common" .
So, if I write to my bot: " who are you?" it will answer "Hi I'm your bot! "
Instead, if I write " tell me who you are" it recognize the LUIS intent related to the question but it will not answer "Hi I'm your bot! " like I imagine.
So what I imagine is: I ask the question "Tell me who you are" --> the bot triggers the intent common (LUIS) --> then I want that the bot will answer me looking into the QnA KB --> "Hi I'm your bot! "
Is it possible?
Hope this code could help:
var intents = new builder.IntentDialog({ recognizers[luisRecognizer,qnarecognizer] });
bot.dialog('/', intents);
intents.matches('common_question', [
function (session, args, next) {
session.send('Intent common');
qnarecognizer.recognize(session, function (error, result) {
session.send('answerEntity.entity');
});
}
]);
You will have to forward the user message to QnaMaker from the method/dialog associated to the intent detected by LUIS. Take a look to this article (https://blog.botframework.com/2017/11/17/qna-maker-node-js-bots/) to find how implement QnAMaker in Node.js
Something like:
var recognizer = new cognitiveservices.QnAMakerRecognizer({
knowledgeBaseId: 'set your kbid here',
subscriptionKey: 'set your subscription key here'});
var context = session.toRecognizeContext();
recognizer.recognize(context, function (error, result) { // your code... }
You should explore the samples also and try to understand how everything works: https://github.com/Microsoft/BotBuilder-CognitiveServices/tree/master/Node/samples/QnAMaker
If you vary a lot your question; could be possible that QnA won't detect the question you expected and in that case you will have to train your KB more (like you do in LUIS with the utterances/intents)
I wrote this because I want more practice with node and this was an excuse to use node, but what Ezequiel is telling you is completely correct. I'll also post on your GitHub issue. This is a functioning node app that does what you need
var builder = require('botbuilder');
var restify = require('restify');
var cog = require('botbuilder-cognitiveservices');
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log('%s listening to %s', server.name, server.url);
});
var connector = new builder.ChatConnector({
appId: "APP ID",
appPassword: "APP PASSWORD"
});
server.post('/api/messages', connector.listen());
var bot = new builder.UniversalBot(connector, function(session) {
session.send('Sorry, I did not understand \'%s\'. Type \'help\' if you need assistance.', session.message.text);
});
var recognizer = new builder.LuisRecognizer("https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/{LUIS APP ID}?subscription-key={LUIS KEY}&verbose=true&timezoneOffset=0&q=");
bot.recognizer(recognizer);
var qnaRecognizer = new cog.QnAMakerRecognizer({
knowledgeBaseId: 'QNA APP ID',
subscriptionKey: 'QNA SUBSCRIPTION KEY'
});
bot.dialog('Common', function(session) {
var query = session.message.text;
cog.QnAMakerRecognizer.recognize(query, 'https://westus.api.cognitive.microsoft.com/qnamaker/v2.0/knowledgebases/{QNA APP ID}}/generateAnswer', '{QNA SUBSCRIPTION KEY}', 1, 'intentName', (error, results) => {
session.send(results.answers[0].answer)
})
}).triggerAction({
matches: 'Common'
});
As of 2018 (BotBuilder V4)
You can now use the Dispatch Command Line tool to dispatch intent across multiple bot modules such as LUIS models and QnA.
So first you will get to LUIS app that will decide based on the score to redirect to another LUIS app or to a QnA.
Dispatch Tool
Example using LUIS as dispatch service

Use multiple QnA services in one bot

I have multiple QnA services running, each with it's own knowledgeBaseId and subscriptionKey. I want to use them both in a single chatbot and I've written a piece of code which takes the user input and assigns the correct Knowledgebase details. However, I'm unable to get the 2nd QnA service to become active and the bot is linking only to the first service. What might be going wrong here?
Sample code:
var knowledgeId = "FIRST_QNA_SERVICE_KNOWLEDGE_ID";
var subscriptionId = "FIRST_QNA_SERVICE_SUBSCRIPTION_ID";
var bot = new builder.UniversalBot(connector);
var qnarecognizer = new cognitiveservices.QnAMakerRecognizer({
knowledgeBaseId: knowledgeId,
subscriptionKey: subscriptionId,
qnaThreshold:0.3,
top:1});
var intentrecognizer = new builder.IntentDialog();
var intents = new builder.IntentDialog({ recognizers: [intentrecognizer, qnarecognizer] });
bot.dialog('/', intents);
intents.matches('qna', [
function (session, args, next) {
args.entities.forEach(function(element) {
session.send(element.entity);
}, this);
}
]);
intents.matchesAny([/hi/i, /main menu/i], [
function (session) {
builder.Prompts.choice(session, "Hi, What would you like to ask me about?", ["Service1","Service2"],{ listStyle: builder.ListStyle.button});
},
function (session, result) {
var selection = result.response.entity;
switch (selection) {
case "Service1":
knowledgeId = "FIRST_QNA_SERVICE_KNOWLEDGE_ID";
subscriptionId = "FIRST_QNA_SERVICE_SUBSCRIPTION_ID";
session.send('You can now ask me anything about '+selection+'. Type \'main menu\' anytime to choose a different topic.')
session.endConversation();
return
case "Service2":
knowledgeId = "SECOND_QNA_SERVICE_KNOWLEDGE_ID";
subscriptionId = "SECOND_QNA_SERVICE_SUBSCRIPTION_ID";
session.send('You can now ask me anything about '+selection+'. Type \'main menu\' anytime to choose a different topic.')
session.endConversation();
return
}
}
])
You never updated the knowledgeId/subscriptionId on the QnAMakerRecognizer... that's the reason you are always seeing the first QnA service being called.
See if there is a way to update those values in the QnAMakerRecognizer.
Check out if my answer is valid to your purpose on this question:
Multiple QnA Maker services for a single bot
Hope you find it useful.

dialogs in botframework using LUIS.ai

I have a piece of code that works perfectly on my local bot, and weird when integrated with LUIS. It's a simple dialogue that redirects to another dialog:
// Modelo de datos cargado en luis.ai
var recognizer = new builder.LuisRecognizer(process.env.LUIS_MODEL_URL);
bot.recognizer(recognizer);
//first intent, greeting intent to say hi to the user
bot.dialog('greetings', [
function (session) {
var greetings = ["¡Hola!", "Bonjour amigo!", "zdravstvuyte! (Así se dice hola en ruso)"];
var pickAGreeting = function () {
var rnd_greeting = greetings[Math.floor(Math.random() * 4)];
return rnd_greeting;
};
session.send(pickAGreeting(), session.message.text);
builder.Prompts.text(session, 'What can I do for you about Office?');
},
function (session, results) {
var user_response = results.response;
session.beginDialog('getProductoOffice', user_response);
}
]).triggerAction({
matches: 'greetings',
onInterrupted: function (session) {
session.send('Can I help you with something?');
}
});
bot.dialog('getProductoOffice', [
function (session, args) {
session.send('Welcome to O365 help!', session.message.text);
...
And the bot does this:
[me]: Hola
[bot]: ¡Hola!
[bot]: What can I do for you about Office?
[me]: Tell me about Skype
[bot]: Can I help you with something?
The weird thing is that after prompting me about Office, it never enters the "function (session, results)" and goes directly into the interrupted dialogue code.
This piece of code works perfectly without LUIS integration and moves correctly between dialogues.
The dialog was interrupted every time I entered an utterance recognized by LUIS because of the triggerAction behavior.
To disable the recognizer when a task is running I had to use the method onEnabled in the recognizer as follows:
var recognizer = new builder.LuisRecognizer('<model>').onEnabled(function (context, callback) {
var enabled = context.dialogStack().length == 0;
callback(null, enabled);
});
This won't interrupt the dialog stack and the recognizer will work only when there is no conversation running.

How can I integrate my MS text bot program written in NodeJS to skype bot?

I'd like to develop a skype bot that would take user name as input and say hello username in the opposite char case based on the user input. In brief, if the user types his name as james, my bot would respond to him as Hello JAMES. The program runs fine, however I am finding it ambiguous to integrate my textbot program to skype bot.
Here's my code:
var builder = require('botbuilder');
var helloBot = new builder.TextBot();
helloBot.add('/', [
function (session, args, next) {
if (!session.userData.name) {
session.beginDialog('/profile');
} else {
next();
}
},
function (session, results) {
session.send('Hello %s!', session.userData.name);
}
]);
helloBot.add('/profile', [
function (session) {
builder.Prompts.text(session, 'Hi! What is your name?');
},
function (session, results) {
if(results.response == results.response.toUpperCase())
{
//console.log("in if");
session.userData.name = results.response.toLowerCase();
}
else
{
//console.log("else");
session.userData.name = results.response.toUpperCase();
}
session.endDialog();
}
]);
console.log("Hi!");
helloBot.listenStdin();
The output would be like :
bot : Hi
user: Hello.
bot : What is your name?
user: james.
bot : Hello JAMES.
To create a chat bot compatible with Skype, use the UniversalBot type instead of TextBot. You can find sample code that demonstrates how to send different card types in BotBuilder-Samples/Node/cards-RichCards.
To configure your bot to work with Skype, login to the Bot Portal at https://dev.botframework.com and register your bot. After your bot is registered, go to 'My bots', click on your bot name, and you will see the 'Channels' section with Skype and WebChat enabled by default. Under 'Test link', click the 'Add to Skype' button. This will redirect you to the Skype website where it will ask you to confirm that you want to add the Skype bot to your Skype contacts.
For more information on Skype bots check out the Getting Started Guide.

Resources