25
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

BluemixAdvent Calendar 2015

Day 13

Node-REDにNatural Language Classifierノードを追加する

Last updated at Posted at 2015-12-13

Node-RED Starterは非常に便利ですが、Watsonに関しては最新のAPIに追随しているとは言いがたい状況です。たとえば、現時点ではNatural Language Classifier (NLC)のノード定義がありません。そこで、NLCのノードを自作して追加してみました。

前提

  • Bluemixアカウント(IBM-ID)の取得
  • Cloud Foundry CLI (cf)のインストール
  • Curlのインストール
  • jqのインストール

サンプル分類器の作成

あとで使うためのサンプル分類器を作ります。
ここでは、IBM Watsonチームが提供している、天気に関するサンプル(weather_data_train.csv)を借用して、天気に関する質問文の分類器を作成します。

#
# 分類器に学習させるサンプルCSVを取得
#

# IBM Watsonチームのサンプルプロジェクトをクローン
$ git clone https://github.com/watson-developer-cloud/natural-language-classifier-nodejs.git

# ファイルの中身を確認
$ cat natural-language-classifier-nodejs/training/weather_data_train.csv

#
# NLCサービスを作成
#

# サービス、およびサービスにアクセスするためのcredential情報を作成
$ cf create-service natural_language_classifier standard weather-classifier
$ cf create-service-key weather-classifier credentials

# Credential情報の中身を確認し、コマンドの結果の"username"と"password"を以下で使用
$ cf service-key weather-classifier credentials

#
# 天気に関する質問文の分類器を作成
#

# 分類器を作成(curlが出力する"classifier_id"はあとで分類器を特定するために使用)
$ curl -s -u "{usernamne}:{password}" -X POST -F training_data=@natural-language-classifier-nodejs/training/weather_data_train.csv -F training_metadata="{\"language\":\"en\",\"name\":\"weather\"}" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers

# 学習状況を確認
# このコマンドが出力するjsonにある"status"が"Training"から"Available"に変わった時点で学習が終了
$ curl -s -u "{usernamne}:{password}" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/{classifier_id}

# 分類器を使ってみる("class_name"と"confidence"を含むjsonが出力されればOK)
$ curl -s -u "{usernamne}:{password}" -X POST -H "Content-Type:application/json" -d "{\"text\":\"Is it cloudy today?\"}" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/{classifier_id}/classify | jq '.classes[0]'

Node-REDアプリケーションの作成

BluemixコンソールのCATALOGからNode-RED Starterアプリケーションを作成します。
CATALOGでは次のアイコン(Node-RED Starter / Community BETA)です。

noderednlc-starter-icon.png

このアイコンを選択するとアプリケーション設定画面に移りますので、プロジェクトの名前(この例では"weatherqclass")のみ入力してアプリケーションを作成します。

noderednlc-create-app.png

Node-RED Starterでは自動的にアプリケーションのステージングが開始されます。画面には「Your application is staging ...」と出ますので、暫く待っていると、「Your app is running」に変わります。
それでは、ブラウザでhttp://weatherqclass.mybluemix.net/に接続してみましょう。

noderednlc-initial-app.png

右の方にある「Goto your Node-RED flow editor」をクリックすると、フローエディタが開きます。
フローエディタの左側にノード一覧があり、この最下部にWatsonサービス群のノードがあります。

noderednlc-watson-nodes.png

NLCはありません。今回のゴールはここにNLCノードを作成し、フローで使ってみることです。

Node-REDフローエディタへのノードの追加

Node-REDアプリケーションのソースファイルのダウンロード

まず、フローエディタのソースをローカル開発環境にダウンロードします。具体的には、さきほど「Your app is running」と表示された画面(左側のメニューでは「Start Coding」)に戻り、「Download Starter Code」と記されたボタンをクリックします。

noderednlc-download-code.png

すると、ブラウザのダウンロードフォルダにzipがダウンロードされますので、これを適当なディレクトリに展開します。

$ mkdir weatherqclass
$ cd weatherqclass
$ unzip ~/Downloads/weatherqclass.zip 

ノードを追加する手順

ノードを追加する手順は以下の通りです。

  1. ノードの外形的表現(nodes/nlc.html)
  2. ノードの振る舞い表現(nodes/nlc.js)
  3. ノードのアイコン(nodes/icons/nlc.png)
  4. パッケージへの追加(package.json)

なお、すべてを変更したソースのサンプルがgithub上に置いてあります。

1. ノードの外形的表現(nodes/nlc.html)

ノードの外形的表現は、nodesディレクトリ以下にhtmlで作成します。このhtmlは大きく3つのscriptから構成します。

(1) 設定項目と設定ダイアログの名称、アイコン、プレイスホルダ等

nodes/nlc.html
<script type="text/x-red" data-template-name="natural-language-classifier">
  <div class="form-row">
    <label for="node-input-name"><i class="fa fa-tag"></i>Name</label>
    <input type="text" id="node-input-name" placeholder="Name">
  </div>
  <div class="form-row">
    <label for="node-input-username"><i class="fa fa-user"></i>Username</label>
    <input type="text" id="node-input-username" placeholder="NLC Username">
  </div>
  <div class="form-row">
    <label for="node-input-password"><i class="fa fa-key"></i>Password</label>
    <input type="password" id="node-input-password" placeholder="NLC Password">
  </div>
  <div class="form-row">
    <label for="node-input-classifierid"><i class="fa fa-tag"></i>Classifier ID</label>
    <input type="text" id="node-input-classifierid" placeholder="NLC Classifier ID">
  </div>
</script>

(2) ヘルプの記述

nodes/nlc.html
<script type="text/x-red" data-help-name="natural-language-classifier">
  <p>The natural language indentifier service.</p>
</script>

(3) エディタ上のノードの基本的な設定

nodes/nlc.html
<script type="text/javascript">
  (function() {
    RED.nodes.registerType('natural-language-classifier', {
      category: 'IBM_Watson',
      defaults: {
        name: { value: "" },
        username: { value: "" },
        password: { value: "" },
        classifierid: { value: "", required: true }
      },
      color: "#FFAAAA",
      inputs: 1,
      outputs: 1,
      icon: "nlc.png",
      paletteLabel: function() {
        return this.name || "Natural Language Classifier";
      },
      label: function() {
        return this.name || "Natural Language Classifier";
      },
      labelStyle: function() {
        return this.name ? "node_label_italic" : "";
      }
    });
  })();
</script>

2. ノードの振る舞い表現(nodes/nlc.js)

ノードの振る舞いは同じくnodesディレクトリにjavascriptファイルで配置します。基本的には、ノードオブジェクトを作成し、on('input', function(msg){})で前のノードから受け取ったpayloadの処理を記述します。後ろのノードにpayloadを送り出す処理はsend(msg)です。

nodes/nlc.js
module.exports = function(RED) {

  function NLCNode(config) {
    RED.nodes.createNode(this, config);
    this.username = config.username;
    this.password = config.password;
    this.classifierid = config.classifierid;
    var node = this;

    this.status({fill:"red",shape:"ring",text:"--------"});

    this.on('input', function(msg) {

      if (!msg.payload) {
        node.error('Missing property: msg.payload');
        return;
      }

      var username = this.username;
      var password = this.password;
      if (!username || !password) {
        node.error('Missing service credentials.');
        this.status({fill:"red",shape:"ring",text:"--------"});
        return;
      }

      this.status({fill:"blue",shape:"ring",text:"--------"});

      var watson = require('watson-developer-cloud');
      var nlc = watson.natural_language_classifier({
        url: 'https://gateway.watsonplatform.net/natural-language-classifier/api',
        username: username,
        password: password,
        version: 'v1'
      });

      nlc.classify({
        text: msg.payload,
        classifier_id: this.classifierid },
        function(err, response) {
          if (err) {
            node.error(err);
          } else {
            msg.text = response.text;
            msg.payload = response.top_class;
            msg.classified = response.classes[0].class_name;
            msg.confidence = response.classes[0].confidence;
          }
          node.send(msg);
        });

      this.status({fill:"green",shape:"ring",text:"--------"});

    });
  }

  RED.nodes.registerType("natural-language-classifier", NLCNode, {
    username: { type: "text" },
    password: { type: "password" },
    classifierid: { type: "text" }
  });
}

3. ノードのアイコン(nodes/icons/nlc.png)

上述したnodes/nlc.htmlの(3)の中に以下のような行があります。

nodes/nlc.html
      icon: "nlc.png",

これはエディタ上に表現されるアイコンを示します。このアイコンファイルは、nodes/iconsディレクトリに配置します。

4. パッケージへの追加(package.json)

最後に、これまで作成したnodes以下のファイルをパッケージそしてNode-REDに認識させるために、package.jsonに以下のような記述を追加します。

package.json
    "keywords":[ "node-red" ],
    "node-red": {
        "nodes": {
            "natural-language-classifier": "nodes/nlc.js"
        }
    },

なお、この例では、NLCを使うためにwatson-developer-cloudパッケージを使っていますので、dependenciesにも以下の行を追加しています。

package.json
    "dependencies": {
        "when": "~3.x",
        "mongodb": "~1.4.x",
        "nano": "~5.11.0",
        "cfenv":"~1.0.0",
        "feedparser":"~0.19.2",
        "redis":"~0.10.1",
        "node-red": "0.x",
        "node-red-bluemix-nodes":"0.x",
        "node-red-node-cf-cloudant":"0.x",
        "node-red-contrib-scx-ibmiotapp":"0.x",
        "node-red-contrib-ibmpush":"0.x",
        "node-red-contrib-bluemix-hdfs":"0.x",
        "node-red-nodes-cf-sqldb-dashdb":"0.x",
        "watson-developer-cloud": "*" # これを追加した(前の行のカンマに注意)
    },

NLC追加版Node-REDを動かす

さて、それでは修正したNode-REDをcf pushします。

$ cf push weatherqclass

いつものように最後にrunningというログが出ればOKです。

     state     since                    cpu    memory           disk           details   
#0   running   2015-12-13 08:25:48 PM   0.0%   207.7M of 512M   317.6M of 1G 

ブラウザで確認します。

noderednlc-watson-with-nlc.png

無事に「Natural Language Classifier」というノードが追加されました。
早速使ってみます。Injectで文字列を投げ込み、NLCで分類した結果をdebugに吐く、というだけの例です。

noderednlc-flow.png

NLCの設定は以下のようになります。入力されている内容は、サンプル分類器のcredential情報(username, password)と分類器ID (classifier ID)です。

noderednlc-nlc-config.png

このフローを実行する(Injectノードの左側にある四隅の丸い四角のアイコンをクリックする)と、debugログに以下のようにNLCの分類結果が表示されます。

noderednlc-result.png

このフローの詳細は以下のjsonの通りです。これをインポートすればサンプルフローを再現することができます。

[{"id":"7f2f030e.ba7c14","type":"inject","z":"69f50d6e.27d11c","name":"","topic":"","payload":"Is it cloudy today?","payloadType":"string","repeat":"","crontab":"","once":true,"x":127,"y":154,"wires":[["db86397f.5a46f"]]},{"id":"22108696.9cfe6a","type":"debug","z":"69f50d6e.27d11c","name":"","active":true,"console":"false","complete":"false","x":542,"y":338,"wires":[]},{"id":"db86397f.5a46f","type":"natural-language-classifier","z":"69f50d6e.27d11c","name":"","username":"9b9e911b-538d-4d4a-8f11-5e185e69cca0","password":"qMicYuKpxs6s","classifierid":"3B015Fx14-nlc-2340","x":364,"y":252,"wires":[["22108696.9cfe6a"]]}]

まとめ

  • Node-RED StarterにはNatural Language Classifier (NLC)が含まれていませんが、自作のノードを作成することで、Node-REDエディタのフローを簡単に作ることができました。
  • 自作のノードを作成するにはある程度javascriptやhtmlの知識をもち、またcfコマンドに慣れている必要があります。
  • 実際には学習の工程が存在するため、curlやjqにも慣れておくほうがよさそうです。
25
27
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?