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/
Related
I have created a Microsoft teams app which consists of tabs and a bot. I took this as reference for creating teams addon. Here I am using the Waterfall flow model which was suggested by bot framework. While using this I have to give fixed number of actions, but I wanted to have dynamic actions. here is the example
class MainDialog extends ComponentDialog {
constructor(luisRecognizer, bookingDialog) {
super('MainDialog');
if (!luisRecognizer) throw new Error('[MainDialog]: Missing parameter \'luisRecognizer\' is required');
this.luisRecognizer = luisRecognizer;
if (!bookingDialog) throw new Error('[MainDialog]: Missing parameter \'bookingDialog\' is required');
// Define the main dialog and its related components.
// This is a sample "book a flight" dialog.
this.addDialog(new TextPrompt(TEXT_PROMPT))
.addDialog(bookingDialog)
.addDialog(nominationDialogue)
.addDialog(new ChoicePrompt(CHOICE_PROMPT))
.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.introStep.bind(this),
this.decidestep.bind(this),
this.originStep.bind(this),
this.actStep.bind(this),
this.Actualstep.bind(this)
]));
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}
/**
* The run method handles the incoming activity (in the form of a TurnContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} turnContext
* #param {*} accessor
*/
async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results && results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
How can I go to previous function i.e, actStep to decidesStep again without having any problem. I tried calling the decideStep from actStep then I am having an exception and bot is failing. When there is some repetitive work to be done I am not able to do due to the fixed number of actions.
Thanks in advance.
I had the same problem and I solved it using something like the following code (C#). It's not clean (kind of hack) but it works
private static async Task<DialogTurnResult> actStep (WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
.
.
.
stepContext.ActiveDialog.State["stepIndex"] = (int)stepContext.ActiveDialog.State["stepIndex"] - 2;
return await stepContext.NextAsync(null, cancellationToken);
}
Could you please look into the sample code for Conversation Bot .
You could find more sample solutions here
How to implement a welcome activity when the bot first starts - NLP is from Google Dialogflow.
I have designed the chatbot -intent, entities and NLP from Google Dialogflow and I have integrated successfully with the botframework webchat in a html file on referring this url.
The bot design and also the bot response is good to go. My most expected is am not getting the Bot response first here.
The welcome intent from Google Dialogflow has to get trigger from the following code as per the link given above.
But I am unable to get the bot trigger first here.
How to trigger the event of Google Dialogflow from the code.
I am expecting same like this
Note: Also referred this url
When a user joins WebChat, a conversation update activity will be sent to the bot. Once the activity is received, you can check if a member was added and send the welcome message accordingly.
If you are using the Activity Handler that was released in v4.3, you can simply add an onMembersAdded handler and send the welcome message from there.
class Bot extends ActivityHandler{
constructor() {
super();
this.onMembersAdded(async (context, next) => {
const { membersAdded } = context.activity;
for (let member of membersAdded) {
if (member.id !== context.activity.recipient.id) {
await context.sendActivity("Welcome Message!");
}
}
await next();
});
...
}
}
If you are not using the activity handler, in the bot's onTurn method, you can check if the incoming activity handler is a conversation update and if a member has been added.
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
if (turnContext.activity.membersAdded && turnContext.activity.membersAdded.length > 0) {
for (let member of turnContext.activity.membersAdded) {
if (member.id !== turnContext.activity.recipient.id) {
await turnContext.sendActivity("Welcome Message!");
}
}
}
} ...
}
For more details on sending welcome messages, please take a look at this sample.
Hope this helps!
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".
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.
How can I send a message to the user without the user sending me a message? Like for example CNN bot is sending messages every day in the morning by itself. How can I do that in the bot framework?
See this.
In fact, you do not strictly need to receive a message from the user first, but addressing manually can be error-prone (you have to know the user's and bot's channel account, the service URL, etc.)
And in turn (per #thegaram's message), that only works for some channels. For example, Skype requires that the user contact the bot before the bot can message the user.
Once contacted, you can store the user's channelAccount data once they contact you and use that to send them proactive messages. For example if the user has subscribed to hear sports scores for a particular team over time.
Any sort of unsolicited spam messages of course are prohibited by the policies of the Bot Framework (and most of the channels).
Yes you can do that. We called it Greeting from Bot. I have done it and sharing a sample code with you.
Write this code in your messageController or first dialog used in bot.
if (activity.Text == null)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity isActivityTyping = activity.CreateReply();
isActivityTyping.Type = ActivityTypes.Typing;
await connector.Conversations.ReplyToActivityAsync(isActivityTyping);
await Conversation.SendAsync(activity, () => new Dialogs.GreetDialog());
}
after this code you need to create a dialog GreetDialog. Below is the cs file code for your reference.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
namespace GPP.Bot.Dialogs
{
[Serializable]
internal class GreetDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
context.Wait(Greeting);
}
private async Task Greeting(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
if (string.IsNullOrEmpty(message.Text))
{
// Hero Card
var cardMsg = context.MakeMessage();
var attachment = BotWelcomeCard("Hello, I am a bot. Right now I am on training and in a prototype state", "");
cardMsg.Attachments.Add(attachment);
await context.PostAsync(cardMsg);
context.Call<object>(new ActionDialog(), AfterGreetingDialogCompleted);
}
else
{
context.Call<object>(new ActionDialog(), AfterGreetingDialogCompleted);
}
}
private static Attachment BotWelcomeCard(string responseFromQNAMaker, string userQuery)
{
var heroCard = new HeroCard
{
Title = userQuery,
Subtitle = "",
Text = responseFromQNAMaker,
Images = new List<CardImage> { new CardImage("https://i2.wp.com/lawyerist.com/lawyerist/wp-content/uploads/2016/08/docubot.gif?fit=322%2C294&ssl=1") },
Buttons = new List<CardAction> { new CardAction(ActionTypes.ImBack, "Show Menu", value: "Show Bot Menu") }
};
return heroCard.ToAttachment();
}
private async Task AfterGreetingDialogCompleted(IDialogContext context, IAwaitable<object> result)
{
context.Done<object>(new object());
}
}
}
this is a working code. Do let me know in case you face ant issue.
~cheers :)