Hubot:概要〜インストール〜実用的なモノが作れるまで

  • 199
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

GitHubが作ったチャットのbotフレームワーク、Hubotを使ってみる(Mac)。
これがあればいろんなチャットツールにbotを導入できる!

ここでは、Hubotのインストールと各種機能のスクリプトの実装の説明をする。
各種チャットツールとの連携方法やHerokuへのデプロイ方法などはココでは説明しない。

Hubotの構造

Hubotは以下の構造になっている

[チャットツール]
 ↑↓
[Adapter] : チャットツールとRobotとの橋渡し。ここを入れ替えることでいろんなチャットツールに対応可能。
 ↑↓
[Robot]:Hubot本体。
 ↑↓
[scripts]:botの挙動を実装したスクリプト。CoffeeScriptで書く。

Hubotのインストール

Hubotはnode.jsで動くので、まずnode.jsをインストール。(node.js参考)

$ brew install node

そしてHubotのジェネレータをインストール。
npmはnode.jsのパッケージ管理ツールで、node.jsをインストールすると使えるようになる。
yoは対話形式でプロジェクトのひな形を生成するYeomanというツールを構成するものの一つ。(Yeoman参考)

$ npm install -g yo generator-hubot

任意のディレクトリでプロジェクトを作成

$ mkdir myhubot
$ cd myhubot
$ yo hubot

まず、yeoman改善のために匿名でフィードバックを収集していいか聞かれるのでy/nでお返事。

[?] ==========================================================================
We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
==========================================================================:

その後、対話形式でのインストールとなる。以下に答える。
はじめはデフォルト値がカッコ書きで入ってるけど、何か入力したらそちらに上書きされる。

  • 製作者名
  • botの名前
  • botの説明
  • Adapterに何を使うか(どのチャットツール向けに作るか)

adapterは、irc twitter hipchat chatwork slack などがあるみたい。

                     _____________________________
                    /                             \
   //\              |      Extracting input for    |
  ////\    _____    |   self-replication process   |
 //////\  /_____\   \                             /
 ======= |[^_/\_]|   /----------------------------
  |   | _|___@@__|__
  +===+/  ///     \_\
   | |_\ /// HUBOT/\\
   |___/\//      /  \\
         \      /   +---+
          \____/    |   |
           | //|    +===+
            \//      |xx|

? Owner: kta-m
? Bot name: myhubot
? Description: my first hubot
? Bot adapter: slack
   create bin/hubot
   create bin/hubot.cmd
   create Procfile
   create README.md
   create external-scripts.json
   create hubot-scripts.json
   create .gitignore
   create package.json
   create scripts/example.coffee
   create .editorconfig
                     _____________________________
 _____              /                             \
 \    \             |   Self-replication process   |
 |    |    _____    |          complete...         |
 |__\\|   /_____\   \     Good luck with that.    /
   |//+  |[^_/\_]|   /----------------------------
  |   | _|___@@__|__
  +===+/  ///     \_\
   | |_\ /// HUBOT/\\
   |___/\//      /  \\
         \      /   +---+
          \____/    |   |
           | //|    +===+
            \//      |xx|

あとはいい感じにいろいろインストールしてくれる。

インストールが完了したら、試しにローカルで動作確認してみる。

$ bin/hubot --name myhubot

warningがいくつか出るかもだけど、気にせずhubotに語りかけてみる。
名前を指定するのが面倒なら、--nameは付けなくても大丈夫。ただ、その場合はhubotで呼びかけないと反応してくれない。

Hubot> hubot ping
Hubot> PONG

他にデフォルトでできることはhelpコマンドで見れる。

Hubot> hubot help
Hubot> Events:
debug - {user: <user object to send message to>}
Hubot <user> is a badass guitarist - assign a role to a user
Hubot <user> is not a badass guitarist - remove a role from a user
Hubot animate me <query> - The same thing as `image me`, except adds a few parameters to try to return an animated GIF instead.
Hubot die - End Hubot process
Hubot die - End Hubot process
Hubot echo <text> - Reply back with <text>
Hubot echo <text> - Reply back with <text>
Hubot fake event <event> - Triggers the <event> event for debugging reasons
Hubot help - Displays all of the help commands that Hubot knows about.
Hubot help <query> - Displays all help commands that match <query>.
Hubot image me <query> - The Original. Queries Google Images for <query> and returns a random top result.
Hubot map me <query> - Returns a map view of the area returned by `query`.
Hubot mustache me <query> - Searches Google Images for the specified query and mustaches it.
Hubot mustache me <url> - Adds a mustache to the specified URL.
Hubot ping - Reply with pong
Hubot ping - Reply with pong
Hubot pug bomb N - get N pugs
Hubot pug me - Receive a pug
Hubot show storage - Display the contents that are persisted in the brain
Hubot show users - Display all users that Hubot knows about
Hubot the rules - Make sure Hubot still knows the rules.
Hubot time - Reply with current time
Hubot time - Reply with current time
Hubot translate me <phrase> - Searches for a translation for the <phrase> and then prints that bad boy out.
Hubot translate me from <source> into <target> <phrase> - Translates <phrase> from <source> into <target>. Both <source> and <target> are optional
Hubot who is <user> - see what roles a user has
Hubot youtube me <query> - Searches YouTube for the query and returns the video embed link.
ship it - Display a motivation squirrel

スクリプトを書く

独自スクリプトは、scriptsディレクトリに入れる。

呼びかけに応える(respond)

明示的にhubotに対して呼びかけを行なったときに反応する。
呼びかけ内容は正規表現で判別。マッチした箇所も取得できる。
呼びかけ方法はいろいろあって、どれでもOK。

MYHUBOT xxx
myhubot xxx
@myhubot xxx
myhubot: xxx

実装

hoge.coffee
module.exports = (robot) ->

  robot.respond /つー/i, (msg) ->
    msg.send "かー"

  # 正規表現でマッチングした部分の取得もできる
  robot.respond /I am (.*)/i, (msg) ->
    msg.send "Hi, #{msg.match[1]}"

  # msg.randomで配列の文字列の中からランダムに選択して発言する
  robot.respond /おみくじ/i, (msg) ->
    msg.send msg.random ["大吉", "中吉", "小吉", "凶"]

結果

Hubot> myhubot つー
Hubot> かー
Hubot> myhubot I am Ken
Hubot> Hi, Ken
Hubot> myhuobt おみくじ
Hubot> 大吉

チャット上の発言に反応する(hear)

チャット上の発言に特定の文字列が含まれていたら反応する。

実装

hoge.coffee
module.exports = (robot) ->

  robot.hear /疲れた/i, (msg) ->
    msg.send "がんばって!"

結果

Hubot> もう疲れたよ。。。
Hubot> がんばって!

定期的に発言する(cron)

cronモジュールが必要なので、package.jsonの中にcronモジュールを追加する。
また、標準だとUTCなので、タイムゾーンを指定したい場合は別途timeモジュールが必要。
npm installとかしなくても、初回実行時にインストールしてくれる。

package.json
{
  (略)
  "dependencies": {
    (略)
    "cron": "^1.0.5",
    "time": "^0.11.0"
  },
  (略)
}

実行時間の指定はLinuxのcronと同じようにできるけど、
こちらは秒単位で指定できるので、要素が6つあるので注意。

実装

hoge.coffee
cronJob = require('cron').CronJob

module.exports = (robot) ->
  cronjob = new cronJob(
    cronTime: "0 0 9 * * *"     # 実行時間
    start:    true              # すぐにcronのjobを実行するか
    timeZone: "Asia/Tokyo"      # タイムゾーン指定
    onTick: ->                  # 時間が来た時に実行する処理
      robot.send {room: "#ROOM_NAME"}, "おはようございます!"
    )

結果

(毎朝9:00に)

Hubot> おはようございます!

ちなみに、定期的に発言させたいだけなら、hubot-cronを使うという手もある。

データの永続化を行う(brain)

hubotにデータを記憶させる機能。
redisが必要になる。(redis参考)

redisサーバの準備

homebrewでインストール

$ brew install redis

一応バージョン確認してみる。

% redis-server --version
Redis server v=2.8.13 sha=00000000:0 malloc=libc bits=64 build=96319fcc2102d7fa

Redisサーバ起動。(Ctrl-Cで終了)

% redis-server /usr/local/etc/redis.conf

Redisサーバが自動実行されるよう登録しておくのもいいかも。

% ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents
% launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.redis.plist

念のためプロセスを確認してみる。

% ps ax | grep redis-server
13443   ??  S      0:00.44 /usr/local/opt/redis/bin/redis-server 127.0.0.1:6379
13836 s005  S+     0:00.00 grep redis-server

これでMacを再起動しても自動でRedisサーバが起動してくれる。

自動起動をやめたいときはコチラ。

% launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.redis.plist

実装

hoge.coffee
module.exports = (robot) ->

  # redisに保存するためのキー
  KEY_DERBY_POINTS = 'derby_points'

  # 対象と点数を指定
  robot.hear /^(.*)さんに([0-9]+)/, (msg) ->
    name  = msg.match[1]
    points = (robot.brain.get KEY_DERBY_POINTS) or {}
    points[name] = (points[name] or 0) + Number(msg.match[2])

    robot.brain.set KEY_DERBY_POINTS, points

    msg.send "#{name}さん: #{points[name]}点"

  # 点数の合計を表示
  robot.respond /derby list/i, (msg) ->
    points = (robot.brain.get KEY_DERBY_POINTS) or {}
    for name, point of points
      msg.send "#{name}さん: #{point}点"

  # 点数をリセット
  robot.respond /derby reset/i, (msg) ->
    robot.brain.set KEY_DERBY_POINTS, {}
    msg.send "reset: done"

結果

Hubot> はらたいらさんに3000点
Hubot> はらたいらさん: 3000点
Hubot> 竹下景子さんに2000点
Hubot> 竹下景子さん: 2000点
Hubot> はらたいらさんに5000点
Hubot> はらたいらさん: 8000点
Hubot> hubot derby list
Hubot> はらたいらさん: 8000点
Hubot> 竹下景子さん: 2000点

WebAPIを叩く(http)

WebAPIでデータをjsonなり何なりで取ってくる。
例として、Google Geocoding APIを使って住所から緯度経度を取得してみる。

実装

module.exports = (robot) ->
  robot.hear /location (.*)/, (msg) ->
    request = robot.http("https://maps.googleapis.com/maps/api/geocode/json")
                   .query(address: msg.match[1])
                   .get()
    request (err, res, body) ->
      json = JSON.parse body
      location = json['results'][0]['geometry']['location']

      msg.send "#{location['lat']}, #{location['lng']}"

結果

Hubot> location 福岡市中央区大名
Hubot> 33.5869827, 130.3949105

環境変数

これだけrobotのメソッドじゃないけど、環境変数を使う方法を知っておくと設定が楽。

ローカルで環境変数を設定するには、hubot関係なくターミナルでこんな感じに。

$ export HUBOT_ENV_TEST_VAR=hogehoge

スクリプトで読み込むときはこんな感じ。

TEST_VAR = process.env.HUBOT_ENV_TEST_VAR

まとめ

これだけできれば大抵のことはできると思う。
あとはアイデアと実装する根気があれば…!