yutaponのブログ

javascript界隈の興味あるネタを備忘録的に残しておく場所

Hubot+HipChat+Yukkuroidで喋るBotを作る

Hubotのスクリプトを作るときに、Yukkuroidと連携するとすぐに声を加えることができるのでオススメ。
やってみたら簡単にできました。

環境について

今回の動作環境はこちら。
Yukkuroidの話なので、Macじゃない方はあまり参考にならないかも。

  • MacOSX 10.9
  • Yukkuroid 0.6
  • Node.js 0.10.26
  • Hubot 2.7.5
  • NodObjC 0.0.15

Yukkuroidとは

ゆっくりの声で文章を再生できるソフトのことです。
MAC用テキスト読み上げソフト「ゆっくろいど」

今回はHubotを喋らせるのにこれを使いました。
(sayコマンドで頑張るって手もある)

また、今回の記事の内容はこちらの記事を参考に進めました。 node.jsからゆっくりボイスをしゃべらせる

NodObjCとは

NodObjCはNodeとObjective−C間のやりとりを可能にするライブラリです。
NodObjC

Yukkuroidが持つAPIを叩くのに使います。

検索すると、Node.js 0.8系じゃないと動かないとか出てきましたが、v0.10系で動かしても問題ありませんでした。
OSXが10.9だから問題なかった(?)のかも)

Hubot + Hipchatの連携について

HubotとHipchatの連携は前回も貼ったこちらの記事に書いてます。
開発のお手伝いボット Hubot で定期処理を自動化しよう!

自分とBotのHipChatアカウントを取得するためにメールアドレスが2つ必要です。

自分のHipChatアカウントでHipChatにログインして、画面上部のGroup adminを選択して、Usersタブの+ Add userを押します。

Bot用のメールアドレス等を入力すると、そのメールアドレスに参加用のリンクが届くので、そのリンクからBot用のHipChatアカウントを作成してください。

一つの部屋に自分のアカウントとBot用のアカウントがいる状態になれば準備よしです。

BotアカウントのHubot連携用情報を確認する

BotのアカウントでHipChatにログインして、Account settingsXMP/Jabber infoを開きます。

そこでJabber IDと表示されているものをメモしておきます。
12345_xxxxxx@chat.hipchat.comみたいなフォーマットのやつです。)

Hubot起動スクリプトを作る

HubotとHipChatを連携されるためにnode-hipchatモジュールを入れておきます。

$ npm install hubot-hipchat --save

次に、HipChatと連携するためのスクリプトを作成します。
(作る階層はどこでも大丈夫。今回はプロジェクトルートに作成した。)

$ vim run.shなどでファイルを作り、内容は以下の通りで作ります。

#!/bin/bash

export HUBOT_HIPCHAT_JID="Jabber ID"
export HUBOT_HIPCHAT_PASSWORD="Login password"
bin/hubot --adapter hipchat

ファイルに実行権限を加えます。

$ chmod +x run.sh

あとは$ ./run.shスクリプトを実行してHubotを起動します。

Hubotスクリプトの作り方

Hubotスクリプトの作り方はこちらが参考になりました。
hubotスクリプトの書き方とサンプル集

まず簡単なものから作ってみます。

ぬるぽ」に反応して「ガッ」と喋るスクリプト

nullpo.coffeeとしてscripts/以下に保存しました。

# Description:
#   talk back "NURUPO"

module.exports = (robot) ->
    robot.hear /ぬるぽ/, (msg) ->
        console.log(msg)
        msg.send "@#{msg.message.user.mention_name} ガッ"

実行結果はこれ。

f:id:sskyu:20140609010304p:plain

メンション付きで返事をしたい場合は、msg.message.user.mention_nameの先頭に@を足して返信すれば良いようです。

robot.hear正規表現を組み合わせることで、チャットルーム内の発言に反応できます。

声付きで答えるスクリプト

YukkuroidとHubot連携するまえに、簡単なモジュールを作っておきます。

libs/yukkuri.jsというファイル名で以下の内容を保存します。

var $ = require('NodObjC');
$.import('Foundation');
$.import('Cocoa');

var processName,
    host,
    proxy,
    pool;

/**
 * 初期化処理.
 * ここで自動解放プールの作成と必要なNSStringの作成.
 */
function init() {
    pool        = $.NSAutoreleasePool('alloc')('init');
    processName = $.NSString('stringWithUTF8String', 'com.yukkuroid.rpc');
    host        = $.NSString('stringWithUTF8String', '');
    proxy       = $.NSConnection('rootProxyForConnectionWithRegisteredName',processName,'host',host);
}

/**
 * 終了処理.リソースを解放する.
 */
function release() {
    pool('drain');
}

/**
 * NSConnectionを取得する.
 */
function getProxy() {
    return proxy;
}

/**
 * 通常テキスト欄に値をセット.
 */
function setKanjiText(jsStr) {
    var objCStr = $.NSString('stringWithUTF8String', jsStr);
    proxy('setKanjiText',objCStr);
}

function getKanjiText() {
    return proxy('getKanjiText');
}

/**
 * 音声を再生する.
 */
function play() {
    proxy('pushPlayButton',0);
}

/**
 * 引数に受け取ったテキストをゆっくりボイスで再生する
 * リソース設定からリソース解放まで行う
 * @param  {String} msg
 */
function say(msg) {
    var text;
    init();
    setKanjiText(msg);
    play();
    release();
}

module.exports = {
    init         : init,
    release      : release,
    getProxy     : getProxy,
    setKanjiText : setKanjiText,
    getKanjiText : getKanjiText,
    play         : play,
    say          : say
};

次にscripts/hi.coffeeに実際に使うHubotスクリプトを作成します。

これはBothiとメッセージが飛んできたら、hiと返して、「はい」と喋るスクリプトです。

# Commands:
#   hubot hi
#
#   Commands:
#       hubot hi - Reply with hi

yukkuri = require('../libs/yukkuri')

module.exports = (robot) ->
    robot.respond /hi/i, (msg) ->
        msg.send 'hi'
        yukkuri.say('はい')

実行結果はこんな感じ。

f:id:sskyu:20140609004446p:plain

ゆっくりボイスで発言と同時に「はい」と聞こえます。

Yukkuroid関連の処理を簡略化して、yukkuri.say(MESSAGE)でよしなに喋ってくれるようにしてます。

時間指定で定期的に発言するスクリプト

cron使ってBotが能動的に発言するようにできます。

まずはcronモジュールをインストールします。

$ npm install --save cron

scripts/cron.jsとしてスクリプトファイルを作成します。

これは1分毎にチャットルーム内にルイズコピペを投稿するスクリプトです。

# Description:
#   send message to chat room by cron

roomId = '12345_xxxxx@conf.hipchat.com'

cronJob = require('cron').CronJob
yukkuri = require('../libs/yukkuri')

module.exports = (robot) ->
    send = (room, msg) ->
        response = new robot.Response(robot, {user : {id : -1}, text : "none", done : false, room: room}, [])
        response.send msg

    # *(sec) *(min) *(hour) *(day) *(month) *(day of the week)
    new cronJob('1 * * * * *', () ->
        msg = """
ルイズ!ルイズ!ルイズ!ルイズぅぅうううわぁああああああああああああああああああああああん!!!
とどけえええええええ!
        """
        send roomId, "#{msg}"
        yukkuri.say(msg)
    ).start()

実行結果はこんな感じ。

f:id:sskyu:20140609004933p:plain

ルイズのコピペを全文乗せたらYukkuroidが反応しなくなったので適当に省略しました。

roomIdというのはHubotを起動したときに表示されるやつを指定して下さい。

$ ./run.sh
[Mon Jun 09 2014 00:36:39 GMT+0900 (JST)] INFO Connecting HipChat adapter...
[Mon Jun 09 2014 00:36:44 GMT+0900 (JST)] INFO Connected to hipchat.com as @beatkun
[Mon Jun 09 2014 00:36:44 GMT+0900 (JST)] WARNING The HUBOT_AUTH_ADMIN environment variable not set
[Mon Jun 09 2014 00:36:47 GMT+0900 (JST)] INFO Data for brain retrieved from Redis
[Mon Jun 09 2014 00:36:47 GMT+0900 (JST)] INFO Joining 12345_xxxxx@conf.hipchat.com # ← roomIdはこれ

複数定期的に発言させたい場合はnew cronJob(/* いろいろ */).start()をどんどん書いていけばできそうです。

おわりに

Botを声付きで喋らせることで何か愛着がわきます。

今後は

yutapon> @hubot 電気つけて
hubot> 電気つけたよー

みたいに、IRKitを組み合わせて家電制御していく予定。