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}))
Related
I have a bot dialog which asks a user for an order id:
bot.dialog("orderId", [
(session, args, next) => {
return builder.Prompts.text(session, "Please provide order id");
},
(session, results, next) => {
const matched = results.response.match(/\d{3}-?\d{7}/g);
if (matched) {
// ...
session.endDialogWithResult(matched);
} else {
// ...
}
}
]);
This works as expected when user enters a valid order id and has validation
code which is omitted.
The problem i am facing is that users from time to time upload a screenshot
of the order id which triggers a default action which is just to re-prompt with a system prompt.
I know i can use retryPrompt property if the IPromptOptions interface, but this does not solve my issue.
I want to be able to start another dialog or end the conversation.
Any ideas how should i make this work ?
Edit:
In another case instead of saying "Yes" or any other positive phrase, user replies to Prompts.text with a "Thumbs Up" image from Facebook Messenger. which will also break Prompts.text flow.
I want to be able to treat the "Thumbs Up" image as a positive answer
to my question and control conversation flow according to that.
As build-in Prompts will create a individual dialog, and Prompts.text() will verify the user input strictly for string type only, when you upload an image file to bot, which will not be verified by Prompts.text() dialog, and that raises your issue.
You can consider to add an step for your user to choice one approch to verify the code (by inputing code string, or uploading code picture).
var bot = new builder.UniversalBot(connector, [
(session) => {
const choices = ['code', 'image'];
var msg = new builder.Message(session)
.text("Which will you prefer to provide your code?")
.suggestedActions(
builder.SuggestedActions.create(
session, [
builder.CardAction.imBack(session, "code", "By Code"),
builder.CardAction.imBack(session, "image", "By Image")
]
)
);
builder.Prompts.choice(session, msg, choices);
}, (session, args, next) => {
const type = args.response.entity;
session.send(`Your choice is ${type}`);
if (type == 'code') {
session.replaceDialog('verifyCode')
} else {
session.replaceDialog('verifyAttachmenet')
}
}
]);
bot.dialog('verifyCode', [(session) => {
builder.Prompts.text(session, 'Input your code');
}, (session, args, next) => {
session.send(args.response);
session.endDialog();
}])
bot.dialog('verifyAttachmenet', [(session) => {
builder.Prompts.attachment(session, 'update your image');
}, (session, args, next) => {
session.send(`You upload ${args.response.length} images`);
session.endDialogWithResult(args.response);
}])
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;
}
}));
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.
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();
}
}
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)