Hands-on: Create a TV guide Google Chat with Google Workspace and Dialogflow

1. Introduction

Now that you've built a Dialogflow chatbot for a TV Guide in the previous codelab, we're going to show you how to extend it to Google Chat. You will learn how to construct dynamic, interactive cards for this platform and have multiple integrations.

What you will build

We will build a Dialogflow chatbot that can respond in your Google Workspace domain with customizable responses.

2e16770ceed20cb2.png

What you'll learn

  • How to deploy and configure a Google Chat app
  • How to build display cards in Google Chat
  • How to build custom payloads in Dialogflow fulfillment

What you'll need

  • Complete the first codelab in this 2-part series.
  • A web browser and an email address to log into the Dialogflow console
  • Chat enabled in your Google Workspace domain

2. Enable and Configure Google Chat

We will start with the Dialogflow Agent you have created in the previous codelabs.

  1. In the Dialogflow console, click d7d792687e597dd5.png.
  2. In the General tab, scroll to Project ID, then click Google Cloud f2bffd4fcdb84fa9.png.

cb893582402e4092.png

  1. In the Google Cloud Console, click Navigation menu ☰ > APIs & Services > Library.
  2. Search for "Google Chat API," then click Enable to use the API on your Google Cloud project.
  3. Now we will configure your Google Chat app, navigate to the Configuration page for the API. Please note each GCP project can have at most one Google Chat app. 85794eaaaedc7eb5.png
  4. You should see the Dialogflow fields populating the configuration options.
  5. Change the Avatar URL field to this tv image: [https://fonts.gstatic.com/s/i/googlematerialicons/tv/v5/black-48dp/1x/gm_tv_black_48dp.png](https://fonts.gstatic.com/s/i/googlematerialicons/tv/v5/black-48dp/1x/gm_tv_black_48dp.png)
  6. Enable your Google Chat app for both direct messages and spaces 9d439f492c8b71bb.png

Click Save and exit the Cloud Console.

Additionally Dialogflow Integrations. Google Chat is enabled by default but if you would like to serve multiple platforms, you may navigate to the Integrations page in the Dialogflow Console to enable them.

63296523b678ff8d.png

3. Test in Google Chat

Now that your Google Chat app is configured, let's add it to a chat space and test it out. Open Google Chat and create a test chat space. In the upper right corner of the space click the drop down and select Add people & apps.

f0dd1f5e205ef8e2.png

Search for tvguide and add the Google Chat app to the space.

e60fa78fdd020304.png

You can now interact with the Google Chat app you already have built in Google Chat by simply typing @tvguide in the space. Type @tvguide hello to test it out.

e8399e33185c63ec.png

Next we will use the customizations in Google Chat to add richer responses.

4. Custom Google Chat Cards

With Google Chat, you can have your app return the user a basic Text Response or a Card Response which allows you a richer interface built by different widgets including images, buttons, etc. Now that we have connected your Dialogflow Agent to a Google Chat app, you simply need to return the JSON in the correct format to display in Google Chat in your fulfillment code. Let's look at some JSON examples.

The basic text response looks like:

{
  "text": "Welcome, I am the TV Guide agent. I can tell you what is currently playing on a TV channel. For example, you can ask me: What is on MTV?"
}

e8399e33185c63ec.png

A sample card response with widgets looks like:

{
  "cards": [
    {
      "sections": [
        {
          "widgets": [
            {
              "image": { "imageUrl": "https://freesvg.org/img/fttv.png" }
            },
            {
              "buttons": [
                {
                  "textButton": {
                    "text": "Check Listings",
                    "onClick": {
                      "openLink": {
                        "url": "https://tvlistings.com/..."
                      }
                    }
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

c390a0cb75486fe0.png

5. Custom Payloads and Chat Cards

Custom payloads in Dialogflow allow for platform-specific rich response messages. This is where we will add our Hangout Chat JSON cards where they will be served back to the user by the agent.

Let's start by adding a basic card for the welcome intent. In the Dialogflow Console, navigate to the Default Welcome Intent and scroll down to the responses section.

9624208f0d266afd.png

Click on Google Chat and unselect Use responses from the DEFAULT tab as the first responses, then ADD RESPONSES > Custom Payload.

You will see a JSON skeleton.

bb064f7ec1237fd3.png

Copy and paste the following code below. We have set up a card with a TextParagraph widget.

{
  "hangouts": {
    "header": {
      "title": "TV Guide App"
    },
    "sections": [
      {
        "widgets": [
          {
            "textParagraph": {
              "text": "Welcome, I am the TV Guide agent. I can tell you what is currently playing on a TV channel. For example, you can ask me: What is on MTV?"
            }
          }
        ]
      }
    ]
  }
}

Hit Save then let's go to your test chat space to see this card is rendered. In the chat space, type ‘@tvguide hello'

6941003ee06e4655.png

Next we will add a custom payload in the fulfillment code so we can dynamically generate the content with our code.

To learn more about cards please see the Message Format documentation. In the next section we will add cards.

6. Adding a Card in Fulfillment

Now we will create a card with widgets to show TV listings. Let's add a function called getGoogleCard where we will render the resulting listing information. We will use keyValue and button widgets to construct the card response.

Add the function below to your code in index.js at the bottom.

/**
*  Return a Google Chat Card in JSON
* @param {Object} JSON tv results
*/
var getGoogleCard = function(tvresults) {
   console.log('In Google Chat card, tv results: ' + JSON.stringify(tvresults));

   if(tvresults['Listings'][0]) {
       let channelName = tvresults['Name'];
       let currentlyPlayingTime = getShowTime(tvresults['Listings'][0]['Time']);
       let laterPlayingTime = getShowTime(tvresults['Listings'][1]['Time']);

       const cardHeader = {
           title: channelName + ' Shows',
       };

       const currentWidget = {
           keyValue: {
               content: `${tvresults['Listings'][0]['Title']}`,
               bottomLabel: `${currentlyPlayingTime}`,
           }
       };

       const laterWidget = {
           keyValue: {
               content: `${tvresults['Listings'][1]['Title']}`,
               bottomLabel: `${laterPlayingTime}`
           }
       };

       const buttonWidget = {
           buttons: [
             {
               textButton: {
                 text: 'View Full Listing',
                 onClick: {
                   openLink: {
                     url: TVGUIDE_WEBSERVICE + '/' + tvresults['ID'],
                   },
                 },
               },
             },
           ],
         };

       return {
           'hangouts': {
               header: cardHeader,
               sections: [{widgets: [currentWidget, laterWidget, buttonWidget]}],
           }
       };
   } else {
       const errorWidget = {
           keyValue: {
               content: 'No listings found',
               bottomLabel: 'Please try again.'
           }
       };
       return {
           'hangouts': {
               'sections': {widgets: [errorWidget]},
           }
       };
   }
}

Now we need to call this method so the agent can get the response to send back to the user. In the function channelHandler, replace the contents of the function with the code below.

function channelHandler(agent) {
   console.log('in channel handler');
   var jsonResponse = `{"ID":10,"Listings":[{"Title":"Catfish Marathon","Date":"2018-07-13","Time":"11:00:00"},{"Title":"Videoclips","Date":"2018-07-13","Time":"12:00:00"},{"Title":"Pimp my ride","Date":"2018-07-13","Time":"12:30:00"},{"Title":"Jersey Shore","Date":"2018-07-13","Time":"13:00:00"},{"Title":"Jersey Shore","Date":"2018-07-13","Time":"13:30:00"},{"Title":"Daria","Date":"2018-07-13","Time":"13:45:00"},{"Title":"The Real World","Date":"2018-07-13","Time":"14:00:00"},{"Title":"The Osbournes","Date":"2018-07-13","Time":"15:00:00"},{"Title":"Teenwolf","Date":"2018-07-13","Time":"16:00:00"},{"Title":"MTV Unplugged","Date":"2018-07-13","Time":"16:30:00"},{"Title":"Rupauls Drag Race","Date":"2018-07-13","Time":"17:30:00"},{"Title":"Ridiculousness","Date":"2018-07-13","Time":"18:00:00"},{"Title":"Punk'd","Date":"2018-07-13","Time":"19:00:00"},{"Title":"Jersey Shore","Date":"2018-07-13","Time":"20:00:00"},{"Title":"MTV Awards","Date":"2018-07-13","Time":"20:30:00"},{"Title":"Beavis & Butthead","Date":"2018-07-13","Time":"22:00:00"}],"Name":"MTV"}`;
   var results = JSON.parse(jsonResponse);
   var listItems = {};
   textResults = getListings(results);


   for (var i = 0; i < results['Listings'].length; i++) {
       listItems[`SELECT_${i}`] = {
           title: `${getShowTime(results['Listings'][i]['Time'])} - ${results['Listings'][i]['Title']}`,
           description: `Channel: ${results['Name']}`
       }
   }

   if (agent.requestSource === 'hangouts') {
        const cardJSON = getGoogleCard(results);
        const payload = new Payload(
           'hangouts',
           cardJSON,
           {rawPayload: true, sendAsMessage: true},
       );
       agent.add(payload);
   } else {
       agent.add(textResults);
   }
}

Take note of the code at the bottom where the response is added. If the agent's request source is identified as this platform we construct the JSON payload with the tag ‘hangouts'. This is important for correctly passing back the payload in fulfillment.

Now go back to your chat space and test it out. Type @tvguide What is on MTV?. You should see a similar response.

2e16770ceed20cb2.png

7. Congratulations

You have created your first Google Chat bot with Dialogflow!

What's next?

Enjoyed this code lab? Have a look into these great labs!