通过将 Dialogflow 与日历集成,了解 fulfillment 的原理

1. 准备工作

在此 Codelab 中,您将了解 Dialogflow 如何与后端系统连接,以便为用户提供丰富的动态响应问题。

前提条件

在继续操作之前,您需要完成以下 Codelab:

  1. 使用 Dialogflow 构建预约安排程序
  2. 将 Dialogflow 与 Actions on Google 集成
  3. 了解 Dialogflow 中的实体

您还需要了解 Dialogflow 的基本概念和结构,您可以从使用 Dialogflow 构建聊天机器人在线课程中的以下视频中获得这些信息。

学习内容

  • 什么是 fulfillment
  • 如何为日历设置服务账号
  • 如何设置日历
  • 如何在 Dialogflow 中启用 fulfillment
  • 如何测试 fulfillment

构建内容

  • 使用 Cloud Functions 的 Fulfillment
  • Dialogflow 和日历之间的集成

所需条件

  • 用来登录 Dialogflow 控制台的网络浏览器和电子邮件地址
  • 用于访问日历的 Google 账号

2. 什么是 fulfillment?

Fulfillment 是部署为 webhook 的代码,可让 Dialogflow 代理逐个意图地调用业务逻辑。在对话过程中,fulfillment 允许您使用通过 Dialogflow 的自然语言处理操作提取的信息,在后端生成动态响应或触发操作。大多数 Dialogflow 代理都使用 fulfillment。

以下是一些有关在什么情况下可以使用 fulfillment 来扩展代理的示例:

  • 根据从数据库中查找的信息生成动态响应
  • 根据客户要求的商品下订单
  • 实现游戏规则和获胜条件

3. 启用日历 API

  1. Dialogflow 控制台中,点击 d7d792687e597dd5.png
  2. 常规标签页中,滚动到项目 ID,然后点击 Google Cloudf2bffd4fcdb84fa9.png

34be16fcd4c5aeff

  1. 在 Google Cloud Console 中,点击导航菜单 ☰ > API 和服务 >
  2. 搜索“Google 日历 API”,然后点击启用,以便在您的 Google Cloud 项目中使用该 API。

4. 设置服务账号

  1. 依次点击导航菜单 ☰ > API 和服务 > 凭据
  2. 点击创建凭据 > 服务账号

86f51af0e7886fdd.png

  1. 服务账号详情中,输入“appointment-scheduler”作为服务账号名称,然后点击创建

845d25f3e07ff770

  1. 在显示向此服务账号授予对项目的访问权限的位置,点击继续以跳过它。
  2. 在显示向用户授予对此服务账号的访问权限(可选)的位置,点击创建密钥,然后选择 JSON,并点击创建

系统会将 JSON 文件下载到您的计算机上,您在后续设置部分需要用到此文件。a424cec60144d707.png

5. 日历设置

  1. 导航至日历,然后点击主菜单 ☰ >添加其他日历 fbc354048b0a2c6c.png>创建新日历

d6ec2fcf0bd2ae22.png

  1. 输入“预约日历”作为日历名称,然后点击创建日历
  2. 重新加载页面,然后点击预约日历,滚动到与特定人员共享,然后点击添加人员
  3. 从在服务账号设置过程中下载的 JSON 文件中复制 client_email,并将其粘贴到对话框中。

7927f6fa675e3e87

  1. 点击权限下拉列表,然后点击更改活动 > 发送

2ee99d3d15eed97b

  1. 设置中,滚动到集成日历并复制日历 ID

df8a731f0713c52.png

6. 在 Dialogflow 中设置 fulfillment

将服务账号和日历 ID 添加到 fulfillment

  1. 导航到 AppointmentScheduler Dialogflow 代理,然后点击 Fulfillment
  2. 启用内嵌编辑器

c8574c6ef899393f.png

  1. 使用以下代码更新 index.js 文件:
'use strict';

// Import the Dialogflow module from Google client libraries.
const functions = require('firebase-functions');
const {google} = require('googleapis');
const {WebhookClient} = require('dialogflow-fulfillment');

// Enter your calendar ID below and service account JSON below
const calendarId = "<INSERT YOUR CALENDAR ID>";
const serviceAccount = {<INSERT CONTENTS OF YOUr JSON FILE HERE>}; // Starts with {"type": "service_account",...

// 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:*'; // enables lib debugging statements

const timeZone = 'America/Los_Angeles';
const timeZoneOffset = '-07:00';

// Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
 const agent = new WebhookClient({ request, response });
 console.log("Parameters", agent.parameters);
 const appointment_type = agent.parameters.appointment_type;
 function makeAppointment (agent) {
   // Calculate appointment start and end datetimes (end = +1hr from start)
   const dateTimeStart = new Date(Date.parse(agent.parameters.date.split('T')[0] + 'T' + agent.parameters.time.split('T')[1].split('-')[0] + timeZoneOffset));
   const dateTimeEnd = new Date(new Date(dateTimeStart).setHours(dateTimeStart.getHours() + 1));
   const appointmentTimeString = dateTimeStart.toLocaleString(
     'en-US',
     { month: 'long', day: 'numeric', hour: 'numeric', timeZone: timeZone }
   );
    // Check the availability of the time, and make an appointment if there is time on the calendar
   return createCalendarEvent(dateTimeStart, dateTimeEnd, appointment_type).then(() => {
     agent.add(`Ok, let me see if we can fit you in. ${appointmentTimeString} is fine!.`);
   }).catch(() => {
     agent.add(`I'm sorry, there are no slots available for ${appointmentTimeString}.`);
   });
 }

// Handle the Dialogflow intent named 'Schedule Appointment'.
 let intentMap = new Map();
 intentMap.set('Schedule Appointment', makeAppointment);
 agent.handleRequest(intentMap);
});

//Creates calendar event in Google Calendar
function createCalendarEvent (dateTimeStart, dateTimeEnd, appointment_type) {
 return new Promise((resolve, reject) => {
   calendar.events.list({
     auth: serviceAccountAuth, // List events for time period
     calendarId: calendarId,
     timeMin: dateTimeStart.toISOString(),
     timeMax: dateTimeEnd.toISOString()
   }, (err, calendarResponse) => {
     // Check if there is a event already on the Calendar
     if (err || calendarResponse.data.items.length > 0) {
       reject(err || new Error('Requested time conflicts with another appointment'));
     } else {
       // Create event for the requested time period
       calendar.events.insert({ auth: serviceAccountAuth,
         calendarId: calendarId,
         resource: {summary: appointment_type +' Appointment', description: appointment_type,
           start: {dateTime: dateTimeStart},
           end: {dateTime: dateTimeEnd}}
       }, (err, event) => {
         err ? reject(err) : resolve(event);
       }
       );
     }
   });
 });
}
  1. <INSERT YOUR CALENDAR ID> 替换为您在上一部分中复制的日历 ID。
  2. <INSERT CONTENTS OF YOUR JSON FILE HERE> 替换为您的 JSON 文件的内容。
  3. (可选)根据预约日历的时区更改 const timeZoneconst timeZoneOffset
  4. 点击部署

启用 fulfillment 响应

  1. 导航到 Dialogflow 控制台并点击意图
  2. 点击安排预约意图
  3. 向下滚动到 Fulfillment 并开启为此意图启用网络钩子调用

a5b41336b5249e44.png

  1. 点击保存
  2. 点击部署

7. 测试聊天机器人

您可以在 Actions 模拟器中测试聊天机器人,也可以使用之前了解的 Web 或 Google Home 集成。

  1. 用户:“Set an appointment for vehicle registration at 2 PM tomorrow.”
  2. 聊天机器人:“Ok, let me see if we can fit you in.April 24, 2 PM is fine!"

96d3784c103daf5e

  1. 日历会预订回复。

b7da9da814271db8.png

8. 清理

如果您计划完成其他 Dialogflow Codelab,请暂时跳过此部分,稍后再回来查看。

删除 Dialogflow 代理

  1. 点击现有代理旁边的 dc4ac6f9c0ae94e9.png

520c1c6bb9f46ea6

  1. 常规标签页中,滚动到底部,然后点击删除此代理
  2. 在对话框中输入 Delete,然后点击删除

9. 恭喜

您在 Dialogflow 中创建了一个聊天机器人,并将它与日历集成。您现在已经是聊天机器人开发者了!

了解详情

如需了解详情,请查看 Dialogflow GitHub 页面上的代码示例。