Help us understand the problem. What is going on with this article?

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

More than 5 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

まとめ

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

Kta-M
fusic
個性をかき集めて、驚きの角度から世の中をアップデートしつづける。
https://fusic.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away