2
votes

I am developing a bot using MS Bot Framework and LUIS and there are a lot of Adaptive Cards with buttons in my conversation flow. I need a way to handle this flow with buttons (Action.Submit buttons to be precise).

I first tried:

public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
   if (activity.Type == ActivityTypes.Message)
   {
       if (activity.Text != null & activity.Value == null)
       {
          await Conversation.SendAsync(activity, () => new RootLuisDialog());
       }
       else if (activity.Text == null & activity.Value != null)
       {
         await Conversation.SendAsync(activity, () => new ButtonHandler());
       }
   }
   else
   {
       this.HandleSystemMessage(activity);
   }

   var response = Request.CreateResponse(HttpStatusCode.OK);
   return response;
}

Because when the button on an Adaptive Card is clicked activity.Value contains the properties of the Action.Submit button.

The idea was to be able to separate the button controllers and the intent controller which is RootLuisDialog(). But it did not work, I don't know why: With this code, always the RootLuisDialog() exit is taken. In other words, the dialog stays inside RootLuisDialog()

Second idea was to use None Luis Intent like so:

    [LuisIntent("")]
    [LuisIntent("None")]
    public async Task None(IDialogContext context, LuisResult result)
    {
        var act = context.Activity as IMessageActivity;
        string message = String.Empty;
        if (act.Text != null & act.Value == null)
        {
            message = $"Sorry, I did not understand '{act.Text}'. Type 'help' if you need assistance.";
        }
        else if (act.Text == null & act.Value != null)
        {
            Button btn = JsonConvert.DeserializeObject<Button>(act.Value.ToString());
            message = $"You clicked on {btn.Type}";
        }
        await context.PostAsync(message);

        context.Wait(this.MessageReceived);
    }

While this works, it does not look right to be pushing button code under None intent.

I also tried context.Wait(buttonHandler) where the buttonHandler is an async function to handle the button press but then I got this error message:

   "exceptionMessage": "Object reference not set to an instance of an object.",
   "exceptionType": "System.NullReferenceException",

I am sure what I am trying to achieve has already a good answer but this being my first C# project/task, I need help to get this sorted. Many thanks in advance!!!

1

1 Answers

2
votes

I think that a better design if you want to separate the handling of the buttons from the LUIS intents, could be having a RootDialog that does 3 things:

  1. Inspect the incoming activity
  2. If activity.Value is null, then FWD the activity to LuisDialog (using context.Forward. Assuming that you want to inspect all the messages for 1), then you will have to "end" the LUIS dialog after you perform your logic with context.Done (instead of doing context.Wait(...))
  3. If activity.Value is not null, then you can process the message in the RootDialog and end with a context.Wait(...);