2020년 5월 17일 일요일

Slack bot 만들기 (using RTM)


지난 포스트에서 Slack bot을 classic 앱설정하는 방법과 post 하는 방법에 대해서 알아 보았습니다.

아래 예제가 동작이 안되면 bot 설정을 꼭 확인하시기 바랍니다.


이전 예제는 특정 채널에 메세지를 보내는 동작이었습니다. 이번에는 내용을 모니터링 하고 있다가 들어오는 내용에 답변을 하는 동작입니다. 이것을 구현하기 위해서는 모니터링을 계속 해야만 합니다. 이때 사용하는 기능이 RTM(Real time messaging)기능 입니다.
이전 예제에서는 봇이 어떤방에 속해있지 않더라도 채널명만 알면 보낼 수 있었습니다. 그러나 내용을 읽는것은 workspace내에 bot을 add 해주어야 합니다.


봇 만들기

첫번째로 봇 부터 만들어 보겠습니다.

아래 예제를 따라하면 되는데 주의할점 있습니다.
https://www.fullstackpython.com/blog/build-first-slack-bot-python.html

Slack client 버전이 변경되어서 꼭 해당 버전을 설치해야 합니다.
pip install slackclient==1.3.2

전체 소스

import os
import time
import re
from slackclient import SlackClient


# instantiate Slack client
slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))
# starterbot's user ID in Slack: value is assigned after the bot starts up
starterbot_id = None

# constants
RTM_READ_DELAY = 1 # 1 second delay between reading from RTM
EXAMPLE_COMMAND = "do"
MENTION_REGEX = "^<@(|[WU].+?)>(.*)"

def parse_bot_commands(slack_events):
    """
        Parses a list of events coming from the Slack RTM API to find bot commands.
        If a bot command is found, this function returns a tuple of command and channel.
        If its not found, then this function returns None, None.
    """
    for event in slack_events:
        print("event['type'],event['text']:",event.get("type"),event.get("text"))
        if event["type"] == "message" and not "subtype" in event:
            user_id, message = parse_direct_mention(event["text"])
            if user_id == starterbot_id:
                return message, event["channel"]
    return None, None

def parse_direct_mention(message_text):
    """
        Finds a direct mention (a mention that is at the beginning) in message text
        and returns the user ID which was mentioned. If there is no direct mention, returns None
    """
    matches = re.search(MENTION_REGEX, message_text)
    # the first group contains the username, the second group contains the remaining message
    return (matches.group(1), matches.group(2).strip()) if matches else (None, None)

def handle_command(command, channel):
    """
        Executes bot command if the command is known
    """
    # Default response is help text for the user
    default_response = "Not sure what you mean. Try *{}*.".format(EXAMPLE_COMMAND)

    # Finds and executes the given command, filling in response
    response = None
    # This is where you start to implement more commands!
    if command.startswith(EXAMPLE_COMMAND):
        response = "Sure...write some more code then I can do that!"

    # Sends the response back to the channel
    slack_client.api_call(
        "chat.postMessage",
        channel=channel,
        text=response or default_response
    )

if __name__ == "__main__":
    if slack_client.rtm_connect(with_team_state=False):
        print("Starter Bot connected and running!")
        # Read bot's user ID by calling Web API method `auth.test`
        starterbot_id = slack_client.api_call("auth.test")["user_id"]
        print("starterbot_id:",starterbot_id)
        while True:
            command, channel = parse_bot_commands(slack_client.rtm_read())
            if command:
                handle_command(command, channel)
            time.sleep(RTM_READ_DELAY)
    else:
        print("Connection failed. Exception traceback printed above.")
공유 소스 대비 로그를 추가하였습니다.
자세히 보시면 속해있는 방의 모든 내용을 받을 수 있습니다.

실행시 token을 아래와 같이 bat 파일에 설정합니다.
run.bat 파일 내용
set SLACK_BOT_TOKEN=xoxb-xxxxx
python slack_client.py

동작 화면

C:\Users\USER\Documents\slack>python slack_client.py
Starter Bot connected and running!
starterbot_id: U013R483Q1F
event['type'],event['text']: hello None
event['type'],event['text']: user_typing None
event['type'],event['text']: message do
event['type'],event['text']: desktop_notification None
event['type'],event['text']: user_typing None
event['type'],event['text']: message do try
event['type'],event['text']: desktop_notification None
event['type'],event['text']: user_typing None
event['type'],event['text']: message ddd
event['type'],event['text']: user_typing None
event['type'],event['text']: message d
event['type'],event['text']: desktop_notification None
event['type'],event['text']: user_typing None
event['type'],event['text']: message a
event['type'],event['text']: desktop_notification None
event['type'],event['text']: desktop_notification None
event['type'],event['text']: user_typing None
event['type'],event['text']: user_typing None
event['type'],event['text']: message <@U013R483Q1F> do it
event['type'],event['text']: message Sure...write some more code then I can do that!
event['type'],event['text']: desktop_notification None
event['type'],event['text']: user_typing None
event['type'],event['text']: message <@U013R483Q1F> hello
event['type'],event['text']: desktop_notification None
event['type'],event['text']: message Not sure what you mean. Try *do*


사용하기전에 채널에 bot을 Add해줍니다.



테스트 하기 위해서는 @봇이름 do 내용 이렇게 보내야 봇이 동작합니다.















댓글 없음:

댓글 쓰기