Change Flow of Messages in Microsoft Bot Framework

Change flow of messages in Microsoft Bot Framework

This is a great question.The key thing is to use the SetActive and SetNext methods of the Field<T> class. You should consider using the FieldReflector class; though you can implement your own IField.

SetActive is described in the Dynamic Fields section of the FormFlow documentation. Basically it provides a delegate that enables the field based on a condition.

SetNext will allow you to decide what step of the form should come next based on your custom logic.

You can take a look to the ContosoFlowers sample. In the Order form; something similar is being done.

 public static IForm<Order> BuildOrderForm()
{
return new FormBuilder<Order>()
.Field(nameof(RecipientFirstName))
.Field(nameof(RecipientLastName))
.Field(nameof(RecipientPhoneNumber))
.Field(nameof(Note))
.Field(new FieldReflector<Order>(nameof(UseSavedSenderInfo))
.SetActive(state => state.AskToUseSavedSenderInfo)
.SetNext((value, state) =>
{
var selection = (UseSaveInfoResponse)value;

if (selection == UseSaveInfoResponse.Edit)
{
state.SenderEmail = null;
state.SenderPhoneNumber = null;
return new NextStep(new[] { nameof(SenderEmail) });
}
else
{
return new NextStep();
}
}))
.Field(new FieldReflector<Order>(nameof(SenderEmail))
.SetActive(state => !state.UseSavedSenderInfo.HasValue || state.UseSavedSenderInfo.Value == UseSaveInfoResponse.Edit)
.SetNext(
(value, state) => (state.UseSavedSenderInfo == UseSaveInfoResponse.Edit)
? new NextStep(new[] { nameof(SenderPhoneNumber) })
: new NextStep()))
.Field(nameof(SenderPhoneNumber), state => !state.UseSavedSenderInfo.HasValue || state.UseSavedSenderInfo.Value == UseSaveInfoResponse.Edit)
.Field(nameof(SaveSenderInfo), state => !state.UseSavedSenderInfo.HasValue || state.UseSavedSenderInfo.Value == UseSaveInfoResponse.Edit)
.Build();
}
}
}

Cancel Or Exit from PromptDialog.Choice Flow in Microsoft Bot Framework

First of all this is not a Form Flow. This is prompt.
Now You can do something like, either you exit the dialog from the stack like this

try
{
string optionSelected = await result;

switch (optionSelected)
{
case FlightsOption:
context.Call(new FlightDialog(), this.ResumeAfterOptionDialog);
break;

case HotelsOption:
context.Call(new HotelsDialog(), this.ResumeAfterOptionDialog);
break;
case TrainOption:
context.Call(new TrainDialog(), this.ResumeAfterOptionDialog);
break;
case GobackOption:
context.Done<object>(null);
break;

}
}

Or,
You can tell something and then wait for other message in the same dialog like this

 try
{
string optionSelected = await result;

switch (optionSelected)
{
case FlightsOption:
context.Call(new FlightDialog(), this.ResumeAfterOptionDialog);
break;

case HotelsOption:
context.Call(new HotelsDialog(), this.ResumeAfterOptionDialog);
break;
case TrainOption:
context.Call(new TrainDialog(), this.ResumeAfterOptionDialog);
break;
case GobackOption:
await context.PostAsync("Ok, you came back. Now tell something new.");
context.Wait(MessageReceivedAsync);
break;
}
}

And the next message will go here

public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var message = await result;
context.Wait(MessageReceivedAsync);
}

How can i customize answer of Bot Framework Help Command?

You can use the Template attribute on top of your Form definition to override the Help string pattern. The pattern is located in the Resources.resx of Microsoft.Bot.Builder project.

[Template(TemplateUsage.Help, new string[] { "My custom Help message" })]

Sample Image

MS Bot Framework Conversation with Decisions

This, as suspected, turned out to be much easier that I thought..

Here is my solution...

This is my controller:

/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
// check if activity is of type message
if (activity != null && activity.GetActivityType() == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.BillSharkDialog());
}
else
{
HandleSystemMessage(activity);
}
return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
}

And here is the "Dialog" with just 2 steps...

[Serializable]
public class BillSharkDialog : IDialog<object>
{
Model.Customer customer = new Model.Customer();

public async Task StartAsync(IDialogContext context)
{
context.Wait(WelcomeMessageAsync);
}
public async Task WelcomeMessageAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
IMessageActivity message = await argument;
await context.PostAsync("We're excited to start helping you save! Let's start by getting your name?");
context.Wait(CaptureCustomerNameAsync);
}
public async Task CaptureCustomerNameAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
IMessageActivity message = await argument;
customer.customerName = message.Text;
await context.PostAsync($"Thanks {message.Text}. Now we need your email address?");
context.Wait(CaptureCustomerEmailAsync);
}
}

You can obviously change the route by checking the incoming message..

Here is an example:

public async Task DoesCustomerHaveBillAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
IMessageActivity message = await argument;
switch (message.Text.ToLower())
{
case "yes":
await context.PostAsync($"Great. Go ahead and take a picture of the first couple of pages and attach them to this conversation.\n\n\nWhen you have finished, please send the message 'finished'.");
context.Wait(CustomerHasBillAsync);
break;
case "no":
await context.PostAsync($"That's OK. Do you happen to have the login information for your provider account?");
context.Wait(CustomerDoesntHaveBillAsync);
break;
default:
await context.PostAsync($"Sorry, I didn't undestand. Please reply with 'yes' or 'no'.");
context.Wait(DoesCustomerHaveBillAsync);
break;
}
}

How do I give a delayed response in Microsoft Bot Framework

Try instantiating the client in the following way

using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var client = scope.Resolve<IConnectorClient>();
client.Messages.SendMessage(message);
}


Related Topics



Leave a reply



Submit