1. 概览
在此 Codelab 中,您将学习如何使用 Botkit 工具包构建 Slack 聊天机器人,并在 Google Cloud 上运行该聊天机器人。您将能够在 Slack 直播频道中与该聊天机器人互动。
学习内容
- 如何在 Slack 中创建聊天机器人自定义集成
- 如何使用 Secret Manager 保护 Slack 密钥
- 如何在 Cloud Run 上部署 Slack 聊天机器人,Cloud Run 是一个可自动扩缩无状态容器的全代管式计算平台
所需条件
您打算如何使用本教程?
您如何评价自己使用 Google Cloud 的体验?
<ph type="x-smartling-placeholder">2. 设置和要求
自定进度的环境设置
- 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个。
- 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
- 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用
PROJECT_ID
标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。 - 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档。
- 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。
启动 Cloud Shell
虽然 Google Cloud 可以通过笔记本电脑远程运行,但在本教程中,您将使用 Cloud Shell,这是一个在云端运行的命令行环境。
激活 Cloud Shell
- 在 Cloud Console 中,点击激活 Cloud Shell。
如果这是您第一次启动 Cloud Shell,系统会显示一个中间屏幕,说明它是什么。如果您看到中间屏幕,请点击继续。
预配和连接到 Cloud Shell 只需花几分钟时间。
这个虚拟机装有所需的所有开发工具。它提供了一个持久的 5 GB 主目录,并在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的大部分(即使不是全部)工作都可以通过浏览器完成。
在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设为您的项目 ID。
- 在 Cloud Shell 中运行以下命令以确认您已通过身份验证:
gcloud auth list
命令输出
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
- 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目:
gcloud config list project
命令输出
[core] project = <PROJECT_ID>
如果不是上述结果,您可以使用以下命令进行设置:
gcloud config set project <PROJECT_ID>
命令输出
Updated property [core/project].
3. 启用 API
在 Cloud Shell 中,启用 Artifact Registry、Cloud Build、Cloud Run 和 Secret Manager API:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ run.googleapis.com \ secretmanager.googleapis.com
这会输出如下所示的成功消息:
Operation "operations/..." finished successfully.
现在,您已准备好准备和部署您的应用...
4. 创建 Slack 工作区
您需要一个 Slack 工作区,您可以在其中创建自定义集成。如果您没有要在本教程中使用的工作区,可以免费创建工作区。
5. 创建 Slack 聊天机器人用户
聊天机器人用户可以在 Slack 上监听消息、发布消息以及上传文件。在此 Codelab 中,您将创建一个聊天机器人来发布简单的问候消息。
创建一个新的 Slack 应用
- 转到 Slack 应用管理页面。
- 点击右上角的 Create new app(创建新应用)按钮。
- 为应用命名,例如“Kittenbot”。
- 选择您要将它安装到的 Slack 团队。
创建聊天机器人用户
- 前往左侧面板中的 Features(功能)下方的 App Home(应用主屏幕)
- 点击查看要添加的范围,为聊天机器人令牌分配范围
- 向下滚动到 Bot Token Scopes,然后点击 Add an OAuth Scope。选择
chat:write
即可“以小猫的身份发送消息”
- 向上滚动,然后点击 Install App to your Workspace 按钮。
- 此操作会为您的团队安装应用,添加您刚刚创建的聊天机器人用户,并生成聊天机器人令牌。
- 出现提示时,点击允许以授权聊天机器人在您的工作区中聊天。
启用消息和命令
- 向下滚动到 Show Tabs(显示标签页),并确保这两个选项均已启用:
获取客户端签名密钥
- 转到设置下的基本信息。
- 向下滚动到 Signing Secret(签名密钥),点击 Show(显示),然后将该密钥复制到剪贴板:
- 将密钥保存在环境变量中:
CLIENT_SIGNING_SECRET=PASTE_THE_SIGNING_SECRET
获取聊天机器人令牌
- 转到 OAuth &功能下的权限。
- 点击复制按钮,将聊天机器人用户 OAuth 访问令牌文本复制到剪贴板。
- 将聊天机器人令牌保存在环境变量中:
BOT_TOKEN=PASTE_THE_BOT_TOKEN
别担心。如果您需要再次获取这些令牌,可以从 应用管理页面 返回此配置页面。
6. 保护您的密钥
我们希望确保妥善存储您的聊天机器人令牌和客户端签名密钥。如果在源代码中对这些 Secret 进行硬编码,则可能会导致通过将其发布到版本控制系统或将其嵌入到 Docker 映像中来意外公开这些 Secret。
Secret Manager 提供了一种安全便捷的方法来存储 API 密钥、密码、证书和其他敏感数据。Secret Manager 提供了一个集中、单一的数据源,便于您管理、访问和审核 Google Cloud 中的 Secret。
创建 Secret
使用以下命令保存您的客户端签名密钥和聊天机器人令牌:
- 客户端签名密钥
echo -n $CLIENT_SIGNING_SECRET | gcloud secrets create client-signing-secret \ --replication-policy automatic \ --data-file -
- 聊天机器人令牌
echo -n $BOT_TOKEN | gcloud secrets create bot-token \ --replication-policy automatic \ --data-file -
访问您的 Secret
请确认您已正确创建 Secret,并且权限正常。使用以下命令访问您的 Secret:
echo $(gcloud secrets versions access 1 --secret client-signing-secret) echo $(gcloud secrets versions access 1 --secret bot-token)
您还可以在 Google Cloud 控制台中查看和管理您的密钥。
7. 获取示例代码
在 Cloud Shell 的命令行上,运行以下命令以克隆 GitHub 代码库:
git clone https://github.com/googlecodelabs/cloud-slack-bot.git
将目录更改为 cloud-slack-bot/start
。
cd cloud-slack-bot/start
了解代码
使用您偏好的命令行编辑器(nano、vim、emacs 等)打开 kittenbot.js
文件,或者使用以下命令直接打开 Cloud Shell Editor 中的当前文件夹:
cloudshell workspace .
小猫机器人代码有两个主要函数。一个是检索 Secret,另一个是运行聊天机器人。
首先,导入依赖项:
kittenbot.js
const { Botkit } = require('botkit');
const {
SlackAdapter,
SlackEventMiddleware,
} = require('botbuilder-adapter-slack');
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
SlackAdapter 和 SlackEventMiddleware 是用于扩展 Botkit 的软件包,可让聊天机器人轻松地在 Slack API 之间来回翻译消息。Secret Manager 客户端将允许您访问在之前步骤中保存的 Secret。
接下来,我们有用于检索 Secret 的函数:
/**
* Returns the secret string from Google Cloud Secret Manager
* @param {string} name The name of the secret.
* @return {Promise<string>} The string value of the secret.
*/
async function accessSecretVersion(name) {
const client = new SecretManagerServiceClient();
const projectId = process.env.PROJECT_ID;
const [version] = await client.accessSecretVersion({
name: `projects/${projectId}/secrets/${name}/versions/1`,
});
// Extract the payload as a string.
const payload = version.payload.data.toString('utf8');
return payload;
}
此函数会返回对聊天机器人进行身份验证所需的密钥的字符串值。
下一个函数会初始化聊天机器人:
/**
* Function to initialize kittenbot.
*/
async function kittenbotInit() {
const adapter = new SlackAdapter({
clientSigningSecret: await accessSecretVersion('client-signing-secret'),
botToken: await accessSecretVersion('bot-token'),
});
adapter.use(new SlackEventMiddleware());
const controller = new Botkit({
webhook_uri: '/api/messages',
adapter: adapter,
});
controller.ready(() => {
controller.hears(
['hello', 'hi', 'hey'],
['message', 'direct_message'],
async (bot, message) => {
await bot.reply(message, 'Meow. :smile_cat:');
}
);
});
}
该函数的第一部分使用密钥配置 SlackAdapter,然后指定用于接收消息的端点。控制器开启后,聊天机器人会回复包含“hello”“hi”或“hey”的任何消息上面写着“喵,😺?”。
请查看应用清单中的以下特定部分:
package.json
{
// ...
"scripts": {
"start": "node kittenbot.js",
// ...
},
"engines": {
"node": "16"
},
// ...
}
您可以使用 Cloud Run 直接从源代码部署 Node.js 应用。在后台,会发生以下情况:
- Cloud Run 会调用 Cloud Build 来构建容器映像(请参阅从源代码部署)。
- 如果源代码目录中存在
Dockerfile
,Cloud Build 会使用它来构建容器映像。 - 由于不是这样,Cloud Build 将调用 Buildpack 来分析源代码并自动生成可用于生产环境的映像。
- Buildpack 检测
package.json
清单并构建 Node.js 映像。 scripts.start
字段决定了应用的启动方式。engines.node
字段决定了容器基础映像的 Node.js 版本。- 部署时,系统会自动应用已知的安全修复程序。
您现在可以部署应用了!
8. 部署应用
Slack Events API 使用网络钩子发送有关事件的传出消息。配置 Slack 应用时,您必须提供一个可公开访问的网址,以便 Slack API 执行 ping 操作。
Cloud Run 是托管 webhook 目标的理想解决方案。它允许您使用您喜欢的任何语言或运行时,并提供并发机制,这意味着您的应用将能够处理更多的数据量。
检索您的项目 ID
定义 PROJECT_ID 环境变量:
PROJECT_ID=$(gcloud config get-value core/project)
定义 Cloud Run 区域
Cloud Run 是区域级的,这意味着运行 Cloud Run 服务的基础架构位于特定区域并由 Google 托管,以便在该区域内的所有可用区以冗余方式提供。定义将用于部署的区域,例如:
REGION="us-central1"
更新权限
为了能够从 Secret Manager 访问 Secret,需要为 Cloud Run 服务账号授予 roles/secretmanager.secretAccessor
角色。
首先,将默认服务账号保存到环境变量中:
SERVICE_ACCOUNT=$(gcloud iam service-accounts list \ --format "value(email)" \ --filter "displayName:Compute Engine default service account")
确认您已保存电子邮件地址:
echo $SERVICE_ACCOUNT
服务账号采用以下格式:PROJECT_NUMBER-compute@developer.gserviceaccount.com
。
获得电子邮件地址后,为服务账号启用该角色:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT \ --role roles/secretmanager.secretAccessor
部署应用
Cloud Run 服务会公开唯一端点,并根据需要处理的传入请求数量自动扩缩底层基础架构。
将应用部署到 Cloud Run:
gcloud run deploy kittenbot \ --source . \ --platform managed \ --region $REGION \ --set-env-vars PROJECT_ID=$PROJECT_ID \ --allow-unauthenticated
- 这将创建一个名为
kittenbot
的服务。 --source
选项使用当前文件夹通过 Cloud Build 构建应用。Cloud Build 会自动检测package.json
文件是否存在。- 您也可以使用以下命令定义默认区域:
gcloud config set run/region $REGION
- 您还可以使用以下命令将 Cloud Run 设为默认托管:
gcloud config set run/platform managed
--set-env-vars
选项可设置服务环境变量。--allow-unauthenticated
选项可公开提供该服务。
第一次,您会收到创建 Artifact Registry 代码库的提示。点按 Enter 键即可验证:
Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [REGION] will be created. Do you want to continue (Y/n)?
这会启动将源代码上传到 Artifact Registry 代码库并构建容器映像的过程:
Building using Dockerfile and deploying container ... * Building and deploying new service... Building Container. OK Creating Container Repository... OK Uploading sources... * Building Container... Logs are available at ...
然后,等待构建和部署完成。成功部署后,命令行中便会显示该服务的网址:
... OK Building and deploying new service... Done. OK Creating Container Repository... OK Uploading sources... OK Building Container... Logs are available at ... OK Creating Revision... Creating Service. OK Routing traffic... OK Setting IAM Policy... Done. Service [SERVICE]... has been deployed and is serving 100 percent of traffic. Service URL: https://SERVICE-PROJECTHASH-REGIONID.a.run.app
您可以通过以下命令获取服务网址:
SERVICE_URL=$( \ gcloud run services describe kittenbot \ --platform managed \ --region $REGION \ --format "value(status.url)" \ ) echo $SERVICE_URL
网址格式如下:
https://kittenbot-PROJECTHASH-REGIONID.a.run.app
此网址将成为用于启用 Slack Events API 的基础网址。将其复制到剪贴板,以便在下一步中使用。
您的服务现已上线并公开发布!前往 Cloud Run 控制台了解详情。
您可以查看上一个修订版本的创建时间、接收的流量,并查看日志。如果点击日志,我们可以看到 Botkit 控制器已打开,可以接收消息。
现在,让我们开始从 Slack 频道发送消息!
9. 启用 Slack 事件
如前所述,小猫机器人代码为 webhook 目标指定了相对端点。
kittenbot.js
const controller = new Botkit({
webhook_uri: '/api/messages',
adapter: adapter,
});
这意味着,我们的完整网址将是 Cloud Run 服务的基础部分加上 /api/messages
。
启用事件
在应用管理页面的边栏,前往活动订阅部分,将启用事件切换为开启。输入您的服务网址:
PASTE_THE_SERVICE_URL/api/messages
根据您输入的网址的速度,系统可能会在完成输入之前尝试验证。如果失败,请点击“重试”。
订阅
订阅所有聊天机器人事件。
点击页面底部的保存更改。系统会提示您重新安装您的应用。浏览系统提示,然后点击允许。
此时,您的聊天机器人已完全集成!工作区中的消息将触发 Slack 向 Cloud Run 服务发送消息,而该服务反过来会使用简单的问候语进行响应。
10. 测试聊天机器人
向 Kittenbot 发送一条私信:
输入“@kittenbot”即可将 kittenbot 添加到您的频道然后点击“邀请他们”:
现在你频道中的所有人都能与 Kittenbot 互动!
Slack 中的每条消息都会触发一个事件,并将 HTTP POST 消息发送到我们的 Cloud Run 服务。查看 Cloud Run 服务日志,您会看到每封邮件与日志中的一个 POST 条目相对应。
小猫机器人会以“猫咪”回应每条消息,😺?”。
11. 奖励 - 更新聊天机器人
此可选部分可能需要几分钟时间。您可以直接跳转到“清理”。
对话线程
我们希望聊天机器人做得不仅仅是“喵”!但是,如何部署在 Cloud Run 上运行的新版本?
转到 cloud-slack-bot/extra-credit
目录:
cd ../extra-credit/
在 Cloud Shell Editor 中打开当前文件夹:
cloudshell workspace .
Botkit 提供了处理对话的功能。有了这些信息,聊天机器人可以请求更多信息,并对消息做出回应,而不仅限于单字回复。
定义对话框
首先,在文件末尾查看对话函数是如何定义的:
// ...
const maxCats = 20;
const catEmojis = [
':smile_cat:',
':smiley_cat:',
':joy_cat:',
':heart_eyes_cat:',
':smirk_cat:',
':kissing_cat:',
':scream_cat:',
':crying_cat_face:',
':pouting_cat:',
':cat:',
':cat2:',
':leopard:',
':lion_face:',
':tiger:',
':tiger2:',
];
/**
* Function to concatenate cat emojis
* @param {number} numCats Number of cat emojis.
* @return {string} The string message of cat emojis.
*/
function makeCatMessage(numCats) {
let catMessage = '';
for (let i = 0; i < numCats; i++) {
// Append a random cat from the list
catMessage += catEmojis[Math.floor(Math.random() * catEmojis.length)];
}
return catMessage;
}
/**
* Function to create the kitten conversation
* @param {Object} controller The botkit controller.
* @return {Object} The BotkitConversation object.
*/
function createKittenDialog(controller) {
const convo = new BotkitConversation('kitten-delivery', controller);
convo.ask('Does someone need a kitten delivery?', [
{
pattern: 'yes',
handler: async (response, convo, bot) => {
await convo.gotoThread('yes_kittens');
},
},
{
pattern: 'no',
handler: async (response, convo, bot) => {
await convo.gotoThread('no_kittens');
},
},
{
default: true,
handler: async (response, convo, bot) => {
await convo.gotoThread('default');
},
},
]);
convo.addQuestion(
'How many would you like?',
[
{
pattern: '^[0-9]+?',
handler: async (response, convo, bot, message) => {
const numCats = parseInt(response);
if (numCats > maxCats) {
await convo.gotoThread('too_many');
} else {
convo.setVar('full_cat_message', makeCatMessage(numCats));
await convo.gotoThread('cat_message');
}
},
},
{
default: true,
handler: async (response, convo, bot, message) => {
if (response) {
await convo.gotoThread('ask_again');
} else {
// The response '0' is interpreted as null
await convo.gotoThread('zero_kittens');
}
},
},
],
'num_kittens',
'yes_kittens'
);
// If numCats is too large, jump to start of the yes_kittens thread
convo.addMessage(
'Sorry, {{vars.num_kittens}} is too many cats. Pick a smaller number.',
'too_many'
);
convo.addAction('yes_kittens', 'too_many');
// If response is not a number, jump to start of the yes_kittens thread
convo.addMessage("Sorry I didn't understand that", 'ask_again');
convo.addAction('yes_kittens', 'ask_again');
// If numCats is 0, send a dog instead
convo.addMessage(
{
text:
'Sorry to hear you want zero kittens. ' +
'Here is a dog, instead. :dog:',
attachments: [
{
fallback: 'Chihuahua Bubbles - https://youtu.be/s84dBopsIe4',
text: '<https://youtu.be/s84dBopsIe4|' + 'Chihuahua Bubbles>!',
},
],
},
'zero_kittens'
);
// Send cat message
convo.addMessage('{{vars.full_cat_message}}', 'cat_message');
convo.addMessage('Perhaps later.', 'no_kittens');
return convo;
}
这个新对话会根据回复来引导消息串。例如,如果用户回复“no”,它就会跳到标记为“no_kitten”的消息,即该对话的结尾。
将对话框添加到控制器
现在,我们已定义对话,了解如何将其添加到控制器:
async function kittenbotInit() {
// ...
const controller = new Botkit({
webhook_uri: '/api/messages',
adapter: adapter,
});
// Add Kitten Dialog
const convo = createKittenDialog(controller);
controller.addDialog(convo);
// Controller is ready
controller.ready(() => {
// ...
});
}
触发对话框
现在,控制器可以使用该对话框,我们来看看在聊天机器人听到“小猫”“小猫”“猫”或“猫”时如何开始对话:
// ...
controller.ready(() => {
controller.hears(
['hello', 'hi', 'hey'],
['message', 'direct_message'],
async (bot, message) => {
await bot.reply(message, 'Meow. :smile_cat:');
return;
}
);
// START: listen for cat emoji delivery
controller.hears(
['cat', 'cats', 'kitten', 'kittens'],
['message', 'direct_message'],
async (bot, message) => {
// Don't respond to self
if (message.bot_id !== message.user) {
await bot.startConversationInChannel(message.channel, message.user);
await bot.beginDialog('kitten-delivery');
return;
}
}
);
// END: listen for cat emoji delivery
// ...
});
// ...
更新应用
将应用重新部署到 Cloud Run:
gcloud run deploy kittenbot \ --source . \ --platform managed \ --region $REGION \ --set-env-vars PROJECT_ID=$PROJECT_ID \ --allow-unauthenticated
试试看
恭喜!您刚刚将一个在 Cloud Run 上运行的 Slack 聊天机器人更新到新版本。
斜杠命令
如果您不想与该用户对话,该怎么办?如果您只想使用一个命令触发操作,该怎么办?
Slack 通过 Slash 命令提供此功能,允许用户通过在消息框中输入命令来调用您的应用。
启用 Slack Slash 命令
- 前往“应用管理”页面上功能下的斜杠命令部分。
- 点击创建新命令。
- 使用您的 kittenbot 服务网址配置一条
/cats
命令。请务必使用您用于启用 Events API 的同一端点!这是您的网址,以及'/api/messages'
。
- 按照提示更新应用和权限。
向控制器添加斜杠命令
请参阅如何在 controller.ready 函数中添加斜杠命令处理程序:
// ...
// Controller is ready
controller.ready(() => {
// ...
// START: slash commands
controller.on('slash_command', async (bot, message) => {
const numCats = parseInt(message.text);
const response = makeCatMessage(numCats);
bot.httpBody({ text: response });
});
// END: slash commands
});
// ...
试试看
输入 /cats 后加一个数字即可发送斜杠命令。例如:/cats 8
聊天机器人将回答 8 只猫,只有你自己可以看到:
12. 清理
恭喜,您现在有一个 Slack 聊天机器人在 Cloud Run 上运行了。是时候清理所用资源了(以节省费用并成为优秀的云公民)。
删除项目
您可以直接从 Cloud Shell 删除整个项目:
gcloud projects delete $PROJECT_ID
或者,如果您希望逐个删除不同的资源,请继续学习下一部分。
删除部署
gcloud run services delete kittenbot --region $REGION
命令输出
Service [kittenbot] will be deleted. Do you want to continue (Y/n)? y Deleted service [kittenbot].
删除客户端签名密钥
gcloud secrets delete client-signing-secret
命令输出
You are about to destroy the secret [client-signing-secret] and its [1] version(s). This action cannot be reversed. Do you want to continue (Y/n)? y Deleted secret [client-signing-secret].
删除聊天机器人令牌密钥
gcloud secrets delete bot-token
命令输出
You are about to destroy the secret [bot-token] and its [1] version(s). This action cannot be reversed. Do you want to continue (Y/n)? y Deleted secret [bot-token].
删除存储分区
首先,列出 Google Cloud Storage 存储分区以获取存储分区路径:
gsutil ls
命令输出
gs://[REGION.]artifacts.<PROJECT_ID>.appspot.com/ gs://<PROJECT_ID>_cloudbuild/
现在,删除工件存储分区:
gsutil rm -r gs://[REGION.]artifacts.${PROJECT_ID}.appspot.com/
命令输出
Removing gs://[REGION.]artifacts.<PROJECT_ID>.appspot.com/...
最后,删除 cloudbuild 存储分区:
gsutil rm -r gs://${PROJECT_ID}_cloudbuild/
命令输出
Removing gs://<PROJECT_ID>_cloudbuild/...
13. 恭喜!
您现在已经知道如何在 Cloud Run 上运行 Slack 聊天机器人了!
我们只是这项技术的冰山一角,建议您进一步探索自己的 Cloud Run 部署。
所学内容
- 在 Slack 中创建聊天机器人自定义集成
- 使用 Secret Manager 保护您的 Slack 密钥
- 在 Cloud Run 上部署 Slack 聊天机器人
后续步骤
- 完成更多 Cloud Run 教程
了解详情
- 查看 GitHub 上的其他 Google Cloud Slack 集成示例。
- 试用其他 Google Cloud 功能。查阅我们的教程。