Swapping the context between the flows - botframework

I am try to implement Swapping context between dialog flows .Assume i am in middle of one dialog flow and i wants to move to another functionality or dialog flow with new utterance..Here bot should prompt Do you want to move to another flow ?...However we have implemented Global Message Scorables here.... Please help me any one. Thanks in advance
i am trying to get the result, i am created one more method in core bot and try to check the luis score again and redirect to new dialog flow based on luis score
enter code here
var msg = stepContext.Context.Activity.Text;
var recognizerResult=await
_services.BasicBotLuisApplication.RecognizeAsync(stepContext.Context, cancellationToken);
var topScoreIntent = recognizerResult?.GetTopScoringIntent();
elseif(topScoreIntent.Value.score>double.Parse(appSettings.Value.LuisScore))
{
var luisRes = recognizerResult.Properties["luisResult"] as LuisResult;
return await stepContext.BeginDialogAsync(nameof(CreateDialog), luisRes,
cancellationToken);
}
it is working normal flows or type any other keywords like help, cancel, stop. but i give it any dialog flow at that time it's not working.

I'm not sure why this isn't working, as the logic seems sound. But you say that the other interrupts (which I think in latest core-bot sample are specific utterances) are working. Have you tried checking intent in the interrupt function? Here is what I have done with my nodejs bot, hopefully this will help in your case. Instead of checking for utterances, I'm checking intent. Cancel and Help just provide text, but Expedite and Escalate start new dialogs.
async isTurnInterrupted(dc, luisResults) {
const topIntent = LuisRecognizer.topIntent(luisResults);
const topIntentScore = luisResults.intents[topIntent].score;
// see if there are any conversation interrupts we need to handle
if (topIntent === CANCEL_INTENT & topIntentScore > 0.6) {
if (dc.activeDialog) {
// cancel all active dialog (clean the stack)
await dc.cancelAllDialogs();
await dc.context.sendActivity('Ok. I\'ve cancelled our last activity.');
} else {
await dc.context.sendActivity('I don\'t have anything to cancel. If you\'re not trying to cancel something, please ask your question again.');
}
return true; // this is an interruption
}
if (topIntent === HELP_INTENT & topIntentScore > 0.5) {
await dc.context.sendActivity('Let me try to provide some help.');
await dc.context.sendActivity('Right now I am trained to help you with order status and tracking. If you are stuck in a conversation, type "Cancel" to start over.');
return true; // this is an interruption
}
if (topIntent === EXPEDITE_INTENT & topIntentScore > 0.5) {
await dc.beginDialog(INTERRUPT_DIALOG, topIntent);
return false; // pushing new dialog so not an interruption
}
if (topIntent === ESCALATE_INTENT & topIntentScore > 0.5) {
await dc.beginDialog(INTERRUPT_DIALOG, topIntent);
return false; // pushing new dialog so not an interruption
}
return false; // this is not an interruption
}

Related

endOfConversation not a function

My bot right now is using local memory, the goal is whenever a conversation end. I want to delete everything from local memory about this user. So I tried this onEndOfConversation.
Apparently this error shows up saying that onEndOfConversation is not a function.
This is my code :
const { CardFactory } = require('botbuilder');
const { DialogBot } = require('./dialogBot');
const WelcomeCard = require('./resources/welcomeCard.json');
class DialogAndWelcomeBot extends DialogBot {
constructor(conversationState, userState, dialog) {
super(conversationState, userState, dialog);
this.onMembersAdded(async (context, next) => {
const membersAdded = context.activity.membersAdded;
for (let cnt = 0; cnt < membersAdded.length; cnt++) {
if (membersAdded[cnt].id !== context.activity.recipient.id) {
//const welcomeCard = CardFactory.adaptiveCard(WelcomeCard);
//await context.sendActivity({ attachments: [welcomeCard] });
await dialog.run(context, conversationState.createProperty('DialogState'));
}
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
this.onEndOfConversation(async (context, next) => {
console.log("END!");
await conversationState.delete(context);
await userState.delete(context);
});
}
}
module.exports.DialogAndWelcomeBot = DialogAndWelcomeBot;
So how should I do this? If onEndOfConversation isn't recognize, what alternatives I can do to clear user and conversation from the memory after a dialogue ends.
The endOfConversation activity handler is used internally when a bot is also coupled with a skill. When a conversation is ended by the user, the bot then sends this activity type to the skill notifying it that the conversation has ended with the user.
There are different ways you could attack this. The method I use is component dialogs. Modeled after the cancelAndHelpDialog design, when a user types "cancel" or "quit", the user is brought to an exit dialog where feedback is gathered, etc.
As part of the exiting process, you could call conversationState.delete() within the dialog followed by cancelAllDialogs(true).
Hope of help!

DisplayAlert causing crash of Xamarin app

I am using a display alert for a simple yes or no dialogue but it's freezing my UI and I have no idea why.
private async void BtnDeleteStockTake_Clicked(object sender, EventArgs e)
{
var selectedItem = gridItems.SelectedItem as StockTakeTransArgsSage;
var action = await DisplayAlert("First 1", "Are you sure you wish to delete Stock Take", "Yes", "No");
if (action)
{
StockTakeTransArgsSage _item = new StockTakeTransArgsSage();
_item =database.GetSingleStockTake(selectedItem.StockTakeId).Result;
_item.Quantity = decimal.Parse(txtQty.Text);
int updated = await database.DeleteStockTake(_item);
await DisplayAlert("Second 1", "Stock Take Deleted", "OK");
await RebindData();
}
}
The weird thing, as well as the display alert from the first one, do not dismiss
It's causing the UI to crash out with a fatal error however if I step through my code normally without the display alert it's fine it does display the alert but then freezes.
My Delete stock function
public async Task<int> DeleteStockTake(StockTakeTransArgsSage args)
{
return await database.DeleteAsync(args);
}
My Get Single function.
public async Task<StockTakeTransArgsSage> GetSingleStockTake(int ID)
{
StockTakeTransArgsSage _stocktake = new StockTakeTransArgsSage();
_stocktake = await database.Table<StockTakeTransArgsSage>().Where(w => w.StockTakeId == ID).FirstOrDefaultAsync();
return _stocktake;
}
Most likely from the behavior you are describing (and looking at your code), it sounds like it's because the Display Alert is not being run on the UI thread, and this causes the app to wait for you to dismiss this alert box before being able to do anything. So your app is not crashing or freezing, it's just launching the alert on a different thread.
So change it to the following:
Device.BeginInvokeOnMainThread(() =>
{
DisplayAlert("Second 1", "Stock Take Deleted", "OK");
});
Let me know if that makes sense.
In your code only those lines can cause that behavior:
StockTakeTransArgsSage _item = new StockTakeTransArgsSage();
_item =database.GetSingleStockTake(selectedItem.StockTakeId).Result;
_item.Quantity = decimal.Parse(txtQty.Text);
int updated = await database.DeleteStockTake(_item);
Those lines cannot be executed on UI thread without freezing it for some time. That may cause the crash, you haven't provided any information of what you see in output for the crash so it is the only likely explanation.
Have you tried awaiting like below
StockTakeTransArgsSage _item = new StockTakeTransArgsSage();
_item = await database.GetSingleStockTake(selectedItem.StockTakeId);
_item.Quantity = decimal.Parse(txtQty.Text);
As I can see this will work. And also make sure that until finish the process you are not touching any other UI component in the screen.

How to send an activity from a bot dialog (c#) trough direct line to a client (angular)

I'm trying to send an event activity from the bot to the client when I'm in a certain dialog, but I just can't get it to work... Any suggestions or code samples I can look at?
Also I already tried to make a back channel and it works but on the bot side as far as I could tell it only works in the message controller.
EDIT*
I'm sorry, for not providing any details, I was in a hurry last week.
So i'm making a bot that will fill a "report" for a user, the bot asks questions, and the user gives the answers. For the first question i have to call a function in my angular app when i'm in the first dialog, that is after the root dialog, that will check the user input and return an "Account" object to the bot if the account exists, if it doesn't then it returns null... (and i know it would be easier to just make an API and connect directly to the bot, but i have to use angular)
I'm using the back channel like so:
botConnection.activity$
.filter( activity => {
// tslint:disable-next-line:max-line-length
return (activity.type === 'message' && activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') ||
(activity.type === 'message' && activity.from['id'] === 'user' && this.accountFlag)
})
.subscribe(activity => {
if (activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') {
console.log('"account" received');
this.accountFlag = true;
postAccountInfo();
} else if (activity.from['id'] === 'user' && this.accountFlag) {
console.log('"account" flag recieved');
this.accountFlag = false;
}
});
It's probably completely wrong but i didn't know how else to do it..
tl;dr:
So in short, i need to check if i'm in the first dialog (or the one that asks me for the account) and if I am then wait for the next user input and call the angular function to check the input and see if there are any accounts that match, if not return null if they do return the serialized object to the bot for some more processing... I hope this explains some more.
In your messages controller you are probably only forwarding activities with a type of Message to your dialogs. If you used the default bot template, you probably have something like
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.GetActivityType() == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
that you need to change to
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.GetActivityType() == ActivityTypes.Message || activity.GetActivityType() == ActivityTypes.Event)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
That will send both messages and events to your dialogs. Keep in mind though that you need to check for both of them in each of you dialog methods now especially when you are expecting events as the user can type and send a message before your event gets sent.
EDIT
You can't get the dialog name from activity.from['id']. However, in your dialog you can create an Activity reply and set the name to be something else. For example in your dialog,
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
Activity activity = await result as Activity;
Activity reply = activity.CreateReply();
reply.Text = "Please select an account...";
reply.Name = "VisitReportV3";
await context.PostAsync(reply);
}
then in your back channel JavaScript you would change from checking if activity.from['id'] === "VisitReportV3" to activity.name === "VisitReportV3".

How to integrate FormFlow and QnA dialogs in a single bot

How to integrate FormFlow and QnA dialogs in a simple bot. I'm not able to call FormFlow context once QnA is completed. If there are any samples for the same, then please share.
If you want to use QnA and FormFlow, create a dialog QnADialog and you can send all your messages first to the root dialog from there you can call your QnA Dialog like
var qnadialog = new QnADialog();
var messageToForward = await message;
await context.Forward(qnadialog, ResumeAfterQnA, messageToForward, CancellationToken.None);
Once th QnADilalog is executed, it will call the ResumeAfterQnA and there you can call your FormFlow Dialog.
private async Task ResumeAfterQnA(IDialogContext context, IAwaitable<object> results)
{
SampleForm form = new SampleForm();
var sampleForm = new FormDialog<SampleForm>(form, SampleForm.BuildForm, FormOptions.PromptInStart);
context.Call(sampleForm, RootDialog.SampleFormSubmitted);
}
You need to have a SampleFormSubmitted method that will be called after you form is submitted.
private async Task SampleFormSubmitted(IDialogContext context, IAwaitable<SampleForm> result)
{
try
{
var query = await result;
context.Done(true);
}
catch (FormCanceledException<SampleForm> e)
{
string reply;
if (e.InnerException == null)
{
reply = $"You quit. Maybe you can fill some other time.";
}
else
{
reply = $"Something went wrong. Please try again.";
}
context.Done(true);
await context.PostAsync(reply);
}
}
One approach is to start of from a Luis template.
Then make a specific Intent to start the Form.
Then you can have an empty Luis Intent of ”” and even ”None” and you put your QnA there.
That way the Qna will be on the background LUIS will give you great flexibility to trigger a specific dialogue with intents
Here is an example
http://www.garypretty.co.uk/2017/03/26/forwarding-activities-messages-to-other-dialogs-in-microsoft-bot-framework/

Is it possible to detect when a user opens the chat window on Facebook?

I'm trying to create a chatbot where in order to avoid the user opening the chat window and not knowing the available options, I want to give some basic instructions when the user opens the chat window.
Is there any trigger available when the user opens a chat window? Maybe then I can check, and if there's not an ongoing conversation I could provide basic instructions.
I did some googling and found nothing about this. Is it possible to do something like this, and if not, is there a way to mitigate this problem, and provide the user with information regarding the chatbot capabilities and supported instructions?
Facebook does not allow bots to initiate a conversation, unlike Skype or other platforms.
There are still some tricks you can do :
Go on the Settings of your Facebook page, then Messaging and check "Show a Messenger Greeting" as below, and write your greeting sentence.
The result will look like this :
You can also set a "Get Started" button to trigger an event.
Here's the doc :
"https://developers.facebook.com/docs/messenger-platform/thread-settings/get-started-button"
You can monitor for two event types: ConversationUpdate and ContactRelationUpdate.
The first one (ConversationUpdate) is called when a user is added or removed from the conversation. So, there's a place where you can introduce available options. It will be each type the new conversation has started. So, it may become annoying, you may add a check - do not show it if the user has been using the bot for some time.
The second (ContactRelationUpdate) is called when a user adds or removes the bot to/from the contacts. In general, it is only called once per user action.
Here's the extract from the Bot-Frameworks examples:
For Node.Js
bot.on('conversationUpdate', function (message) {
// Check for group conversations
if (message.address.conversation.isGroup) {
// Send a hello message when bot is added
if (message.membersAdded) {
message.membersAdded.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Hello everyone!");
bot.send(reply);
}
});
}
// Send a goodbye message when bot is removed
if (message.membersRemoved) {
message.membersRemoved.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Goodbye");
bot.send(reply);
}
});
}
}
});
bot.on('contactRelationUpdate', function (message) {
if (message.action === 'add') {
var name = message.user ? message.user.name : null;
var reply = new builder.Message()
.address(message.address)
.text("Hello %s... Thanks for adding me. Say 'hello' to see some great demos.", name || 'there');
bot.send(reply);
} else {
// delete their data
}
});
For C#
private void HandleMessage(Activity message)
{
if (message.Type == ActivityTypes.ConversationUpdate)
{
if (activity.MembersAdded.Any(m => m.Id == activity.Recipient.Id))
{
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = activity.CreateReply();
response.Text = "Hi! I am Bot. Here's what you can do...";
await connector.Conversations.ReplyToActivityAsync(response);
}
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
if (Activity.AsContactRelationUpdateActivity().Action == ContactRelationUpdateActionTypes.Add)
{
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = activity.CreateReply();
response.Text = "Hi! I am Bot. Thanks for adding me. Here's what you can do...";
}
}
return null;
}
I think the acid answer is not.
But you can intercept the IConversationUpdateActivity type message to know if the user has added the bot to a conversation. In the C# project template you can find a code block that ask for this message type but do nothing.

Resources