8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

Create fulllment using webhook

In Dialogow, fulllment is a service, app, feed, conversation, or other logic that can resolve a user request. In our case, we need fulllment that can schedule an appointment for the bike shop given the time and date information provided by the intent Make Appointment.

For this setup, we provide a webhook as a backend service that can receive the time and date parameters from the intent and create an event on Calendar using the API. To accomplish this, we need to perform two tasks:

Obtain credentials for API.

Create a new calendar and congure the code in the webhook.

Create a webhook with the inline editor

Dialogow has an inline editor in the console that allows you to directly write NodeJS code, which then can be deployed to run as a webhook on Firebase.

To create a webhook using Dialogow's inline editor, follow these steps:

1. Click on the Make Appointment intent.

2. In the Fulllment section, toggle on the Enable Webhook call for this intent button.

3. Click SAVE.

4. Click the Fulllment tab on the navigation bar to go to the fulllment page.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 1/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

5. Toggle the inline editor's button to ENABLED.

6. Delete the existing content in the package.json tab of the inline editor.

7. Copy and paste the JSON content below to the package.json tab of the inline editor:

{ "name": "DialogflowFirebaseWebhook", "description": "Firebase Webhook dependencies for a agent.", "version": "0.0.1", "private": true, "license": "Apache Version 2.0", "author": "Google Inc.", "engines": { "node": "6" }, "scripts": {

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 2/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

"lint": "semistandard --fix \"**/*.js\"", "start": "firebase deploy --only functions", "deploy": "firebase deploy --only functions" }, "dependencies": { "firebase-functions": "^2.0.2", "firebase-admin": "^5.13.1", "googleapis": "^27.0.0", "actions-on-google": "2.2.0", "dialogflow-fulfillment": "0.5.0" } }

8. Delete the existing code in the index.js tab of the inline editor.

9. Copy and paste the code below to the index.js tab of the inline editor:

/** * Copyright 2017 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */

'use strict';

const functions = require('firebase-functions'); const {google} = require('googleapis'); const {WebhookClient} = require('dialogflow-fulfillment');

// Enter your calendar ID and service account JSON below.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 3/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

const calendarId = ''; // Example: 6ujc6j6rgfk02cp02vg const serviceAccount = {}; // The JSON object looks like: { "type": "service_ac

// Set up Google Calendar service account credentials const serviceAccountAuth = new google.auth.JWT({ email: serviceAccount.client_email, key: serviceAccount.private_key, scopes: 'https://www.googleapis.com/auth/calendar' });

const calendar = google.calendar('v3'); process.env.DEBUG = 'dialogflow:*'; // It enables lib debugging statements

const timeZone = 'America/Los_Angeles'; // Change it to your time zone const timeZoneOffset = '-07:00'; // Change it to your time zone offset

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, res const agent = new WebhookClient({ request, response });

function makeAppointment (agent) { // Use the Dialogflow's date and time parameters to create Javascript Date // which are used to specify the appointment's time. const appointmentDuration = 1;// Define the length of the appointment to be const dateTimeStart = convertParametersDate(agent.parameters.date, agent.pa const dateTimeEnd = addHours(dateTimeStart, appointmentDuration); const appointmentTimeString = getLocaleTimeString(dateTimeStart); const appointmentDateString = getLocaleDateString(dateTimeStart); // Check the availability of the time slot and set up an appointment if the return createCalendarEvent(dateTimeStart, dateTimeEnd).then(() => { agent.add(`Got it. I have your appointment scheduled on ${appointmentDate }).catch(() => { agent.add(`Sorry, we're booked on ${appointmentDateString} at ${appointme }); } let intentMap = new Map(); intentMap.set('Make Appointment', makeAppointment); // It maps the intent 'M agent.handleRequest(intentMap); });

function createCalendarEvent (dateTimeStart, dateTimeEnd) { return new Promise((resolve, reject) => { calendar.events.list({ // List all events in the specified time period auth: serviceAccountAuth, calendarId: calendarId, timeMin: dateTimeStart.toISOString(),

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 4/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

timeMax: dateTimeEnd.toISOString() }, (err, calendarResponse) => { // Check if there exists any event on the calendar given the specified th if (err || calendarResponse.data.items.length > 0) { reject(err || new Error('Requested time conflicts with another appointm } else { // Create an event for the requested time period calendar.events.insert({ auth: serviceAccountAuth, calendarId: calendarId, resource: {summary: 'Bike Appointment', start: {dateTime: dateTimeStart}, end: {dateTime: dateTimeEnd}} }, (err, event) => { err ? reject(err) : resolve(event); } ); } }); }); }

// A helper function that receives Dialogflow's 'date' and 'time' parameters an function convertParametersDate(date, time){ return new Date(Date.parse(date.split('T')[0] + 'T' + time.split('T')[1].spli }

// A helper function that adds the integer value of 'hoursToAdd' to the Date in function addHours(dateObj, hoursToAdd){ return new Date(new Date(dateObj).setHours(dateObj.getHours() + hoursToAdd)); }

// A helper function that converts the Date instance 'dateObj' into a string th function getLocaleTimeString(dateObj){ return dateObj.toLocaleTimeString('en-US', { hour: 'numeric', hour12: true, t }

// A helper function that converts the Date instance 'dateObj' into a string th function getLocaleDateString(dateObj){ return dateObj.toLocaleDateString('en-US', { weekday: 'long', month: 'long', }

10. Click DEPLOY.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 5/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

Figure 7. Flowchart showing the connection to the webhook function makeAppointment().

We now have the intent Make Appointment connected to the function makeAppointment() in the webhook. Let's examine the following piece of code in the webhook:

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 6/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

ts.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => st agent = new WebhookClient({ request, response });

ction makeAppointment (agent) { / Calculate appointment start and end datetimes (end = +1hr from start) onst dateTimeStart = convertParametersDate(agent.parameters.date, agent.parameters.t onst dateTimeEnd = addHours(dateTimeStart, 1); onst appointmentTimeString = getLocaleTimeString(dateTimeStart); onst appointmentDateString = getLocaleDateString(dateTimeStart); / Check the availability of the time, and make an appointment if there is time on th eturn createCalendarEvent(dateTimeStart, dateTimeEnd).then(() => { agent.add(`Got it. I have your appointment scheduled on ${appointmentDateString} at ).catch(() => { agent.add(`Sorry, we're booked on ${appointmentDateString} at ${appointmentTimeStri );

intentMap = new Map(); entMap.set('Make Appointment', makeAppointment); nt.handleRequest(intentMap);

In the code above, notice the line,

tMap.set('Make Appointment', makeAppointment);

The function set()is called on a Map object, intentMap. This function links an intent to a specic function in the code. In this case, the call establishes the mapping between the intent Make Appointment and the function makeAppointment().

The function makeAppointment(agent){} reads the date and time parameter values from the input object agent via agent.parameters.date and agent.parameters.time. After parsing and formatting the date and time values, the function then calls a custom function createCalendarEvent(), which makes an API call to Google Calendar to create an event on the calendar.

Lastly, the function agent.add()is used to deliver a customized string as a response to the user. Unlike using the Dialogow console to provide responses, with a webhook, we can use the logic of code to construct highly dynamic responses. For instance, when the agent schedules an appointment successfully, it replies with the following response:

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 7/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

Got it. I have your appointment scheduled on ${appointmentDateString} at ${appointmentTimeString}. See you soon. Good-bye.

However, if the agent fails to make an appointment on the specic time and date provided, it returns the following response:

Sorry, we're booked on ${appointmentDateString} at ${appointmentTimeString}. Is there anything else I can do for you?

At this point, we cannot test the code properly because it does not have access to the Google Calendar API. Notice that we have the following variables in the code for personalizing Google Calendar API setup:

calendarId = ''; // Example: 6ujc6j6rgfk02cp02vg6h38cs0@gr serviceAccount = {}; // The JSON object looks like: { "type": "service_account", ..

Next, we need to congure the code to access the Google Calendar API.

gow Feature ow lets you easily import a prebuilt agent to your account. Click the button below if you want to import an ag built up to this point in the tutorial. You can either create a new agent or add the prebuilt agent to an existing a

s://dialogow.cloud.google.com/#/oneclick? ateUrl=https%253A%252F%252Fstorage.googleapis.com%252Fdialogow- ck%252FBestPracticesTutorial.zip)

Obtain credentials for the Google Calendar API

To obtain credentials for the Google Calendar API, follow these steps:

1. On Dialogow's navigation bar, click the settings ⚙ button next to the name of the agent.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 8/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

2. In the GOOGLE PROJECT table, click the Project ID link to open the Platform console.

3. In the console, click the menu button ☰ and select APIs & Services > Library.

4. Click on the Google Calendar API card.

5. Click ENABLE on the Google Calendar API page.

6. On the navigation bar, click Credentials.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 9/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

7. Click Create credentials and select the Service account key item from the dropdown menu.

8. Click the Service account dropdown menu and select the New service account item.

9. In the Service account name input eld, enter bike-shop-calendar.

10. For the Role eld, select Project > Owner from the dropdown menu.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 10/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

11. Click Create. (A JSON le that contains your service account key is downloaded.)

Create a new calendar and congure the code in the webhook

Next, we need to create a new calendar for the bike shop to track appointments. We use the information from the downloaded JSON le to integrate the agent's webhook code with the new Google calendar. Make sure that you can view and copy the content of the JSON le before you continue with the next set of instructions.

To create a new calendar and complete the integration, follow these steps:

1. Open your Google Calendar (https://calendar.google.com/).

2. On the Google Calendar's navigation bar, click the + button next to the Add a friend's calendar input eld.

3. Select the New calendar item from the dropdown menu.

4. In the Name eld, enter Mary's Bike Shop.

5. Click the CREATE CALENDAR link. (The new calendar Mary's Bike Shop is created under the Settings for my calendars window of the navigation bar.)

6. Click Mary's Bike Shop and select Share with specic people.

7. In the Share with specic people section, click ADD PEOPLE. (The Share with specic people pop-up window appears on the screen.)

8. Open the previously downloaded JSON le and copy the email address in the client_email eld, without the quotation marks:

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 11/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

{ "type": "service_account", "project_id": "marysbikeshop-...", "private_key_id": "...", "private_key": "...", "client_email": "bike-shop-calendar@.iam.gserviceaccount.com", "client_id": "...", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token", "auth_provider_x509_cert_url": "https://www.googleapis.com...", "client_x509_cert_url": "https://www.googleapis.com/robot/v..." }

9. In the Share with specic people pop-up window, paste the email address from client_email in the Add email or name input eld.

10. In the Permissions dropdown menu, select the Make changes to events item.

11. Click SEND.

12. Scroll down the Integrate calendar section and copy the content of Calendar ID.

13. In the Dialogow console, go to your agent's Fulllment page.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 12/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

14. In the index.js tab of the inline editor, nd the variable calendarId.

const calendarId = '';

15. Paste the content of Calendar ID to replace , as shown in the following code:

const calendarId = '[email protected]';

16. In the index.js tab of the inline editor, nd the variable serviceAccount.

const serviceAccount = {};

17. Revisit the previously downloaded JSON le and copy the entire content, including the outermost curly brackets ({}).

18. Paste the content to replace the value of serviceAccount, as shown in the following code snippet:

const serviceAccount = { "type": "service_account", "project_id": "marysbikeshop-...", "private_key_id": "...", "private_key": "...", "client_email": "bike-shop-calendar@.iam.gserviceaccount.com", "client_id": "...", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token", "auth_provider_x509_cert_url": "https://www.googleapis.com...", "client_x509_cert_url": "https://www.googleapis.com/robot/v..." };

19. Click DEPLOY.

20. Test the agent to verify that new events are correctly created on the calendar.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 13/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

Fuher improvement

Currently, your agent can provide services only when users cooperate nicely; it doesn't handle conversations well if users say things that are outside of the scripted dialogs. In conversational interfaces, a big part of the effort goes into making an agent capable of recovering from unexpected user utterances. We recommend you explore Dialogow's powerful feature, Contexts (/dialogow/docs/contexts-overview), that allows an agent to effectively control the ow of conversation.

Previous  Create an intent with parameters (/dialogow/docs/tutorials/build-an-agent/create-intent-with-parameters)

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 14/15 8/23/2020 Create fulfillment using webhook | Dialogflow Documentation

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License (https://creativecommons.org/licenses/by/4.0/), and code samples are licensed under the Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0). For details, see the Site Policies (https://developers.google.com/site-policies). Java is a registered trademark of Oracle and/or its aliates.

Last updated 2020-08-20 UTC.

https://cloud.google.com/dialogflow/docs/tutorials/build-an-agent/create-fulfillment-using-webhook/ 15/15