Search code examples
c#azurebotframeworkbotsazure-language-understanding

How detect/listen for action.submit from adaptive card


I'm using the botframework (enterprise bot template) and LUIS.ai:

My problem is that , when I fill in a custom adaptive card (it has three text input fields) and click submit I get the following message: "I’m sorry, I’m not able to help with that." I can see in the emulator the submit button posts back the entered values, but I'm unsure as to how I listen for the button action.My thoughts are that I have to listen for when the ID of the action is called, but I'm not entirely sure how to do that.

Below is the code that calls the dialog:

    public static IMessageActivity SendTicketFormCard(ITurnContext turnContext, dynamic data)
    {
        var response = turnContext.Activity.CreateReply();
        var introcard = File.ReadAllText(@".\dialogs\main\resources\Ticket_Fields.json");

        response.Attachments = new List<Attachment>();
        response.Attachments.Add(new Attachment()
        {
            ContentType = "application/vnd.microsoft.card.adaptive",
            Content = JsonConvert.DeserializeObject(introcard),
        });

        return response;
    }

Where the JSON dialog looks like so:

{
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "TextBlock",
      "horizontalAlignment": "Center",
      "size": "Medium",
      "weight": "Bolder",
      "color": "Dark",
      "text": "Search Ticket"
    },
    {
      "type": "TextBlock",
      "id": "94358428-5ef2-43a5-9056-d3cac1abfabd",
      "text": "Ticket ID:",
      "maxLines": 1
    },
    {
      "type": "Input.Text",
      "id": "68e1e180-4cdc-4ad6-bb8f-743554f1f58b",
      "placeholder": "Ticket ID (required)",
      "maxLength": 10
    },
    {
      "type": "TextBlock",
      "id": "2da1df9d-7f61-4e5c-9ff9-7aba2c5b306b",
      "text": "Summary:",
      "maxLines": 1
    },
    {
      "type": "Input.Text",
      "id": "403979a3-ccba-4baa-a885-2abca754cc69",
      "placeholder": "Summary (optional)",
      "maxLength": 250,
      "isMultiline": true
    },
    {
      "type": "TextBlock",
      "id": "a25464c7-07ea-4270-995f-5e57b783b52d",
      "text": "Status:",
      "maxLines": 1
    },
    {
      "type": "Input.Text",
      "id": "7794d725-feb5-4516-9786-d18684892106",
      "placeholder": "Status (optional)",
      "maxLength": 30
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "id": "783fe2e4-4056-449e-8cc6-5dc9c406222a",
      "title": "Search"
    }
  ],
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.0"
}

Solution

  • The message "I’m sorry, I’m not able to help with that." is a response to the "None" LUIS intent in the Enterprise Template's MainDialog class. You can find the message in MainStrings.resx.

    The adaptive card's submit action sends a message with no text to the bot, and then LUIS tries to interpret the intent of that message using the message's text but there is no text. The submitted data will be contained in the activity's Value property. To read the data from the Value property, you'll need to use the card's input fields' ID's as keys.

    private const string TICKETFIELD = "68e1e180-4cdc-4ad6-bb8f-743554f1f58b";
    private const string SUMMARYFIELD = "403979a3-ccba-4baa-a885-2abca754cc69";
    private const string STATUSFIELD = "7794d725-feb5-4516-9786-d18684892106";
    

    You'll want to check incoming messages to see if they have no text and then respond as though that's a possible submit action. You could do this once LUIS has already determined the intent to be "None," but you may as well do the check before the message is even sent to LUIS. Go to your MainDialog's RouteAsync method and wrap all the existing code in an else block, and then you can put the code that responds to a submit action in your if block:

    protected override async Task RouteAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
    {
        if (string.IsNullOrEmpty(activity.Text))
        {
            dynamic value = dc.Context.Activity.Value;
    
            await turnContext.SendActivityAsync($"Ticket = {value[TICKETFIELD]}, Summary = {value[SUMMARYFIELD]}, Status = {value[STATUSFIELD]}");
        }
        else
        {
            // All the code that was already there
        }
    }