この記事は**『Mobb/Repp Advent Calendar Advent Calendar 2018』**9日目の記事です。
3行でおk
- 友人のツイートを真似するbotをつくったよ
- botを簡単につくるライブラリとして mobb / repp をつかったよ
- reppはデフォルトでTwitter対応してないので、Twitter対応コードを書いてみたよ
どういうわけか?
昔のゲーム仲間のなかで一時期Twitter botが流行ったことがありました。
twittbotのようなサービスをつかって、名言(というか迷言)ツイートを集めて定期的にツイートするbotが作られたりしていたのですが、
僕はプログラムが書けるのだし、簡単なマルコフ連鎖でツイートをつくるbotをつくったら面白いんじゃないかな?と思い、
Rubotyをつかって簡単につくってインターネットに解き放っていました。
……が、時は流れTwitterのUserStreamAPIはなくなり、ruboty-twitterをつかって作ったbotは起動できなくなってしまったため、
昔の思い出のbotはそのまま眠りについてしまいました。。。
そんな中、期待の新星botフレームワークの『mobb』が生まれました!
SinatraライクなDSLを持つmobbは、
こういったちょっとしたbotをつくるには最適なbotフレームワークです。
require 'mobb'
cron '0 * * * *' do
"定期発言するよー(#{Time.now})"
end
昔がんばってつくったbot。
せっかくなので、今のやり方でもう一度復活させてあげることにしました!
botの機能について
昔作ったbotは以下の機能を持っていました
- 友人のツイートを形態素解析してDBに保存する
- 定期的にマルコフ連鎖で文章をつくってツイートする
- リプライされたら、マルコフ連鎖で文章をつくってリプライを返す
- フォローされたらフォロー返しをする
(1)については特にbot的な部分とは関係ないため今回は割愛します。
rakeタスクをたまに実行してDBを更新するような感じです。
また、(4)は業者アカウントに狙い撃ちされてひどいことになったので
今回は仕様から消すことにしました><;
というわけで、(2) (3)の機能を持つbotをつくっていきます!
まず、シェル上で動くようにする
mobbはデフォルトでシェル上で対話環境としてbotが動きます。
まずはここでざっくりと挙動をつくります。
source 'https://rubygems.org'
gem 'mobb'
require 'mobb'
helpers do
# マルコフ連鎖で文章をつくる
def generate_talk
# TODO: 一旦仮の文章を返すようにしておきますね
"いい感じの文字列: #{Time.now}"
end
end
# リプライをされたら発言
on /.+/ do
generate_talk
end
# 毎時0分に発言
cron '0 * * * *' do
generate_talk
end
mobbは定期実行系の発言をするbotも簡単につくれるところがお気に入りです。
結構ほかのフレームワークだと大変だったりするんですよね……
$ bundle exec ruby app.rb
== Mobb (v0.4.0) is in da house with Shell. Make some noise!
> こんにちは!
いい感じの文字列: 2018-12-08 00:58:32 +0900
いいですね!
マルコフ連鎖部分をつくる
ググると死ぬほど記事が出てくるので、どうやって実現するかはサラっと流してしまいます。
- 学習させたい言葉を入力する
- それを形態素解析して単語ごとにわける
- 単語自体、単語同士のつながりをDBに保存する
形態素解析: okura
Rubyで日本語の形態素解析を使いたい場合、mecabのgemを使うのが定番だと思います。
ただ、mecabはHeroku上で動かす際にちょっと面倒くさいイメージがあったため、Herokuにデプロイしたい僕はokuraを使いました。
……のはずだったのですが、すでにいろんなものをHerokuで動かしていたせいで、
Herokuの無料枠が残っていませんでした><
というわけで、いまは個人的に借りているVPSでdocker-composeで立ち上げている運用にしています。。。
実行環境的に問題がないのであれば、mecabを使うのが良いと思います。参考になる記事も多いし。
データベース: mobb-activerecord
Rubyでデータベースいじるなら、やっぱりActiveRecordを使いたい!
とはいえ、Rails以外の場所でActiveRecordを使うのは結構大変だったりします。
でも大丈夫!
mobbにはmobb-activerecordというActiveRecordを3秒で使えるようにするGemがあるため、
それを読み込むだけで何も悩まずにActiveReordが使えます。
mobb-activerecordについては、明日の記事でmobbの作者の @Kinoppyd さんが解説してくれるそうなので、興味がある方はそちらを読むと良いと思います。
今回は単語自体を記録するWordモデル、
単語同士のつながりを記録するWordChainモデルの2つを定義して実装しました。
mobb/reppを任意のWebサービスに対応させる
いい感じの文章がつくれるようになったら、
あとはTwitterにつながるようにしてインターネットに解き放てば終了です!
…が! mobbの裏で動いているインタフェース部分のreppは、
デフォルトではTwitterに対応していません。
でも、だいじょうぶ!
reppを新しいWebサービスに対応させるのは、100行くらいのRubyコードで実現できます。
Twitterのハンドラをつくってみる
かつてのTwitterにはUserStreamAPIというリアルタイムにツイートを取得する機能がありましたが、
現在は通常のWebAPI、またはAccount Activity APIという新しいAPIを使う必要があります。
僕は新しいTwitterのdeveloper登録申請が通らなかったため、
昔つくったアプリケーションのトークンで、通常のAPIだけを使ったハンドラをつくってみました(◞‸◟)
repp標準のSlackのハンドラを参考に実装しています。
通常のメッセージを受け取る部分は自分に対するリプライの取得と読み替えることで、今回やりたかったリプライに反応するTwitter botをつくれるようにしています。
ただし、 @Kinoppyd さんの7日目の記事『Reppのインターフェイス』で触れられている通り、
reppのインタフェースは今後のバージョンアップで変わる可能性が高いそうです。
とはいえ、そんなに厚みもないので、死ぬほど困ることは起きないと僕は信じています><
誰かTwitterAPIの審査通ったひとがいい感じのハンドラを書いてくれるといいな…!
(僕は使えないけど!)
おわりに
mobb/reppをつかって、昔つくったbotをサクっと蘇らせてみました。
僕の感じていることとして、既存のbotフレームワークは結構しっかり作ることが求められているように感じてます。
確かに再利用ができたほうがコード的に良さそうな気もしますが、
僕が実際つくりたいbotのことを考えると、唯一無二の存在みたいなbotになることが多く、
これ再利用することあるか……?のようになるケースが多いです。。。
mobbはとにかく薄く書き始めることができるため、
再利用が必要ないものは薄くベタッと!
再利用が必要になったものはモジュール化して分離!
のような段階にわけた使い方もしやすいな、と思っています。
botのソースコード
ちなみに今回つくったbotのコードは以下にあります。
mobb-activerecordの登場前につくったりしていたので、ちょっと昔の名残があったりはするのですが、
mobbをつかって作られたbotの1つとして参考になれば幸いです。