Enhance the answers of your bot using Adaptive Cards

December 20, 2020

Adaptive Cards are platform-agnostic snippets of UI, authored in JSON, that apps and services can openly exchange. When delivered to a specific app, the JSON is transformed into native UI that automatically adapts to its surroundings. It helps design and integrate light-weight UI for all major platforms and frameworks.

Intergrading them to an Azure Bot Service project provides the user a more aesthetically pleasing and intuitive user interface. Works seamlessly with every channel, making multiplatform support effortless.

  • Portable - To any app, device, and UI framework
  • Open - Libraries and schema are open source and shared
  • Low cost - Easy to define, easy to consume
  • Expressive - Targeted at the long tail of content that developers want to produce
  • Purely declarative - No code is needed or allowed
  • Automatically styled - To the Host application UX and brand guidelines

Learn more about Adaptive Cards here.


Setup

In this demo we will be using a fresh created Core Bot from Azure. You can find out how to make one in this post. In Visual Studio navigate to Project and select Manage NuGet Packages.


In Browse search for Adaptive Cards and find the AdaptiveCards package by Microsoft. Click on the install button an your right and click OK in the next prompt. If it fails to install try to updating all of your existing packages.



Code

In this segment we will be modifying the booking result message to appear as an Adaptive Card.

Put this line on top, with the rest of the using statements.

      using AdaptiveCards;

The following code creates our card as an Attachment. We use a BookingDetails object as an argument because we will need our booking details information to be displayed in the card. If you are using the card in another project, you can completely ignore the arguments, or change them to the information that your card requires. The card.Speak section is especially important in our use case, as is what the bot will tell if it is connected to a personal assistant with speech capabilities. This is useful because a spoken channel might not have the ability to convey the card visually to the user as it might not be required to have a screen in order to use it. In the first AdaptiveTextBlock we are modifying the text to be Large and Bolder. In the second one the text is displayed regularly. Next we display an AdaptiveImage and we input the URL. You can remove or add more body segments if you wish.

public Attachment CreateAdaptiveCardAttachment(BookingDetails result)
{
    AdaptiveCard card = new AdaptiveCard("1.0");

    var timeProperty = new TimexProperty(result.TravelDate);
    var travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);

    card.Speak = $"I have you booked to {result.Destination} from {result.Origin} on {travelDateMsg}";

    card.Body.Add(new AdaptiveTextBlock()
    {
        Text = $"I have you booked\n\nTo {result.Destination}\n\nFrom {result.Origin}\n\nOn {result.TravelDate}",
        Size = AdaptiveTextSize.Large,
        Weight = AdaptiveTextWeight.Bolder
    });

    card.Body.Add(new AdaptiveTextBlock()
    {
        Text = $"Have a nice Flight!"
    });

    card.Body.Add(new AdaptiveImage()
    {
        Url = new Uri($"https://images.unsplash.com/photo-1587019158091-1a103c5dd17f?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80")
    });

    Attachment attachment = new Attachment()
    {
        ContentType = AdaptiveCard.ContentType,
        Content = card
    };

    return attachment;
}

Next we replace the regular prompt message with our newly created card.

private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    if (stepContext.Result is BookingDetails result)
    {
        var resultCard = CreateAdaptiveCardAttachment(result);
        var response = MessageFactory.Attachment(resultCard);
        await stepContext.Context.SendActivityAsync(response, cancellationToken);
    }

    // Restart the main dialog with a different message the second time around
    var promptMessage = "What else can I do for you?";
    return await stepContext.ReplaceDialogAsync(InitialDialogId, promptMessage, cancellationToken);
}

This is how the card looks like presented by the bot!


This way you can utilise Adaptive Cards with minimal changes to many different supporting frameworks, not only Bot Framework is supported.

About Me

Hi, my name is Demetris Bakas and I am a software engineer that loves to write code and be creative. I always find new technologies intriguing and I like to work with other people and be a part of a team. My goal is to develop software that people will find useful and will aid them in their everyday lives.
For any questions feel free to contact me at social media using the links below.