I am using node js, I want to call luis dialog("morningUpdate") from
general dialog("work")
dialog.matches('morningUpdate',[
function (session, args, next) {
}
]);
bot.dialog('/work', [
function (session, args) {
//how to call here "morningUpdate" dialog
}
]);
how we can achieve this.
To call a new dialog, you can just use session.beginDialog('nameOfDialog');. Take a look at the basic and advanced Multi Dialogs samples.
If you need a LUIS sample, take a look at this one.
here is actual answer
link for code
dialog.matches('morningUpdate', 'morningUpdate');
bot.dialog('morningUpdate', [
function (session, args, next) {
}
]);
Related
I've created a chatbot using Node.js and the flow of dialogs works fine til the endDialog. Im having issues implementing a back option so it can jump back only to previous dialog. Can anyone please guide me how to solve that?
.reloadAction(
"restartBenefits", "Ok. Let's start over.",
{
matches: /^start over$|^restart$/i
}
)
.cancelAction(
"cancelRequest", "Thank you for reaching out, Good bye!",
{
matches: /^nevermind$|^cancel$|^cancel.*request/i,
confirmPrompt: "This will cancel your request. Are you sure?"
}
);
Use a customAction
In this case you can listen for whatever you want to be a keyword for "back" and then simply route the user back to that dialog using replaceDialog
bot.customAction({
matches: /back|last/gi, //whatever prompts you want to match.
onSelectAction: (session, args, next) => {
session.replaceDialog(PreviousDialog); //variable with the last dialog in it, set that somewhere, such as the end of your previous dialog
}
})
I think that at the final step of the dialog waterfall you need to add the last lines in this sample step:
/**
* This is the final step in the main waterfall dialog.
* It wraps up the sample "book a flight" interaction with a simple confirmation.
*/
async finalStep(stepContext) {
// If the child dialog ("bookingDialog") was cancelled or the user failed to confirm, the Result here will be null.
if (stepContext.result) {
const result = stepContext.result;
// Now we have all the booking details.
// This is where calls to the booking AOU service or database would go.
// If the call to the booking service was successful tell the user.
const timeProperty = new TimexProperty(result.travelDate);
const travelDateMsg = timeProperty.toNaturalLanguage(new Date(Date.now()));
await stepContext.context.sendActivity(ActivityFactory.fromObject(this.lgTemplates.evaluate('BookingConfirmation', {
Destination: result.destination,
Origin: result.origin,
DateMessage: travelDateMsg
})));
}
// =====> HERE: Restart the main dialog with a different message the second time around
return await stepContext.replaceDialog(this.initialDialogId, { restartMsg: 'What else can I do for you?' });
}
Just change the this.initialDialogId accordingly.
Note
I am using Microsoft Botbuilder SDK in node.js using ES6 babel.
The Problem
I have a dialog, '/MainMenu', that prompts the user for a free-response reply in order to dive into another, more relevant dialog. I also, however, want the user to be able to trigger an action that is completely irrelevant to subject matter (i.e. a dialog asking the bot, "how are you?"), returning back to the original MainMenu dialog just as they left off. I understand that in the documentation for the SDK, onSelectAction can be used to put the triggered dialog on top of the stack rather than replacing the entire stack, but once the '/HowAreYou' dialog ends, the bot also thinks that response was for the initial MainMenu prompt, replying with "I didn't understand. Please try again," like so:
Code
// I am using the builder.Library routing standard, and have confirmed that
// this gets triggered as expected. this dialog exists in a different file
lib.dialog('/HowAreYou', [
(session, args, next) => {
session.send('I\'m doing well. Thanks for asking!');
builder.Prompts.text(session, 'How are you doing today?');
}, (session, results) => {
session.endDialog('Good to hear that!');
}
]).triggerAction({
matches: /^how are you?$/i,
onSelectAction: (session, args, next) => {
// Add the help dialog to the top of the dialog stack (override the
// default behavior of replacing the stack)
session.beginDialog(args.action, args);
}
});
bot.dialog('mainMenu', [
(session, args, next) => {
builder.Prompts.text(session, 'Hi there! What can I do for you today?');
},
(session, results) => {
session.endConversation('Goodbye!');
}
]).beginDialogAction('weatherAction', '/Weather', {
matches: /^weather$/i,
}).beginDialogAction('sportsAction', '/Sports', {
matches: /^sports$/i,
}).beginDialogAction('cookingAction', '/Cooking', {
matches: /^cooking$/i,
});
Desired Behavior
Although the current result is very close to the desired behavior, I ideally want the bot to reply with the same MainMenu prompt it began with, without saying it didn't understand after the HowAreYou dialog finishes.
The Question
Is this possible? If so, how? If not, what are alternatives?
Thank you for any help you can give.
There is an explain on GitHub at https://github.com/Microsoft/BotBuilder/issues/2421, with what we can realize that the Prompts are built-in dialog which will handle the input validation.
As you first step in the Prompts dialog in mainMenu, and then you trigger the HowAreYou dialog when the first Prompts dialog is waiting for the input text.
Then the HowAreYou end as session.endDialog('Good to hear that!'); without an result for the first Prompts dialog in mainMenu, which is failed in the validation.
the root cause should be equivalent to input an empty text for builder.Prompts.text(session, 'Hi there! What can I do for you today?');.
update
Found the promptAfterAction property of IPromptOptions for prompt dialog, and i think about this issue. I think this should be by design.
As the sentence I don't understand... is a default text for property retryPrompt. So when you end the HowAreYou dialog and back the to mainPage dialog stack. The prompt dialog will restart and send the retryPrompt to user, which raises your issue.
For the accessibility, you can try to use:
builder.Prompts.text(session, 'Hi there! What can I do for you today?', {
retryPrompt: 'Hi there! What can I do for you today?'
});
Note: I am using Microsoft Bot Builder's SDK in Node.js.
The Desired Task
I am attempting to use beginDialogAction to initiate another sub-dialog so that by the end of the sub-dialog dialog, the stack would go right back to the dialog they left off. At the same time, however, I want to give the user the option of activating this same sub-dialog as a triggerAction in any other conversation.
The Problem
Implementing as follows puts TWO COPIES of the sub-dialog in the stack, by both the triggerAction and beginDialogAction. This is unwanted behavior because once one of those dialogs complete, a duplicate of that dialog runs again.
Here is the code:
// user dialog
bot.dialog('/', [
function (session, args, next) {
session.send('Starting root dialog');
},
function (session) {
session.send('Ending root dialog.');
]).beginDialogAction('addUser', 'UserAdd', {
matches: /^user add$/i
});
// branch dialog
bot.dialog('UserAdd', [
function (session, args, next) {
session.send('Adding user.');
}
]).triggerAction({
matches: /^user add$/i
})
The Question
What is the correct way to enable both a beginDialogAction and triggerAction of a dialog, but only run that dialog ONCE if it is triggered by a beginDialogAction, so that the root dialog can continue where it left off? If this is not traditional way of thinking to use this framework, I welcome other perspectives.
This is unwanted behavior because once one of those dialogs complete, a duplicate of that dialog runs again.
I couldn't reproduce this issue. The problem in your code is that you didn't end the UserAdd dialog after it is triggered whether it is called by beginDialogAction or triggerAction, this makes the dialog stack always stays inside of this UserAdd dialog and never end.
Based on your description, I don't think there would be any conflicts between beginDialogAction and triggerAction, tried to modify your code as below and it works fine on my side:
bot.dialog('/', [
function (session, args, next) {
session.send('Starting root dialog');
builder.Prompts.text(session, "How many people are in your party?");
},
function (session, results) {
builder.Prompts.text(session, "Who will be there?");
},
function (session, results) {
session.send('Ending root dialog.');
session.endDialog();
}
])
.beginDialogAction('addUser', 'UserAdd', {
matches: /^user add$/i
})
// // branch dialog
bot.dialog('UserAdd', [
function (session, args, next) {
session.send('Adding user.');
session.endDialog();
}
]).triggerAction({
matches: /^user add$/i
});
If there's any further concern or more problem, please feel free to leave a comment.
I am looking at the nodejs code here
https://github.com/Microsoft/BotBuilder/blob/master/Node/examples/basics-waterfall/app.js
I am trying to understand this piece of code
var bot = new builder.UniversalBot(connector, [
function (session) {
...
},
function (session, results) {
...
},
function (session, results) {
...
},
function (session, results) {
...
}
]);
I understand that
var bot is a function expression and takes in two parameters one is a connector and another is an array of functions.
Do these array of functions execute serially in the order they are defined ?
Comming from another programming background i am not familiar with this dialect.
How can i make this program more C# like is async await the answer ?
If async await is the answer how do i convert this to use the async/await paradigm ?
Yes, it seems like they are executing in the order they are defined.
You are supposed to provide only the function body in that array, the actual execution happens somewhere in the bot implementation, so you'd have to look there to get a clearer picture.
But judging from that example and common sense, it's clear that they are executed sequentially. It's a bot that answers questions in the order they are defined.
I'm not sure what you understand by "async" in this context, but if you want it to answer arbitrary requests, you can look at the other examples like basics-logging.
Specifically when doing MonoDroid uses of threads all the documentation I can find recommends calling RunOnUiThread() to call the callback. There is a similar function that can be used on MonoTouch however both of them require a GUI (Activity or whatever its counter part is on IOS). What I would like is to be able to start a thread, pass in a callback and call that callback on the thread that started the thread. For example
ThreadPool.QueueUserWorkItem(state =>
{
//Do Stuff
execute_callback_magically_on_main_thread(() => callback(response));
});
Any ideas? To be clear I would prefer this to not need a handle to the Activity etc.
What if you do something like this? (assuming they have the same signature) I haven't messed with RunOnUiThread, so I don't know it's signature.
public delegate void InvokeOnUIMethod(Action action);
public void CallingMethod()
{
//iOS
MyMethod(InvokeOnMainThread, () => { /* Your callback functionality */ });
//Android
MyMethod(RunOnUiThread, () => { /* Your callback functionality */ });
}
public void MyMethod(InvokeOnUIMethod execute_callback_magically_on_main_thread, Action callback)
{
System.Threading.ThreadPool.QueueUserWorkItem(state =>
{
//Do Stuff
execute_callback_magically_on_main_thread(() => callback(response));
});
}
I hope this helps.
Using the Alpha builds (Hopefully soon to be available as stable) you can use the new Async await idiom.
here is an overview on MSDN:
http://msdn.microsoft.com/en-gb/library/vstudio/hh191443.aspx
and here is a great video series on Channel9:
http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Tip-1-Async-void-is-for-top-level-event-handlers-only
I found a solution that works and does not appear to be dependent on either platform.
Task<string> t = new Task<string>(() =>
{
//Do Stuff
return "my results";
});
t.ContinueWith(task =>{
if(callback != null)
callback(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
t.Start();
The important part is the TaskScheduler.FromCurrentSynchronizationContext() which tells the "ContinueWith" to execute on the original thread.