[2019/7改訂版] Watson Discovery&Translatorを利用する最初のレシピ


**2019/07/16更新　記事の画像を大幅に充実。DiscoveryのCollection作成(GUI版）に対応。また、サンプルプログラムが動かなくなっていたため大幅にリニューアル！**

# このページについて
このページはハッカソンを迅速にお楽しみいただくために開発した開発レシピ集です。レシピのまとめページは[IBM Cloudのビギナー開発者向け「最初のレシピ」集](https://qiita.com/yutaka-maruoka/items/5e38bed6d130eb427e2c)になります。

あくまで個人の活動として掲載しているので、[IBM ソーシャル・コンピューティング・ガイドライン](https://www.ibm.com/blogs/think/jp-ja/social-computing-guideline/)に則っています。

すなわち、このサイトの掲載内容は私自身の見解であり、必ずしもIBMの立場、戦略、意見を代表するものではありません。

# はじめに
IBM CloudとはIBM社が提供するクラウドサービスです。

クラウドとは・・・と紙で理解するよりは、実際に使って理解したほうが早いです。

そのため、ここでは言語系サービスであるDiscovery&Translatorについてレシピとしてまとめます。


なお、ここの記事は、単体でも実行環境は構築できますが、Node-RED自体については、別記事を参考いただいたほうがわかりやすいかもしれません。
[Visual Recognitonを利用する最初のレシピ](https://qiita.com/yutaka-maruoka/items/a4c161dba3200b9f9ecf#%E3%81%93%E3%81%AE%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

# Watson Discovery Service環境の構築
IBM Cloud環境上にDiscovery Serviceを構築します。

## IBM Cloudにログイン
ログイン後の画面が下記です。ここで、画面上部のカタログを選びます
<img width="811" alt="スクリーンショット 2019-07-16 5.56.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/055c1816-19df-457a-2a97-bd13253d2466.png">

## Watson Discovery Serviceを構築する
「label:ライト discovery」で検索すると「Discovery」のタイルが出現するので、これをクリックします。

<img width="810" alt="スクリーンショット 2019-07-16 5.58.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/6837c45a-8bdc-cbeb-f0f1-d03d2e55b440.png">

その後、Discoveryの説明があるので、「作成」ボタンを押します。
<img width="638" alt="スクリーンショット 2019-07-16 6.02.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/5302c7b0-a3b0-4b6a-cdd7-3dc20b9df0dd.png">

＊ライトアカウントの場合は無料枠のサービスがデフォルト設定されますので、ご安心ください。
<img width="768" alt="スクリーンショット 2019-07-16 6.03.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/29a8d785-a1ca-5a06-8c53-c2008b37d7ad.png">


＊作成後、画面が切り替わり、「リソースリスト」に戻ってくると思います。そのとき、Discoveryは「プロビジョニング進行中」となっていると思いますので、しばらくおまちください。
 
**なお、「プロビジョニング進行中」となって画面が切り替わらないようであれば、ブラウザ環境の問題で、画面の表示が切り替わっていないだけかもしれないので、画面を更新するようにお願いします。いつのまにか「プロビジョニング済」となっている場合があります。**

<img width="1137" alt="スクリーンショット 2019-07-16 6.05.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/9e1a536d-d2f3-74e6-ae04-44c2148302b8.png">


## Watson Discovery Serviceを開く
Discoveryを設定して、Watson Discovery Serviceを利用するための実行環境を構築します。

ディスカバリーサービスを選択します
<img width="812" alt="スクリーンショット 2019-07-16 6.13.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/f2525651-6709-91da-ed26-f016849ecf6e.png">

「Watson Discoveryの起動」を選択します

<img width="811" alt="スクリーンショット 2019-07-16 6.14.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/efbb302e-547d-3195-7a71-afae0104a0cc.png">

Watson Discovery Serviceの画面が出たら、初期説明が不要であれば「X」を選択してください。
<img width="738" alt="スクリーンショット 2019-07-16 6.23.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/6d8b3e4f-0cda-2762-aad6-6d617714f365.png">

### ご参考：Watson Discovery Newsについて
Watson Discovery Serviceには、日本の著名な記事を解析したWatson Discovery Newsが着いてきます。

設定を「English」から「Japanese」に変更してクリックすると、IBM社が収集したニュースデータをDiscoveryで解析した情報が見れます。

<img width="807" alt="スクリーンショット 2019-07-16 6.25.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/644e96ff-b838-65e5-2d30-cd3a29ba753e.png">

<img width="1135" alt="スクリーンショット 2019-07-16 6.33.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/6fa74e55-01cb-7fb3-e034-ca2e920bb8d9.png">

クエリー画面に移動して「Watsonについて教えて」といった一般的な質問文にて、記事を検索することができます。しかも、検索結果にはキーワードやポジティブ記事なのかなどの洞察も含めて応答してくれます。ここでは付加情報は少しですが、条件を高度にすれば他の付加情報も取得できるかもしれません。
<img width="811" alt="スクリーンショット 2019-07-16 6.35.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/78492f1c-82b0-d221-d258-4de096fb000c.png">


## Watson Discovery Serviceの実行環境を構築する
実行環境は画面右上の「Create Enviroment」で構築します。
<img width="703" alt="スクリーンショット 2019-07-16 6.38.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/f23ee045-1b5e-6658-0979-9b326ce536f4.png">

注意画面が出ますが「現在のプラン（ライトプランのこと）」である「set up current plan」を選択します。
<img width="608" alt="スクリーンショット 2019-07-16 6.39.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/af7bc7f1-fb89-06d2-358c-b2cf39e9119f.png">

その後、元の画面に自動的に戻ると思います。一見何も変わっていないように見えますが、先程選んだ右上のボタンを押すと「Enviroment」が構築されていることが確認できます。

<img width="1135" alt="スクリーンショット 2019-07-16 6.40.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/8ca3adf6-61b9-bb80-3955-1514a01928ae.png">

create a new data collectionの右にある「Upload your own data」を選択します。これでWatson Collectionが構築できます。
<img width="703" alt="スクリーンショット 2019-07-16 6.42.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/bf6e7788-f246-c617-f7f5-9f75f18c9d1e.png">

Collectionの設定画面が出ると思いますが、[collection name]は好きな名前を入力してください。[select language]は日本のドキュメントを扱う時は日本語がいいでしょう
<img width="356" alt="スクリーンショット 2019-07-16 6.44.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/f5b0f069-a78b-ac09-f01e-dfa119b8d004.png">

あとはドキュメントを登録すれば、検索等に利用するだけです。
<img width="1172" alt="スクリーンショット 2019-07-16 6.46.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/fc0d3846-9137-17d8-830b-ec4ae2b20093.png">

ちなみに、次回からは初期画面から新しい名前のCollection名のタイルができていると思います。そこをクリックすれば上記と同じ、文書のアップロード画面に移動できます。
<img width="709" alt="スクリーンショット 2019-07-16 6.50.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/f03e8076-b48a-18de-b617-e472fa41891a.png">


# Documentを追加する。
Watson Discoveryサービスの管理画面にて「ツールを起動」を押す。
すると、Discoveryの管理画面が出ます。
ここで、文書（今回はJSON）を登録します。

ドキュメントの例。こういうのを3個用意してみました。
下記のようなファイルをご準備ください。

```json:document1.json
{
  "title": "本人確認書類に記載された住所と現住所が違う場合、口座開設できますか？"
}
```

画像をドラッグ＆ドロップとありますが、ダイアログでアップロードするのが無難です。
<img width="706" alt="スクリーンショット 2019-07-16 6.54.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/820ed75e-b158-7346-49ad-0e39d75f339d.png">

アップロード後、Collection名を選択した画面が下記のように変わります。文書を登録する時は、右側のボタンを押せば同じように追加登録できます。
２つめ、３つめのドキュメントを登録してみましょう。

<img width="704" alt="スクリーンショット 2019-07-16 6.56.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/e4d4e3a4-cd9a-2459-3450-8024c160daec.png">


```json:document2.json
{
  "title": "口座開設申し込みに必要な本人確認書類はなんですか？"
}
```

```json:document3.json
{
  "title": "家族も一緒に口座開設をしますが、本人確認書類は同じものなので1通でいいですか？"
}
```

ドキュメントが増えました。
<img width="1164" alt="スクリーンショット 2019-07-16 6.59.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/657b2d8e-27fd-442b-8497-0f1d3cbb01ae.png">

なお、この画面で「Configure data」を選ぶと、環境設定のキーとなるIDが取得できます。
アプリを開発するときに必要になりますので、控えておくようにしてください
（＊注意１）

<img width="705" alt="スクリーンショット 2019-07-16 7.38.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/73e0a1ec-2e67-4b9b-af7a-44496681e1f7.png">




###　検索してみる
余談ですが、実際に検索するテストを行うことができます。
Newsのときと同じように検索アイコンの画面を開き、「口座について教えて」と入力し、Enterを押すと、検索結果が出ると思います。
<img width="705" alt="スクリーンショット 2019-07-16 7.06.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/6cb55b13-7e2f-54e7-b121-5127be4806bc.png">


# Watson Translatorを使う
Discoveryのときと同様に、IBM Cloudの画面（カタログ）画面に移動します。

そして、検索キーに「Translator」を追記して出てくる、Language Translatorを追加します。
(全角の空白文字が入ると検索結果が0件になるのでご注意ください）

![スクリーンショット 2018-06-11 16.14.24.jpg](https://qiita-image-store.s3.amazonaws.com/0/3168/afef5487-cdc0-1d2f-99a2-3dc8611ee24e.jpeg)

そして、作成ボタンを押します。
<img width="1168" alt="スクリーンショット 2019-07-16 7.02.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/e4650f8a-61b8-5f7d-785a-b1d7a97cd2ac.png">


# Node-RED開発環境と関連付ける。
Discoveryのときと同様に、IBM Cloudの画面（カタログ）画面に移動します。

そして、検索キーに「node-red」を追記して出てくる、Node-RED StarterKitを追加します。
(全角の空白文字が入ると検索結果が0件になるのでご注意ください）
<img width="706" alt="スクリーンショット 2019-07-16 7.05.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/c71ed9fb-7ed1-199c-496c-a050e1acb681.png">

Node-REDスターターキットはWebアプリを提供するため、URLの名称（ドメイン）を設定する必要があります。下記のように、アルファベットで名前を好きに入力した後で、「作成」ボタンを押してください。

<img width="1169" alt="スクリーンショット 2019-07-16 7.08.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/779673ef-d095-83a3-3621-060b1491c3e4.png">

なお、このスターターキットでは、Web上で開発できるNode-REDという環境と、データベースであるCloudantDBがセットで構築できます。
<img width="731" alt="スクリーンショット 2019-07-16 7.09.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/05c3f759-3f00-26d3-3bc8-4241c308224f.png">

## Node-RED環境とWatsonの関連付け

Node-REDスターターキットを作成したら、サービスを関連付けます。

### 初見の人向け
Node-RED環境を構築すると、以下の画面に遷移します。
<img width="731" alt="スクリーンショット 2019-07-16 7.09.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/3b859b4b-c968-d5fa-96c8-e1793573ce29.png">

説明は読みたい人が読めばいいと思いますが、次に進めるために、左上のメニューを選んで、「リソースリスト」を選択します。
<img width="705" alt="スクリーンショット 2019-07-16 7.14.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/2041a25b-4bb4-3fa2-c6f6-0c4a398726ef.png">

リソースリストの画面では、今まで「カタログ」で追加した、アプリ実行環境やサービスが一覧化されています。
ここで、「Cloud Foundaryアプリ」の「Node-REDのときに入力した名前」を選択します。
（先の画面キャプチャーでは、hogehogeとしていましたが、値重複でエラーになってしまったので、ここからは心機一転、hogehoge002でキャプチャーしていきます）

<img width="707" alt="スクリーンショット 2019-07-16 7.15.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/3fa0646f-2ec3-726a-24d2-72bfb83be258.png">

Node-RED環境の画面が出てきます。
ここでは、ランタイムという実行環境に割り当てられたメモリサイズなどが見れます。
今回は、Watsonと連携させたいので、「接続」ボタンを押します。
<img width="675" alt="スクリーンショット 2019-07-16 7.18.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/737ef9f7-a58c-64ee-3813-61c8721f4771.png">

そうすると、今まで「カタログ」を使って作成してきたWatsonサービス（Discovery、Translator）が出現します。
まずはDiscoveryサービスを接続してみましょう。Discoveryサービスの行にある「接続」を選択します。

<img width="704" alt="スクリーンショット 2019-07-16 7.20.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/eb9d381c-6482-635d-171b-64054fbd8d1e.png">

接続の設定画面が出てきますが、初期設定で問題ないので、そのまま「接続」ボタンを押します。

<img width="419" alt="スクリーンショット 2019-07-16 7.22.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/d6929d0c-79f8-e837-407f-72c6d169c05d.png">

「再ステージ」の確認が出たら、「再ステージ」のボタンを選択します。
<img width="430" alt="スクリーンショット 2019-07-16 7.24.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/1b183f71-afd8-9fdb-cc76-0b7c0ca71d13.png">

その後、先ほどと同じようにまたリソースリストに移動し、Node-RED名前を選び、接続ボタンを選択し、下記の画面に戻ってきたら、Language Translatorの接続を選択しましょう。
<img width="1141" alt="スクリーンショット 2019-07-16 7.24.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/5a1c776d-ff46-d931-a21b-a1b3422c8cb3.png">

もちろん、その後の作業もDiscoveryの接続と同じです。

これで環境が整いました！

# Node-REDを使う

Node-REDは「アプリURLにアクセス」リンクから開くことができます。
<img width="1138" alt="スクリーンショット 2019-07-16 7.28.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/897dce4e-c0c4-941d-bdbf-81ae942da612.png">

## 初心者向け
###  Node-REDの初期設定
URLを開くと初期設定画面になります。

基本的に「NEXT」を押していけば問題ないです。
<img width="1137" alt="スクリーンショット 2019-07-16 7.29.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/fd4bf62f-c191-2579-acce-f29beb1ae17f.png">

2画面目はユーザーIDとパスワードを任意で設定してください。
<img width="813" alt="スクリーンショット 2019-07-16 7.31.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/5adcd4af-4df8-0386-5c20-4623532e6c12.png">

3については何も気にせず「NEXT」
<img width="808" alt="スクリーンショット 2019-07-16 7.32.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/c8a76022-da26-079a-07a7-de8f8ae90c48.png">

4については何も気にせず「FINISH」
<img width="820" alt="スクリーンショット 2019-07-16 7.32.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/8de622ea-b0a0-e9d5-f7ff-b10fe164d656.png">

Node-RED開発画面が表示されたら準備完了です。今後は「アプリのURLを開く」で開くと、この画面が出てきます。「Get to your Node-RED」を選択して、ログインしましょう。
<img width="1079" alt="スクリーンショット 2019-07-16 7.33.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/8b623e43-1993-1284-1312-c96fed3abd28.png">

ログイン画面
<img width="1155" alt="スクリーンショット 2019-07-16 7.34.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/51379381-76af-979a-f995-fec5244bf95f.png">


## プログラムをロードする

以下のプログラムをNode-REDの読み込みを行います。

```json:Node-RED.json
[{"id":"82ffd03b.6bc1f","type":"tab","label":"Discovery&Translatorサンプル","disabled":false,"info":""},{"id":"c6534a0c.9ea638","type":"comment","z":"82ffd03b.6bc1f","name":"質問応答機能","info":"","x":85.312255859375,"y":279.58636474609375,"wires":[]},{"id":"893ce6a6.305358","type":"http in","z":"82ffd03b.6bc1f","name":"","url":"/index","method":"get","upload":false,"swaggerDoc":"","x":100,"y":80,"wires":[["e3ff3da3.fc724"]]},{"id":"e3ff3da3.fc724","type":"template","z":"82ffd03b.6bc1f","name":"view program","field":"payload","fieldType":"msg","syntax":"mustache","template":"\n<!DOCTYPE html>\n<html lang=\"ja\" class=\"no-js\">\n\n<head>\n<meta charset=\"UTF-8\" />\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n\n<!-- Bootstrap CSS -->\n<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css\">\n\n<style>\n  body{\n    font-size: 28px;\n  }\n  #container {\n    position : relative;\n    width : 370px;\n    margin : 0px auto;\n  }\n\n /* Watson Discover Answer */\n #ans_p{\n   border: 1px solid #000000;\n   padding-right: 5px;\n   color: #00F;\n   text-decoration: underline;\n }\n #ans_score {\n   text-align: right;\n   color: #000;\n   font-size: 24px;\n }\n #answer_list{\n   overflow: scroll;\n   font-size: 20px;\n }\n\n</style>\n\n<!-- jQuery -->\n<script src=\"https://code.jquery.com/jquery-1.11.2.min.js\" crossorigin=\"anonymous\"></script>\n\n<!-- Bootstrap and Bootcards JS -->\n<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js\"></script>\n\n</head>\n\n<body>\n<!--  <body class=\"fadeout\" onload=\"displayLineChart();\"> -->\n<section class=\"page\">\n  <article>\n\n  \t<div class=\"container-fluid\" id=\"page-3-1\"  style=\"display: block;\">\n  \t\t<div class=\"row\">\n\n        <div class=\"col-sm-12\">\n          <div class=\"panel panel-success\">\n            <div class=\"panel-heading\">\n                FAQ候補\n                <a class=\"btn btn-primary pull-right btn-xs\" href=\"#\"　value=\"\" onclick=\"requestWatson()\" id=\"requestWatson\">\n                  <i class=\"fa fa-pencil\"  id=\"videoStart\" >入力文字<br>解析</i>\n                </a>\n                <a class=\"btn btn-danger pull-right btn-xs\" href=\"#\"　value=\"\" onclick=\"startRecognition()\" id=\"startRecognition\">\n                  <i class=\"fa fa-pencil\"  id=\"videoStart\" >顧客の声<br>音声処理</i>\n                </a>\n            </div>\n            <div class=\"panel-body\">\n              <div\n              <div class=\"col-sm-12\" style=\"height:80px;text-align:left;background-color: #FFF;\">\n                <input type=\"text\" id=\"recognizedText\" size=\"40\" value=\"\">\n                <div id=\"translator\"></div>\n              </div>\n              <div class=\"row\">\n                <div class=\"col-sm-12\" style=\"height:500px;text-align:left;background-color: #FFF;\">\n<!--                  <div id=\"answer_list\" onclick=\"sendNextPages('page-3-3')\"></div> -->\n                  <div id=\"answer_list\"></div>\n                </div>\n              </div>\n\n              <!-- 音声認識エリア（利用していない） -->\n              <div class=\"row\" style=\"display:none;\">\n                <div class=\"col-sm-12\" style=\"height:50px;text-align:left;background-color: #FFF;\">\n                  <div style=\"display:none;\">\n<!--                    連続認識<input id=\"continuous\" type=\"checkbox\" checked=\"checked\"> -->\n                    連続認識<input id=\"continuous\" type=\"checkbox\">\n                    中間結果の表示<input id=\"interim\" type=\"checkbox\" checked=\"checked\">\n                  </div>\n                  <div class=\"col-sm-12\" style=\"height:100px;text-align:left;background-color: #FFF; \">\n                    <p>Debug詳細情報</p>\n                    <div id=\"recognizedDetail\"></div>\n                  </div>\n                </div>\n              </div>\n\n            </div>\n\n            <div class=\"panel-footer\">\n              <div id=\"state\">ステータス：停止中</div>\n            </div>\n          </div>\n        </div>\n\n  \t\t</div>\n  \t</div>\n\n<script>\n    var recognition = new webkitSpeechRecognition();\n    recognition.lang = \"ja-JP\";\n    recognition.maxAlternatives = 2;\n    //認識停止\n    function stopRecognition(){\n        $(\"#state\").text(\"ステータス：停止\");\n        recognition.stop();\n    }\n    //認識開始+設定の変更\n    function startRecognition(){\n        //連続認識\n        if($(\"#continuous\").prop(\"checked\") == true) recognition.continuous = true;\n        else recognition.continuous = false;\n        //中間結果の表示\n        if($(\"#interim\").prop(\"checked\") == true) recognition.interimResults = true;\n        else recognition.interimResults = false;\n\n        $(\"#state\").text(\"ステータス：発話待ち\");\n        recognition.start();\n    }\n    //話し声の認識中\n    recognition.onsoundstart = function(){\n        $(\"#state\").text(\"ステータス：認識中\");\n    };\n    //マッチする認識が無い\n    recognition.onnomatch = function(){\n        // $(\"#state\").text(\"ステータス：認識できない言葉が検出されました\");\n        console.log(\"recognition.onnomatch発生\");\n\n        //連続認識の場合は再度実行する\n        //0.01秒後に停止\n        setTimeout(\"stopRecognition()\",10);\n        if($(\"#continuous\").prop(\"checked\") == true){\n          //0.01秒後に再接続\n          setTimeout(\"startRecognition()\",300);\n        }\n    };\n    //エラー\n    recognition.onerror= function(){\n        // $(\"#state\").text(\"ステータス：認識に失敗しました\");\n        console.log(\"recognition.onerror発生\");\n\n        //連続認識の場合は再度実行する\n        //0.01秒後に停止\n        setTimeout(\"stopRecognition()\",10);\n        if($(\"#continuous\").prop(\"checked\") == true){\n          //0.01秒後に再接続\n          setTimeout(\"startRecognition()\",300);\n        }\n    };\n    //話し声の認識終了\n    recognition.onsoundend = function(){\n        $(\"#state\").text(\"ステータス：認識終了\");\n\n        //連続認識の場合は再度実行する\n        //0.01秒後に停止\n        setTimeout(\"stopRecognition()\",10);\n        if($(\"#continuous\").prop(\"checked\") == true){\n          //0.01秒後に再接続\n          setTimeout(\"startRecognition()\",300);\n        }\n    };\n    //認識が終了したときのイベント\n    recognition.onresult = function(event){\n        var results = event.results;\n        for (var i = event.resultIndex; i<results.length; i++){\n            //認識の最終結果\n            if(results[i].isFinal){\n              $(\"#state\").text(\"ステータス：認識終了時、結果\");\n              $(\"#recognizedText\").val(results[i][0].transcript);\n\n              //WebSocket通知＆翻訳サービスへ送信する\n              //sendMessage();\n              requestWatson();\n\n              //0.01秒後に停止\n              setTimeout(\"stopRecognition()\",10);\n            }\n            //認識の中間結果\n            else{\n              $(\"#state\").text(\"ステータス：認識中、中間結果\");\n              $(\"#recognizedText\").val(results[i][0].transcript);\n              //console.log(results[i][0].transcript);\n            }\n        }\n        //トップ10の認識仮説の表示\n        $(\"#recognizedDetail\").empty();\n        for (var i = event.resultIndex; i<results.length; i++){\n            if(results[i].isFinal){\n                for (var j = 0; j<Math.min(recognition.maxAlternatives,results[i].length); j++){\n                    $(\"#recognizedDetail\").append(\"<p>\" + \"ランク\" + j + \" \" + results[i][j].transcript +\n                                                    \": \" + results[i][j].confidence +\n                                                 \"</p>\");\n                }\n            }\n        }\n    };\n</script>\n\n\n<script>\nfunction requestWatson() {\n  translatorWatson();\n  askWatson();\n}\n</script>\n<script type=\"text/javascript\">\n    // Node-REDのWeb API連携\n    var translatorWatson = function() {\n      // Watson連携\n      $.ajax({\n          type: \"GET\",\n          url: \"./lt2\",\n          dataType: \"text\",\n          timeout: 10000,\n          data: {\n              //質問文を取得してパラメータとして渡す\n              text: $(\"#recognizedText\").val()\n          }\n      })\n      .done(function(data, textStatus, jqXHR) {\n          // 通信成功\n          var message;\n          if ( data.length < 70 ){\n            message = document.createTextNode(data);\n          }else{\n            message = document.createTextNode(data.substr(0, 70) + \"...\");\n          }\n          var messageBox = document.createElement('p');\n          messageBox.className = 'system';\n          messageBox.appendChild(message);\n\n          var translator = document.getElementById('translator');\n          // 子ノードを全削除\n          if (translator.hasChildNodes()){\n        \t\tfor (var i=translator.childNodes.length-1; i>=0; i--) {\n        \t\t\ttranslator.removeChild(translator.childNodes[i]);\n        \t\t}\n        \t}\n          translator.appendChild(messageBox);\n      })\n      .fail(function(jqXHR, textStatus, errorThrown) {\n          // 通信エラー\n          //$(\"#answer\").val(\"通信エラー  \" + jqXHR.status + \" : \" + jqXHR.statusText);\n          return;\n      })\n      .always(function(data) {\n          // Debug\n          console.log(data);\n      });\n    }\n</script>\n\n<script type=\"text/javascript\">\n    // Node-REDのWeb API連携\n    var askWatson = function() {\n      var const_disp_num = 5;\n      var msgP,msgPBox;\n      var msgDocId,msgDocIdBox;\n      var msgPText,msgPTextBox;\n      var score,msgScore,msgScoreBox;\n      var br;\n\n      // Watson連携\n      $.ajax({\n          type: \"GET\",\n          url: \"./ask\",\n          dataType: \"text\",\n          timeout: 10000,\n          data: {\n              //質問文を取得してパラメータとして渡す\n              q: $(\"#recognizedText\").val()\n          }\n      })\n      .done(function(data, textStatus, jqXHR) {\n          // 通信成功\n          //　応答データをリスト化して表示\n          // リスト要素を取得\n          var anserList = document.getElementById('answer_list');\n          // 子ノードを全削除\n          if (anserList.hasChildNodes()){\n        \t\tfor (var i=anserList.childNodes.length-1; i>=0; i--) {\n        \t\t\tanserList.removeChild(anserList.childNodes[i]);\n        \t\t}\n        \t}\n\n          // Discovery 検索0件対応\n          if (data=='404'){\n            msgPBox = document.createElement('div');\n            msgPBox.className = 'row';\n            msgPBox.id = 'ans_p';\n\n            msgPText = document.createTextNode('該当候補がありませんでした。');\n            msgPBox.appendChild(msgPText);\n            // 表示領域に子要素として追加する\n            anserList.appendChild(msgPBox);\n            return;\n          }\n\n          var objAnswer = JSON.parse(data);\n          console.log('objAnswer');\n          console.log(objAnswer);\n\n          objAnswer.results.forEach(function(match_doc) {\n            msgPBox = document.createElement('div');\n            msgPBox.className = 'row';\n            msgPBox.id = 'ans_p';\n\n            // add passage_text\n            msgPTextBox = document.createElement('div');\n            msgPTextBox.className = 'col-sm-8';\n            msgPTextBox.id = 'ans_text';\n\n            // Passage Text\n            msgPText = document.createTextNode(match_doc.title);\n            msgPTextBox.appendChild(msgPText);\n\n            msgPBox.appendChild(msgPTextBox);\n\n            // add score\n            msgScoreBox = document.createElement('div');\n            msgScoreBox.className = 'col-sm-4';\n            msgScoreBox.id = 'ans_score';\n\n            score = Math.floor(match_doc.result_metadata.score * 100) / 100;\n            msgScore = document.createTextNode(score+\"%\");\n            msgScoreBox.appendChild(msgScore);\n            msgPBox.appendChild(msgScoreBox);\n\n            // 表示領域に子要素として追加する\n            anserList.appendChild(msgPBox);\n          });\n\n      })\n      .fail(function(jqXHR, textStatus, errorThrown) {\n          //　応答データをリスト化して表示\n          // リスト要素を取得\n          var anserList = document.getElementById('answer_list');\n          // 子ノードを全削除\n          if (anserList.hasChildNodes()){\n        \t\tfor (var i=anserList.childNodes.length-1; i>=0; i--) {\n        \t\t\tanserList.removeChild(anserList.childNodes[i]);\n        \t\t}\n        \t}\n\n          msgPBox = document.createElement('div');\n          msgPBox.className = 'row';\n          msgPBox.id = 'ans_p';\n\n          msgPText = document.createTextNode(\"通信エラー  \" + jqXHR.status + \" : \" + jqXHR.statusText);\n          msgPBox.appendChild(msgPText);\n          // 表示領域に子要素として追加する\n          anserList.appendChild(msgPBox);\n          return;\n      })\n      .always(function(data) {\n          // console.log(data);\n      });\n    }\n</script>\n\n  </article>\n</section>\n\n</body>\n</html>\n","x":280,"y":80,"wires":[["462eede.3d9e114"]]},{"id":"462eede.3d9e114","type":"http response","z":"82ffd03b.6bc1f","name":"","x":450,"y":80,"wires":[]},{"id":"5cc66977.5acd18","type":"comment","z":"82ffd03b.6bc1f","name":"画面プログラム","info":"","x":100,"y":20,"wires":[]},{"id":"485fd422.ae9fbc","type":"http in","z":"82ffd03b.6bc1f","name":"","url":"/lt2","method":"get","upload":false,"swaggerDoc":"","x":100,"y":180,"wires":[["e3c834b1.f40be8"]]},{"id":"e7bef9e6.66ded8","type":"watson-translator","z":"82ffd03b.6bc1f","name":"lt engine","action":"translate","basemodel":"es-en","domain":"news","srclang":"ja","destlang":"en","password":"maRuto9905","custom":"","domainhidden":"news","srclanghidden":"ja","destlanghidden":"en","basemodelhidden":"","customhidden":"","filetype":"forcedglossary","trainid":"","lgparams2":true,"neural":false,"default-endpoint":true,"service-endpoint":"https://gateway.watsonplatform.net/language-translator/api","x":380,"y":180,"wires":[["538016bd.28db48","a0165932.4ae288"]]},{"id":"a0165932.4ae288","type":"http response","z":"82ffd03b.6bc1f","name":"TL","statusCode":"","headers":{},"x":550,"y":180,"wires":[]},{"id":"e3c834b1.f40be8","type":"change","z":"82ffd03b.6bc1f","name":"change","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.text","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":180,"wires":[["e7bef9e6.66ded8"]]},{"id":"ee76095b.621408","type":"comment","z":"82ffd03b.6bc1f","name":"日本語ー英語翻訳機能","info":"","x":120,"y":140,"wires":[]},{"id":"538016bd.28db48","type":"debug","z":"82ffd03b.6bc1f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":450,"y":240,"wires":[]},{"id":"271d68c.7e38198","type":"template","z":"82ffd03b.6bc1f","name":"bk_view program","field":"payload","fieldType":"msg","syntax":"mustache","template":"\n<!DOCTYPE html>\n<html lang=\"ja\" class=\"no-js\">\n\n<head>\n<meta charset=\"UTF-8\" />\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n\n<!-- Bootstrap CSS -->\n<link rel=\"stylesheet\" href=\"https://sm0002contents.mybluemix.net/css/lib/bootstrap.min.css\">\n<!-- Bootcards CSS for desktop: -->\n<link rel=\"stylesheet\" href=\"https://sm0002contents.mybluemix.net/css/lib/bootcards-desktop.min.css\">\n\n<!-- Custom CSS -->\n<link rel=\"stylesheet\" href=\"https://sm0002contents.mybluemix.net/css/counseling_list.css\">\n<link rel='stylesheet' href=\"https://sm0002contents.mybluemix.net/css/transition.css\" type='text/css' media='all' />\n\n\n\n<!--  <link href=\"https://fonts.googleapis.com/css?family=Work+Sans:200\" rel=\"stylesheet\"> -->\n<style>\n  body{\n    font-size: 28px;\n  }\n  #container {\n    position : relative;\n    width : 370px;\n    margin : 0px auto;\n  }\n\n /* Watson Discover Answer */\n #ans_p{\n   border: 1px solid #000000;\n   padding-right: 5px;\n   color: #00F;\n   text-decoration: underline;\n }\n #ans_score {\n   text-align: right;\n   color: #000;\n   font-size: 24px;\n }\n #answer_list{\n   overflow: scroll;\n   font-size: 20px;\n }\n\n</style>\n\n<!-- jQuery -->\n<script src=\"https://code.jquery.com/jquery-1.11.2.min.js\" crossorigin=\"anonymous\"></script>\n\n<!-- Bootstrap and Bootcards JS -->\n<script src=\"https://sm0002contents.mybluemix.net/js/lib/bootstrap.min.js\"></script>\n<script src=\"https://sm0002contents.mybluemix.net/js/lib/bootcards.min.js\"></script>\n\n</head>\n\n<body>\n<!--  <body class=\"fadeout\" onload=\"displayLineChart();\"> -->\n<section class=\"page\">\n  <article>\n\n  \t<div class=\"container-fluid\" id=\"page-3-1\"  style=\"display: block;\">\n  \t\t<div class=\"row\">\n\n        <div class=\"col-sm-12\">\n          <div class=\"panel panel-success\">\n            <div class=\"panel-heading\">\n                FAQ候補\n                <a class=\"btn btn-primary pull-right btn-xs\" href=\"#\"　value=\"\" onclick=\"requestWatson()\" id=\"requestWatson\">\n                  <i class=\"fa fa-pencil\"  id=\"videoStart\" >入力文字<br>解析</i>\n                </a>\n                <a class=\"btn btn-danger pull-right btn-xs\" href=\"#\"　value=\"\" onclick=\"startRecognition()\" id=\"startRecognition\">\n                  <i class=\"fa fa-pencil\"  id=\"videoStart\" >顧客の声<br>音声処理</i>\n                </a>\n            </div>\n            <div class=\"panel-body\">\n              <div\n              <div class=\"col-sm-12\" style=\"height:80px;text-align:left;background-color: #FFF;\">\n                <input type=\"text\" id=\"recognizedText\" size=\"40\" value=\"\">\n                <div id=\"translator\"></div>\n              </div>\n              <div class=\"row\">\n                <div class=\"col-sm-12\" style=\"height:500px;text-align:left;background-color: #FFF;\">\n<!--                  <div id=\"answer_list\" onclick=\"sendNextPages('page-3-3')\"></div> -->\n                  <div id=\"answer_list\"></div>\n                </div>\n              </div>\n\n              <!-- 音声認識エリア（利用していない） -->\n              <div class=\"row\" style=\"display:none;\">\n                <div class=\"col-sm-12\" style=\"height:50px;text-align:left;background-color: #FFF;\">\n                  <div style=\"display:none;\">\n<!--                    連続認識<input id=\"continuous\" type=\"checkbox\" checked=\"checked\"> -->\n                    連続認識<input id=\"continuous\" type=\"checkbox\">\n                    中間結果の表示<input id=\"interim\" type=\"checkbox\" checked=\"checked\">\n                  </div>\n                  <div class=\"col-sm-12\" style=\"height:100px;text-align:left;background-color: #FFF; \">\n                    <p>Debug詳細情報</p>\n                    <div id=\"recognizedDetail\"></div>\n                  </div>\n                </div>\n              </div>\n\n            </div>\n\n            <div class=\"panel-footer\">\n              <div id=\"state\">ステータス：停止中</div>\n            </div>\n          </div>\n        </div>\n\n  \t\t</div>\n  \t</div>\n\n<script>\n    var recognition = new webkitSpeechRecognition();\n    recognition.lang = \"ja-JP\";\n    recognition.maxAlternatives = 2;\n    //認識停止\n    function stopRecognition(){\n        $(\"#state\").text(\"ステータス：停止\");\n        recognition.stop();\n    }\n    //認識開始+設定の変更\n    function startRecognition(){\n        //連続認識\n        if($(\"#continuous\").prop(\"checked\") == true) recognition.continuous = true;\n        else recognition.continuous = false;\n        //中間結果の表示\n        if($(\"#interim\").prop(\"checked\") == true) recognition.interimResults = true;\n        else recognition.interimResults = false;\n\n        $(\"#state\").text(\"ステータス：発話待ち\");\n        recognition.start();\n    }\n    //話し声の認識中\n    recognition.onsoundstart = function(){\n        $(\"#state\").text(\"ステータス：認識中\");\n    };\n    //マッチする認識が無い\n    recognition.onnomatch = function(){\n        // $(\"#state\").text(\"ステータス：認識できない言葉が検出されました\");\n        console.log(\"recognition.onnomatch発生\");\n\n        //連続認識の場合は再度実行する\n        //0.01秒後に停止\n        setTimeout(\"stopRecognition()\",10);\n        if($(\"#continuous\").prop(\"checked\") == true){\n          //0.01秒後に再接続\n          setTimeout(\"startRecognition()\",300);\n        }\n    };\n    //エラー\n    recognition.onerror= function(){\n        // $(\"#state\").text(\"ステータス：認識に失敗しました\");\n        console.log(\"recognition.onerror発生\");\n\n        //連続認識の場合は再度実行する\n        //0.01秒後に停止\n        setTimeout(\"stopRecognition()\",10);\n        if($(\"#continuous\").prop(\"checked\") == true){\n          //0.01秒後に再接続\n          setTimeout(\"startRecognition()\",300);\n        }\n    };\n    //話し声の認識終了\n    recognition.onsoundend = function(){\n        $(\"#state\").text(\"ステータス：認識終了\");\n\n        //連続認識の場合は再度実行する\n        //0.01秒後に停止\n        setTimeout(\"stopRecognition()\",10);\n        if($(\"#continuous\").prop(\"checked\") == true){\n          //0.01秒後に再接続\n          setTimeout(\"startRecognition()\",300);\n        }\n    };\n    //認識が終了したときのイベント\n    recognition.onresult = function(event){\n        var results = event.results;\n        for (var i = event.resultIndex; i<results.length; i++){\n            //認識の最終結果\n            if(results[i].isFinal){\n              $(\"#state\").text(\"ステータス：認識終了時、結果\");\n              $(\"#recognizedText\").val(results[i][0].transcript);\n\n              //WebSocket通知＆翻訳サービスへ送信する\n              //sendMessage();\n              requestWatson();\n\n              //0.01秒後に停止\n              setTimeout(\"stopRecognition()\",10);\n            }\n            //認識の中間結果\n            else{\n              $(\"#state\").text(\"ステータス：認識中、中間結果\");\n              $(\"#recognizedText\").val(results[i][0].transcript);\n              //console.log(results[i][0].transcript);\n            }\n        }\n        //トップ10の認識仮説の表示\n        $(\"#recognizedDetail\").empty();\n        for (var i = event.resultIndex; i<results.length; i++){\n            if(results[i].isFinal){\n                for (var j = 0; j<Math.min(recognition.maxAlternatives,results[i].length); j++){\n                    $(\"#recognizedDetail\").append(\"<p>\" + \"ランク\" + j + \" \" + results[i][j].transcript +\n                                                    \": \" + results[i][j].confidence +\n                                                 \"</p>\");\n                }\n            }\n        }\n    };\n</script>\n\n\n<script>\nfunction requestWatson() {\n  translatorWatson();\n  askWatson();\n}\n</script>\n<script type=\"text/javascript\">\n    // Node-REDのWeb API連携\n    var translatorWatson = function() {\n      // Watson連携\n      $.ajax({\n          type: \"GET\",\n          url: \"./lt2\",\n          dataType: \"text\",\n          timeout: 10000,\n          data: {\n              //質問文を取得してパラメータとして渡す\n              text: $(\"#recognizedText\").val()\n          }\n      })\n      .done(function(data, textStatus, jqXHR) {\n          // 通信成功\n          var message;\n          if ( data.length < 70 ){\n            message = document.createTextNode(data);\n          }else{\n            message = document.createTextNode(data.substr(0, 70) + \"...\");\n          }\n          var messageBox = document.createElement('p');\n          messageBox.className = 'system';\n          messageBox.appendChild(message);\n\n          var translator = document.getElementById('translator');\n          // 子ノードを全削除\n          if (translator.hasChildNodes()){\n        \t\tfor (var i=translator.childNodes.length-1; i>=0; i--) {\n        \t\t\ttranslator.removeChild(translator.childNodes[i]);\n        \t\t}\n        \t}\n          translator.appendChild(messageBox);\n      })\n      .fail(function(jqXHR, textStatus, errorThrown) {\n          // 通信エラー\n          //$(\"#answer\").val(\"通信エラー  \" + jqXHR.status + \" : \" + jqXHR.statusText);\n          return;\n      })\n      .always(function(data) {\n          // Debug\n          console.log(data);\n      });\n    }\n</script>\n\n<script type=\"text/javascript\">\n    // Node-REDのWeb API連携\n    var askWatson = function() {\n      var const_disp_num = 5;\n      var msgP,msgPBox;\n      var msgDocId,msgDocIdBox;\n      var msgPText,msgPTextBox;\n      var score,msgScore,msgScoreBox;\n      var br;\n\n      // Watson連携\n      $.ajax({\n          type: \"GET\",\n          url: \"./ask\",\n          dataType: \"text\",\n          timeout: 10000,\n          data: {\n              //質問文を取得してパラメータとして渡す\n              q: $(\"#recognizedText\").val()\n          }\n      })\n      .done(function(data, textStatus, jqXHR) {\n          // 通信成功\n          // フローから返ってきた結果をanswerに入れる\n          // $(\"#answer\").val(data);\n\n          //　応答データをリスト化して表示\n          // リスト要素を取得\n          var anserList = document.getElementById('answer_list');\n\n          // 子ノードを全削除\n          if (anserList.hasChildNodes()){\n        \t\tfor (var i=anserList.childNodes.length-1; i>=0; i--) {\n        \t\t\tanserList.removeChild(anserList.childNodes[i]);\n        \t\t}\n        \t}\n\n          // Discovery 検索0件対応\n          if (data=='404'){\n            msgPBox = document.createElement('div');\n            msgPBox.className = 'row';\n            msgPBox.id = 'ans_p';\n\n            msgPText = document.createTextNode('該当候補がありませんでした。');\n            msgPBox.appendChild(msgPText);\n            // 表示領域に子要素として追加する\n            anserList.appendChild(msgPBox);\n            return;\n          }\n\n          var objAnswer = JSON.parse(data);\n          console.log(objAnswer);\n\n          // tree表示\n          /*\n          $('#tree1').jstree({ 'core' : {\n            'data' :data,\n            autoOpen: true\n            ,\n            openedIcon:'-',\n            closedIcon:'+',\n            autoEscape:false,\n            selectable:false,\n            dragAndDrop:true\n          });\n          */\n\n          // for (var i=0; i<Math.min(const_disp_num, objAnswer.matching_results); i++) {\n          objAnswer.results.forEach(function(match_doc) {\n            msgPBox = document.createElement('div');\n            msgPBox.className = 'row';\n            msgPBox.id = 'ans_p';\n\n            // add passage_text\n            msgPTextBox = document.createElement('div');\n            msgPTextBox.className = 'col-sm-8';\n            msgPTextBox.id = 'ans_text';\n\n            /*\n            // Doc Id\n            msgDocId = document.createTextNode(objAnswer.passages[i].document_id);\n            msgPTextBox.appendChild(msgDocId);\n\n            br = document.createElement('br');\n            msgPTextBox.appendChild(br);\n            */\n\n            // Passage Text\n            msgPText = document.createTextNode(\"[\" + match_doc.category + \"] \" + match_doc.title);\n            msgPTextBox.appendChild(msgPText);\n\n            msgPBox.appendChild(msgPTextBox);\n\n            // add score\n            msgScoreBox = document.createElement('div');\n            msgScoreBox.className = 'col-sm-4';\n            msgScoreBox.id = 'ans_score';\n\n            score = Math.floor(match_doc.result_metadata.score * 100) / 100;\n            msgScore = document.createTextNode(score+\"%\");\n            msgScoreBox.appendChild(msgScore);\n            msgPBox.appendChild(msgScoreBox);\n\n            // 表示領域に子要素として追加する\n            anserList.appendChild(msgPBox);\n          });\n\n      })\n      .fail(function(jqXHR, textStatus, errorThrown) {\n          // 通信エラー\n          //$(\"#answer\").val(\"通信エラー  \" + jqXHR.status + \" : \" + jqXHR.statusText);\n\n          //　応答データをリスト化して表示\n          // リスト要素を取得\n          var anserList = document.getElementById('answer_list');\n          // 子ノードを全削除\n          if (anserList.hasChildNodes()){\n        \t\tfor (var i=anserList.childNodes.length-1; i>=0; i--) {\n        \t\t\tanserList.removeChild(anserList.childNodes[i]);\n        \t\t}\n        \t}\n\n\n          msgPBox = document.createElement('div');\n          msgPBox.className = 'row';\n          msgPBox.id = 'ans_p';\n\n          msgPText = document.createTextNode(\"通信エラー  \" + jqXHR.status + \" : \" + jqXHR.statusText);\n          msgPBox.appendChild(msgPText);\n          // 表示領域に子要素として追加する\n          anserList.appendChild(msgPBox);\n          return;\n      })\n      .always(function(data) {\n          // Debug\n          // console.log(data);\n      });\n    }\n/*\n    // 質問文入力済み判定\n    var checkLengthQ = function() {\n        if ($(\"#recognizedText\").val().length > 0) {\n            // ボタン有効\n            $(\".btn\").removeClass(\"disabled\").removeClass(\"btn-default\").addClass(\"btn-primary\");\n        } else {\n            // ボタン無効\n            $(\".btn\").addClass(\"disabled\").addClass(\"btn-default\").removeClass(\"btn-primary\");\n        }\n    }\n    */\n</script>\n\n\n\n  </article>\n</section>\n\n</body>\n</html>\n","x":350,"y":120,"wires":[[]]},{"id":"60d3b9bb.7870e8","type":"watson-discovery-v1","z":"82ffd03b.6bc1f","name":"Discovery","environmentname":"","environment_id":"","collection_id":"","configurationname":"","configuration_id":"","collection_name":"","count":"","passages":false,"nlp_query":false,"query":"","filter":"","aggregation":"","return":"","description":"","size":"","discovery-method":"query","default-endpoint":true,"service-endpoint":"","x":200,"y":380,"wires":[["8d5d7c4e.c5046","81f8b248.dab24"]]},{"id":"45b8e692.f4a4d8","type":"change","z":"82ffd03b.6bc1f","name":"質問文の取り出し","rules":[{"t":"set","p":"discoveryparams.query","pt":"msg","to":"payload.q","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":320,"wires":[["60d3b9bb.7870e8","7619eb65.3da124"]]},{"id":"8d5d7c4e.c5046","type":"debug","z":"82ffd03b.6bc1f","name":"Debug","active":true,"tosidebar":true,"console":false,"complete":"search_results","x":510,"y":400,"wires":[]},{"id":"81f8b248.dab24","type":"function","z":"82ffd03b.6bc1f","name":"回答取り出し","func":"if (msg.search_results.results.length > 0 ) {\n    msg.payload = msg.search_results;\n} else {\n    msg.payload = \"404\";\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":280,"y":420,"wires":[["bb33fae7.9bb7f8"]]},{"id":"7619eb65.3da124","type":"debug","z":"82ffd03b.6bc1f","name":"Debug","active":false,"console":"false","complete":"payload","x":490,"y":320,"wires":[]},{"id":"15f417ea.a3b448","type":"http in","z":"82ffd03b.6bc1f","name":"","url":"/ask","method":"get","upload":false,"swaggerDoc":"","x":88.312255859375,"y":323.58636474609375,"wires":[["45b8e692.f4a4d8"]]},{"id":"bb33fae7.9bb7f8","type":"json","z":"82ffd03b.6bc1f","name":"","property":"payload","action":"str","pretty":false,"x":410,"y":460,"wires":[["a84b52f8.30823"]]},{"id":"a84b52f8.30823","type":"http response","z":"82ffd03b.6bc1f","name":"","x":510,"y":500,"wires":[]}]
```

次にNodeが読み込めたら、Discoveryをダブルクリック。

![スクリーンショット 2018-06-11 16.20.49.jpg](https://qiita-image-store.s3.amazonaws.com/0/3168/5b9b258b-933b-fe1e-c808-95565b0779fd.jpeg)

Discoveryの環境を変更する。
ここの設定は　**（＊注意１）** にあった設定値になります。

enviroment_idとcollection_idは作成したときの戻りで得た値をコピーする。
![スクリーンショット 2018-06-11 16.21.35.png](https://qiita-image-store.s3.amazonaws.com/0/3168/849ddfdd-ee3f-4ad2-593c-fc2b7ddc39cc.png)

「デプロイボタンを押す」

# アプリの稼働確認

アプリを起動して、テキストボックスに文字を入れたら、「入力文字解析」のボタンを押します。

そうすると、１秒前後ぐらいで翻訳された英語と、Discoveryで検索された情報が出てきます。
<img width="1105" alt="スクリーンショット 2019-07-16 9.24.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3168/fca259de-393d-8333-a84e-7b182f8f1cb2.png">


＊おまけ
「顧客の声　音声処理」を選ぶと、Chrome限定だけど、Web Speech APIに基づいた音声認識（Chromeに実装された音声認識）が楽しめます。


# リファレンス情報
今後いろいろ拡張するので、リンクまとめページのレシピ集もご参考ください。
- [IBM Cloudのビギナー開発者向け「最初のレシピ」集](https://qiita.com/yutaka-maruoka/items/5e38bed6d130eb427e2c)

それでは。


# 特別付録：Watson DiscoveryのCollectionのコマンドライン作成編
日本語版は最初の下ごしらえとして、コマンドで実行する必要があるので、以下を実行します。

## Discoveryを追加する
Discoveryを使います。まずは、Discoveryから、カタログから選び、購入します。
費用がかからない、ライトアカウントから使うことが出来ます。
![スクリーンショット 2018-06-11 15.53.54.jpg](https://qiita-image-store.s3.amazonaws.com/0/3168/0a550964-e96d-9151-939e-3ebe13a7a16a.jpeg)

サービスを選ぶと、資格情報が見れます。
ここは後々のコマンドで使うので覚えておくこと！

↓これら。
![スクリーンショット 2018-06-11 15.51.34.png](https://qiita-image-store.s3.amazonaws.com/0/3168/60d51a4b-7d4e-63c1-e43b-414d0140394c.png)

今後はこのような伏せ字でコマンド説明をします。

```json:command.json
{
  "url": "https://gateway.watsonplatform.net/discovery/api",
  "username": "[user]",
  "password": "[pass]"
}
```

Discoveryに覚え込ませるドキュメントの日本語用の格納庫（Collection）はコマンドでしか作れないので、コマンドを使います。
コマンドは、CURLというソフトを用いたコマンドを実行します。

**2019/7/13追記：いつのまにか、コマンド無しで環境構築できるようになりました。いつかこのチュートリアルもコマンド無し版に変更予定です**

ソフトは個人の判断でインストールいただければと思います。macOSなら初期から入っているかもしれません。

## DiscoveryのCollectionを作る(旧認証方式）

* コマンドを使う時に必要な認証情報は仕様がかわりつつあります。
* user / passが資格情報から取得できず、IAM方式になっていたら、後述のIAM認証方式を参照してください。

IBMCloudにサービスを登録して、少し待てば以下のコマンドでenviroment_idが得られます。

### 環境を構築する

```json:command.json
curl -u "[user]":"[pass]" "https://gateway.watsonplatform.net/discovery/api/v1/environments?version=2017-11-07"
```

```json:command.json
{
  "environments" : [ {
    "environment_id" : "system",
    "name" : "Watson System Environment",
    "description" : "Shared system data sources",
    "read_only" : true
  }, {
    "environment_id" : "[env-id]",
    "name" : "byod",
    "description" : "",
    "created" : "2018-06-11T06:41:32.582Z",
    "updated" : "2018-06-11T06:41:32.582Z",
    "read_only" : false
  } ]
}
```
このenv_idは後で使います。

### 環境の設定を作る
environment_idを指定して日本語にカスタムしたconfiguration_idを作成します。

```json:command.json
curl -u "[user]":"[pass]" "https://gateway.watsonplatform.net/discovery/api/v1/environments/[env_id]/configurations?version=2017-11-07"
```

応答はこんな感じです。

```json:command.json
{
  "configurations": [
    {
      "configuration_id": "[config_id]",
      "name": "Default Configuration",
      "description": "The configuration used by default when creating a new collection without specifying a configuration_id.",
      "created": "2018-06-11T06:41:32.618Z",
      "updated": "2018-06-11T06:41:32.618Z"
    },
    {
      "configuration_id": "[collection_id]",
      "name": "Default Contract Configuration",
      "description": "Extract party, nature, and category from elements in PDFs.",
      "created": "2018-06-11T06:41:35.169Z",
      "updated": "2018-06-11T06:41:35.169Z"
    }
  ]
}
```
###　コレクション（文書の保管場所）を作る
日本語にカスタムしconfiguration_idを指定して日本語のcollectionを作成します。

```json:command.json
curl -X POST -u "[user]":"[pass]" -H "Content-Type: application/json" -d '{ "name": "ja-collection",  "description": "japanese collection",  "configuration_id": "[collection_id]", "language": "ja"}' "https://gateway.watsonplatform.net/discovery/api/v1/environments/[env_id]/collections?version=2017-11-07"
```

応答はこちら。

```json:command.json
{
  "name" : "ja-collection",
  "collection_id" : "[collection_id]",
  "description" : "japanese collection",
  "created" : "2018-06-11T06:48:49.084Z",
  "updated" : "2018-06-11T06:48:49.084Z",
  "configuration_id" : "392511be-07df-415a-8041-686a4df0285f",
  "language" : "ja",
  "status" : "active"
}
```

これで、Collectionが作成されます。
最初のコマンドで取得した[env_id]と今回のコマンドで取得した[collection_id]は後で使います。


## DiscoveryのCollectionを作る(IAM認証方式）
IAM認証方式だと資格情報は以下のような情報になっていると思います。

```json:command.json
{
  "apikey": [api_key],
  "iam_apikey_description": "hoge",
  "iam_apikey_name": "hoge",
  "iam_role_crn": "hoge",
  "iam_serviceid_crn": "hoge",
  "url": [api_url]
}
```
ユーザーパスワードの情報がなくなっていますね。
これは、パスワードをトークンという情報でAPI呼び出しの認証を行う方式に変わった影響です。

APIを呼び出す時は少し面倒になりますが、パスワードが固定化されないので、よりセキュアになったと前向きに考えたほうが良いと思います。

コマンドの仕様はコチラを参照ください。
[Authenticating with IAM tokens](https://console.bluemix.net/docs/services/watson/getting-started-iam.html#iam)


### 認証を行い、トークンを取得する。
まずはトークンを取得し、APIを呼び出せるようにします。

```json:command.json
認証取得
curl -k -X POST --header "Authorization: Basic Yng6Yng="  --header "Content-Type: application/x-www-form-urlencoded"   --header "Accept: application/json"  --data-urlencode "grant_type=urn:ibm:params:oauth:grant-type:apikey"   --data-urlencode "apikey=[api_key]"   "https://iam.bluemix.net/identity/token"
```

はい、api_key以外は固定値です。
実行が成功すると、以下のような結果が帰ってきます。

```json:result.json
{
"access_token":[token]",
"refresh_token":[refresh_token]",
"token_type":"Bearer",
"expires_in":3600,
"expiration":1530419009,
"scope":"ibm openid"
}
```
基本的には[token]のみを利用します。

### 環境を構築する
以下のコマンドで環境を構築します。

```json:command.json
{
curl -X POST --header "Authorization: Bearer [token]" 
-H "Content-Type: application/json" -d '{ "name":"my-first-environment", "description":"exploring environments"}' 
"[api_url]/v1/environments?version=2017-11-07"
```

実行が成功すると以下のとおりです。

```json:result.json
{
  "environment_id" : "[enviroment_id]",
  "name" : "my-first-environment",
  "description" : "exploring environments",
  "created" : "2018-07-01T03:24:47.805Z",
  "updated" : "2018-07-01T03:24:47.805Z",
  "status" : "active",
  "read_only" : false,
  "index_capacity" : {
    "documents" : {
      "available" : 0,
      "maximum_allowed" : 2000
    },
    "disk_usage" : {
      "used_bytes" : 0,
      "maximum_allowed_bytes" : 200000000
    },
    "collections" : {
      "available" : 0,
      "maximum_allowed" : 0
    }
  }
}
```

### 環境の設定を行う
以下のコマンドを使って、環境設定を行います。

```json:command.json
curl -X GET --header "Authorization: Bearer [token]"  "[api_url]/v1/environments/[enviroment_id]/configurations?version=2017-11-07"
```

結果はこのようになります。

```json:result.json
{
  "configurations": [
    {
      "configuration_id": "[configuration_id]",
      "name": "Default Configuration",
      "description": "The configuration used by default when creating a new collection without specifying a configuration_id.",
      "created": "2018-07-01T03:24:47.900Z",
      "updated": "2018-07-01T03:24:47.900Z"
    }
  ]
}
```

### コレクション（文書を保管する箇所）を構築する

以下のコマンドを用いてコレクションを作成します。

```json:command.json
curl -X POST --header "Authorization: Bearer [token]" 
-H "Content-Type: application/json" -d '{ "name": "ja-collection-sj",  "description": "japanese collection for SJ",  "configuration_id": "[configuration_id]", "language": "ja"}'  
"[api_url]/v1/environments/[enviroment_id]/collections?version=2017-11-07"
```

結果はこのようになります。

```json:result.json
{
  "name" : "ja-collection-sj",
  "collection_id" : "[collection_id]",
  "description" : "japanese collection for SJ",
  "created" : "2018-07-01T03:39:18.034Z",
  "updated" : "2018-07-01T03:39:18.034Z",
  "configuration_id" : "[configuration_id]",
  "language" : "ja",
  "status" : "active"
}
```

この[collection_id]はNode-REDでも利用するのでメモしておいてください。