How to get results from Prompt in Bot Framework Dialog - node.js

I am trying to get the response to builder.Prompt.choice(...); The list of choices gets loaded and when I make a choice nothing happens.
But it doesn't seems like function(session, results) ever gets executed.
session.send("Choice Made) and the other code doesn't get executed. How can I get my response. I'm not sure what is going wrong here. It looks just like code from the docs.
bot.dialog('LifecycleDialog', function (session, args) {
var softwareEntity = builder.EntityRecognizer.findEntity(args.intent.entities, 'Software');
var choices = Object.keys(SoftwareDict[softwareEntity.entity]);
builder.Prompts.choice(session, "Select a version by typing the number: ", choices, "Sorry I don't see that version.");
},
function (session, results) {
session.send("Choice Made"); //DOES NOT WORK
session.endDialogWithResult(results); //DOES NOT WORK
}).triggerAction({
matches: 'LifecycleStatus'
});

You should put the square brackets at the beginning of the functions part i.e. after the comma
Like " 'LifecycleDialog', [ function (session, args) "
bot.dialog('LifecycleDialog', [
function (session, args) {
var softwareEntity = builder.EntityRecognizer.findEntity(args.intent.entities, 'Software');
var choices = Object.keys(SoftwareDict[softwareEntity.entity]);
builder.Prompts.choice(session, "Select a version by typing the number: ", choices, "Sorry I don't see that version.");
},
function (session, results) {
session.send("Choice Made"); //DOES NOT WORK
session.endDialogWithResult(results); //DOES NOT WORK
}
]).triggerAction({
matches: 'LifecycleStatus'
});

I figured it out. The only difference is the dialog should have brackets [] instead of curly braces {}.
bot.dialog('LifecycleDialog', function (session, args) [
var softwareEntity = builder.EntityRecognizer.findEntity(args.intent.entities, 'Software');
var choices = Object.keys(SoftwareDict[softwareEntity.entity]);
builder.Prompts.choice(session, "Select a version by typing the number: ", choices, "Sorry I don't see that version.");
},
function (session, results) {
session.send("Choice Made"); //DOES NOT WORK
session.endDialogWithResult(results); //DOES NOT WORK
]).triggerAction({
matches: 'LifecycleStatus'
});

Related

Azure bot Nodejs Function calls

I am trying to call a dialog in the bot which has to go to specific function, Here is the scenario...
I have a dialog bot as shown below
bot.dialog('/Welcome', [
function(session){
builder.Prompts.text(session, "Welcome to the Bot");
},
function (session, args) {
// Has some code
},
function (session, args){
//has some code
}......
When ever i do replace dialog ie.
bot.replaceDialog('/Welcome')
it should not go to the first function ie. Welcome to the Bot It should skip this and go to next function.
Is there any way to accomplish this in azure bot?
This is quite simple if you look at their article
https://learn.microsoft.com/en-us/azure/bot-service/nodejs/bot-builder-nodejs-dialog-replace
Their example is like below
// This dialog prompts the user for a phone number.
// It will re-prompt the user if the input does not match a pattern for phone number.
bot.dialog('phonePrompt', [
function (session, args) {
if (args && args.reprompt) {
builder.Prompts.text(session, "Enter the number using a format of either: '(555) 123-4567' or '555-123-4567' or '5551234567'")
} else {
builder.Prompts.text(session, "What's your phone number?");
}
},
function (session, results) {
var matched = results.response.match(/\d+/g);
var number = matched ? matched.join('') : '';
if (number.length == 10 || number.length == 11) {
session.userData.phoneNumber = number; // Save the number.
session.endDialogWithResult({ response: number });
} else {
// Repeat the dialog
session.replaceDialog('phonePrompt', { reprompt: true });
}
}
]);
So yours would be something like below
bot.dialog('/Welcome', [
function(session, args, next){
if (!args || args.prompt)
builder.Prompts.text(session, "Welcome to the Bot");
else
next();
},
function (session, args) {
// Has some code
},
function (session, args){
//has some code
}......
and you will call it like below
bot.replaceDialog('/Welcome', {prompt: false}))

Azure Bot NodeJS wait for other dialog to be finished

I'm currently building a chatbot with Azure's Bot service. I use a NLU-Bot, mixed with a waterfall flow, because dependent on the intent I want to get some specific information.
Therefore I match the intent1 and want to
var intents = new builder.IntentDialog({ recognizers: [recognizer] })
.matches('intent1', (session, args, results) =>{
session.beginDialog("getRequiredInformations");
session.send("I received your information");
})
bot.dialog('getRequiredInformations', [
(session) =>{
var levels = ['Beginner', 'Intermediate', 'Expert'];
builder.Prompts.choice(session, "What's your level ?", levels, { listStyle: builder.ListStyle.button, maxRetries: 0 });
},
(session, results) => {
session.conversationData.level = results.response.entity;
}
]);
What I want to do is to wait until we received the answer from the getRequiredInformations dialog and then continue with the original dialog containing the recognized intent. With the code above the session.send("I received your information");is sent before the user entered an answer.
I also tried with bot.beginDialogAction('getRequiredInformations', 'getRequiredInformations'); but I think it's not possible to call this inside the dialog.
How am I able to achieve this?
Found there several misstakes in your code snippet, please refer the following modification:
bot.dialog('intent1', [(session, args, next) => {
session.beginDialog("getRequiredInformations");
}, (session, args, next) => {
session.send("I received your information");
session.send(session.conversationData.level)
}]).triggerAction({
matches: 'intent1'
})
bot.dialog('getRequiredInformations', [
(session) => {
var levels = ['Beginner', 'Intermediate', 'Expert'];
builder.Prompts.choice(session, "What's your level ?", levels, {
listStyle: builder.ListStyle.button,
maxRetries: 0
});
},
(session, results) => {
session.conversationData.level = results.response.entity;
session.endDialog();
}
]);
But this means there is not really an opportunity to wait for the dialog to finish like a callback or anything, I need to do this with a waterfall?
If I understand correct, you can try to use the following code snippet to enable the luis recognizer only if there is no dialog in stack.
var recognizer = new builder.LuisRecognizer(luisAppUrl)
.onEnabled(function (context, callback) {
var enabled = context.dialogStack().length == 0;
callback(null, enabled);
});
Move the send to next waterfall step of the intent1 dialog. I think this should work.
var intents = new builder.IntentDialog({ recognizers: [recognizer] })
.matches('intent1', [(session, args, results) =>{
session.beginDialog("getRequiredInformations");
}, (session, args, results) =>{
session.send("I received your information");
}]);
matches method takes IWaterfallStep or IWaterfallStep[]. More info here.

Azure Botframework: How to re-prompt the Prompt.text if user responds with invalid value

I have a single dialog which has multiple Prompts(Prompts.text, Prompts.number, Prompts.Choice, Prompts.confirm). Though Prompts.choice and Prompts.confirm seems to have inbuilt validations but how to validate Prompts.text?
I have gone through this thread How to handle wrong input from the user? but it was rectified by converting text into choice.
Also I do not want to restart the whole dialog as it ask the questions form beginning then as shown in create custom prompts to validate input
Here is shorter version for my dialog:
bot.dialog('/getDetails', [
function (session, args, next) {
let options = {
retryPrompt: 'The response id invalid'
}
builder.Prompts.text(session, 'What is your full name?', options);
//passing options as argument works for Prompts.choice, which seems an inbuilt validation
},
function (session, results, next){
var name = session.dialogData.name;
//How to to reprompt if user does not enters its full name?
if (results.response) {
name.fullname = results.response;
}
builder.Prompts.text(session, 'Can you please provide your country name?');
},
function (session, results) {
var name = session.dialogData.name;
//How to reprompt only last Prompts.text if user enter an invlid value?
if (results.response) {
name.text = results.response;
}
}
}]).triggerAction({
matches: 'GetDetails',
})
Here is how i solved it through DialogAction.validatedPrompt
bot.dialog('/getDetail', [
function (session) {
session.beginDialog('/validateAge', { prompt: "What's your age?" });
//if false response, then prmopts "I did not understand {age}""
},
function (session, results) {
if (results.response) {
session.send("Thank you for adding your age");
}
}
]).triggerAction({
matches: /^lets validate$/i
})
bot.dialog('/validateAge', builder.DialogAction.validatedPrompt(builder.PromptType.text, function (response) {
if(response> 0 && response < 70){
return response;
}
}));

How to use Waterfall process in Nodejs using LUIS

I have LUIS app created, with 1 intent(Order Pizza) and 9 entities(Order,Kind, Signature, Size, Toppings, address, Time, Duration, Range).
I need to create a bot in Azure Bot Framework. I'm unable to understand and use the waterfall for all the entities. Please let me know how to go about it
Code :
dialog.matches('OrderPizza', [
function (session, args, next) {
var order = builder.EntityRecognizer.findEntity(args.entities, 'order');
var kind = builder.EntityRecognizer.findEntity(args.entities, 'Kind');
session.dialogData.intentScore = args.score;
if (!order) {
builder.Prompts.text(session, 'welcome please order pizza');
} else {
session.dialogData.order = order;
next();
}
},
function (session, results) {
var order = session.dialogData.order;
if (results.response) {
session.send('what kind?');
}else{
session.send(`we don't have that kind of pizza`);
}
}
]);
How to go further for other entities?
I'm not sure what you mean by only being able to write 2 functions; but if you're trying to call LUIS inside of your dialog you can follow this example. You'll call a LuisRecognizer inside your waterfall step on session.message.text. The snippet from the example is below:
builder.LuisRecognizer.recognize(session.message.text, '<model url>', function (err, intents, entities) {
if (entities) {
var entity = builder.EntityRecognizer.findEntity(entities, 'TYPE');
// do something with entity...
}
});
This would allow you to call LUIS inside a waterfall for recognizing your user's messages.
Regarding your code there is a number of issues:
// Original Code
dialog.matches('OrderPizza', [
function (session, args, next) {
var order = builder.EntityRecognizer.findEntity(args.entities, 'order');
var kind = builder.EntityRecognizer.findEntity(args.entities, 'Kind');
session.dialogData.intentScore = args.score;
if (!order) { // What about kind?
builder.Prompts.text(session, 'welcome please order pizza');
} else {
session.dialogData.order = order; // What about kind?
next();
}
},
function (session, results) {
var order = session.dialogData.order;
if (results.response) {
session.send('what kind?');
}else{
session.send(`we don't have that kind of pizza`);
}
}
]);
In your first waterfall step you're not saving the "Kind" entity to your dialogData.
function (session, args, next) {
var order = builder.EntityRecognizer.findEntity(args.entities, 'order');
var kind = builder.EntityRecognizer.findEntity(args.entities, 'Kind');
session.dialogData.intentScore = args.score;
if (kind) {
session.dialogData.kind = kind;
}
if (!order) {
builder.Prompts.text(session, 'welcome please order pizza');
} else {
session.dialogData.order = order;
next();
}
}
In your second waterfall step you are not calling next, nor are you sending a Prompt to the user, which results in you being stuck after two functions.
function (session, results, next) {
var order = session.dialogData.order ? session.dialogData.order : results.response;
var kind = session.dialogData.kind;
if (results.response && !kind) {
builder.Prompts.text(session, 'what kind?');
} else {
session.send('we don\'t have that kind of pizza');
next();
}
}

How to validate phone number in bot framework?

I'm using following code to get user input for a phone number. I want to validate user input and if it is incorrect, need to ask the user to enter again.
[function (session, results, next) {
builder.Prompts.text(session, 'I will also need to know your contact number.');
}
,function (session, results, next) {
session.userData.contactNo = results.response;
next();
}]
I tried this example, but it gives a warning saying it is deprecated. Appreciate any help regarding the correct way to do this(without using the deprecated method). My phone number regex is ^[689]\d{3}\s?\d{4}$
There is an interesting sample in the documentation:
bot.dialog('/phonePrompt', [
function (session, args) {
if (args && args.reprompt) {
builder.Prompts.text(session, "Enter the number using a format of either: '(555) 123-4567' or '555-123-4567' or '5551234567'")
} else {
builder.Prompts.text(session, "What's your phone number?");
}
},
function (session, results) {
var matched = results.response.match(/\d+/g);
var number = matched ? matched.join('') : '';
if (number.length == 10 || number.length == 11) {
session.endDialogWithResult({ response: number });
} else {
session.replaceDialog('/phonePrompt', { reprompt: true });
}
}
]);
Here you can see that in the function handling the result, they are performing some checks and then if not valid they are doing a replaceDialog with a reprompt parameter.
You may try the same here with your business logic (ie: doing your regex check instead of the number length check in the sample)

Resources