はじめに
バイク川崎バイクとは
何でも略したらBKB(ベッドで急に爆睡など)になるネタなどがある。ネタの中では『BKB』というフレーズを多用し、身の回りの事を何でも『BKB』にして表現[11]し、最後に両腕を広げて「ヒィーーーアッ」と叫び、身体でBKB文字を作りながら「ススス!」と言う。他に主なセリフには「今日もアクセル全開でがんばります、バイクだけにブンブン」などがある。
目的
業務用Slackにバイク川崎バイクを召喚します。
チャネル投稿中の文章を勝手にみて、略したらBKBになる文章があればその人にリプライを飛ばすbotを実装します。
イメージ(slack)
設計
大体こんな感じで作ろうと妄想します。
- チャネルの投稿文を常時監視して、BKBを含んだ投稿をした人にリプライする。BKB自体にリプライが来たら適当なリプライを返す
- BKBの判定ロジックは形態素解析と正規表現でいけそう 慣れているPythonと、MeCabで動かす
- BotのロジックはPythonのライブラリslackbotを使う
- Herokuにデプロイして恒常的に動くようにする
実装
BKB判定ロジック
概ね、以下の順で文章をBKB文に変換します。
実装例(botmodule.py)
# BKB文判定ロジック
@listen_to(r'.*')
def reply_bkb(message):
# 1. 元文章を読み込み
TEXT = message.body['text']
m = MeCab.Tagger()
# 2. 形態素分割して単語にインデックスを振る(リスト化する)
node = m.parseToNode(TEXT)
raws = []
features = []
# 3. 読みがなに変換
while node:
try:
feature = node.feature.split(',')[9]
except IndexError:
feature = node.surface.split(',')[0]
raw = node.surface.split(',')[0]
if feature != "*":
features.append(feature)
raws.append(raw)
node = node.next
# 4. 単語の頭文字の読みが、「Bから始まる」→B「Kから始まる」→K「それ以外」→O に変換
features2 = []
for feature in features:
if feature:
if feature[0] in {"バ", "ビ", "ブ", "ベ", "ボ", "B", "b"}:
tmp="B"
elif feature[0] in {"カ", "キ", "ク", "ケ", "コ", "K", "k"}:
tmp="K"
else:
tmp="O"
else:
tmp="O"
features2.append(tmp)
features2 = "".join(features2)
# 5. B/K/Bが先頭になるように文字を区切りなおす
p_bkb = re.compile(r'.*?B.{0,3}?K.{0,3}?B.*?')
if p_bkb.match(features2):
b1 = re.compile(r'.*?(B.{0,3}?)K.{0,3}?B.*?').match(features2).span(1)
k1 = re.compile(r'.*?B.{0,3}?(K.{0,3}?)B.*?').match(features2).span(1)
b2 = re.compile(r'.*?B.{0,3}?K.{0,3}?(B).*?').match(features2).span(1)
b1_text = "".join(raws[b1[0]:b1[1]])
k1_text = "".join(raws[k1[0]:k1[1]])
b2_text = "".join(raws[b2[0]:b2[1]])
# 6. 5.のB/K/Bのインデックスを参照して、BKB文を生成する
message.reply("\n{}!\n{}!\n{}!\n\nBKB!ヒィア!!".format(b1_text, k1_text, b2_text))
else:
pass
5.の文字の区切り直しの手順が少し複雑です。下の4種類の正規表現のパターンを使用します。
変数名 | パターン | 用途 | 補足 |
---|---|---|---|
p_bkb | r'.?B.{0,3}?K.{0,3}?B.?' | 文章がB,K,Bを含むか判定する | 間の文字が長すぎると美しくないので、間は3単語以内とする |
b1 | r'.?(B.{0,3}?)K.{0,3}?B.?' | 最初のB~Kの直前までを抽出する | |
k1 | r'.?B.{0,3}?(K.{0,3}?)B.?' | K~2回目のBの直前までを抽出する | |
b2 | r'.?B.{0,3}?K.{0,3}?(B).?' | 2回目のBを抽出する | Bだけを抽出する(後ろの方まで取るか迷ったが、元ネタもこれに近い |
botの作成
下記の記事を参考に実装しました。
SlackのAPIキーなど大事な情報はHerokuの環境変数に記載して読み込むように実装します。
│ .buildpacks
│ .cellar
│ .gitignore
│ Procfile # Herokuでの挙動の設定を記述する
│ pyvenv.cfg
│ README.md
│ requirements.txt
│ run.py # 初回起動時の処理を記載する
│ runtime.txt
│ slackbot_settings.py # APIのKeyを読み込む処理などを記述する
│
│
└─plugins
botmodule.py # BKBロジック判定など主要な処理を書く
__init__.py
完成品
動いた!
メンションしなくても勝手に拾ってくるのが 鬱陶し ユーモアあふれています。
ちなみにメンションすると適当な返事を返してくれます。
改善点
- 辞書は
ipadic-neologd
を使っていないので、今風の言葉の判定は弱い。とはいえ、Herokuにインストールする方法も分からないし、そもそも無料枠のストレージには乗り切らなそうなので断念。 - Herokuには
Free dyno time
なるものが設定されており、無料枠だと月550時間≒22日ぐらいしか稼働しない。月末はお休みをいただいている状態である。ラズパイとかに乗せれば365日稼働するけどそこまでするほどのものでもない。
終わりに
TwitterのBotにすることも考えましたが、API申請が面倒だったり世に出すことへの諸々の懸念があったので、身内だけで楽しむ用に作りました。
本記事を参考にお仕事中のBKBを楽しんでもらえると幸いです。
参考資料