Node.js
Socket.io
Bluemix
Watson

Node.js初心者がNode.js + Watson Conversation でチャットボットを実装してみた

始めに

既出の記事が多くある感じもありますが、ローカル環境でも動かせるチャットボットを気楽に作ってみました。この記事ではNode.js + Socket.ioを使ったチャットツールにAPIを組み込んでチャット機能を作る方法について記述しています。
※Watson Conversationの開発方法についてはこちらを参照して下さい。
(本当はNode-REDで組んでみたかったのですが、サンプルすら上手く動かせずに断念…こうなったら、一から組もうかなと思ったのが正直なところです。)

構成について

今回は下記の構成で作っています。下記は全てインストール済みという前提で進めていきます。
・ npm
・ Node.js
・ Express
・ ejs

プロジェクトの作成

まず、express exp01 -e ejsでプロジェクトを作成します。
次にプロジェクトディレクトリに移動して、npm installで必要なモジュールをプロジェクトに追加します。
これだけで下記の構成の基本的なプログラムが作成できました。
キャプチャ.PNG

早速、node bin/wwwを実行してみましょう。
ポートなどを変更していなければ、http://localhost:3000でアクセス出来ちゃいます。
こんな画面が出来たらひとまず、準備作業は完了です。とっても簡単ですね。
キャプチャ.PNG

必要なモジュールのインストール

次に、Socket.iowatson-developer-cloudを追加します。package.jsondependenciesに下記の2行を追加しましょう。

"socket.io": "2.0.3",
"watson-developer-cloud": "2.39.2"

もう一度、npm installを実行します。
これで必要なモジュールが全て揃いました。

API呼び出し処理の組み込み

次に、bin/wwwを編集していきます。

/**
 * Create HTTP server.
 */
var server = http.createServer(app);

後ろに下記のソースコードを追加します。
ConversationのAPIの使い方は、ここを参考にしました。
また、Socket.IOのチュートリアルも元にしています。

var io = require('socket.io').listen(server);
io.on('connection', function(socket){
    var ConversationV1 = require('watson-developer-cloud/conversation/v1');

    // Set up Conversation service.
    var conversation = new ConversationV1({
      url: 'https://gateway.watsonplatform.net/conversation/api',
      username: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', // ユーザー名を置き換えてください。
      password: 'xxxxxxxxxxxx', // パスワードを置き換えてください。
      path: { workspace_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' }, // ワークスペースIDを置き換えてください。
      version_date: 'YYYY-MM-DD'//何でもいいのかも?
    });
    var res = [];
    // このページにアクセスしたときに、空のメッセージをConversationに投げる
    conversation.message({}, processResponse);
    // Conversationのレスポンスを取得する
    function processResponse(err, response) {
        if (err) {
          console.error(err); // something went wrong
          return;
        }
        // intentがマッチしたらコンソールに出力する
        if (response.intents.length > 0) {
            console.log('chat message', 'Detected intent: #' + response.intents[0].intent);
        } 
       // 何らかの返答があれば、それをbotからの返答として全て返す(ループはjump to の時に必要)
        for (var i = 0, len = response.output.text.length; i < len; i++) {
            if(response.output.text[i] !== ''){ 
                io.to(socket.id).emit('bot message', response.output.text[i]);                
            }
        }
        res[socket.id] = response;
    }
    //新しいメッセージを受信したときの動作
    socket.on('chat message', function(msg){
        //受信したメッセージをそのまま、チャット画面に表示
        io.to(socket.id).emit('chat message',msg);
        // 受信したメッセージをAPIに投げる
        conversation.message({
          input: { text: msg },
          context : res[socket.id].context
        }, processResponse);
    });
});

ちなみに、ユーザー名とパスワードはダッシュボードのサービス資格情報、ワークスペースIDはConversationのダッシュボードから、自分が作ったアプリの右上にある…をクリック→view detailsから参照可能です。

最後に、/views/index.ejs/stylesheets/style.cssをそれぞれ書き換えます。
index.ejs

<!doctype html>
<html>
  <head>
    <title>チャットボットテスト</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
      <div class="chat-box">
        <ul id="messages"></ul>
        <form action="">
          <input id="m" autocomplete="off" /><button>Send</button>
        </form>          
      </div>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
        $(function () {
          var socket = io();
          $('form').submit(function(){
            socket.emit('chat message', $('#m').val());
            $('#m').val('');
            return false;
          });
          socket.on('chat message', function(msg){
            $('#messages').append($('<li>').text(msg).addClass('chat-hukidashi someone').wrap('<div />'));
          });
          socket.on('bot message', function(msg){
            $('#messages').append($('<li>').text('QA botくん:'+msg).addClass('chat-hukidashi').wrap('<div />'));
          });          
        });
    </script>
  </body>
</html>

style.css

* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin:auto 0; padding: 0; }
#messages li { padding: 5px 10px; display: block }
/* チャットレイアウト */
.chat-box {
    width: 80%;
    height: auto;
    overflow: hidden; /*floatの解除*/
    margin-bottom: 20px;
}
.chat-face {
    float: left;
    margin-right: -120px;
}
.chat-face img{
    border-radius: 30px;
    border: 1px solid #ccc;
    box-shadow: 0 0 4px #ddd;
}
.chat-area {
    width: 100%;
    float: right;
}
.chat-hukidashi {
    display: inline-block; /*コメントの文字数に合わせて可変*/
    padding: 15px 20px;
    margin-left: 120px;
    margin-top: 8px;
    margin-right: 20px;
    border-radius: 10px;
    position: relative; 
    background-color: #D9F0FF; 
}

.chat-hukidashi:after {
    content: "";
    position: absolute;
    top: 50%; left: -10px;
    margin-top: -10px;
    display: block;
    width: 0px;
    height: 0px;
    border-right: 10px solid #D9F0FF;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;}
.someone {
    background-color: #BCF5A9;
}
.someone:after {
    left: auto;
    right: -8px;
    border-right: none;
    border-left: 10px solid #BCF5A9;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
}

これで、改めてnode bin/wwwを実行してみましょう。
http://localhost:3000にアクセスすると、こんな感じでConversationと会話が出来るようになると思います。
キャプチャ2.PNG

こんな簡単な手順で、チャットボットっぽいものが出来ました。APIの利用のしやすさがbluemixのいいところなんでしょうね。
弄りがいがあってとっても面白いです。皆さんも、ぜひ、トライしてみてくださいね。