LoginSignup
39
43

More than 5 years have passed since last update.

Bluemix Node-REDを使ってWatson APIを呼び出す

Last updated at Posted at 2016-02-13

はじめに

以前、BluemixのWatson APIを駆使して日本語質問応答システムを作る~その2~で作った質問応答アプリを、Node-REDで作り直してみたが、Node-REDからWatson APIを呼ぶには一工夫必要なので、そこを整理してみる。
Speech to Textの組み込みはどうしたの?という意見は受け付けない。

NLCノードの使い方

NLCを呼ぶ場合は、IBM_WatsonのNLCノードを使う。
フローエディターの左側のIBM_Watsonグループ(下の方)にNLCノードがある。
NLCnode_00.png

これをドラッグ&ドロップする。
NLCnode_01.png

ドロップしたNLCノードをダブルクリックすると設定画面が開く。
NLCnode_02.png
Nameはフロー上の名前、UsernameとPasswordはNLCのサービス呼び出しをする際のユーザーIDとパスワード、Classifier IDはクラス分類に使うインスタンスのIDを指定する。
ModeはClassifyとTrainingが選択できるが、ここではトレーニング済みのNLCを使うのでClassifyでいい。

NLCノードは、msg.payloadの値を入力とし、NLCの結果をmsg.payloadに出力してくれる。

NLCノードへの入力

msg.payloadへの値のセットはchangeノード2016-02-10 18_00_33-Node-RED _ satohdai-nodered.mybluemix.net.pngを使うのがいいだろう。
HTTPリクエストのパラメーターとして質問文を渡す場合(例えば /ask?q=質問文 というケース)はmsg.payload.qに質問文が保管されているので、そこから取り出せばよい。
msg.payloadは何度か上書きすることになるので、msg.payload.qをmsg.questionなど、payload配下ではないところに最初に退避させておくと後々便利だ。

話が横道にそれたので戻すとする。
質問文がmsg.questionに保存されているならば、以下のように設定すればよい。
2016-02-10 18_01_32-Node-RED _ satohdai-nodered.mybluemix.net.png

これでNLCノードの入力準備は完了だ。

NLCノードの出力

NLCノードの出力例は以下の通りだ。

msg.payload
{ "classes": [ { "class_name": "Android", 
                 "confidence": 0.9951245879757794 }, 
               { "class_name": "iPhone", 
                 "confidence": 0.0048754120242205535 } ], 
  "top_class": "Android" }

応答は、クラス名とConfidence(確信度)のリストを返す"classes"と、一番確信度が高いクラスを返す"top_class"がある。見てわかるように、top_classはあるがtop_confidenceが無い。なんでだろう。使い勝手をあげるには、top_confidenceを作るのもいい。functionノードの中で以下のような命令を書くと実現できる。

functionノード
msg.payload.top_confidence = msg.payload.classes[0].confidence;
return msg;

msg.payload.classesがリストであり1番目の要素にアクセスするには、msg.payload.classes[0]と記述すればよい。
ここで注意が必要なのが、changeノードやdebugノードでは配列が使えないことだ。なぜか使えない。配列にアクセスしたければfunctionノードを間に入れる必要がある。めんどい。

こうすると、以下のようにtop_confidenceが追加されるので、色々便利になる。

msg.payload
{ "classes": [ { "class_name": "Android", 
                 "confidence": 0.9951245879757794 }, 
               { "class_name": "iPhone", 
                 "confidence": 0.0048754120242205535 } ], 
  "top_class": "Android",
  "top_confidence": 0.9951245879757794 }

サンプル・フロー

ということで、Node-REDでNLCを呼び出して結果を取得しようとしたら、次のようなフローを作ればよいことになる。
NLCnode_03.png

HTTPリクエストの場合は以下のようなフローを作ればよい。
NLCnode_04.png

なお、msgの中にHTTP req,resが格納されているので、msg本体を引き継がないといけないのにも注意。

R&Rの呼び出し方

R&RはまだNode-REDのノードが無い(2016年2月13日現在)。そのため、functionノードで値をセットし、httpリクエストノードを使って呼び出してあげないといけない。

R&Rへの入力

functionノードを使い、msg.urlにWebサービスのURLをセットする。
msg.questionに質問文が入っている場合、以下のようにセットしてあげればよい。

functionノード
var param = "ranker=<<ランカーID>>&wt=json&fl=id,title,body&q=" + msg.question;
msg.url = encodeURI("https://gateway.watsonplatform.net/retrieve-and-rank/api/v1/solr_clusters/<<クラスターID>>/solr/<<コレクション名>>/fcselect" + "?" + param);
return msg;

ランカーID、クラスターID、コレクション名は各自の環境に合わせて欲しい。
質問文が日本語(全角)の場合、URIエンコードを行わないと正しく送信できない。そのため、msg.urlはencodeURI関数を使ってエンコードを行う。

R&Rの呼び出し

呼び出しはhttpリクエストノードを使用する。
ベーシック認証の使用にチェックを入れて、ユーザーID、パスワードの入力欄を出し、R&Rの呼び出し時に使用するユーザーIDとパスワードを入力する。
また、Returnはデフォルトで「UTF-8 String」が選択されているが、出力結果を処理するためにJSONパースが必要になってしまうので、最初からJSON形式で返すようにしておこう。
node-red_httprequest_01.png

R&Rの出力

出力は以下のようなJSON形式で返される。

R&Rの出力
{"responseHeader":{"status":0,
                   "QTime":6},
 "response":{"numFound":11,
             "start":0,
             "maxScore":1.3636142,
             "docs": [ { "id": "40", 
                         "body": [ "Android 4.4.4以降でVoLTEに対応しています。" ] }, 
                       { "id": "39",
                         "body": [ "メールアプリケーションのバージョンが4.1.1以上か確認してください。バージョンが古い場合は、メールアプリケーションの更新をお願いいたします。" ] }, 
                       { "id": "28", 
                         "body": [ "機種変更後の機種が「アニメ放題」対応機種であれば、引き続きご利用いただけます。機種変更後の機種で、再度アプリケーションをインストールしてください。ダウンロードしたコンテンツは引き継がれません。" ] }, ・・・・

docsの中身がランクの高い順に並んでいるので、docs配列の一番最初の要素を取り出せばいい。取り出しにはfunctionノードを使う。httpレスポンスとして返したい情報は、msg.payloadに格納する。

functionノード
msg.payload = msg.payload.response.docs[0].body[0];
return msg;

最後にこれをhttpレスポンスノードに入れてあげればよい。

サンプル・フロー

ということで、サンプル・フローはこちら。httpリクエスト/レスポンス版は割愛。
ハマりやすいところは、R&R(httpリクエスト)の返りの型の指定だろう。StringにしてしまうとJSONパースノードを使ってパースしてあげないとエラーになるので注意。
node-red_r&r_flow1.png

TTSの呼び出し方

TTSは、Node-REDのノードはある。が、日本語に対応していない(2016年2月13日現在)。そのためR&Rと同様、functionノードで値をセットし、httpリクエストノードを使って呼び出す。
TTSの応答は音声データになるため、ブラウザー等のコードを使って再生してあげる必要がある。

TTSへの入力

msg.payload.textにしゃべらせたい文章が入っている場合、以下のようにセットする。
voiceの指定を変えれば、いろいろな音声でしゃべらせることが可能だ。使える音声に何があるかは、こちらの記事を参考に調べてみて欲しい。

functionノード
var param = "voice=ja-JP_EmiVoice&accept=audio/wav&text=" + msg.payload.text;
msg.url = encodeURI("https://stream.watsonplatform.net/text-to-speech/api/v1/synthesize" + "?" + param);
return msg;

TTSの呼び出し

呼び出しはhttpリクエストノードを使用する。
ベーシック認証の使用にチェックを入れて、ユーザーID、パスワードの入力欄を出し、TTSの呼び出し時に使用するユーザーIDとパスワードを入力する。
また、Returnはデフォルトで「UTF-8 String」が選択されているが、音声データなのでa binary bufferを選択しておく。
node-red_tts_request.png

TTSの出力

結果は、そのままhttpレスポンスノードで返せばよい。
むしろ問題は再生方法だ。
音声の再生にはクライアントが必要。curlで出力した場合は結果をファイルに落としてプレイヤーで再生できるし、ブラウザーで直接URLを入力した場合は結果をプレイヤーで開いて再生ができる。テストするだけならそれでもいいが、アプリケーションに組み込むならちゃんと再生させないといけない。
ということでクライアント側のHTMLファイルにjavascriptでこんな感じのコードを書いておくと再生可能だ。

クライアント側
var audio = document.createElement("audio");
audio.src = "./t2s?text=" + "こんにちは"; 
audio.play();

サンプル・フロー

ということで、TTSのサンプル・フローはこちら。ノードを使った方が色々簡単のはず。早く日本語化が待ち望まれる。
node-red_tts_flow.png

終わりに

これらを全て組み合わせて、BluemixのWatson APIを駆使して日本語質問応答システムを作る~その2~で作った質問応答アプリを、Node-REDで作り直してみた。
が、今回かなり長くなってしまったので、次回にまわそうと思う。

39
43
0

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
39
43