IT業務効率化

PythonとSlackでtipsボットを作る。その2【Slack上の命令を取得する】

Slackの会話でtipsを追加したい

前回の記事ではbotがSlackのチャンネルに呟いてくれるところまで作成しました。今回はSlackのチャンネルの中で、tips_botに命令するだけで、新しいtipsを覚えたり、不要なものを削除したりする部分を作りたいと思います。

そのために利用するライブラリがこちら、どん。slackbotです。

まずはこのslackbotで言葉に反応するところまで作りたいと思います。

結論

下記plugins.pyというファイルを作成することで実現できる。

from slackbot.bot import respond_to
from slackbot.bot import listen_to
import re


@respond_to('learn tip(\d*) (.*)')
def learn_tip(message, tip_number, tip_msg):
    message.reply('I learned tips{} as {}'.format(tip_number, tip_msg))

slackbotをQuick Startしてみる

First create a slackbot_settings.py and a run.py in your own instance of slackbot.

git hub のREADMEにしたがって進めていこうと思います。。slackbot_settings.pyを以下のように作成しました。

API_TOKEN = "<あなたのAPI TOKEN>"
DEFAULT_REPLY = "Sorry but I didn't understand you"

次にrun.pyを以下のように作成しました。ではこれで一旦実行してみます。$python run.py

slackで話しかけてみました。

ちゃんとDEAFAULT_REPLYに設定した返事をしてくれました。

次はオリジナルのリプライを作ってみます。skackbot_settings.pyに以下の項目をPLUGINSを追加しました。

API_TOKEN = ""
DEFAULT_REPLY = "Sorry but I didn't understand you"
ERRORS_TO = 'general'

PLUGINS = [
    'plugins'
]

そして同じディレクトリ常にplugins.pyというファイルを作成します。このファイル名はPLUGINSのリストの中の文字列と一致している必要があります。

from slackbot.bot import respond_to
from slackbot.bot import listen_to
import re


@respond_to('hi', re.IGNORECASE)
def hi(message):
    message.reply('I can understand hi or HI!')
    # react with thumb up emoji
    message.react('+1')

それではbotにhiと話しかけてみます。

無事に関数hiの中で定義した内容で返事が来ました!これでslackbotの基本構成ができました。

tipsを記憶させる

ここからが本題です。こちらの言った言葉を覚えてもらいます。ただしどんな命令をした時に覚えるかを先に決めておきたいと思います。主に次の4つの命令で動く仕組みを作ります。

この4つのコマンドで動くように作成します

  • learn tip1 insert or update tip
    • 上書きもしくは新しくtipを作成する
  • forget tip1 `remove tip`
    • tipを削除する
  • view tips
    • tipsの一覧を表示する
  • sort tips
    • tipsを番号を振り直す

learn tip<No> <tip>の命令を受け取れるように実装する

まずは言葉を受け取ってくれるようにしたいと思います。git hubのチュートリアルを少し書き換えて下のようなpythonコードを作成しました。

@respond_to('learn tip1 `.*`')
def learn_tip(message, something):
    message.reply('I learned {}'.format(something))

これでバッククォート「`」で囲った範囲内を返してくれる気がしております。試してみます。

あれ?デフォルトのお返事が返ってきましたね。色々試してみると()を取っちゃダメみたいです。

@respond_to('learn tip1 (.*)')
def learn_tip(message, something):
    message.reply('I learned {}'.format(something))

正規表現をちゃんと勉強しなくては・・・

いい感じですね。tips1の1も拾って欲しいです。色々試してみます。デコレータを書き換えてみました。

@respond_to('learn tips(.*) (.*)')

エラーが出てしまいました。pythonの実行結果をみてみると以下のエラーでした。

TypeError: learn_tip() takes 2 positional arguments but 3 were given

引数は2つまでしか指定がないのに、3つ来ているよ。と言っています。もしかしてデコレータを適用している関数の引数の数なのでしょうか?次は以下のように書き換えてみました。

@respond_to('learn tips(.*) (.*)')
def learn_tip(message, tip_number, tip_msg):
    message.reply('I learned tips{} as {}'.format(tip_number, tip_msg))

これだと認識できるでしょうか?

完璧ですね。と思ったのですが、tipの中でスペース空けるとどうなるのか確かめていませんでした。嫌な予感しかしません。

「定時は」と「16時」の間にスペースを空けたのですが、そこで区切られていますね。)あとは今更ですが、tips1ではなくtip1にしたくなってきました。)tipの後には数字しか入らないはずなので、数字の正規表現を用いてみようと思います。

@respond_to('learn tip(\d*) (.*)')
def learn_tip(message, tip_number, tip_msg):
    message.reply('I learned tips{} as {}'.format(tip_number, tip_msg))

この場合の結果がこちらです。

なんとかうまくできました!

終わりに

今回はlearn tip<n> <tip>という命令内容を取得できるように作成しました。正規表現の難しさを実感しました。次回はjsonに保存していくところと、jsonのリストを表示するところ、不要なtipを削除するところを作成したいと思います。

読んでいただきありがとうございました。

git hubのソースコード

前回の記事次回の記事

ABOUT ME
hirayuki
今年で社会人3年目になります。 日々体当たりで仕事を覚えています。 テーマはIT・教育です。 少しでも技術に親しんでもらえるよう、noteで4コマ漫画も書いています。 https://note.mu/hirayuki