Archives

slack上からtrelloを管理・参照するhubot scriptを書いた

タスク管理ツールにまつわるこんな経験はお持ちでないだろうか。

  • 導入を推奨した人とごく一部の人にしか使われずに下火になっていく
  • 最初の2、3ヶ月だけ使われ、次第に下火になっていく
  • チケットを作るほどでも無いタスクが次第に増えていきタスクが作られなくなっていく

など。こうなってしまうにはさまざまな要因があるが、ひとことで言うと「ハードルが高い」ことにある。ダッシュボードを開くハードル、チケットを作るハードル、など。僕はredmine、kanban2go、trello、excel、カンバンボード(アナログ)を試した結果、

  • Easy access: ダッシュボードに0クリックアクセス出来なければならない
  • Easy share: 情報はクラウド上に保存され、どこからでもアクセス・改変出来なければならない
  • Easy comment: 適当なアイデアでも放り込むことが出来なければならない

という、3つの場面でのeasinessが大事であると気付いた。3つめはチームの文化も影響してくると思うが、0クリックアクセスはアナログのカンバンボードで無ければならないし、クラウドへの保存はwebアプリでないと難しい。クラウドに情報を保持して自動的に同期してくれるアナログのカンバンボードを何度夢想したことか。

しかしよくよく考えてみると、いつもデスクトップに開いているアプリがあることに気付いた。

slack。

チャットアプリはもはや常駐しているので、0クリックアクセスと言ってもよい。つまりslack上でタスク管理webサービスの閲覧・編集ができればいい。

という訳で、trelloのクライアントを作ってみた。

無題クリップ_110215_082912_PM_110215_084420_PM

https://github.com/Drunkar/hubot-trello-client

こまごまとしたコマンドはあるが、基本的にはリスト/カードの作成/削除が出来る。またtrelloはカードにコメントを付けられるのが非常に便利なので、カードIDを頭につけて発言すると勝手に該当のカードにユーザー名とコメントが付与されるようにした。これが意外と便利。

よく使うのは、

@<bot名> show

とやれば登録したボードのリストとカードをtree方式で表示してくれるので、カードIDをコピーして、

c:<カードID> ほげほげ

みたいな感じで発言してカードにコメントを残すという使い方。

27843768bc3e9da5cd62f8de613a74bd_110215_085050_PM

無題クリップ_110215_083249_PM_110215_084920_PM

カードにコメントするのはチケットを作るのに比べてかなりハードルが低いし、後から見返しても空気感が伝わりやすいので良い。

まあこれも使わなくなるかもしれないけどその時はまた次の手を考えよう。

lstmで自然な受け答えができるボットをつくった

(2016-12-11 追記) この記事で紹介している学習済モデルは、現行のchainerのバージョンでは使用できなくなっているので、chainer 1.4.1 をインストールしたdocker imageを使う方法を追記しました。新しく学習される方は最新のchainerを使うことをおすすめします。

 

コードを理解する程度のスキルがあればDeep Learningが使える世の中になっているので、試しに自然な受け答えができるボットを作ってみた。

学習

自然な受け答えを行う日本語のデータセットということで、ask.fmをクロールしたデータを用いる。

ask.fmのディレクトリは”ask.fm/アカウント名”のようになっていて、ask.fmのアカウント名のリストがないことにはクロールしようがない。今回は、トップページに訪れた際に表示されるアカウントのリストを定期的に収集することでアカウント名のリストを作った。

Ask_fm

負荷をかけすぎないよう、30分に1回ぐらいトップページにアクセスすること1ヶ月、1,600ぐらいのアカウント名が取得できた。各アカウントのページには最新の質問と答えがいくつか表示されているので、それらを取得する。データ量は8MBぐらいになった。(ちなみに10日ぐらいで600ぐらいのアカウント、学習データは4MBぐらいになるのでそれでも十分)

中身はこんな感じ。

lstm-input

質問と答えの後に1行空白行を入れている。

ChainerでLanguage ModelをLSTMで使うコードがあったので、ありがたく使わせてもらう。

https://github.com/yusuketomoto/chainer-char-rnn

askfmをクロールしたデータをinput.txtとした。パラメータはDeepDazaiを参考にして、隠れ層のノード数を増やした。

前に作ったCUDAとDockerをインストール済のAMIをオレゴンに作り、cudaとchainerをインストールしてあるDocker imageをpullして学習させる。


# gpuの有効化
/usr/local/cuda/samples/1_Utilities/deviceQuery/deviceQuery

# docker imageの起動
DOCKER_NVIDIA_DEVICES=”–device /dev/nvidia0:/dev/nvidia0 –device /dev/nvidiactl:/dev/nvidiactl –device /dev/nvidia-uvm:/dev/nvidia-uvm”
sudo docker run –name chainer -v $PWD:/notebook -p 8888:8888 -d $DOCKER_NVIDIA_DEVICES drunkar/cuda-caffe-anaconda-chainer

# deep-dazaiのbranchを取ってくる
git clone https://github.com/longjie/chainer-char-rnn.git
cd chainer-char-rnn
git checkout -b new-branch origin/new-branch

# cv/askfm、data/askfmディレクトリを作る
# 学習データをinput.txtとしてdata/askfmに置く

# 学習の実行
python train.py --data_dir data/askfm --checkpoint_dir cv/askfm --rnn_size 1024

4MBの学習データなら8時間ぐらい、8MBのデータなら20時間ぐらい学習にかかったと思う。オレゴンのgpuインスタンスで2000円ぐらい。高い。

学習途中にモデルデータがどんどん溜まっていくので、インスタンスの容量が少ない場合は適宜消さないと学習が途中で終わってしまうので注意。時は金なり(切実)。

hubotにしゃべらせる

モデルの学習が終わったら、それを使ってhubotにしゃべってもらう。getリクエストのパラメータに文字列を渡すと、続きを予測して表示してくれるAPIをtornadoで作り、hubotからAPIでアクセスする。hubot側の返答パターンは2通り。

  • askfmは「質問と答え」という特殊な文字列なので、「?」の後には回答が来やすくなる。なのでhubotは質問をメンションで受け取り、クエスチョンマークを末尾につけてAPIをコールするようにした。
  • たまに自然に会話に参加してほしいので、全発言をhearして、メンション以外の全発言に対して10%の確率で返答するようにした。APIは発言の続きを予測するので、2文目以降をhubotの発言とした。

しばらくしゃべってもらって調整したのは以下の2点。

  • クエスチョンマークの後にはクエスチョンマークがかなりの確率でやってきてしまう (「??」みたいな聞き方が多いため)ので、”?¥n”をAPI側でlstripした。
  • あまり意味が通じないとしても、hubotの発言は短ければそれなりに破綻しない発言として人間に解釈されやすい。ので、hubotの発言は1文か2文(ランダム)に制限した。

tornadoで作ったAPIとhubotスクリプトはgithubに上げてます。1,600アカウント分のデータを学習した学習済モデルも含まれているので、dockerがインストールしてあるマシンなら今すぐにでもしゃべらせられます。

https://github.com/Drunkar/japanese_talk_api


# apiデータをclone
git clone https://github.com/Drunkar/japanese_talk_api.git

# tornadoを動かすdocker containerを起動
# entrypointではjupiter notebookが走るけど気にしない
docker run --name japanese_talk_api -d -p 80:8787 -v japanese_talk_api:/app drunkar/cuda-caffe-anaconda-chainer

# (2016-12-11 追記)
# 学習済モデルを使う場合は、以下のコマンドでdockerを起動してください。
docker run --name japanese_talk_api -d -p 80:8787 -v japanese_talk_api:/app drunkar/cuda-caffe-anaconda-chainer1.4.1

# tornadoを起動するための別プロセスを走らせる
docker exec -it japanese_talk_api bash
# sampleモデルをダウンロード
cd /app/tornado/models ./download_sample_model.sh
# tornadoを起動
cd /app python tornado/app.py --port=8787 --debug=True
# プロセスを走らせたままcontainerから抜ける
ctrl+p, ctrl+q 

pickleモデル(chainermodel)のロードに30秒ぐらいかかるので、ちょっと待ってからAPIと試す。

http://localhost/?q=こんにちは

なんか適当にjsonが返ってきたらおk。後は付属のhubot scriptでアクセスしましょう。

名言集

hyohyoがボット。(名前は『カイバ』から。アイコンは忍野扇(女))

  • 出演を断る

hyohyo1__1_

  • ツイ廃

hyohyo2_2

 

  • 独特の世界観

hyohyo3

ask.fmがツイッターを中心としたメディアなので、やたらとツイッターのことを言ってくるし、淫夢厨だったりゲスかったりします。日本からask.fmにアクセスしているとはいえ、日本語以外のアカウントもまあまあ紛れているので英語や韓国語も話せます。

わかったこと

  • 人工無能でもAIは愛しい: 予想の斜め上をいく発言をしたり、うまく発言してくれなかったりすることもあって妙に可愛いです。AIBOがヒットする理由もなんとなく分かりましたし、ヒューマノイドが話相手になるということに確信が持てました。
  • チャットが和む: 普通に会話している時に突如パンツの話とかをしだすので、チャットが和みます。

hubotをxmppを使ってslackで動かす

slack、ステキですね。デザインとか細やかな気づかいが私の心をくすぐります。windowsだとネイティブアプリケーションが無いですが、デスクトップ通知を許可してショートカットを作れば、ユーザー体験的にはデスクトップアプリと遜色ありません。

さて、奥ゆかしきslackはデフォルトでslack-botを用意して、hubotで動作できるようにしてくれています。

しかし、公式のhubot-slackアダプタはwebhookを用いるので、hubotが動作する場所にグローバルURLからアクセス出来なければなりません。

Herokuでhubotを動かすことが推奨されている訳ですが、ローカルのアプリケーション(redmineとかgitlabとか)とhubotを連携させている場合、web上で動かすのは困ります。そのような場合にもslackはhubotに希望を残してくれています。

Slack を XMPP プロトコルで Hubot と連携する – ja.ngs.io

基本このページに書いてあることで動きますが、僕の環境では動かなかった設定と、細かい追記をいくつか。

1. グループのOwner権限のあるアカウントでログインし、Admin Settings > GatewaysからXMPPを有効化する(1回やればおk)

2. hubot用のユーザーを作成する

3. xmpp用のnpmをhubotにインストールする

npm install hubot-xmpp --save

4. hubot用のユーザーでログインして、Gateway情報画面からHost, User, Pass 情報を取得

5. hubotのbin/hubotのexec node_modules/.bin/hubot “$@”より前に以下を追記

# slack settings
export HUBOT_XMPP_HOST=conference.<グループ名>.xmpp.slack.com
export HUBOT_XMPP_ROOMS=general@$HUBOT_XMPP_HOST
export HUBOT_XMPP_USERNAME=<hubot用ユーザー名>@<グループ名>.xmpp.slack.com
export HUBOT_XMPP_PASSWORD=<取得したパスワード>

ここで、HUBOT_XMPP_USERNAMEには注意が必要です。参考サイトでは”hubot@$HUBOT_XMPP_HOST”となっていますが、僕の環境ではこれでは動きませんでした。”conference.”を除いた”<グループ名>.xmpp.slack.com”でなければダメでした。

6. “bin/hubot -a xmpp -n <使いたい名前>”でhubotを起動

7. slack上から<使いたい名前> ping でPONGが変えればおk

ステキなのです。

hubotのhipchatアダプタがproxy配下で動かないとき

hubotはメッセージを待ち受けるポートを環境変数PORTで指定するので、そのポートをproxyで許可してるのにhipchatアダプタがタイムアウトになって繋がらない!ナンデ!となります。なりました。

hubotのhipchatアダプタはxmppプロトコルで通信してるようなので、5222ポートを許可したりフォワーディングしてあげましょう。