# 第二章 如何綁定一個服務
學習目標
1. 建立 Watson "Natural Language Understanding" 服務
2. 整合 Watson "Natural Language Understanding" 服務
## 1. 建立 Watson "Natural Language Understanding" 服務
step 1: Login IBM Cloud https://cloud.ibm.com/login
step 2: 點選 "型錄" , 然後在左邊的選單中, 點選 "服務" 後,再勾選 "AI/機器學習", 就可以看到 watson cognitive 相關的服務.
step 3: 點選 "Natural Language Understanding" 服務. "選取地區" 用預設值 "達拉斯", 將服務名稱取名為 "Natural Language Understanding-ntust" 後,點選右邊的 "建立" 按鈕.
step 4: 點選左邊選單中的 "連線", 然後再點選右上方 "建立連線", 即可看到目前可選用的 Cloud Foundry 應用程式, 點選欲連接的應用程式, 並點選 "下一個" 按鍵, 保留預設值, 按 "建立" 按鍵, 並確認 "重新編譯打包" 按鈕.
step 5: 在狀態變為 "已啟動" 的時候, 可以從應用程式的 url 去驗證.
## 2. 整合 Watson "Natural Language Understanding" 服務
API 參考資料
https://cloud.ibm.com/apidocs/natural-language-understanding?code=node
接下來, 在整合Watson "Natural Language Understanding" 服務到應用程式時, 參考上述 IBM Watson API 資料.
step 1: 在開發環境安裝 ibm-watson 函式庫.
```
PS D:\cloud109\ntust-find-author> npm install --save ibm-watson
```
step 2: 創建 “services” 資料夾, 並建立 “articleServices.js” 檔案
step 3: articleServices 模組會處理跟 "文章" 有關的邏輯. 首先, 必須先初始化 Natural
Language Understanding 服務, 並從 IBM Cloud 上面取得 {apikey} 及 {url}.
```javascript=
const NaturalLanguageUnderstandingV1 = require('ibm-watson/natural-language-understanding/v1');
const { IamAuthenticator } = require('ibm-watson/auth');
const natural_language_understanding = new NaturalLanguageUnderstandingV1({
version: '2020-08-01',
authenticator: new IamAuthenticator({
apikey: '{apikey}',
}),
serviceUrl: '{url}',
});
```
step 4: 接下來 extractArticleAuthorNames() 函數來調用 Natural
Language Understanding 服務來取出網頁文章的作者.
```javascript=
/*
* Call Watson NLU Service to extract the list of author names for the requested article URL
*/
exports.extractArticleAuthorNames = function(req){
};
```
step 5: 準備調用 Natural Language Understanding 服務時, 需要傳入的參數
```javascript=
// url is the parameter passed in the POST request to /author
// It contains the URL of the article
// The metadata feature returns the author, title, and publication date.
var parameters = {
'url': req.body.url,
'features': {
'metadata': {}
}
};
```
step 6: 調用 Natural Language Understanding 服務時, 會回傳包含作者姓名的 callback function. 因此,
a. 需要增加 callback 參數到 exports.extractArticleAuthorNames 函數
```javascript=
exports.extractArticleAuthorNames = function(req, callback){
}
```
b. 接著調用 natural_language_understanding 服務模組裡的 analyze 函式. 如果請求成功, 會回傳文章的 metadata 物件. 由於我們的應用程式是找出文章的作者, 因此, 我們直接取出作者的陣列回傳. 將下列程式片段放到傳入參數, parameters 初始化之後.
```javascript=
// Call the Watson service and return the list of authors
natural_language_understanding.analyze(parameters, function(err, response) {
if (err)
callback(err,null);
else
callback(null, response.result.metadata.authors);
});
```
step 7: 為了讓函式的調用更流暢, 需要檢查傳入的參數是否存在. 如果請求的內容是空的, 需要回傳 err 給使用者.
a. 在 natural_language_understanding 服務初始化之後, 將錯誤訊息的內容以 constant 變數型態宣告.
```javascript=
//error message for missing URL
const MISSING_URL_ERROR = 'URL not passed';
```
b. 檢查 URL 是否為 null. 在進入函式 extractAuthorNames 之後,
(line exports.extractArticleAuthorNames = function(req, callback){}), 加入下列程式片段檢查請求內容是否為空的, 如果URL沒有值, 回傳錯誤信息.
```javascript=
//If the url is not passed, return error to the caller
if(req===null||req.body===null||req.body.url===null){
callback(MISSING_URL_ERROR,null);
return;
}
```
最後完整的 articleServices.js” 檔案, 如下:
請記得修改 {apikey} 及 {url}
```javascript=
const NaturalLanguageUnderstandingV1 = require('ibm-watson/natural-language-understanding/v1');
const { IamAuthenticator } = require('ibm-watson/auth');
const natural_language_understanding = new NaturalLanguageUnderstandingV1({
version: '2020-08-01',
authenticator: new IamAuthenticator({
apikey: '{apikey}',
}),
serviceUrl: '{url}',
});
//error message for missing URL
const MISSING_URL_ERROR = 'URL not passed';
/*
* Call Watson NLU Service to extract the list of author names for the requested article URL
*/
exports.extractArticleAuthorNames = function(req, callback){
//If the url is not passed, return error to the caller
if(req===null||req.body===null||req.body.url===null){
callback(MISSING_URL_ERROR,null);
return;
}
// url is the parameter passed in the POST request to /author
// It contains the URL of the article
// The metadata feature returns the author, title, and publication date.
var parameters = {
'url': req.body.url,
'features': {
'metadata': {}
}
};
// Call the Watson service and return the list of authors
natural_language_understanding.analyze(parameters, function(err, response) {
if (err)
callback(err,null);
else
callback(null, response.result.metadata.authors);
});
};
```
step 8 編輯 author route 調用 authorServices.extractArticleAuthorNames 函式.
a. 打開 route 目錄並點選 author.js 檔案.
b. 在 router 參數初始化之後, 新增使用authorServices 模組
```javascript=
var articleServices = require('../services/articleServices');
```
c. 修改 author.js 路由調用 articleServices 模組裡的
extractArticleAuthorNames 函式. 並取代掉現有的 line res.send('You called the server
requesting the author of the article: ' + req.body.url);
```javascript=
articleServices.extractArticleAuthorNames(req, function(err, response) {
if (err)
res.status(500).send('error: ' + err);
else
res.send(response);
});
```
最後完整的 author.js” 檔案, 如下:
```javascript=
// author.js - Author route module
var express = require('express');
var router = express.Router();
var articleServices = require('../services/articleServices');
router.post('/', function (req, res) {
articleServices.extractArticleAuthorNames(req, function(err, response) {
if (err)
res.status(500).send('error: ' + err);
else
res.send(response);
});
});
module.exports = router;
```
step 9: 先在本地端做測試.
```
PS D:\cloud109\ntust-find-author> npm start
```
step 10: 如果成功在本地端測試, 就可以修改雲端app的描述檔, manifest.yml, 並將應用程式部署到 IBM Cloud.
```yaml=
applications:
- path: .
name: coke1015cloud
environment_json: {}
memory: 64M
instances: 1
disk_quota: 1024M
services:
- Natural Language Understanding-ntust
```