Posted at

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

More than 3 years have passed since last update.

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


まとめ

これだけできれば大抵のことはできると思う。

あとはアイデアと実装する根気があれば…!