使用 DialogFlow、Node.js 和 React 构建聊天机器人

汪甫
2023-12-01

对我们人类来说,交谈是第二天性。 它对我们来说很自然,但对于机器人来说却不能这样说。 即使是一个简单的问题,例如“你今天过得怎么样?”,也可以用几种方式重新表述(例如,“最近怎么样?”、“你好吗?”),机器人通常无法理解这些问题。

我们可以解释问题背后的意图,但是构建逻辑以促进与机器人进行更智能的对话,而且对于大多数开发人员来说,从头开始编写代码是不可行的。

好吧,幸运的是,有一种叫做 NLU(自然语言理解)的东西,它可以实现更好的人机对话——换句话说,一个利用机器学习和其他技术更好地理解人类交互的智能聊天机器人。

NLU 算法不仅可以识别文本,还可以解释其背后的意图。 因此,它是聊天机器人的理想算法。 阅读有关 NLU 在此处 的更多信息。

这就是本文的目的所在。我们将使用 Google 的 NLU 平台 DialogFlow 构建我们的聊天机器人。 继续阅读以了解有关 DialogFlow 的更多信息,以及如何通过本后续教程将其集成到 React 应用程序中。

  • 开始使用 DialogFlow

  • 什么是代理?

  • 什么是意图?

  • 添加常规意图

  • 连接 NodeJS 服务器

    • 建立我们的服务器<

    • 公开服务器

    • 启用网络钩子

  • 验证

    • DialogFlow ES:通信集成

    • 将 Kommunicate 聊天小部件集成到 React 应用程序中

开始使用 DialogFlow

简单来说,DialogFlow 是一个由 NLU 提供支持的端到端工具,用于设计聊天机器人并将其集成到我们的界面中。 它使用由我们提供的语言训练的机器学习 (ML) 模型将自然语言翻译成机器可读的数据。 它是如何工作的? 让我们在构建聊天机器人的同时学习。

打开 DialogFlow 控制台并使用您的 Google 帐户登录。 登录成功后,我们看到如下界面:

可能引起您注意的第一件事是 创建代理 选项。

什么是代理?

没有什么花哨! 聊天机器人本身就是一个代理。 收集用户的查询,对其进行操作,最后发送响应都由我们的代理处理。


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验 了解更多 →


让我们创建我们的聊天机器人; 例如,咖啡店的机器人怎么样? 猜测我的咖啡店灵感没有奖品。

这就是控制台现在的样子:

现在,屏幕上出现了更多的行话—— 意图 。

什么是意图?

控制台说,“意图是用户查询和您的软件实现的操作之间的映射”。 那么这是什么意思?

Let me explain: in the case of our bot, we expect to receive queries like, “I would like a cappuccino” and, “When does the shop open?”, etc. We can categorize these queries into user intentions such as “Take Order”, “Timings”, etc. To handle them, we define these categories as intents in our agent.

We also see that our agent comes with two default intents; Default Welcome Intent and Default Fallback Intent. Let’s explore them in a little more detail:

这里有很多行话; 让我们一一介绍:

上下文

在人类对话中,要理解短语,我们通常需要一些上下文。 同样,对于机器人,意图需要知道查询的上下文。 为了使这成为可能,我们通过上下文连接一个或多个意图。 我们将在本文后面部分了解更多信息。

训练短语

这些是用于训练和帮助我们的代理以正确意图匹配查询的示例短语。 更多的短语和变体将提高意图匹配的准确性。

通过查看默认的短语列表,很明显这个意图是用来向我们的用户打招呼的。

活动

我们刚刚了解到代理会寻找训练短语来触发意图。 但是,意图也可以由事件触发。 有两种类型的事件:

  • 平台事件 :这些由平台本身提供,并在特定于平台的事件发生时发生(例如, 欢迎 事件)

  • 自定义事件 :这些是由我们定义的(例如,我们进行的 API 调用的响应)

动作和参数

一旦查询与正确的意图相匹配,接下来就是对其采取行动。 为了采取行动,有时我们需要从查询中提取一些数据。 为了提取,我们用实体类型定义参数。 举个例子:“咖啡店今天开门吗?”; 此处提取的参数是 today ,这是执行某些逻辑并做出相应响应所需的关键信息。 我们将在本教程的后面部分了解更多信息。

回应

响应用户。 在这里,我们看到静态短语,但如果我们使用参数或实现,它们也可以是动态的。

履行

当我们启用履行时,代理通过我们定义的 API 调用给出动态响应(例如,如果用户想要预订餐桌,我们可以检查数据库并根据可用性做出响应)。 再说一次,稍后再谈。

让我们先试试这个默认意图,然后再继续。 在右侧,我们有一个 Dialogflow Simulator 来测试我们的代理。 我们说一些类似于训练短语的内容,代理从响应列表中做出响应:

而且,如果我们说一些完全不同的东西,代理会触发 Default Fallback Intent :

因此,如果代理未能找到正确的意图,它会触发回退意图。 很流畅,对吧? 但是,让我们尽量避免它并添加意图来进行整个对话。

添加常规意图

让我们尝试创建如下图所示的对话:

海阔视界App,搜索资源看片追剧必备,支持磁力资源在线播放!

修改 Default Welcome Intent 的响应以打招呼并询问订单。 像这样的东西; “问候! 你要点些什么?”。

创建一个接受订单的意图,并将该意图命名为简单且有意义的名称,例如 Take Order 。

现在,我们添加训练短语。 用户可能会说,“我想要两杯拿铁”。 将其添加到训练短语列表中足以使其与此意图相匹配。 但是,我们还需要资格信息; “2”和“拿铁”。

中添加几个 参数 为了提取它们,我们将在短语 ——数量 (@sys.number 实体类型)和 项目 (@sys.any 实体类型):

添加更多变体以使其更好。 这是我添加的一些:

一旦添加了参数丰富的短语,该表就会自动填充。 我们可以将它们标记为 必需/可选 ,并在需要时设置 默认值 。 另外,我们需要定义一个问题作为 提示 ,如果第一次没有输入,强制用户输入所需的参数。

因此,这意味着如果我们从列表中获得第一个短语“我想订购”,并且缺少项目(必需),则会触发提示来询问它。 如果我们从列表中得到第二个短语; “I would like to order a mocha”,并且数量(可选)不存在,那么我们不会提示用户输入数量,而是将默认值设置为 1 并使用它。

我们可以返回一个动态响应来使用 参数 来重复订单并询问他们是否想要一个附加组件:

为此,请创建一个意图来处理用户对附加问题的响应。

响应将是 Yes 或 No 。 这是引入 后续意图 的理想场景。 顾名思义,这些用于跟进父意图中的对话。


来自 LogRocket 的更多精彩文章:

  • 不要错过 The Replay 来自 LogRocket 的精选时事通讯

  • 使用 React 的 useEffect 优化应用程序的性能

  • 之间切换 在多个 Node 版本

  • 了解如何 使用 AnimXYZ 为您的 React 应用程序制作动画

  • 探索 Tauri ,一个用于构建二进制文件的新框架

  • 比较 NestJS 与 Express.js

  • 发现 TypeScript 领域中使用的流行 ORM


DialogFlow 为常见回复提供了许多预定义的后续意图,例如“是”、“否”或“取消”。 此外,如果您需要处理自定义回复,您可以创建自己的自定义跟进。 我们将在本教程中使用预定义的,但如果您想自己动手,这取决于您。

从意向列表中,将鼠标悬停在 TakeOrder 意向上,然后单击 添加后续意向 。 选择 Yes 的后续意图 并创建名为Take Order – yes 。

您可能已经注意到添加了一个输入上下文 ( TakeOrder-followup )。 为了使后续工作起作用,它们需要与父意图相关联,这就是上下文派上用场的地方。

当我们创建后续 Intent 时,会自动将输出上下文添加到父 Intent 中,并将同名的输入上下文添加到后续 Intent 中。

我们不需要担心训练短语,因为它们已经到位。 现在,为此意图添加动态响应。 当上下文到位后,我们可以使用父意图中的参数,如下所示:

同样,创建一个预定义的后续意图来处理 “否 ”作为响应。 这个将被命名为 Take Order – no 。 只需在此处添加动态响应即可:

代理已准备好进行对话。 我们总是可以在模拟器中测试它,但让我们尝试一些不同的东西。 单击 侧边栏中的集成 并启用 Web Demo 。 打开那里提供的 URL 并开始对话:

代理按预期工作正常,但显示订单的总账单金额不是很好吗? 我们可以从服务器获取价格并将计算的金额返回给用户。

连接 NodeJS 服务器

在讨论意图时,我们遇到了 Fulfillment ,它通过我们定义的 API 调用来帮助返回动态响应。 这就是我们需要在这里与我们的服务器交互的东西。

找到 Fulfillment 在侧边栏中 并打开它。 DialogFlow 提供了两种使用实现的方法:

  • An in-line editor powered by Google Cloud Functions. But, to enable this, we need to add a valid billing account as this integration has charges, if used beyond a certain limit

    • A webhook service

I’m going to build a webhook service and make it public. Before proceeding, make sure the service meets the requirements mentioned here.

Building our server

Create a node app in a new directory and install the necessary dependencies:

mkdir centralperk-server
cd centralperk-server
npm init -y
npm i express dialogflow-fulfillment

从 index.js 中的基本服务器开始:

const express = require("express");
const app = express();
​
app.get("/", (req, res) => {
  res.send("Hi from server!");
});
​
app.listen(8080, () => {
  console.log("server running...");
});

这只是在端口 8080 上运行服务器。现在,让我们编写一些代码来处理来自 DialogFlow 的 webhook 请求:

const express = require("express");
const app = express();
​
const { WebhookClient } = require("dialogflow-fulfillment");
const getPrice = require("./helpers");
​
app.get("/", (req, res) => {
  res.send("Hi from server!");
});
​
app.post("/", express.json(), (req, res) => {
  const agent = new WebhookClient({ request: req, response: res });
​
  function handleIntent(agent) {
    const intent = agent.intent;
    const item = agent.contexts[0].parameters.item;
    const quantity = agent.contexts[0].parameters.quantity;
    const billingAmount = getPrice(intent, item, quantity);
​
    const response =
      intent === "Take Order - yes"
        ? `Great! Your ${quantity} ${item} and cookies will be ready in no time. Please pay ${billingAmount}$.`
        : `Okay! Your ${quantity} ${item} will be ready in no time. Please pay ${billingAmount}$.`;
​
    agent.add(response);
  }
​
  const intentMap = new Map();
  intentMap.set("Take Order - yes", handleIntent);
  intentMap.set("Take Order - no", handleIntent);
  agent.handleRequest(intentMap);
});
​
app.listen(8080, () => {
  console.log("server running...");
});

帮助计算价格:

const priceList = {
  mocha: 5,
  latte: 7,
  cookies: 2,
};
​
module.exports = function (intent, item, quantity) {
  const total =
    intent === "Take Order - yes"
      ? priceList[`${item}`] * quantity + priceList["cookies"]
      : priceList[`${item}`] * quantity;
​
  return total;
};

让我们来看看上面的实现。

导入的 WebhookClient 将处理与 DialogFlow 的 webhook 实现 API 的通信。 当一个启用实现的意图被匹配时,一个 HTTPS POST webhook 请求被发送到我们的服务器。 此请求由 agent.handleRequest(intentMap) 处理。 它接受处理程序的映射,每个处理程序都是一个函数回调。 这里定义的从传递的实例中提取所有需要的信息,计算计费金额,然后最终返回动态响应。

公开服务器

使用 ngrok 是将服务器放到 Internet 上的最快和最简单的方法。 按照 此处 的步骤进行快速设置和安装。 完成这些步骤后,运行以下命令:

ngrok http 8080

安全的公共 URL 很快就准备好了:

ngrok                                                                                                   (Ctrl+C to quit)                                                                                                                        Visit http://localhost:4040/ to inspect, replay, and modify your requests                                                                                                                                                                       Session Status                online                                                                                    Account                       Piyush (Plan: Free)                                                                       Version                       3.0.6                                                                                     Region                        India (in)                                                                                Latency                       55ms                                                                                      Web Interface                 http://127.0.0.1:4040                                                                     Forwarding                    https://2c73-182-64-199-236.in.ngrok.io -> http://localhost:8080                                                                                                                                                  Connections                   ttl     opn     rt1     rt5     p50     p90                                                                             5       0       0.00    0.01    2.37    5.21

(注意:记得保持本地服务器正常运行)

启用网络钩子

继续并在 Fulfillment 窗口中启用 webhook 并输入安全的公共 URL。 此外,请记住,需要为两个后续意图启用 webhook 调用。

一切看起来都不错。 现在让我们测试一下:

我们的聊天机器人已全部设置完毕!

将 DialogFlow 聊天机器人集成到 React 应用程序中

有很多方法可以将聊天机器人集成到 React 应用程序中:

  • 从头开始在 React 中构建聊天小部件。 使用 Redux 之类的库处理传入和传出消息的状态,并修改 Node 服务器以处理来自 React 应用程序的调用以及将它们发送到 DialogFlow。 这听起来确实很有趣,但要涵盖的内容很多,超出了本文的范围

  • 使用 Kommunicate 更轻松地将 DialogFlow 聊天机器人集成到 React 应用程序中

在本博客教程中,我们将使用 Kommunicate 选项。

DialogFlow ES:通信集成

按着这些次序:

免费试用并使用您的 Google 帐户注册。

单击 机器人集成 并选择 DialogFlow ES 。

使用下图中提到的说明从 DialogFlow 云帐户获取 JSON 密钥:

接下来,我们要选择一个自定义头像:

这就是我们需要为 DialogFlow ES 和 Kommunicate 集成做的所有事情!

将 Kommunicate 聊天小部件集成到 React 应用程序中

创建一个聊天机器人组件并将以下代码粘贴到 useEffect() 中:

(function (d, m) {
      var kommunicateSettings = {
        appId: "<YOUR APP_ID>",
        popupWidget: true,
        automaticChatOpenOnNavigation: true,
      };
      var s = document.createElement("script");
      s.type = "text/javascript";
      s.async = true;
      s.src = "https://widget.kommunicate.io/v2/kommunicate.app";
      var h = document.getElementsByTagName("head")[0];
      h.appendChild(s);
      window.kommunicate = m;
      m._globals = kommunicateSettings;
    })(document, window.kommunicate || {});
import React, { useEffect } from "react";
​
function Chatbot() {
  useEffect(() => {
    (function (d, m) {
      var kommunicateSettings = {
        appId: "<YOUR APP_ID>",
        popupWidget: true,
        automaticChatOpenOnNavigation: true,
      };
      var s = document.createElement("script");
      s.type = "text/javascript";
      s.async = true;
      s.src = "https://widget.kommunicate.io/v2/kommunicate.app";
      var h = document.getElementsByTagName("head")[0];
      h.appendChild(s);
      window.kommunicate = m;
      m._globals = kommunicateSettings;
    })(document, window.kommunicate || {});
  }, []);
  return <div></div>;
}
​
export default Chatbot;

请记住用您的 appId 替换占位符。 最后,在 App 组件中导入:

import "./App.css";
import Chatbot from "./Chatbot";
​
function App() {
  return (
    <div className="App">
      <Chatbot />
    </div>
  );
}
​
export default App;

在本地运行应用程序以测试集成:

就这样,我们将聊天机器人添加到了 React 应用程序中。 访问 此 内容添加更多自定义项。 仪表板,为颜色 、 图标 和 通知声音 等

结论

这就是这个博客的全部内容! 我们学习了聊天机器人开发的几个方面; 从使用 DialogFlow 构建它,与 NodeJS 服务器连接,到最终将其集成到 React 应用程序中。 我希望它对您有意义,并且您能够轻松地学习本教程。

如果您有任何问题,可以在评论中留下,我很乐意为您解答。 请随时在 LinkedIn 或 Twitter 上 与我联系。

全面了解生产 React 应用程序

调试 React 应用程序可能很困难,尤其是当用户遇到难以重现的问题时。 如果您对监控和跟踪 Redux 状态、自动显示 JavaScript 错误以及跟踪缓慢的网络请求和组件加载时间感兴趣,请 尝试 LogRocket 。

LogRocket 就像一个用于 Web 和移动应用程序的 DVR,几乎可以记录您的 React 应用程序上发生的所有事情。 无需猜测问题发生的原因,您可以汇总并报告问题发生时应用程序所处的状态。 LogRocket 还监控您的应用程序的性能,并使用客户端 CPU 负载、客户端内存使用情况等指标进行报告。

LogRocket Redux 中间件包为您的用户会话增加了一层额外的可见性。 LogRocket 记录来自 Redux 存储的所有操作和状态。

 类似资料: