# 第二章 如何綁定一個服務 學習目標 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 ```