Ruby + Bot = Ruboty

https://github.com/r7kamura/ruboty
RubotyというRuby製のChatterbotをつくった。

Herokuで動かす

Herokuにデプロイすれば無料で動く。
Slackというチャットサービスで動かすならこういう感じ (部屋名とかは適宜変える):

$ mkdir mybot
$ cd mybot
$ echo 'source "https://rubygems.org"' >> Gemfile
$ echo 'gem "ruboty"'                  >> Gemfile
$ echo 'gem "ruboty-slack"'            >> Gemfile
$ echo 'bot: bundle exec ruboty'       >> Procfile
$ bundle install
$ git init
$ git add .
$ git commit -m "Initial commit"
$ heroku create
$ git push heroku master
$ heroku scale bot=1
$ heroku config:set ROBOT_NAME=tqbot SLACK_TEAM=tqhouse SLACK_USERNAME=tqbot SLACK_ROOM=general SLACK_PASSWORD=XXX

Gemで拡張する

ruboty-githubやruboty-google_imageなど、Gemを追加すれば新しい挙動を追加できる。

# Gemfile
gem "ruboty-alias"           # Rubotyへの発言にaliasを設定できる (LGTMって言ったらLGTM画像を探してくれるとか)
gem "ruboty-cron"            # Cron形式で時刻を指定して定期的に発言させられる
gem "ruboty-github"          # GitHubを操作してPull Requestを出させたりできる
gem "ruboty-google_image"    # Googleから画像を検索させられる
gem "ruboty-redis"           # 記憶をRedisに永続化させられる
gem "ruboty-slack"           # Slackで利用できる
gem "ruboty-syoboi_calendar" # その日放送されるアニメを教えてくれる

環境変数で設定する

Botの名前や接続するチャットサービスなどの設定は環境変数で伝えるようになっている。 例えばHerokuだったら heroku config:add FOO=bar のように設定すればOK。 設定の環境変数での管理やプラグインのGem形式での分割は、 The Twelve-Factor Appの思想に合わせたもの。 BotもWebアプリと似た構成に近づいていく傾向にあると考えている。

ROBOT_NAME="ruboty"
GITHUB_HOST="my-github-enterprise.example.com"

アダプタを設定する

SlackやHipChatなどの各種チャットサービスとRubotyを接続するためのGemをアダプタと呼んでいる。 今のところHipChatとSlack用のアダプタがある。 需要があれば他のサービス用のアダプタもつくろうと考えてる。 余談だけど、アダプタをつくるためにRubyIRC用ライブラリとXMPP用ライブラリをそれぞれ書き直したりした。(ZirconXrc)

プラグインを自作する

あるパターンに反応して何かを行うという機能を提供するクラスを、Rubotyの内部ではHandlerと呼んでいる。 Ruboty::Handlers::Baseを継承したクラスをつくれば良い。 例えば「@ruboty ping」に反応して「pong」と返すプラグインをつくるには下記のように書く。 プラグインはGemにして配布する必要があるけど、 GemはGistでも公開できる ので気軽に公開していけばいい。好きなGemを組み合わせて君だけの最強のBotをつくろう。

module Ruboty
  module Handlers
    class Ping < Base
      on(
        /ping\z/i,                         # "@ellen ping"に反応して
        name: "ping",                      # #pingメソッドが呼ばれる
        description: "Return PONG to PING" # これは"@ellen help"でhelpを表示したとき説明文として表示される
      )

      def ping(message)
        message.reply("pong")
      end
    end
  end
end

Rubotyは何もアダプタを追加していない状態だとシェルで起動するようになっているので、 開発中のプラグインデバッグなどに使える。

$ bundle exec ruboty
Type `exit` or `quit` to end the session.
> ruboty help
ruboty /help( me)?\z/i - Show this help message
ruboty /ping\z/i       - Return PONG to PING
ruboty /who am i\?/i   - Answer who you are
> ruboty ping
pong

ruboty起動時に --load foo.rb のようにオプションを渡せばそのRubyファイルを起動時に実行してくれる。 プラグインをいちいちGemにして書くのがだるかったら適当なファイルに書いても良い。

進捗

思い付いたときに名前が決まるまでモノをつくれないのが勿体無かったので、元々Ellenという仮名でつくっていたのが先月のこと。 最近ようやくまともに動くようになったので、今日名前をRubotyに変えてversion 1.0.0をリリースしたという。 昔開発されたellen-twitterやellen-idobataなど、最新のversionに追随できていないGemが幾つかあるのでまずはこれを修正したい。 他、Hubotに比べるとプラグインもまだまだ少なくて出来ることが少ないなという感じなので、必要に応じて追加していくつもり。 元々DevOpsのOpsの部分を任せる用途(=ChatOps)で開発をはじめたので、 その辺を便利にするプラグインをつくってBotと仲良くやっていきたいという気持ち。 こういうの欲しいとかこういうのつくったとかは大歓迎です。