用Slack的Bolt API在Node.js中构建一个Slackbot

1,290 阅读13分钟

新的Bolt API

我最近试图用Node Slack SDK开发一个Slackbot,但不幸的是,我遇到了一些错误。这时我偶然发现了新的Bolt API。根据Slack的说法,它是 "用JavaScript开始Slack平台编程的最快速的方法"。

有很多理由可以尝试Slack的新Bolt API来构建你的下一个Slack应用或机器人。首先,它是一个记录良好的库,可以帮助你避免在以后的工作中遇到奇怪的错误和问题。其次,该API是由Slack开发和维护的,这确保了它会经常被更新。

使用这个API进行开发是很容易的,我可以向你保证,Bolt API库是开发Slack应用程序的必经之路。在本教程中,你将学习如何用Bolt API创建你自己的Slackbot。

设置

前提条件

要跟上本教程,你需要。

  • 具备JavaScript和Node.js的基本知识
  • Node.js v.12或更高版本
  • npm

创建一个工作空间

为了开始,我们需要一个工作区来安装我们的机器人。Slack工作区是一种在组织内进行分组沟通的方式。一个组织中的每个人都可以属于一个工作区,然后被细分为多个频道。

在你的设备上安装Slack并创建一个新的工作区。然后Slack会向你的邮箱发送一个6位数的代码,你可以用它来验证。现在是有趣的部分!给你的工作区起个名字;在本教程中,我们将创建一个虚构的公司,名为The Zobo Tea Company。

注: 如果你感到好奇,你可以阅读更多关于芙蓉茶(也称为Zobo)。

Company Name Slack Screen

接下来,Slack会提示你输入你正在进行的项目的名称。你可以随心所欲地称呼该项目。你可以跳过最后一步,Slack提示你添加其他团队成员。

创建一个新的Slack应用程序

现在,我们将创建一个新的Slack应用程序;Slack应用程序是在工作区中提供特定功能的小应用程序。你可以通过登录你的Slack工作区并在Slack应用目录中搜索应用来安装一个预先存在的Slack应用。

我们将创建的Slack应用程序是一个知识库,帮助我们小说组织内的员工快速找到常见问题(FAQ)的答案。

要创建一个新的Slack应用程序,请前往Slack API仪表板。点击右上方的创建新应用按钮。给你的机器人起个名字,然后选择你想把应用安装到哪个工作区。我们将我们的应用程序称为ask-ztc-bot

Create Slack App

点击**"创建应用程序**",你会被转到你的新应用程序的仪表盘。

oAuth和权限

我们需要给我们的新应用程序一定的权限,使其能够在Slack工作区访问数据和执行操作。

在你的Slack仪表板上,你会发现左侧边栏的oAuth和权限菜单选项。一旦你浏览到这里,向下滚动到作用域。我们需要我们的ask-ztc-bot ,以便能够阅读用户的即时信息,并对这些信息作出回应。这里是我们给我们的机器人的范围的截图。

Slack Bot Token Scopes

安装应用程序到你的工作区

完成这些后,我们现在可以将该应用程序安装到我们的工作区。从左边的侧栏,导航到设置 > 安装应用程序 > 安装到工作区。

设置Slackbot服务器

接下来,是时候写一些代码了。我们需要为我们的Slackbot设置一个服务器,我们可以向其发送请求。让我们开始吧!

创建一个名为ask-ztc-bot 的目录并初始化npm。

mkdir ask-ztc-bot && cd ask-ztc-bot 
npm init -y

ask-ztc-bot 目录中安装以下软件包 。

  • @slack/bolt:一个JavaScript框架,用于使用最新的平台功能在瞬间构建Slack应用程序
  • nodemon当检测到目录中的文件变化时,自动重新启动Node.js应用程序的工具。
  • dotenv:一个零依赖性模块,可将环境变量从.env 文件加载到 process.env

我将使用Yarn软件包管理器来安装这些软件包,但你也可以使用npm。

yarn add @slack/bolt
yarn add -D nodemon dotenv

我们需要对我们的package.json 文件做一个小调整。让我们添加一个名为dev 的新脚本,运行nodemon app.js 。你的package.json 应该看起来像这样。

...
  "main": "index.js",
  "scripts": {
    "dev": "nodemon app.js"
  },
....

当我们对代码库中的任何文件进行修改时,dev 脚本会自动重启我们在app.js 的服务器。接下来,创建app.js 文件,该文件将包含我们服务器的代码。

touch app.js

使用令牌和秘密进行认证

Slack需要对我们的机器人进行认证,以便连接它。Slack使用一个SIGNING_SECRET 和一个BOT_TOKEN 来验证应用程序。我们需要将SLACK_SIGNING_SECRETSLACK_BOT_TOKEN 存储在一个.env 文件中,以防止它们在使用版本控制时被暴露。

要找到你的SLACK_SIGNING_SECRET ,导航到基本信息>应用程序凭证>签名秘密。要获得你的SLACK_BOT_TOKEN ,请前往设置>安装应用程序>Bot用户oAuth Token。你的SLACK_BOT_TOKEN 应该以xoxb 开始。

在你项目的根目录下创建一个.env ,并分配你从上面的步骤中获得的SECRETTOKEN

SLACK_SIGNING_SECRET="YOUR SIGNING SECRET"
SLACK_BOT_TOKEN="YOUR BOT TOKEN"

设置服务器

进入我们之前创建的app.js 文件,并添加下面的代码。

const { App } = require("@slack/bolt");
require("dotenv").config();
// Initializes your app with your bot token and signing secret
const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
});

(async () => {
  const port = 3000
  // Start your app
  await app.start(process.env.PORT || port);
  console.log(`⚡ Slack Bolt app is running on port ${port}!`);
})();

运行我们先前创建的yarn run dev 脚本,以确保一切工作正常。你应该在你的终端中得到一个消息,内容是 "⚡ Slack Bolt应用程序正在port 3000 !"。

设置ngrok

我们需要一种方法让我们的Slack应用程序/机器人到达我们在localhost 上创建的服务器。要做到这一点,我们可以通过ngrok等服务创建的公共URL代理到localhost 。一旦你安装了ngrok,在目录中运行以下命令。

./ngrok http 3000

这将创建一个公共URL,代理到你在port 3000 上运行的localhost 。现在,确保你在localhost:3000 上的服务器仍在运行。

套接字模式

Slack也有一个叫做Socket模式的功能,它允许Slack使用WebSockets而不是像我们在上面用ngrok做的那样使用HTTP来连接我们的应用服务器。Socket模式为我们提供了更快的开发体验,因为我们可以跳过ngrok的设置。

开始使用Socket模式

首先,导航到设置>基本信息>应用级令牌。在那里,点击生成令牌和作用域按钮。给你的令牌一个名字,并给你的应用程序两个可用的作用域:connections:write authorizations:read 。点击生成按钮。然后,将下一个屏幕上的令牌复制到你的.env 文件。

接下来,进入设置>套接字 模式。 拨动 " 启用 套接字模式"的开关。最后,进入你的app.js 文件,用socketMode:trueappToken 更新初始化你的app 的代码。

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  socketMode:true, // enable the following to use socket mode
  appToken: process.env.APP_TOKEN
});

完成这些后,所有对你的开发服务器的请求现在将通过WebSockets而不是HTTP发生。

斜线命令

现在我们已经给了我们的应用程序一些权限,并设置了一个服务器和一个公共URL,下一步是让它听从Slash命令。在Slack中,你可以通过发送一个命令作为消息来触发一个动作。例如,一个Slash命令可以是/knowledge ,以显示我们知识库中的所有内容。

要启用斜线命令,请点击左侧边栏的斜线命令菜单选项。然后点击 "创建 新命令"按钮。以下面的图片为指导,填写表格。请求的URL应该是ngrok为你的应用程序自动生成的自定义URL。

Slack Create New Command

点击位于屏幕右下方的保存按钮。Slack会提示你将应用程序重新安装到你的工作区,以便你的更改生效。遵循这些指示,你的/knowledge 命令现在应该已经创建了!

测试/knowledge 命令

现在,我们可以从Slack内部测试/knowledge 命令。首先,我们将创建一个监听器来监听包含/knowledge 命令的事件。在你的app.js 文件中,添加以下代码。

const { App } = require("@slack/bolt");
require("dotenv").config();
// Initializes your app with your bot token and signing secret
const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
});

app.command("/knowledge", async ({ command, ack, say }) => {
    try {
      await ack();
      say("Yaaay! that command works!");
    } catch (error) {
        console.log("err")
      console.error(error);
    }
});

(async () => {
  const port = 3000
  // Start your app
  await app.start(process.env.PORT || port);
  console.log(`⚡ Slack Bolt app is running on port ${port}!`);
})();

让我们测试一下我们的代码!在Slack应用程序中,你应该在 "你的应用程序"部分下看到ask-ztc-bot 应用程序。点击它,向机器人发送消息。输入/knowledge ,然后点击回车。你应该收到一条消息,内容是 "耶!这个命令有效!"。

Bot Working Message Slack

Slack中的信息

我们还可以提到或@ 机器人,并包括额外的文本,作为消息发送给机器人。
在Slack中,提到一个应用程序是一种事件。我们也可以监听其他事件,比如当新用户加入一个频道,一个新频道被创建,等等。为了让我们的机器人/应用程序能够监听事件,我们需要设置事件订阅。

事件订阅

要启用事件,请从Slack应用程序仪表板上导航到功能>事件订阅。拨动启用事件的按钮。

为了让Slack通知我们的应用程序的事件,我们需要提供一个Slack可以验证的公共URL。复制我们之前创建的ngrok URL,并将其粘贴到Request URL输入栏。你需要在URL中添加/slack/events ,因为Slack会通过发送POST请求来验证你的URL。

Enable Event Subscriptions Slack

一旦你看到带有勾号的绿色验证文本,你就知道你的应用程序已经被Slack成功验证了,你就可以开始使用了!

接下来,我们需要给应用程序一些事件权限。点击订阅机器人事件的下拉菜单,添加以下事件。有四个与消息有关的事件。

  • message.channels :监听公共频道中的消息
  • message.groups :监听私人频道中的消息
  • message.im :监听你的应用程序与用户的DMs中的消息
  • message.mpim :监听多人DMs中的消息

在本教程中,我们将只订阅message.im ,因为我们只想让用户对我们的机器人进行DM。

Subscribe Bot Events Slack

点击屏幕右下角的 "保存更改"按钮,保存你的更改。

现在,我们可以测试我们的应用程序,以确保它能够接收和回复信息。在你的app.js ,添加以下代码。

app.message("hey", async ({ command, say }) => {
    try {
      say("Yaaay! that command works!");
    } catch (error) {
        console.log("err")
      console.error(error);
    }
});

回到azk-ztc-bot 应用程序,向它发送一条消息,如@ask-ztc-bot hey 。你应该得到一个回应。

Slackbot Command Works Message

对于像知识库这样的应用程序,我们不能真正匹配精确的词。我们需要一种方法来检查用户发送给我们的机器人的信息是否包含一个与我们的知识库中的关键词相匹配的关键词。为此,Slack允许我们使用regex表达式。例如,让我们更新上面使用的代码块,使其看起来像这样。

// matches any string that contains the string hey
app.message(/hey/, async ({ command, say }) => {
    try {
      say("Yaaay! that command works!");
    } catch (error) {
        console.log("err")
      console.error(error);
    }
});

发送一条信息,其中包括格式为Well, hey there Mr.bot! 的字符串hey 。我们的机器人仍然会做出正确的反应,因为该消息包含字符串hey

String Message Bot Response

创建知识库

现在,我们可以开始实际创建知识库了。

首先,我们将创建一个迷你数据库来存储常见问题和答案。我们的数据库将是我们服务器上的一个简单的JSON文件。如果你的数据要求变得庞大和复杂,你可能想考虑像MongoDB这样的数据库管理系统。

在你项目的根目录下,创建一个db.json 文件并添加以下数据。

{
    "data":[
        {
            "keyword": "products",
            "question": "How many different products do we sell at ZTC?",
            "answer": "ZTC currently has 3 products on the market. Hibiscus tea with a hint of one of Lemon/Pineapple or ginger."
        },
        {
            "keyword": "products",
            "question": "What online stores sell our products?",
            "answer": "Amazon, Macy's and Shoprite."
        },
        {
            "keyword": "people",
            "question": "How many people work at ZTC?",
            "answer": "ZTC currently employs 250 people from 21 different countries."
        },
        {
            "keyword": "reset password",
            "question": "How do I reset my password?",
            "answer": "To reset your company E-mail password, call Ola on ext.8099."
        }

    ]
}

我们已经创建了一组四个问题及其答案,并将它们归入某些关键词下,以便于参考。

对命令的响应

随着我们的JSON数据库的建立,我们需要一种方法来读取其中的数据。我们将使用内置的 [fs](https://nodejs.org/api/fs.html)模块从db.json 文件中读取数据。在你的app.js 文件的顶层,添加以下代码块。

// require the fs module that's built into Node.js
const fs = require('fs')
// get the raw data from the db.json file
let raw = fs.readFileSync('db.json');
// parse the raw bytes from the file as JSON
let faqs= JSON.parse(raw);

现在,我们可以编写响应/knowledge 命令的代码。这个命令将向用户显示我们数据库中的所有问题和答案。

app.command("/knowledge", async ({ command, ack, say }) => {
  try {
    await ack();
    let message = { blocks: [] };
    faqs.data.map((faq) => {
      message.blocks.push(
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: "*Question*",
          },
        },
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: faq.question,
          },
        },
        {
            type: "section",
            text: {
              type: "mrkdwn",
              text: "*Answer*",
            },
          },
          {
            type: "section",
            text: {
              type: "mrkdwn",
              text: faq.answer,
            },
          }
      );
    });
    say(message);
  } catch (error) {
    console.log("err");
    console.error(error);
  }
});

我们正在使用块(由Slack Bolt API提供)和markdown来格式化我们将显示给用户的消息。为了进一步定制你的机器人向用户发送的信息,Slack提供了一个Block Kit Builder,你可以用它来获得你想要的模板。

你可以通过在私人对话中输入命令/knowledge ,来测试一下ask-ztc-bot

Test Command Bot Conversation

正如你所看到的,它正确地列出了我们知识库中的所有常见问题。

接下来,我们将使用一个简单的正则表达式来检测一个用户是否在他们的问题中包含了关键词产品。如果他们有,我们就会向他们显示带有关键词产品的常见问题。

app.message(/products/, async ({ command, say }) => {
  try {
    let message = { blocks: [] };
    const productsFAQs = faqs.data.filter((faq) => faq.keyword === "products");

    productsFAQs.map((faq) => {
      message.blocks.push(
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: "*Question ❓*",
          },
        },
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: faq.question,
          },
        },
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: "*Answer ✔*",
          },
        },
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: faq.answer,
          },
        }
      );
    });

    say(message);
  } catch (error) {
    console.log("err");
    console.error(error);
  }
});

为了测试这一点,向机器人发送一条包含产品这个词的信息,机器人将回应所有与产品这个关键词有关的信息。

Test Bot Keywords Response

更新知识库

最后,我们要让用户能够将自己的数据添加到知识库中。

创建一个新的斜线命令,名为/update 。这个命令将被用户调用,以便向我们的知识库添加新的数据。

Slack Create New Slash Command

我们对这个命令做了一个小小的改动。在使用提示中,我们指定用户应使用管道| 字符分隔不同的字段。这样,我们就可以接受用户发送的输入字符串,并使用管道字符来分割它。

注意。 如果你打算将你的Slackbot添加到一个频道中,并且认为可能有其他应用程序与你的命令相似,那么可能值得创建一个命令,例如*。*** /ask-ztc ,并让 用户为该命令添加一个额外的字符串。例如。 使用 /ask-ztc knowledge 来显示知识库中的所有FAQ。

下面是处理/update 斜线命令的代码。我们更新db.json 文件,首先读取文件中的数据,然后将用户发送的新数据附加到文件中。

app.command("/update", async ({ command, ack, say }) => {
  try {
    await ack();
    const data = command.text.split("|");
    const newFAQ = {
      keyword: data[0].trim(),
      question: data[1].trim(),
      answer: data[2].trim(),
    };
    // save data to db.json
    fs.readFile("db.json", function (err, data) {
      const json = JSON.parse(data);
      json.data.push(newFAQ);
      fs.writeFile("db.json", JSON.stringify(json), function (err) {
        if (err) throw err;
        console.log("Successfully saved to db.json!");
      });
    });
    say(`You've added a new FAQ with the keyword *${newFAQ.keyword}.*`);
  } catch (error) {
    console.log("err");
    console.error(error);
  }
});

让我们来测试一下!

我们将用以下文字调用/update 命令。"人们 | 如果我的互联网有问题,我应该联系谁?| 致电IT部门,电话是Ext.9090"。

/update 端点将回应该信息。

Update Endpoint Message Response

现在,当我们调用我们的/knowledge 命令时,我们应该看到我们新添加的FAQ是我们数据库中返回的FAQ的一部分。

Slack Slash Command New FAQ

就这样,你拥有了它!

你已经成功地创建了一个Slackbot,它可以对命令和提及作出回应。它还可以接受来自用户的新数据并将其存储在数据库中。

这个例子的源代码可以在我的GitHub上找到。

部署

你可以按照部署普通Node.js应用程序的方式,将你的应用程序部署到Heroku等平台上。不要忘记把事件订阅部分的URL改为Heroku提供的新URL。

你可以访问Bolt API文档供你参考。

The postBuild a Slackbot in Node.js with Slack's Bolt API appeared first onLogRocket Blog.