How to retrieve Adaptive Card's form submission in subsequent waterfall step

前端 未结 2 1838
慢半拍i
慢半拍i 2020-11-30 15:17

I\'m using the Bot Framework (V4) and I\'ve got a WaterfallDialog with two steps; first step is to capture form data and the second step is to process form data.

The

相关标签:
2条回答
  • 2020-11-30 15:56

    Adaptive Cards send their Submit results a little different than regular user text. When a user types in the chat and sends a normal message, it ends up in Context.Activity.Text. When a user fills out an input on an Adaptive Card, it ends up in Context.Activity.Value, which is an object where the key names are the id in your card and the values are the field values in the adaptive card.

    For example, the json:

    {
        "type": "AdaptiveCard",
        "body": [
            {
                "type": "TextBlock",
                "text": "Test Adaptive Card"
            },
            {
                "type": "ColumnSet",
                "columns": [
                    {
                        "type": "Column",
                        "items": [
                            {
                                "type": "TextBlock",
                                "text": "Text:"
                            }
                        ],
                        "width": 20
                    },
                    {
                        "type": "Column",
                        "items": [
                            {
                                "type": "Input.Text",
                                "id": "userText",
                                "placeholder": "Enter Some Text"
                            }
                        ],
                        "width": 80
                    }
                ]
            }
        ],
        "actions": [
            {
                "type": "Action.Submit",
                "title": "Submit"
            }
        ],
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "version": "1.0"
    }
    

    .. creates a card that looks like:

    If a user enters "Testing Testing 123" in the text box and hits Submit, Context.Activity will look something like:

    { type: 'message',
      value: { userText: 'Testing Testing 123' },
      from: { id: 'xxxxxxxx-05d4-478a-9daa-9b18c79bb66b', name: 'User' },
      locale: '',
      channelData: { postback: true },
      channelId: 'emulator',
      conversation: { id: 'xxxxxxxx-182b-11e9-be61-091ac0e3a4ac|livechat' },
      id: 'xxxxxxxx-182b-11e9-ad8e-63b45e3ebfa7',
      localTimestamp: 2019-01-14T18:39:21.000Z,
      recipient: { id: '1', name: 'Bot', role: 'bot' },
      timestamp: 2019-01-14T18:39:21.773Z,
      serviceUrl: 'http://localhost:58453' }
    

    The user submission can be seen in Context.Activity.Value.userText.

    Note that adaptive card submissions are sent as a postBack, which means that the submission data doesn't appear in the chat window as part of the conversation--it stays on the Adaptive Card.

    Using Adaptive Cards with Waterfall Dialogs

    Natively, Adaptive Cards don't work like prompts. With a prompt, the prompt will display and wait for user input before continuing. But with Adaptive Cards (even if it contains an input box and a submit button), there is no code in an Adaptive Card that will cause a Waterfall Dialog to wait for user input before continuing the dialog.

    So, if you're using an Adaptive Card that takes user input, you generally want to handle whatever the user submits outside of the context of a Waterfall Dialog.

    That being said, if you want to use an Adaptive Card as part of a Waterfall Dialog, there is a workaround. Basically, you:

    1. Display the Adaptive Card
    2. Display a Text Prompt
    3. Convert the user's Adaptive Card input into the input of a Text Prompt

    In your Waterfall Dialog class (steps 1 and 2):

    private async Task<DialogTurnResult> DisplayCardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        // Create the Adaptive Card
        var cardPath = Path.Combine(".", "AdaptiveCard.json");
        var cardJson = File.ReadAllText(cardPath);
        var cardAttachment = new Attachment()
        {
            ContentType = "application/vnd.microsoft.card.adaptive",
            Content = JsonConvert.DeserializeObject(cardJson),
        };
    
        // Create the text prompt
        var opts = new PromptOptions
        {
            Prompt = new Activity
            {
                Attachments = new List<Attachment>() { cardAttachment },
                Type = ActivityTypes.Message,
                Text = "waiting for user input...", // You can comment this out if you don't want to display any text. Still works.
            }
        };
    
        // Display a Text Prompt and wait for input
        return await stepContext.PromptAsync(nameof(TextPrompt), opts);
    }
    
    private async Task<DialogTurnResult> HandleResponseAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        // Do something with step.result
        // Adaptive Card submissions are objects, so you likely need to JObject.Parse(step.result)
        await stepContext.Context.SendActivityAsync($"INPUT: {stepContext.Result}");
        return await stepContext.NextAsync();
    }
    

    In your main bot class (<your-bot>.cs), under OnTurnAsync(), near the beginning of the method, somewhere before await dialogContext.ContinueDialogAsync(cancellationToken) is called (step 3):

    var activity = turnContext.Activity;
    
    if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
    {
        activity.Text = JsonConvert.SerializeObject(activity.Value);
    }
    
    0 讨论(0)
  • 2020-11-30 16:01

    Here is nodejs version:

    your bot.ts file:

     this.onTurn(async (context, next) => {
      if (context.activity.type == ActivityTypes.Message) {
        // Ensure that message is a postBack (like a submission from Adaptive Cards)
        if (context.activity.channelData != null) {
          if (context.activity.channelData.postBack === true) {
            const postbackActivity = context.activity;
            // Convert the user's Adaptive Card input into the input of a Text Prompt
            // Must be sent as a string
            postbackActivity.text = JSON.stringify(postbackActivity.value);
            // context.activity.text = postbackActivity.value
            await context.sendActivity(postbackActivity);
          }
        }
      }
      await next();
    });
    
    0 讨论(0)
提交回复
热议问题