×

Home

How to make an employee-facing chatbot with Dialogflow in 10 steps

Published Fri 19 Jul 2019

Even though most chatbot projects are customer-facing, it is estimated that up to 26% of chatbots are operations focused. Google's Dialogflow is a popular platform as it's easy to setup a conversational interface with – and free to use.

In this guide, we'll create a Dialogflow chatbot for a work-related, internal use case. Specifically, we will focus on the data-binding aspect to see just how compatible Dialogflow is with integrating enterprise data.

1. Create an agent

Dialogflow is free to get started with, all you need is to register for an account. Then click on Create Agent and assign a name, language and Google Project to the agent.

In this example we simply named our agent Workbot.

2. Create an intent

In our new Workbot agent we first will create an intent. An intent is basically what project managers refer to as a 'user story'.

So for example, 'looking up your leave allowance' or 'book a training session' would be an intent the chatbot should assist the employee with. As an example for this guide, we will be making a chatbot that looks up your website's visitors.

We chose this an example as it consumes another Google API which is free to do with Dialogflow's Firebase Cloud Functions.

Related: We have a whole guide about how to find chatbot use cases and evaluate you should do first.

3. AI training data

The Natural Language Understanding in Dialogflow can differentiate between different intents that a user may have, we need to start entering some training phrases.

So you basically ask yourself all the different ways you can think of to ask for your intent and enter those to start, for example:

Note, that we try and create a wide spread of phrases. We change between questions and commands, use active and passive voice where possible and try and include synonyms for our key trigger words (i.e. visitors, users or people should have the same meaning to the bot).

Putting some thought into this early training data should help the AI get it right more often. However it won't completely get you around having to occasionally retrain the AI using Analytics data.

You may notice the little yellow highlights around the time values, i.e. past 30 days. These represent parameters that the chatbot can capture dynamically from the user. There can be multiple such parameters which each get their own color, e.g. if you enter country names it could be orange.

For the most part this detection should happen by itself as you feed the bot more training sentences. But if you go to the Action and parameters section you can manage what parameters you will have.

We will actually just stick with a time period in this example, as you will later see that every additional parameter creates a lot of extra code.

4. General configuration

Next up are two small matters to deal with: Responses and Fulfillment.

As a response we only really need a fallback answer the bot will resort to, in case it couldn't find an answer for the question.

Why only a fallback? Unlike the training questions, that have those handy highlighted bits to show parameters, there isn't an elegant way to just write text answers and mark spots as placeholders for the number.

Instead we will have to build our answer as part of the Fulfillment script we're going to write below.

That means all we need to write is "I'm sorry, something went wrong" and continue with the Fulfillment section below.

Fulfillment is basically what we tell the bot to do or execute, once Dialogflow determined the correct intent.

For our example we just need to enable the toggle for Enable webhook call for this intent.

5. Start with fulfillment

Fulfillment is where our bot learns to actually give the user a direct answer; as opposed to relying on canned responses or randomly sputtering out links to go somewhere else.

Image from u/ThePeoplesBard

Without fulfillment the bot will have a very hard time to get long-term user adoption as it simply isn't that useful.

To start, we click on the Fulfillment menu on the left, and then we enable the Inline Editor.

Now comes the arguably hardest part and that is writing our fulfillment function.

6. Write fulfillment function

Our function is going to be a webhook function, meaning it is a function that gets triggered by a HTTP request – and Dialogflow will be making this request if it matched the user's query to an existing intent.

Webhooks can be stored on many services like AWS Lambda, Heroku or Azure. But Google conveniently offers it's own service with Cloud Functions for Firebase which we are going to use for our example.

Basically our webhook needs to do four things:

  1. Parse the agent parameters
  2. Connect to our data source (in this case Google Analytics)
  3. Request the data
  4. Return it to Dialogflow in a readable format (i.e. a Card or some text)

To begin with, we'll focus on the package.json file which contains a list of dependencies (necessary resources) for our function. Let's add the googleapis package which shall allow us to easily communicate with the Google Analytics API.

At the time of this writing the latest version was 27, so we're adding to line 20 this:

"googleapis": "^27.0.0"

(Don't forget to add a comma on line 20 at the end.)

Now we go over to index.js where our main function belongs.

We've got the finished code for this further down, so skip ahead if you want but just in case I'll walk you through each section.

'use strict';

const functions = require('firebase-functions');
const {google} = require('googleapis');  // Calling the googleapis dependency we added earlier
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');

These are our project dependencies, where we simply add a new line for googleapis so we can call it in the function.

// Set up view ID from Google Analytics
const viewid = 'Your_view_Id';

// Google Analytics API service account details
const serviceAccount = {};

The view ID is the view in Google Analytics that you want to pull information from. You can find this in the Google Analytics admin panel. ServiceAccount is an account Google APIs uses to authenticate with the Google Analytics API service. You'll need to register for a service account.

There's a good guide here, but here's a quick overview:

  1. Go to the Google Developer Console APIs page and create a new project
  2. From the dashboard, click Enable APIs and services
  3. Search for the Google Analytics API and open it. Click Enable to enable it
  4. When prompted, click Create Credentials and then Help me choose
  5. Fill out the form as follows:

    const serviceAccountAuth = new google.auth.JWT({
      email: serviceAccount.client_email,
      key: serviceAccount.private_key,
      scopes: 'https://www.googleapis.com/auth/analytics.readonly'
    });

    We now authenticate with the Google API service for Google Analytics. The 'scopes' variable refers to what level of access your function requires. You should always choose the lowest level that you need; you can read more about scopes on the Google Identity Platform documentation.

     const startDate = agent.parameters['date-period'].startDate.split('T')[0];
     const startDateString = getLocaleDateString(startDate);
     const endDate = agent.parameters['date-period'].endDate.split('T')[0];
     const endDateString = getLocaleDateString(endDate);

    The first thing our agent needs to do is parse the user-provided parameters into a usable format. Google Analytics requires a specific date format for its API, but we also want to create a user-readable date string that our agent can respond to the user with. 

    Parameters provided by the agent are accessible under agent.parameters; you can see all available parameters from a response in the test window:

    getLocaleDateString(date) is just a helper function which parses the dates.

     function getVisitorCount(agent) {
          return getPageviews(startDate, endDate).then((visitorString) => {
              agent.add(`In the period ${startDateString} to ${endDateString}, there were ${visitorString} visitors to yourwebsite.com.`);
          }).catch(() => {
              agent.add(`Sorry, we couldn't retrieve data for the period ${startDateString} to ${endDateString}. Is there anything else I can do for you?`);
          });
      }

    This is our actual intent handler. If the agent matches a request to an intent, this is the function that gets called. The function calls our API caller function getPageviews(), then depending on whether the function was successful or failed, sends a response back to the agent.

    So if something was found we've got the sentence In the period between [startDate] to [endDate], there were [number] visitors to yourwebsite.com.

    And if we can't get a valid result we will return to Dialogflow simply Sorry, we couldn't retrieve data for the period [startDate] to [endDate]. Is there anything else I can do for you?

    Notice how the negative response is different to our fallback response from point 4. The fallback response only gets used if our function doesn't respond for whatever reason.

      let intentMap = new Map();
      intentMap.set('Page visitor count', getVisitorCount);
      agent.handleRequest(intentMap);

    The intent map maps each intent defined on the intent tab to a function. When our 'Page visitor count' intent is invoked, it will call our function getVisitorCount(). You can map more intents to functions here to add more functionality to your chatbot.

    Dialogflow uses just one webhook to handle all intents for the same agent. So depending on how many different use cases this chatbot should handle, there might be quite a few more functions that you will want to squeeze in here. 😉

    7. Interacting with the API

    Following on from this we now start to actually use the Google Analytics API.

    // Analytics API caller
    function getPageviews(startDate, endDate) {
        return new Promise((resolve, reject) => {
           // Make request to Google Analytics - start and end date provided by user
            google.analytics('v3').data.ga.get({
                'auth': serviceAccountAuth,
                'ids': 'ga:' + viewid,
                'start-date': startDate,
                'end-date': endDate,
                'metrics': 'ga:pageviews'
            }, (err, resp) => {
              if (err) {
                // Something went wrong
                console.log(err);
                reject (err);
              } else {
                // Data received from GA
                var count = resp.data.rows[0][0];
                resolve(count);
              }
          });
        }); 
    }

    We use promises to ensure that our function gets the data it needs before it proceeds. We then make the request to the Google Analytics API using the analytics('v3').data.ga.get method. The parameters it takes are well documented here, but you can query almost any aspect of your Analytics data with the API.

    Here is our function again as one:

    'use strict';
    
    const functions = require('firebase-functions');
    const {google} = require('googleapis');
    const {WebhookClient} = require('dialogflow-fulfillment');
    const {Card, Suggestion} = require('dialogflow-fulfillment');
    
    // Set up view ID from Google Analytics
    const viewid = '12345678';
    
    // Google Analytics API service account details
    const serviceAccount = {
      "type": "service_account",
      "project_id": "...",
      "private_key_id": "...",
      "private_key": "...",
      "client_email": "..."
    ...
    };
    
    // Authenticate with Google API services
    const serviceAccountAuth = new google.auth.JWT({
      email: serviceAccount.client_email,
      key: serviceAccount.private_key,
      scopes: 'https://www.googleapis.com/auth/analytics.readonly'
    });
    
    exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
      const agent = new WebhookClient({ request, response });
    
      // Parse the user provided date parameters into Date object and human readable formats
      const startDate = agent.parameters['date-period'].startDate.split('T')[0];
      const startDateString = getLocaleDateString(startDate);
      const endDate = agent.parameters['date-period'].endDate.split('T')[0];
      const endDateString = getLocaleDateString(endDate);
    
      // Intent handler - creates user responses for success or failure
      function getVisitorCount(agent) {
        return getPageviews(startDate, endDate).then((visitorString) => {
            agent.add(`In the period ${startDateString} to ${endDateString}, there were ${visitorString} visitors to adenin.com.`);
        }).catch(() => {
              agent.add(`Sorry, we couldn't retrieve data for the period ${startDateString} to ${endDateString}. Is there anything else I can do for you?`);
        });
      }
    
      let intentMap = new Map();
      intentMap.set('Page visitor count', getVisitorCount);
      agent.handleRequest(intentMap);
    });
    
    // Analytics API caller
    function getPageviews(startDate, endDate) {
        return new Promise((resolve, reject) => {
              // Make request to Google Analytics - start and end date provided by user
            google.analytics('v3').data.ga.get({
                'auth': serviceAccountAuth,
                'ids': 'ga:' + viewid,
                'start-date': startDate,
                'end-date': endDate,
                'metrics': 'ga:pageviews'
            }, (err, resp) => {
              if (err) {
                // Something went wrong
                console.log(err);
                reject (err);
              } else {
                // Data received from GA
                var count = resp.data.rows[0][0];
                resolve(count);
              }
          });
        }); 
    }
    
    // Helper function to convert date into a user-readable string
    function getLocaleDateString(date) {
      let dateObj = new Date(date);
      return dateObj.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', timeZone: 'America/Los_Angeles' });
    }

    Once the API has responded, we pull out the information we need and pass this back to our intent fulfilment function. The response format is detailed here, but you might find it easier to just print the response to the console to figure out what you need.

    8. Debugging

    Okay that was a lot already, but like any good developer you'll want to test this code extensively now.

    There is debugging available through the Firebase console. There's a link to this underneath the function editor.

    You can use console.log() to print to the Firebase console, and other debugging and error messages are viewable here. General messages about the webhook status can also be seen under Diagnostic Info when you test your chatbot in the Dialogflow console.

    9. Deploy the function

    We can't yet deploy our chatbot to our users, but we can deploy our function now. Do that just click Deploy.

    Dialogflow will notify you once the deployment is complete, and you'll also see a message in the Firebase console. If there are any errors with the deployment, these will be logged in Firebase too.

    You can now use the Dialogflow console on the right to test your chatbot. Start with one of your training phrases to see if the chatbot is communicating with the API properly.

    If so, you can start to test more user phrases to find blind spots in your training phrase list. Your chatbot will work by default with Google Assistant, but of course you can deploy it to many more services.

    10. Deploy the chatbot

    We've worked hard to get this chatbot up and running, and thankfully the one thing Dialogflow make easier than anything else is deploying your chatbot to other channels.

    Let's say you want to deploy your chatbot to Slack (as it is an employee-facing example), then just open the Integrations page, enable the toggle for Slack and authorize Dialogflow with your Slack workspace.

    In Slack simply add the Dialogflow Bot to your Apps and start asking away.

    Bottom line

    As you can see, creating even a rather simple chatbot with Dialogflow requires a deep understanding of Webhooks and APIs.

    While the actual interface to create intents or deploy the chatbot are all as simple as could be, on balance you need to budget for the overhead of having to write hardcore code and debug every single API before you get much mileage out of your chatbot.

    We have a range of chatbots we've created workplace-related use cases with, why don't you look at some other guides.

If you enjoyed this article, you might also like...

Free tool to check your workplace's smart assistant potential

Free tool to check your workplace's smart assistant potential

Build an AI chatbot for your team in 10 steps

Build an AI chatbot for your team in 10 steps

Oracle Digital Assistant comparison

Oracle Digital Assistant comparison

Try Digital Assistant with your team for free

Get started