Multipurpose Bot using Multiple Dialogs in Bot Framework

I am still in a delusion of finalizing this blog and how a reader would react towards it but anyway, there I go!

First of all, you’re most welcome here.

This new and improved blog is all about the business, development tactics, techniques, use cases and fun over Cognitive Services, Bots and Machine Learning. I hope some of them would really be helpful for developers who are trying to achieve some unique, exceptional and innovative solutions of some distinctive problems.

TL;DR: I’ve been working on bots which address some unique features of onboarding customers for banking products, creating leads in CRM and verification of required documents using Cognitive Services. Lately, I came across to a proposition of combining all of the goodness into one bot and there came a challenge of integrating everything into one multipurpose bot while keeping our code organized enough so it doesn’t become spaghetti with the velocity of scope change.

Bot Framework DialogsSource: Microsoft Bot Framework Documentation

This is a 201 level post and I am not going to discuss the basics of chat bot development. Bot Framework team has done a tremendous job to bring you these Bot Framework Docs. It has got a Quick Start section for you to kick off.

Few challenges are already addressed by creative MVPs like Gary Pretty, James MannEzequiel Jadib and Simon Michael. However, the issue which I came across was quite unique.

For the sake of simplicity, I will not be discussing the actual business scenario (as that was propriety code and have not yet been published publicly), therefore, I have come up with another idea of bot that allows you to either book an appointment with your General Physician or Apply for the Broadband connection. This multipurpose bot will be loaded with other functionalities and use cases with the passage of time as I blog about more features / techniques.

PROBLEM

I have multiple dialogs in a bot, some are using FormFlow, some are using IDialog (incl. RootDialog) while others are using LuisDialog (Language Understanding Intelligent Service).  When I try to call LuisDialog from RootDialog, the response from LUIS does not land into any of my intents.

There’s a tremendous support available on GitHub and StackOverflow and the contributors are actively participating in resolving / addressing the issues within botframework. However, I tried to look for the solution I couldn’t get hold of anything concrete. May be I missed out something or no one has actually written about that (or might have not encountered such scenario).

SOLUTION

It’s quite simple but we just have to put the pieces in a right way.

There are two commonly used methods to add the Dialogs on the top of the stack, i.e. context.Call and context.Forward. So when I tried to use the context.Call method to call BroadbandDialog (inherited from LuisDialog), it immediately fired the ResumeAfter<object> method which it should not.

	 
switch (selectedOption)
  {
        case "Doctor":
            context.Call(new DoctorDialog(), this.ResumeAfterDoctorDialog);
            break;
        case "Broadband":
            context.Call(new BroadbandDialog(), this.ResumeAfterBroadbandDialog);
            break;
        default:
            break;
  }

In addition to that, I also tried replacing the context.Call with context.Forward as below but unfortunately, it didn’t work either.

case "Broadband":
  await context.Forward(new BroadbandDialog(), this.ResumeAfterBroadbandDialog, selectedOption, CancellationToken.None);
  break;

Later, I realized that it is necessary for LuisDialog (BroadbandDialog) to get an information as LuisResult (IMessageActivity) not just as simple string. So I did below changes to my code;

private async Task SelectedOption(IDialogContext context, IAwaitable result)
{
    string selectedOption = await result;
    switch (selectedOption)
    {
        case "Doctor":
            context.Call(new DoctorDialog(), this.ResumeAfterDoctorDialog);
            break;
        case "Broadband":
            await CallBroadbandDialog(context, selectedOption);
            break;
        default:
            break;
    }
}

Task CallBroadbandDialog(IDialogContext context, string text)
{
    var message = context.MakeMessage();
    message.Text = text;

    return context.Forward(new BroadbandDialog(), this.ResumeAfterBroadbandDialog, message, CancellationToken.None);
}

By doing this, the bot worked like a charm and it will keep this dialog in the stack until it’s done (context.Done<R>).

I have kept this as opensource on GitHub, you’re most welcome should you want to contribute to this particular bot. If you think there’s a better way to achieve the above, you can always reach out to me on twitter / comments sections and I will surely update this post.

Disclaimer

As a hobbyist, I love to craft apps / bots for above discussed platforms. My repository does not contain any propriety codebase, it’s free for all under MIT License.

All the posts, views and opinions here on this blog are my own, not my employer’s.