如何在 Ubuntu 20.04 上用 Python 构建 Slackbot

作者选择了(https://www.brightfunds.org/funds/tech-education)作为 写给捐款计划的一部分的捐款。

介绍

Slack是一个专为工作场所生产力而设计的通信平台,包括直接消息、公共和私人渠道、语音和视频通话以及机器人集成等功能。

在此教程中您将在 [Python] (https://www.python.org/] 编程语言中构建 Slackbot 。 Python是一种流行语言,以简单和可读性为傲. Slack提供了丰富的Python Slack API,用于与Slack的集成,以完成发送消息等共同任务,在消息中加入emojis,以及更多. Slack还提供了一个Python Slack Events API,用于与Slack中的事件相融合,允许您对消息和提及等事件进行动作.

作为一个有趣的概念证明,这将展示Python及其Slack API的力量,你将建立一个CoinBot,一个Slackbot监控一个频道,当它被触发时,会为你扭转一个硬币。

请注意,本教程使用Python 3并且与Python 2不兼容。

前提条件

为了遵循这个指南,你需要:

如果你创建了工作空间,你有这个能力. 如果你没有这个能力,你可以在Slack网站上创建一个工作空间(https://slack.com/create)。 * (可选) 一个服务器或计算机具有公共IP地址进行开发。 我们建议新安装Ubuntu 20.04,一个非根用户具有sudo特权,并启用SSH。

<$>[注]您可能想在具有公共 IP 地址的服务器上测试此教程. Slack 需要能够向您的机器发送消息等事件. 如果您在本地机器上测试,则需要将流量通过防火墙传输到本地系统。

步骤 1 — 在 Slack UI 中创建 Slackbot

首先在 Slack API 控制面板上创建 Slack 应用程序. 通过 Web 浏览器登录 Slack 中的工作区,然后导航到 API 控制面板

Create Your Slack App

接下来,您将被提示为您的应用程序的名称,并选择一个开发 Slack 工作区. 对于本教程,命名您的应用程序 CoinBot,并选择您有管理员访问的工作区。

Name Your Slack App and Select a Workspace

创建应用后,您将看到以下默认应用程序仪表板. 此仪表板是您通过设置权限、订阅事件、在工作区中安装应用程序等来管理应用程序的位置。

Default Slack App Panel

为了让您的应用能够向频道发布消息,您需要授予该应用程序发送消息的权限。

Select the Permissions Button in the Control Panel

当您到达 OAuth & Permissions 页面时,向下滚动,直到您找到页面的 ** Scopes** 部分,然后在范围中找到 ** Bot Token Scopes** 子部分,然后单击 ** Add an OAuth Scope** 按钮。

Select the Add an OAuth Scope Button

点击该按钮,然后键入chat:write。选择该权限以将其添加到您的机器人中。这将允许应用程序向其可以访问的渠道发布消息。有关可用的权限的更多信息,请参阅Slack的文档(https://api.slack.com/scopes)。

Add the chat:write Permission

现在您已经添加了适当的权限,现在是时候将应用程序安装到您的 Slack 工作区了。 滚动在 OAuth & Permissions 页面上,然后点击顶部的 ** Install App to Workspace** 按钮。

Install App to Workspace

点击此按钮,查看应用程序可以在渠道中执行的操作.一旦您满意,请点击允许按钮来完成安装。

Install App to Workspace

一旦机器人安装,您将收到一个 Bot 用户 OAuth 访问令牌 ,让您的应用程序在尝试在工作空间中执行操作时使用。

Save the Access Token

最后,将您新安装的机器人添加到您工作区内的一个频道中。如果您还没有创建一个频道,您可以使用 Slack 工作区的默认创建的 # general 频道。在 Slack 客户端导航栏的 Apps 部分中找到该应用程序,然后点击它。

Click on the App Details Icon

要完成将应用程序添加到频道中,请点击详细信息页面中的三个点表示的 ** 更多** 按钮,然后选择 ** 将此应用程序添加到频道中...** 。

Add App to a Channel

您现在已经成功创建了您的应用程序,并将其添加到您的 Slack 工作区内的一个频道中。在您为您的应用程序编写代码后,它将能够在该频道中发布消息。

步骤2 — 设置您的Python开发环境

首先,让我们设置您的Python环境,以便您可以开发Slackbot。

打开终端并在您的系统上安装python3和相关工具:

1sudo apt install python3 python3-venv

接下来,您将创建一个虚拟环境,将您的Python包从Python的系统安装中分离出来。 要做到这一点,首先创建一个目录,您将创建您的虚拟环境。

1mkdir ~/.venvs

现在创建您的Python虚拟环境:

1python3 -m venv ~/.venvs/slackbot

接下来,激活您的虚拟环境,以便您可以使用其Python安装和安装包:

1source ~/.venvs/slackbot/bin/activate

您的壳提示将现在显示虚拟环境,它将看起来像这样:

现在使用pip将必要的Python包安装到您的虚拟环境中:

1pip install slackclient slackeventsapi Flask

slackclientslackeventsapi有助于Python与Slack的API进行互动。

现在你已经设置了开发人员环境,你可以开始写你的Python Slackbot:

步骤 3 —在Python中创建Slackbot消息类

Slack 中的消息是通过 专门格式化的 JSON 效能负载发送的。

 1{
 2   "channel":"channel",
 3   "blocks":[
 4      {
 5         "type":"section",
 6         "text":{
 7            "type":"mrkdwn",
 8            "text":"Sure! Flipping a coin....\n\n"
 9         }
10      },
11      {
12         "type":"section",
13         "text":{
14            "type":"mrkdwn",
15            "text":"*flips coin* The result is Tails."
16         }
17      }
18   ]
19}

你可以手动创建这个 JSON 并发送它,但相反,让我们构建一个 Python 类,不仅可以创建这个负载,还可以模拟硬币转换。

首先使用触摸命令创建一个名为coinbot.py的文件:

1touch coinbot.py

接下来,使用nano或您最喜欢的文本编辑器打开此文件:

1nano coinbot.py

现在添加以下代码行来导入适用于您的应用程序的相关库. 您为此类所需的唯一库是来自 Python 标准库的随机库。

将下列行添加到coinbot.py以导入所有必要的库:

1[label coinbot.py]
2# import the random library to help us generate the random numbers
3import random

接下来,创建你的CoinBot类和这个类的实例来创建消息的负载. 添加以下行到coinbot.py来创建CoinBot类:

1[label coinbot.py]
2...
3class CoinBot:

现在,单独编入并创建类所需的常数、构造器和方法。 首先,让我们创建一个将保持消息负载的基础的常数。 本节规定了这个常数是部分类型,并且文本是通过标记格式化。

将下列行附加到coinbot.py中,以创建有效负载的基本模板:

 1[label coinbot.py]
 2...
 3    # Create a constant that contains the default text for the message
 4    COIN_BLOCK = {
 5        "type": "section",
 6        "text": {
 7            "type": "mrkdwn",
 8            "text": (
 9                "Sure! Flipping a coin....\n\n"
10            ),
11        },
12    }

接下来,为您的类创建一个构建器,以便您可以为每个请求创建一个单独的机器人实例。不要担心这里的内存过剩;Python垃圾收集器将清理这些实例,一旦它们不再需要。

将下列行附加到coinbot.py来创建构建器:

1[label coinbot.py]
2...
3    # The constructor for the class. It takes the channel name as the a
4    # parameter and sets it as an instance variable.
5    def __init__(self, channel):
6        self.channel = channel

现在写下模拟翻转硬币的代码. 我们将随机生成一个或零,分别代表头或尾巴。

将下列行附加到coinbot.py中,以模拟硬币转换并返回编造的负载:

 1[label coinbot.py]
 2...
 3    # Generate a random number to simulate flipping a coin. Then return the 
 4    # crafted slack payload with the coin flip message.
 5    def _flip_coin(self):
 6        rand_int =  random.randint(0,1)
 7        if rand_int == 0:
 8            results = "Heads"
 9        else:
10            results = "Tails"
11
12        text = f"The result is {results}"
13
14        return {"type": "section", "text": {"type": "mrkdwn", "text": text}},

最后,创建一种方法,通过调用你的 _flip_coin 方法来制作并返回整个消息效用负载,包括你的构建器的数据。

将下列行附加到coinbot.py中,创建将生成完成的有效负载的方法:

 1[label coinbot.py]
 2...
 3    # Craft and return the entire message payload as a dictionary.
 4    def get_message_payload(self):
 5        return {
 6            "channel": self.channel,
 7            "blocks": [
 8                self.COIN_BLOCK,
 9                *self._flip_coin(),
10            ],
11        }

现在你已经完成了CoinBot类,它已经准备好进行测试,然后再继续前,请验证你的已完成的文件coinbot.py是否包含以下内容:

 1[label coinbot.py]
 2# import the random library to help us generate the random numbers
 3import random
 4
 5# Create the CoinBot Class
 6class CoinBot:
 7
 8    # Create a constant that contains the default text for the message
 9    COIN_BLOCK = {
10        "type": "section",
11        "text": {
12            "type": "mrkdwn",
13            "text": (
14                "Sure! Flipping a coin....\n\n"
15            ),
16        },
17    }
18
19    # The constructor for the class. It takes the channel name as the a 
20    # parameter and then sets it as an instance variable
21    def __init__(self, channel):
22        self.channel = channel
23
24    # Generate a random number to simulate flipping a coin. Then return the 
25    # crafted slack payload with the coin flip message.
26    def _flip_coin(self):
27        rand_int =  random.randint(0,1)
28        if rand_int == 0:
29            results = "Heads"
30        else:
31            results = "Tails"
32
33        text = f"The result is {results}"
34
35        return {"type": "section", "text": {"type": "mrkdwn", "text": text}},
36
37    # Craft and return the entire message payload as a dictionary.
38    def get_message_payload(self):
39        return {
40            "channel": self.channel,
41            "blocks": [
42                self.COIN_BLOCK,
43                *self._flip_coin(),
44            ],
45        }

保存并关闭文件。

现在你有一个Python类准备好为你的Slackbot工作,让我们确保这个类产生有用的消息负载,你可以将其发送到你的工作区。

步骤 4 — 测试您的消息

现在让我们来测试这个类会产生合适的负载,创建一个名为coinbot_test.py的文件:

1nano coinbot_test.py

现在添加以下代码: ** 请确保在 coinbot 类的实例中更改频道名称:coin_bot = coinbot(# YOUR_CHANNEL_HERE)** . 此代码将创建 Python 中的 Slack 客户端,该代码将向您指定已安装应用程序的频道发送消息:

 1[label coinbot_test.py]
 2from slack import WebClient
 3from coinbot import CoinBot
 4import os
 5
 6# Create a slack client
 7slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
 8
 9# Get a new CoinBot
10coin_bot = CoinBot("#YOUR_CHANNEL_HERE")
11
12# Get the onboarding message payload
13message = coin_bot.get_message_payload()
14
15# Post the onboarding message in Slack
16slack_web_client.chat_postMessage(**message)

保存并关闭文件。

在运行此文件之前,您需要将您在步骤 1 中保存的 Slack 代币导出为环境变量:

1export SLACK_TOKEN="your_bot_user_token"

现在测试这个文件,并通过在您的终端运行下面的脚本来验证使用量被生成和发送。 确保您的虚拟环境被激活。 您可以通过看到 bash 提示前面的 (slackbot) 文本来验证。 运行此命令,您将收到来自您的 Slackbot 的消息,其中包含硬币转换的结果:

1python coinbot_test.py

检查您安装应用程序的渠道,并验证您的机器人确实发送了硬币转换消息。

Coin Flip Test

现在你已经验证了你的Slackbot可以扭转硬币,创建消息,并传递消息,让我们创建一个 Flask永久运行这个应用程序,让它模拟一个硬币扭转,并分享结果,每次它看到某些文本在发送在渠道中的消息。

步骤5 —创建一个Flask应用程序来运行您的Slackbot

现在你有一个可以发送消息到你的Slack工作区的应用程序,你需要创建一个漫长的流程,以便你的机器人可以听到在频道中发送的消息,并回复它们,如果文本符合某些标准。

在本节中,您将从具有公共 IP 地址的服务器运行您的 Flask 应用程序,以便 Slack API 可以向您发送事件。如果您在个人工作站上本地运行此功能,则需要将端口从个人防火墙传输到工作站上运行的端口。

首先调整防火墙设置以允许通过端口3000的流量:

1sudo ufw allow 3000

现在检查UFW的状态:

1sudo ufw status

你会看到这样的输出:

1[secondary_label Output]
2Status: active
3
4To Action From
5--                         ------      ----
6OpenSSH ALLOW Anywhere
73000 ALLOW Anywhere
8OpenSSH (v6)               ALLOW Anywhere (v6)
93000 (v6)                  ALLOW Anywhere (v6)

现在为您的 Flask 应用程序创建文件. 命名此文件 app.py:

1touch app.py

接下来,在您最喜欢的文本编辑器中打开此文件:

1nano app.py

现在添加以下导入陈述,您将因以下原因导入以下库:

  • import os - 访问环境变量 * import logging - 登录应用程序的事件 * from flask import Flask - 创建一个Flask应用程序 * from slack import WebClient - 通过Slack发送消息 * from slackeventsapi import SlackEventAdapter - 接收来自Slack的事件并处理它们 * from coinbot import CoinBot - 创建您的CoinBot实例并生成消息负载。

将下列行附加到app.py以导入所有必要的库:

1[label app.py]
2import os
3import logging
4from flask import Flask
5from slack import WebClient
6from slackeventsapi import SlackEventAdapter
7from coinbot import CoinBot

现在创建你的Flask应用程序,并在/slack/events终端点注册Slack事件适配器到Slack应用程序,这将创建Slack应用程序中的路线,在那里Slack事件将被发送和摄入。 要做到这一点,你需要从Slack应用程序中获得另一个代币,你将在教程中稍后进行。 一旦你获得这个变量,你将将其导出作为一个名为SLACK_EVENTS_TOKEN的环境变量。 继续写下你的代码,在创建SlackEventAdapter时读取它,即使你还没有设置代币。

将下列行附加到app.py中,创建 Flask 应用程序并将事件适配器注册到该应用程序中:

1[label app.py]
2...
3# Initialize a Flask app to host the events adapter
4app = Flask(__name__)
5
6# Create an events adapter and register it to an endpoint in the slack app for event ingestion.
7slack_events_adapter = SlackEventAdapter(os.environ.get("SLACK_EVENTS_TOKEN"), "/slack/events", app)

接下来,创建一个 Web 客户端对象,该对象将允许您的应用程序在工作区中执行操作,特别是发送消息。

将下列行附加到app.py,以创建此slack_web_client:

1[label app.py]
2...
3# Initialize a Web API client
4slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))

现在创建一个可调用的函数,将创建一个CoinBot的实例,然后使用该实例创建一个消息的有效载荷,并将消息的有效载荷传送到Slack Web客户端进行交付。

将下列行附加到app.py来创建此函数:

 1[label app.py]
 2...
 3def flip_coin(channel):
 4    """Craft the CoinBot, flip the coin and send the message to the channel
 5    """
 6    # Create a new CoinBot
 7    coin_bot = CoinBot(channel)
 8
 9    # Get the onboarding message payload
10    message = coin_bot.get_message_payload()
11
12    # Post the onboarding message in Slack
13    slack_web_client.chat_postMessage(**message)

现在你已经创建了一个功能来处理你的应用程序的消息方面,创建一个监控Slack事件的特定行动,然后执行你的机器人。

首先,用@slack_events_adapter.on语法来装饰您的函数,使您的函数能够接收事件。 指定您只想要消息事件,并让您的函数接受包含所有必要的Slack信息的负载参数。 一旦您有这个负载,您将对文本进行分析并分析。

将下列代码附加到 app.py 以接收、分析和对接收消息采取行动:

 1[label app.py]
 2# When a 'message' event is detected by the events adapter, forward that payload
 3# to this function.
 4@slack_events_adapter.on("message")
 5def message(payload):
 6    """Parse the message event, and if the activation string is in the text,
 7    simulate a coin flip and send the result.
 8    """
 9
10    # Get the event data from the payload
11    event = payload.get("event", {})
12
13    # Get the text from the event that came through
14    text = event.get("text")
15
16    # Check and see if the activation phrase was in the text of the message.
17    # If so, execute the code to flip a coin.
18    if "hey sammy, flip a coin" in text.lower():
19        # Since the activation phrase was met, get the channel ID that the event
20        # was executed on
21        channel_id = event.get("channel")
22
23        # Execute the flip_coin function and send the results of
24        # flipping a coin to the channel
25        return flip_coin(channel_id)

最后,创建一个主要部分,将创建一个日志器,以便您可以查看您的应用程序的内部信息,以及在端口3000上的外部IP地址上启动应用程序。

将下列行附加到app.py以设置您的主要部分:

 1[label app.py]
 2if __name__ == "__main__":
 3    # Create the logging object
 4    logger = logging.getLogger()
 5
 6    # Set the log level to DEBUG. This will increase verbosity of logging messages
 7    logger.setLevel(logging.DEBUG)
 8
 9    # Add the StreamHandler as a logging handler
10    logger.addHandler(logging.StreamHandler())
11
12    # Run your app on your externally facing IP address on port 3000 instead of
13    # running it on localhost, which is traditional for development.
14    app.run(host='0.0.0.0', port=3000)

您现在已经完成了Flask应用程序,它已经准备好进行测试。在您继续之前,请验证您的已完成的文件,‘app.py’包含以下内容:

 1[label app.py]
 2import os
 3import logging
 4from flask import Flask
 5from slack import WebClient
 6from slackeventsapi import SlackEventAdapter
 7from coinbot import CoinBot
 8
 9# Initialize a Flask app to host the events adapter
10app = Flask(__name__)
11# Create an events adapter and register it to an endpoint in the slack app for event injestion.
12slack_events_adapter = SlackEventAdapter(os.environ.get("SLACK_EVENTS_TOKEN"), "/slack/events", app)
13
14# Initialize a Web API client
15slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
16
17def flip_coin(channel):
18    """Craft the CoinBot, flip the coin and send the message to the channel
19    """
20    # Create a new CoinBot
21    coin_bot = CoinBot(channel)
22
23    # Get the onboarding message payload
24    message = coin_bot.get_message_payload()
25
26    # Post the onboarding message in Slack
27    slack_web_client.chat_postMessage(**message)
28
29# When a 'message' event is detected by the events adapter, forward that payload
30# to this function.
31@slack_events_adapter.on("message")
32def message(payload):
33    """Parse the message event, and if the activation string is in the text, 
34    simulate a coin flip and send the result.
35    """
36
37    # Get the event data from the payload
38    event = payload.get("event", {})
39
40    # Get the text from the event that came through
41    text = event.get("text")
42
43    # Check and see if the activation phrase was in the text of the message.
44    # If so, execute the code to flip a coin.
45    if "hey sammy, flip a coin" in text.lower():
46        # Since the activation phrase was met, get the channel ID that the event
47        # was executed on
48        channel_id = event.get("channel")
49
50        # Execute the flip_coin function and send the results of
51        # flipping a coin to the channel
52        return flip_coin(channel_id)
53
54if __name__ == "__main__":
55    # Create the logging object
56    logger = logging.getLogger()
57
58    # Set the log level to DEBUG. This will increase verbosity of logging messages
59    logger.setLevel(logging.DEBUG)
60
61    # Add the StreamHandler as a logging handler
62    logger.addHandler(logging.StreamHandler())
63
64    # Run our app on our externally facing IP address on port 3000 instead of
65    # running it on localhost, which is traditional for development.
66    app.run(host='0.0.0.0', port=3000)

保存并关闭文件。

现在,您的 Flask 应用已经准备好为您的应用程序服务,让我们测试它。

步骤6 —运行您的Flask应用程序

最后,把一切都汇集在一起,并运行您的应用程序。

首先,添加您的运行应用程序作为您的Slackbot的授权处理器。

Slack UI中,导航到应用程序的 基本信息 部分。

Slack Signing Secret

复制签名秘密并将其导出为环境变量SLACK_EVENTS_TOKEN:

1export SLACK_EVENTS_TOKEN="MY_SIGNING_SECRET_TOKEN"

有了这个,你有所有必要的API代币来运行你的应用程序. 请参阅步骤 1 如果你需要一个更新如何导出你的SLACK_TOKEN。 现在你可以启动你的应用程序,并验证它确实在运行。 确保你的虚拟环境是激活的,并运行以下命令来启动你的Flask应用程序:

1python3 app.py

你会看到这样的输出:

1(slackbot) [20:04:03] sammy:coinbot$ python app.py
2 * Serving Flask app "app" (lazy loading)
3 * Environment: production
4   WARNING: This is a development server. Do not use it in a production deployment.
5   Use a production WSGI server instead.
6 * Debug mode: off
7 * Running on http://0.0.0.0:3000/ (Press CTRL+C to quit)

要验证您的应用程序是否已启动,请打开一个新的终端窗口,并在/slack/events的正确端口弯曲您的服务器的 IP 地址:

1curl http://YOUR_IP_ADDRESS:3000/slack/events

curl将返回如下:

1[secondary_label Output]
2These are not the slackbots you're looking for.

收到这些不是您正在寻找的 slackbots消息表示您的应用已启动和运行。

现在,让这个 Flask 应用程序在您在 Slack UI中完成配置应用程序时运行。

首先,授予您的应用程序适当的权限,以便它可以听取消息并相应地响应。

Enable Events Button

完成此操作后,输入您的 IP 地址、端口和/slack/events终端点到Request URL**字段中。 不要忘记HTTP协议前缀。 Slack 将尝试连接到您的终端点。 一旦成功完成,您将看到一个绿色标记,旁边有Verified字。

Event Subscriptions Request URL

接下来,扩展 **订阅机器人事件 ** ,并将message.channels权限添加到您的应用程序中,这将允许您的应用程序从您的频道接收和处理消息。

Subscribe to bot events permissions

完成此操作后,您将看到您的 ** 订阅 bot 事件 ** 部分中列出的事件,然后在右下角点击绿色 ** 保存更改 ** 按钮。

Confirm and Save changes

一旦您这样做,您将看到屏幕顶部的黄色标签,告知您需要重新安装您的应用程序,以便下列更改适用。

Reinstall your app banner

您将收到一个确认屏幕,概括您的机器人将有权限,并询问您是否想要允许其安装。

Reinstall confirmation

现在你已经完成了,你的应用程序应该准备好了。回到你安装了CoinBot的渠道,并发送一个含有短语 Hey Sammy, Flip a coin 的消息。

Hey Sammy, Flip a coin

结论

一旦你完成了开发你的应用程序,你已经准备好将其迁移到生产中,你需要部署到服务器上。这是必要的,因为Flask开发服务器不是一个安全的生产环境。如果你使用 WSGI部署你的应用程序,甚至可以确保域名并为你的服务器提供DNS记录,你将得到更好的服务。

有更多的方法来部署你的应用程序,而不仅仅是这些. 就像往常一样,当涉及到部署和基础设施时,做什么最适合 you

无论如何,你现在有一个Slackbot,你可以使用它来扭转一枚硬币,以帮助你做出决定,比如吃什么午餐。

您还可以采取这个基本代码,并修改它以满足您的需求,无论是自动支持,资源管理,猫的图像,或任何你可以想到的。

Published At
Categories with 技术
comments powered by Disqus