In microsoft bot framework SDK V3 welcome message gets triggered twice - node.js

I have a bot where the root dialog is a choice prompt(yes/no) which I want to show the user when the bot starts. Below are the code snippets for conversationUpdate and the root dialog. The issue here is when the user clicks yes or no in the root dialog i.e welcome message, the root dialog is triggered second time and it again asks the user to click yes or no. After that the bot is continuing its normal flow but I want the root dialog to trigger only once.
Thanks in Advance
bot.on('conversationUpdate', function (message) {
if (message.membersAdded && message.membersAdded.length > 0) {
message.membersAdded.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
bot.beginDialog(message.address, '/');
}
});
}
});
Root Dialog code:
bot.dialog('/', [
function (session) {
builder.Prompts.choice(session,"some text", ["yes", "no"], { listStyle: builder.ListStyle.button });
},
function (session, results) {
if (results.response.entity == "yes"){
session.send("some text");
}
else if (results.response.entity == "no"){
session.send("some text");
}
session.beginDialog('/nextDialog');
}
]);

This seems to be a known issue
https://github.com/Microsoft/BotBuilder/issues/4387

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}))

imBack payload to resume waterfall

I have a button on my chatbot which once being clicked,
it should resume the dialog to the next step of the waterfall dialog.
I cannot find a payload value that will do that, I tried action?resume and action?next.
[
(session, args, next) => {
let msg = new builder.Message().text('welcome')
.attachments([new builder.HeroCard(session)
.buttons([builder.CardAction.imBack(session, 'next', 'next')])])
session.send(msg);
}, (session, args, next) => {
//I'm here if button clicked - if not, handle somewhere else
}
]
I guess you want to use a hero card to prompt something, i.e. wait for the user to click some button on hero card. Here is the code sample
bot.dialog("/", function(session) {
session.beginDialog("test");
});
bot.dialog("test", [
function(session) {
// create a hero card
let msg = new builder.Message()
.text("welcome")
.attachments([
new builder.HeroCard(session).buttons([
builder.CardAction.imBack(session, "next", "next")
])
]);
// prompt user using hero card
builder.Prompts.text(session, msg);
},
function(session, result) {
// if user clicked some button, then do someting useful
if (result.response === "next") {
// do something, like calling another dialog
} else { // user didn't clicked button, so prompt the hero card again
session.send("please click a button");
session.replaceDialog("test");
}
}
]);

conversationUpdate event not getting user input

I use following method to ask question by bot when user connects first time. But after user answering the question, instead of going to next step bot goes to new dialog.
This works fine with emulator, but not with directline api.
bot.on('conversationUpdate', function (message) {
if (message.membersAdded) {
message.membersAdded.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
bot.beginDialog(message.address, '/startConversation');
}
});
}
});
bot.dialog('/startConversation', [
function (session) {
builder.Prompts.text(session, 'I\'m the SPF VA Assistant. How may I address you?');
},
function (session, results) {
session.userData.name = results.response;
session.send('Hi, %s, Please choose one of the options below to lodge a Police report.', session.userData.name);
var cards = getReportsAsCards();
var reportOptions = new builder.Message(session)
.attachmentLayout(builder.AttachmentLayout.carousel)
.attachments(cards);
session.send(reportOptions).endDialog();
}
]);
After you send the question "Please choose one of the options below..." you are calling endDialog(). This is what causes it to go to the new dialog like you said.
If you want to prompt the user for input, use a Choice Prompt, and add another step in your waterfall dialog to handle the user's choice input.
For example, to get the user's name, first ask the question using a text prompt, then handle the user's response in step 2 of the waterfall dialog. The user's response text will be available in the results.response object in step 2.
bot.dialog('greetings', [
// Step 1
function (session) {
builder.Prompts.text(session, 'Hi! What is your name?');
},
// Step 2
function (session, results) {
session.endDialog('Hello %s!', results.response);
}
]);
To prompt the user with a series of choices use a waterfall dialog combined with a builder.Prompts.choice() call. For example:
var noiseComplaintName = "Noise Complaint";
var trashDumpingName = "Trash Dumping";
var weirdSmellName = "Weird Smell";
var trafficSignalName = "Traffic Signal";
var reportTypes = [
noiseComplaintName,
trashDumpingName,
weirdSmellName,
trafficSignalName
];
bot.dialog('pick-report-type', [
function(session) {
session.send('Choice prompt example:');
var promptOptions = {
listStyle: builder.ListStyle.button
};
builder.Prompts.choice(session, "What do you want to report?", reportTypes, promptOptions);
},
function (session, results) {
// handle response from choice prompt
var selectedReportType = results.response.entity;
switch (selectedReportType) {
case noiseComplaintName:
// handle response here
break;
case trashDumpingName:
// handle response here
break;
case weirdSmellName:
// handle response here
break;
case trafficSignalName:
// handle response here
break;
default
// handle response here
break;
}
}
]);
For a more detailed example that combines prompts with Rich Cards, check out the sample code: BotBuilder-Samples/Node/cards-RichCards on GitHub.

What are "custom prompts" in the Microsoft Bot Framework?

Since version 3.8, the Bot Framework now includes a handful of messages like this one:
DialogAction.validatedPrompt() has been deprecated as of version 3.8. Consider using custom prompts instead.
I don't see any mention of this in the documentation. What are "custom prompts," and where can I learn more about how they improve on the deprecated functionality?
You can find an example on the Git Hub here. The code provided in there can be found in the example is below:
// Create a recognizer for your LUIS model
var recognizer = new builder.LuisRecognizer('<model>');
// Create a custom prompt
var prompt = new builder.Prompt({ defaultRetryPrompt: "I'm sorry. I didn't recognize your search." })
.onRecognize(function (context, callback) {
// Call prompts recognizer
recognizer.recognize(context, function (err, result) {
// If the intent returned isn't the 'None' intent return it
// as the prompts response.
if (result && result.intent !== 'None') {
callback(null, result.score, result);
} else {
callback(null, 0.0);
}
});
});
// Add your prompt as a dialog to your bot
bot.dialog('myLuisPrompt', prompt);
// Add function for calling your prompt from anywhere
builder.Prompts.myLuisPrompt = function (session, prompt, options) {
var args = options || {};
args.prompt = prompt || options.prompt;
session.beginDialog('myLuisPrompt', args);
}
// Then call it like a builtin prompt:
bot.dialog('foo', [
function (session) {
builder.Prompts.myLuisPrompt(session, "Please say something I recognize");
},
function (session, results) {
switch (results.response.intent) {
case 'Bar':
break;
}
}
]);
`

Exiting CommandDialog by a user

I'm trying to find a way exiting a CommandDialog dialog by a user when using back or cancel or otherwise changes their mind.
var startCommands = new builder.CommandDialog();
bot.add('/', [
function (session, results) {
session.send('Hello %s', session.userData.name);
// starting a dialog based on CommandDialog
session.beginDialog('/begin');
},
function (session, results) {
// This is where I want to be when dialog cancel of back is initiated by a user inside /begin
session.send("you are back at the main dialog, start finshing process")
session.beginDialog('/finish');
}
]);
// defining a dialog for CommandDialog class
bot.add('/begin', startCommands)
bot.add('/finish', finishCommands)
startCommands.matches('yo', [
function (session) {
session.send('yo-yo');
}
]);
startCommands.matches('tu', [
function (session) {
session.send('tu-tu');
}
]);
startCommands.matches('.*', [
function (session) {
session.send('any-any');
session.endDialog();
}
]);
To exit a dialog, CommandDialog or otherwise, use a triggerAction on a dialog handler that calls session.endConversation().
For example, here is an exit dialog which ends the conversation when the user sends the message exit or quit.
bot.dialog('exit', function (session) {
session.endConversation('Goodbye!');
}).triggerAction({ matches: /(quit|exit)/i });

Resources