Статьи

Сборка Slack Bot с использованием Python

Конечный продукт
Что вы будете создавать

Slack была основана в 2014 году и рекламируется как самое быстрорастущее бизнес-приложение в истории. В настоящее время у него более 50 000 платящих компаний, использующих его продукт, включая мое нынешнее место работы.

Slack действительно отличался от своих предшественников, которые были более сфокусированы на том, чтобы быть системой обмена сообщениями с некоторыми возможностями голоса и видео. Slack действительно раздвинул конверт и усердно работает над созданием очень мощного каталога приложений. Каталог приложений содержит от сотен до тысяч интеграций, которые могут обеспечить невероятную гибкость для повышения эффективности вашей компании.

Цель этой статьи — продемонстрировать, как вы можете создать собственную уникальную интеграцию со Slack, используя Python для логики.

Чтобы сосредоточиться на понимании механики основ слабого бота, я остановлюсь на собственном боте.

Несмотря на то, что у Slack есть каталог приложений мирового класса, у каждого бизнеса свои бизнес-процессы. Это оставляет многие компании в ситуации, когда они просто не могут найти идеальное приложение для них.

Именно здесь в игру вступает создание собственного Slack Bot.

Задача Slack Bot — получать и обрабатывать события, генерируемые взаимодействием Slack вашей команды. Slack предоставляет как минимум 50 различных типов событий , таких как:

  • message : сообщение было отправлено на канал.
  • team_join : новый участник присоединился к команде.
  • member_joined_channel : пользователь присоединился к общедоступному или частному каналу.

И, конечно же, есть много других типов событий, которые ваш бот может опционально обрабатывать и реагировать. Например, событие team_join — это фантастическое событие, которое может начать весь процесс адаптации.

Цель этой статьи — продемонстрировать, как Slack Bot будет взаимодействовать с событием message для выполнения определенных действий, когда члены команды взаимодействуют с ботом.

В этой статье я создам приложение Python и Slack Bot, которые можно добавить в ваш командный проект для ответа на событие message .

Для начала мне нужно создать бота на Slack. Можно создать два типа ботов:

  • кастомный бот
  • создание приложения и добавление пользователя бота

В этой статье будет создан пользовательский бот, потому что пользователь бот-приложения был бы более уместным, если бы я планировал написать и опубликовать приложение на Slack. Учитывая, что я хочу, чтобы этот бот был приватным для моей команды, подойдет специальный бот.

Пользовательский бот может быть создан здесь: https://my.slack.com/apps/A0F7YS25R-bots . Если вы уже вошли в свою учетную запись Slack, слева нажмите кнопку Add Configuration ; в противном случае, войдите в свою учетную запись Slack, прежде чем продолжить. Если у вас нет учетной записи Slack, вы можете зарегистрироваться бесплатно .

Это перенесет вас на новую страницу, где вам потребуется указать имя пользователя для вашего бота. Введите свое имя пользователя сейчас, убедившись, что вы следуете указаниям Slack. После того, как вы выбрали удивительное имя бота, нажмите Добавить конфигурацию бота .

После того, как вы успешно создали своего бота, Slack перенаправляет вас на страницу, которая позволяет для дальнейшей настройки вашего бота. Я оставлю эту часть вашему творческому я. Единственное, что нужно на этой странице — это xoxb- API, который начинается с xoxb- . Я либо скопировал бы этот токен в безопасное место для последующего использования, либо просто оставил бы эту страницу открытой, пока нам не понадобится токен для приложения Python.

Согласно официальной документации Slack для Slack Developer Kit для Python , в настоящее время он поддерживает версию 2.7. Следует упомянуть, что версия 3 будет поддерживаться в ближайшем будущем.

У меня уже установлена ​​версия 2.7, поэтому сейчас я буду придерживаться этой версии Python. Если ваша установка Python уже настроена и готова к работе, вы можете перейти к следующему шагу; в противном случае перейдите на страницу загрузки Python и загрузите соответствующую версию для вашей операционной системы.

Чтобы установить Slack Developer Kit, я буду использовать PyPi для упрощения установки Slack Client. В некоторых операционных системах команду pip можно запустить непосредственно из командной строки. Если нет, вам нужно будет ссылаться на весь путь к программе pip .

Например, в моей системе Windows я выполнил следующую команду для установки Slack Client из командной строки (ссылаясь на полный путь к файлу pip.exe): \Python27\Scripts\pip install slackclient .

Далее вы захотите выбрать место для размещения вашего приложения. Мне нравится использовать GitHub, поэтому я создал основную папку python которая содержит все мои разные приложения Python. Внутри этой папки я создал подпапку с именем slackbot .

После того, как я выбрал, где будет размещаться мое приложение, я собираюсь сохранить ядро ​​моего приложения в файле с именем slackbot.py .

Пришло время положить пальцы на клавиатуру, подключиться к Slack и сделать наш первый вызов API. Давайте разберемся с кодом, и я объясню, что происходит после:

1
2
3
4
5
6
7
8
9
from slackclient import SlackClient
 
slack_client = SlackClient(«xoxb-*******************»)
 
api_call = slack_client.api_call(«users.list»)
if api_call.get(‘ok’):
    users = api_call.get(‘members’)
    for user in users:
        print user.get(‘name’)

Код начинается с импорта библиотеки Slack Client, после чего SlackClient экземпляр класса SlackClient с SlackClient API вашего Slack Bot, который вы сохранили ранее. Обязательно замените пример токена в этом примере своим токеном.

Объект SlackClient хранится в локальной переменной slack_client которая будет использоваться для дальнейшего взаимодействия со Slack.

Используя slack_client , вызывается API для получения списка пользователей вашей команды. Если вызов API завершился успешно, список членов команды сохраняется в переменной users . Переменная users представляет собой массив, который с помощью цикла for выводит имя каждого члена команды в консольное приложение.

Slack поддерживает несколько различных типов взаимодействий с системой. Первый, который мы только что завершили, сделал вызов API. Slack предлагает множество других типов вызовов API: Web API , API событий, API бесед, API обмена сообщениями в реальном времени и SCIM API . Вызов API, который мы сделали, чтобы получить список пользователей, использовал SCIM API.

В следующем примере я покажу, как использовать систему обмена сообщениями в реальном времени. Как только мы начнем создавать финального бота, API-интерфейс бесед будет использоваться для отправки сообщений в ответ на команды, на которые будет отвечать наш бот.

Система RTM обеспечивает большую мощность, поскольку Slack отправляет события, которые ваше приложение может обрабатывать, и немедленно реагировать на них. Конечно, существует так много событий, что вашему боту может не понадобиться обрабатывать каждое событие. Чтобы продемонстрировать множество различных событий, которые происходят просто при подключении, в следующем примере будет выводиться каждое полученное событие.

Давайте сразу посмотрим на код для подключения и начнем получать события Slack:

01
02
03
04
05
06
07
08
09
10
11
12
13
from slackclient import SlackClient
import time
 
slack_client = SlackClient(«xoxb-****************»)
 
if slack_client.rtm_connect(with_team_state=False):
    print «Successfully connected, listening for events»
    while True:
        print slack_client.rtm_read()
         
        time.sleep(1)
else:
    print «Connection Failed»

Как и в предыдущем примере, этот код начинается с импорта библиотеки Slack Client и создает экземпляр класса SlackClient с тем же SlackClient API, что и ранее. В этом примере также импортируется библиотека времени, которая позже будет использована в коде.

После успешного создания SlackClient следующая строка кода вызывает метод rtm_connect . Это делается с помощью оператора if. Если по какой-либо причине соединение не устанавливается, на консоль выводится сообщение об ошибке. В случае успеха выдается сообщение об успехе, которое сообщает нам, что мы подключены и готовы начать взаимодействовать с событиями Slack.

Затем начинается бесконечный цикл. Внутри этого цикла я rtm_read метод rtm_read библиотеки Slack Client.

Результаты этого вызова заносятся в консоль. После этого приложение спит в течение 1 секунды, а затем читает следующее потенциальное событие из Slack. Ниже приведен пример того, как выглядит чтение событий при первом подключении:

1
2
3
4
5
6
7
Successfully connected, listening for events
[]
[{u’type’: u’hello’}]
[{u’url’: u’wss://lbmulti-yeo0.lb.slack-msgs.com/websocket/Rm8R-Q0PLxK_8UQmBo0Apru-AtL7qnICzeNazVUDQGUCnIY8N51kO07ZUw37jZc4KvXJlu4c1EWDNwTtrXkLzkwn0GBmak_RATHLSFVCCCcht0YLqlgZAS0-6cb1marGhznvmnQStgdW6rd3yub0CpCzmJdgIkRPgIOIB2JurYA=’, u’type’: u’reconnect_url’}]
[{u’type’: u’presence_change’, u’user’: u’U6RM1S17T’, u’presence’: u’active’}]
[]
[]

Когда бот подключен, Slack отправляет три события, как показано выше. Поскольку это происходит в цикле while, при отсутствии события он получает пустой массив, как показано выше, с пустыми скобками [].

Теперь, когда у нас есть общее представление о том, как выполнять вызов API и подключаться к системе обмена сообщениями в реальном времени Slack, пришло время создать полностью функциональный Slack Bot.

Мой Slack Bot будет слушать события, используя систему RTM. Когда он получает сообщение о событии, направленное моему боту, мое приложение ответит пользователю ответом на полученную команду.

Чтобы построить полноценного бота, требуется немало кода. Чтобы упростить организацию и упростить окончательный код, я собираюсь разделить функциональность на три разных класса: Bot, Event и Command. Эти классы должны расширяться вашим собственным приложением, улучшая функциональность вашего собственного бота. Давайте рассмотрим цель каждого из трех разных классов:

  1. Класс Bot будет отвечать за подключение к Slack и начнет цикл while для прослушивания событий.
  2. Класс Event отвечает за чтение событий, полученных от Slack, и анализирует их, чтобы иметь дело только с событиями сообщений, которые направлены непосредственно нашему боту. Когда сообщение получено, оно вызовет класс Command и отправит вызов API с ответом из класса Command.
  3. Класс Command получит текст события и предоставит настраиваемое сообщение на основе полученной команды. Затем это сообщение будет отправлено обратно в исходный класс событий Slack Channel, который будет отправлен в исходный канал сообщения.

Ранее я упоминал, что моя точка входа в приложение Python находится в файле slackbot.py . Этот файл содержит минимум, необходимый для запуска приложения, который должен создать экземпляр класса Bot, который будет обрабатывать остальную часть процесса:

1
2
3
import bot
 
bot.Bot()

Бот-класс содержит суть конфигурации и настройки бота. Давайте посмотрим на весь класс bot.py который я поместил в файл bot.py :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import time
import event
from slackclient import SlackClient
 
class Bot(object):
    def __init__(self):
        self.slack_client = SlackClient(«xoxb-*****************»)
        self.bot_name = «jamiestest»
        self.bot_id = self.get_bot_id()
         
        if self.bot_id is None:
            exit(«Error, could not find » + self.bot_name)
     
        self.event = event.Event(self)
        self.listen()
     
    def get_bot_id(self):
        api_call = self.slack_client.api_call(«users.list»)
        if api_call.get(‘ok’):
            # retrieve all users so we can find our bot
            users = api_call.get(‘members’)
            for user in users:
                if ‘name’ in user and user.get(‘name’) == self.bot_name:
                    return «<@» + user.get(‘id’) + «>»
             
            return None
             
    def listen(self):
        if self.slack_client.rtm_connect(with_team_state=False):
            print «Successfully connected, listening for commands»
            while True:
                self.event.wait_for_event()
                 
                time.sleep(1)
        else:
            exit(«Error, Connection Failed»)

Файл начинается с импорта необходимых библиотек: time, event и SlackClient. Библиотека событий будет создана далее.

С импортированными библиотеками теперь создается класс ботов. Конструктор класса внутри функции __init__ устанавливает несколько переменных, которые будут использоваться в оставшейся части кода. Это включает в себя slack_client , bot_name и bot_id .

Имя бота используется для поиска идентификатора бота. Идентификатор будет использоваться позже для анализа событий, которые направлены непосредственно на бота. Если приложение не может найти бота, приложение закрывается с ошибкой, поскольку оно не может продолжить работу без идентификатора.

Затем создается экземпляр класса событий, который будет использоваться немного позже в классе. Последнее, что делает конструктор, это вызывает функцию listen , которая подключается к системе RTM и запускает бесконечный цикл, ожидающий события, которые бот будет обрабатывать.

Следующая функция, get_bot_id , очень похожа на первый пример, который проходит по пользователям, на этот раз находя идентификатор нашего бота, находя его имя в списке пользователей и возвращая идентификатор. В случае, если бот не может быть найден, возвращается None , что приведет к закрытию предыдущего кода, поскольку он не смог найти бота.

Последняя функция в классе Bot — это вышеупомянутая функция listen . Эта функция очень похожа на второй пример, где мы впервые подключились к RTM-системе Slack. Основное отличие в этом примере заключается в том, что он вызывает функцию wait_for_event которая будет исследована далее в классе Event.

Это завершает класс Bot, делая его ответственным за создание SlackClient и запуск бесконечного цикла ожидания событий. Однако он ничего не делает с этими событиями, оставляя эту ответственность за класс Event.

Целью класса Event является чтение любых событий, возвращаемых системой RTM Slack. Каждое полученное событие будет проверяться на наличие сообщения, содержащего ссылку на идентификатор бота. Ниже приведен класс Event, который я поместил в файл event.py:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import command
 
class Event:
    def __init__(self, bot):
        self.bot = bot
        self.command = command.Command()
     
    def wait_for_event(self):
        events = self.bot.slack_client.rtm_read()
         
        if events and len(events) > 0:
            for event in events:
                #print event
                self.parse_event(event)
                 
    def parse_event(self, event):
        if event and ‘text’ in event and self.bot.bot_id in event[‘text’]:
            self.handle_event(event[‘user’], event[‘text’].split(self.bot.bot_id)[1].strip().lower(), event[‘channel’])
     
    def handle_event(self, user, command, channel):
        if command and channel:
            print «Received command: » + command + » in channel: » + channel + » from user: » + user
            response = self.command.handle_command(user, command)
            self.bot.slack_client.api_call(«chat.postMessage», channel=channel, text=response, as_user=True)

Этот класс начинается с импорта последнего исследуемого класса, класса Command. Конструктор класса Event получает единственный параметр: ссылку на объект Bot. Это хранится в переменной, к которой могут обращаться другие функции этого класса. Внутри функции __init__ создается другая переменная, которая создает экземпляр ранее импортированного класса Command.

Следующая функция, wait_for_event , является функцией, которая была вызвана функцией listen класса listen . Эта функция читает любые события, полученные от RTM-системы Slack. Функция rtm_read() возвращает массив событий. Функция wait_for_event проверяет, содержит ли массив какие-либо события. Если это так, события проходят через parse_event и вызывают внутреннюю функцию parse_event .

Функция parse_event получает событие в качестве входных данных. Затем выполняется проверка свойства в событии, называемом text . Если это свойство существует, оно проверяет, содержит ли свойство text ссылку на идентификатор нашего бота. Когда это условие истинно, эта функция вызывает последнюю функцию в этом классе, функцию handle_event .

Перед вызовом функции handle_event свойство text использует функцию split Python, разделитель строк представлен идентификатором бота. Это преобразует text свойство в массив. Первым элементом в массиве является строка, содержащая текст с идентификатором бота. Второй элемент содержит остаток сообщения. Этот элемент передается в вышеупомянутую функцию handle_event в качестве команды.

Последняя функция handle_event принимает три свойства: пользователя, отправившего сообщение, команду, которая была отправлена, и канал, в котором оно было отправлено.

Функция handle_event гарантирует, что команда и канал содержат допустимые значения. Когда это происходит, на консоль выводится дружественное отладочное сообщение, в котором указывается, какая команда была получена, на каком канале она была отправлена ​​и какой пользователь ее отправил.

После дружественного сообщения отладки handle_event функцию main из ранее упомянутого класса Command. Результат этой функции используется функцией handle_event путем выполнения вызова API, который отправляет ответ от функции класса Command в канал, который инициировал событие.

Давайте теперь посмотрим на класс Command, чтобы увидеть, как он генерирует пользовательский ответ на основе команды, полученной от пользователя.

Чтобы завершить работу нашего бота, пришло время создать последний класс Command в метко названном файле command.py:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Command(object):
   def __init__(self):
       self.commands = {
           «jump» : self.jump,
           «help» : self.help
       }
 
   def handle_command(self, user, command):
       response = «<@» + user + «>: «
    
       if command in self.commands:
           response += self.commands[command]()
       else:
           response += «Sorry I don’t understand the command: » + command + «. » + self.help()
        
       return response
        
   def jump(self):
       return «Kris Kross will make you jump jump»
    
   def help(self):
       response = «Currently I support the following commands:\r\n»
        
       for command in self.commands:
           response += command + «\r\n»
            
       return response

Мне очень нравится, как получился этот класс, потому что он обеспечивает прочную основу, которую легко расширить, чтобы обрабатывать гораздо больше команд, чем я описал выше.

Конструктор класса Command создает словарь ключей с сопровождающим именем функции, который будет выполняться при получении команды из класса Event. В этом сокращенном примере словарь commands содержит две команды: jump и help. Этот словарь может быть расширен для включения других команд, которые вы хотите обрабатывать с помощью своего собственного бота

Следующая функция, handle_command , является функцией, которая вызывается, когда успешное событие, содержащее сообщение, направленное нашему боту, вызывается из функции класса handle_event события.

Функция handle_command принимает два параметра: пользователя, отправившего сообщение, и команду. Функция начинается с построения строки ответа, которая направит сообщение пользователю, отправившему команду. Затем функция проверяет, что полученная команда является допустимой командой в словаре команд, определенных в конструкторе.

Когда команда действительна, вызывается связанная с ней функция, добавляющая строку в переменную response созданную ранее.

Если команда не существует, ответ добавляется, чтобы указать, что команда недопустима. Он также вызывает функцию help команды, чтобы помочь пользователю понять, какие команды поддерживаются этим ботом.

Остальные функции, jump и help , генерируют пользовательский ответ, который будет отправлен пользователю, который инициировал команду.

Как я уже упоминал во время конструктора, словарь команд может быть расширен новой командой. Для завершения этого процесса должна быть создана сопутствующая функция, которая автоматически handle_command функцией handle_command .

Теперь, когда все кодирование завершено, пришло время протестировать нашего нового бота. Для начала мы должны запустить наш основной скрипт Python: slackbot.py. В командной строке выполните этот скрипт с Python, например, python slackbot.py .

Это запустит нашего бота и подключится к системе обмена сообщениями в реальном времени Slack. В случае успеха наше отладочное сообщение должно быть напечатано на консоли, указывая, что наш бот Slack готов к приему команд.

Чтобы выполнить команду, нашего бота нужно пригласить в публичный или частный канал. Как только бот окажется в канале, пользователь может попросить его прыгнуть или попросить о помощи. В моем случае я бы сказал: @jamietest jump . Бот точно ответит: @endyourif: Kris Kross will make you jump jump .

Этот бот не ограничен одним каналом. Поскольку он анализирует канал из сообщения о событии, он может обрабатывать команды из разных каналов.

Теперь ваша очередь попробовать бот и посмотреть, что вы можете сделать, чтобы он сделал!

Мой бот сейчас завершен. Надеюсь, я показал вам силу создания Slack бота. С несколькими классами (Bot, Event и Command), каждый из которых обрабатывает одну проблему, класс Command может быть расширен для обработки многих других команд.

Чтобы увидеть полный исходный код, я создал репозиторий GitHub .

Помните, не стесняйтесь посмотреть, что у нас есть в наличии для продажи и для обучения на Envato Market , и не стесняйтесь задавать любые вопросы и предоставлять ценные отзывы, используя канал ниже.

Небо действительно бесконечно в том, как этот бот может быть расширен. Ниже приведен краткий список идей для расширения начальной настройки классов:

  • Чтобы добавить новую команду, вы должны создать новую функцию в соответствии с шаблоном функции jump и help внутри класса Command. Когда функция создана, ее необходимо добавить в словарь доступных команд.
  • Еще один замечательный способ дальнейшего улучшения вашего бота — это расширение функциональности функции parse_event в классе Event. В настоящее время эта функция явно ищет событие сообщения, которое содержит наш идентификатор бота в тексте. Эта функция может быть расширена для поиска других событий, таких как team_join . Это событие может вызвать новую команду (в классе Command), которая предоставляет новому члену команды входящие документы и политики вашей компании.
  • Наконец, если вы заинтересованы в создании пользовательского приложения или хотите создать свои собственные команды Slack , вы можете изучить создание пользовательского приложения и добавление в него пользователя бота. Многие примеры кода работают с любым типом бота.

Надеюсь, вам понравилась эта статья о создании Slack Bot с использованием Python. Используйте форму комментариев ниже, чтобы ваши коллеги знали, как вы расширили приведенные выше примеры для создания чрезвычайно надежного Slack Bot!