1
votes

During a Dialog using a WaterfallDialog, I wish to prompt the user for a DateTime by allowing the user to choose from a picker. The prompt for DateTimePrompt only waits for the user to submit a string representing a DateTime. :(

What I would rather have is a DateTimePickerPrompt where the Bot sends a calendar and the user can just select from it. That just does not exist.

After reading: https://blog.botframework.com/2019/07/02/using-adaptive-cards-with-the-microsoft-bot-framework/. I was hoping this was a capability. Specifically the section: "Adaptive Cards in Dialogs".

Here is what I have tried: adaptive card json

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.0",
  "body": [
    {
      "type": "TextBlock",
      "text": "Select Start Date and Time."
    },
    {
      "type": "Input.Date",
      "id": "start_date",
      "placeholder": "Enter a date"
    },
    {
      "type": "Input.Time",
      "id": "start_time",
      "placeholder": "Enter a time"
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "title": "OK",
      "data": {
        "key": "still replies with nothing given document says only object types can be returned"
      }
    }
  ]
}

Waterfall Datetime Step Method

    def _create_adaptive_card_attachment(self) -> Attachment:
        """
        Load a random adaptive card attachment from file.
        :return:
        """

        card_path = os.path.join(os.getcwd(), 'resources/datetime_picker.json')
        with open(card_path, "rb") as in_file:
            card_data = json.load(in_file)

        return CardFactory.adaptive_card(card_data)

    async def waterfall_start_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        prompt_options = PromptOptions(
                prompt=MessageFactory.attachment(
                    self._create_adaptive_card_attachment()
                ),
                choices=[Choice("0"), Choice("1")],
                style=ListStyle.none
        )
        return await step_context.prompt(
            TextPrompt.__name__,
            prompt_options
        )

This gets set to an endless loop due to DialogTurnResult.result == None.

Also, step_context.context.activity does say there was a response, but value None.

{
  'additional_properties': {},
  'type': 'message',
  'id': '68c3f2f0-c881-11ea-827f-25034e37bd5f',
  'timestamp': datetime.datetime(2020, 7, 17, 23, 1, 12, 223000, tzinfo=<isodate.tzinfo.Utc object at 0x10b39b9e8>),
  'local_timestamp': datetime.datetime(2020, 7, 17, 18, 1, 12, tzinfo=<FixedOffset '-09:00'>),
  'local_timezone': None,
  'service_url': 'http://localhost:60945',
  'channel_id': 'emulator',
  'from_property': <botbuilder.schema._models_py3.ChannelAccount object at 0x10c0d9b38>,
  'conversation': <botbuilder.schema._models_py3.ConversationAccount object at 0x10c0d9ac8>,
  'recipient': <botbuilder.schema._models_py3.ChannelAccount object at 0x10c0fc240>,
  'text_format': 'plain',
  'attachment_layout': None,
  'members_added': None,
  'members_removed': None,
  'reactions_added': None,
  'reactions_removed': None,
  'topic_name': None,
  'history_disclosed': None,
  'locale': 'en-US',
  'text': 'asdg',
  'speak': None,
  'input_hint': None,
  'summary': None,
  'suggested_actions': None,
  'attachments': None,
  'entities': None,
  'channel_data':
  {
    'clientActivityID': '1595026872220mnbwlxl2k5',
    'clientTimestamp': '2020-07-17T23:01:12.220Z'
  },
  'action': None,
  'reply_to_id': None,
  'label': None,
  'value_type': None,
  'value': None,
  'name': None,
  'relates_to': None,
  'code': None,
  'expiration': None,
  'importance': None,
  'delivery_mode': None,
  'listen_for': None,
  'text_highlights': None,
  'semantic_action': None,
  'caller_id': None
}

My "second" attempt with same _create_adaptive_card_attachment method:

    async def waterfall_start_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        message = Activity(
            text = "Here is an Adaptive Card:",
            type = ActivityTypes.message,
            attachments = [self._create_adaptive_card_attachment()],
        )

        await step_context.context.send_activity(message)
        return DialogTurnResult(status=DialogTurnStatus.Empty,result={})

This returns the same context activity.

I see a very similary question: How to retrieve Adaptive Card's form submission in subsequent waterfall step

This logic in C# seems to be what is describe in the documentation. I believe I implemented this right in python. But I seem to be missing something.

So, if the documentation is true, then I should be able to get the data from an Adaptive Card Submit Action. Any help here would be great. Thanks for you time and effort.

1
Welcome to Stack Overflow. What is your question? Please have a look at the handy guide to see the steps you can take to get a better answer faster: stackoverflow.com/help/how-to-askKyle Delaney
Also, what channel are you using?Kyle Delaney
Are you still working on this?Kyle Delaney

1 Answers

0
votes

I was working on the same exact thing, but I've a form instead of buttons. I've followed the blog and the C# answer you've pointed out. The implementation of card rendering was correct. However, we need to set the activity's text to something that the Prompt can look at as result instead of None or Blank value.

async def on_turn(self, turn_context: TurnContext):
    if turn_context.activity.type == 'message':
        if turn_context.activity.text == None and turn_context.activity.value != None:
            turn_context.activity.text = json.dumps(turn_context.activity.value)      
    await super().on_turn(turn_context)               
    # Save any state changes that might have occurred during the turn.
    await self.conversation_state.save_changes(turn_context, False)
    await self.user_state.save_changes(turn_context, False)

Once the text is updated with the values from your adaptive card input, these will be available as step_context.result in the next step. You'll be able to process the values from it. Please note that the position of placement of the value check before the super is important.