はじめに
以前、BluemixのWatson APIを駆使して日本語質問応答システムを作る~その2~で作った質問応答アプリを、Node-REDで作り直してみたが、Node-REDからWatson APIを呼ぶには一工夫必要なので、そこを整理してみる。
Speech to Textの組み込みはどうしたの?という意見は受け付けない。
NLCノードの使い方
NLCを呼ぶ場合は、IBM_WatsonのNLCノードを使う。
フローエディターの左側のIBM_Watsonグループ(下の方)にNLCノードがある。
ドロップしたNLCノードをダブルクリックすると設定画面が開く。
Nameはフロー上の名前、UsernameとPasswordはNLCのサービス呼び出しをする際のユーザーIDとパスワード、Classifier IDはクラス分類に使うインスタンスのIDを指定する。
ModeはClassifyとTrainingが選択できるが、ここではトレーニング済みのNLCを使うのでClassifyでいい。
NLCノードは、msg.payloadの値を入力とし、NLCの結果をmsg.payloadに出力してくれる。
NLCノードへの入力
msg.payloadへの値のセットはchangeノードを使うのがいいだろう。
HTTPリクエストのパラメーターとして質問文を渡す場合(例えば /ask?q=質問文 というケース)はmsg.payload.qに質問文が保管されているので、そこから取り出せばよい。
msg.payloadは何度か上書きすることになるので、msg.payload.qをmsg.questionなど、payload配下ではないところに最初に退避させておくと後々便利だ。
話が横道にそれたので戻すとする。
質問文がmsg.questionに保存されているならば、以下のように設定すればよい。
これでNLCノードの入力準備は完了だ。
NLCノードの出力
NLCノードの出力例は以下の通りだ。
{ "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ノードの中で以下のような命令を書くと実現できる。
msg.payload.top_confidence = msg.payload.classes[0].confidence;
return msg;
msg.payload.classesがリストであり1番目の要素にアクセスするには、msg.payload.classes[0]と記述すればよい。
ここで注意が必要なのが、changeノードやdebugノードでは配列が使えないことだ。なぜか使えない。配列にアクセスしたければfunctionノードを間に入れる必要がある。めんどい。
こうすると、以下のようにtop_confidenceが追加されるので、色々便利になる。
{ "classes": [ { "class_name": "Android",
"confidence": 0.9951245879757794 },
{ "class_name": "iPhone",
"confidence": 0.0048754120242205535 } ],
"top_class": "Android",
"top_confidence": 0.9951245879757794 }
サンプル・フロー
ということで、Node-REDでNLCを呼び出して結果を取得しようとしたら、次のようなフローを作ればよいことになる。
なお、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に質問文が入っている場合、以下のようにセットしてあげればよい。
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形式で返すようにしておこう。
R&Rの出力
出力は以下のようなJSON形式で返される。
{"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に格納する。
msg.payload = msg.payload.response.docs[0].body[0];
return msg;
最後にこれをhttpレスポンスノードに入れてあげればよい。
サンプル・フロー
ということで、サンプル・フローはこちら。httpリクエスト/レスポンス版は割愛。
ハマりやすいところは、R&R(httpリクエスト)の返りの型の指定だろう。StringにしてしまうとJSONパースノードを使ってパースしてあげないとエラーになるので注意。
TTSの呼び出し方
TTSは、Node-REDのノードはある。が、日本語に対応していない(2016年2月13日現在)。そのためR&Rと同様、functionノードで値をセットし、httpリクエストノードを使って呼び出す。
TTSの応答は音声データになるため、ブラウザー等のコードを使って再生してあげる必要がある。
TTSへの入力
msg.payload.textにしゃべらせたい文章が入っている場合、以下のようにセットする。
voiceの指定を変えれば、いろいろな音声でしゃべらせることが可能だ。使える音声に何があるかは、こちらの記事を参考に調べてみて欲しい。
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を選択しておく。
TTSの出力
結果は、そのままhttpレスポンスノードで返せばよい。
むしろ問題は再生方法だ。
音声の再生にはクライアントが必要。curlで出力した場合は結果をファイルに落としてプレイヤーで再生できるし、ブラウザーで直接URLを入力した場合は結果をプレイヤーで開いて再生ができる。テストするだけならそれでもいいが、アプリケーションに組み込むならちゃんと再生させないといけない。
ということでクライアント側のHTMLファイルにjavascriptでこんな感じのコードを書いておくと再生可能だ。
var audio = document.createElement("audio");
audio.src = "./t2s?text=" + "こんにちは";
audio.play();
サンプル・フロー
ということで、TTSのサンプル・フローはこちら。ノードを使った方が色々簡単のはず。早く日本語化が待ち望まれる。
終わりに
これらを全て組み合わせて、BluemixのWatson APIを駆使して日本語質問応答システムを作る~その2~で作った質問応答アプリを、Node-REDで作り直してみた。
が、今回かなり長くなってしまったので、次回にまわそうと思う。