diff --git a/README.md b/README.md index e00e8026..68f17100 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,18 @@ Node-RED Watson Nodes for IBM Cloud CLA assistant +### New in version 0.8.2 +- Node-RED & IBM-Watson & Use of promises on API invocation & IAM URL construct migration & Removal of default endpoint of + - Document Translator node + - Discovery node + - Discovery Document Loader node + - Discovery Query Builder node + - Assistant V1 Workspace Manager node +- List Expansion list, and List Training data modes added to Discovery node +- Fix to Create Classifier mode in NLC node + ### New in version 0.8.1 -- Node-RED & IBM-Watson & Use of promises on API invokation & IAM URL construct migration & Removal of default endpoint of +- Node-RED & IBM-Watson & Use of promises on API invocation & IAM URL construct migration & Removal of default endpoint of - Speech to Text node - Speech to Text Corpus Builder node - Natural Language Understanding node @@ -33,7 +43,7 @@ During the migration there will be a dependancy on both modules. - Bump dependancy on node to >=10.0.0 - Bump dependancy on cfenv, request, file-type - Bump dependancy on ibm-cloud-sdk-core to 0.3.7 (need to stay on 0.x, for STT Streaming to work) -- Node-RED & IBM-Watson & Use of promises on API invokation & IAM URL construct migration & Removal of default endpoint of +- Node-RED & IBM-Watson & Use of promises on API invocation & IAM URL construct migration & Removal of default endpoint of - Tone Analyzer node. - Personality Insights node. - Visual Recognition V3 node @@ -46,7 +56,7 @@ During the migration there will be a dependancy on both modules. - Update language lists for STT, TTS, Language Translator and Document Translator Nodes ### Watson Nodes for Node-RED -A collection of nodes to interact with the IBM Watson services in [IBM Cloud](http://bluemix.net). +A collection of nodes to interact with the IBM Watson services in [IBM Cloud](http://cloud.ibm.com). # Nodes diff --git a/package.json b/package.json index 2798e354..bcfab526 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red-node-watson", - "version": "0.8.1", + "version": "0.8.2", "description": "A collection of Node-RED nodes for IBM Watson services", "dependencies": { "async": "^1.5.2", @@ -24,7 +24,7 @@ "license": "Apache-2.0", "keywords": [ "node-red", - "bluemix", + "ibm-cloud", "watson" ], "contributors": [ diff --git a/services/assistant/v1-workspace-manager.html b/services/assistant/v1-workspace-manager.html index 369fd05c..60d56705 100644 --- a/services/assistant/v1-workspace-manager.html +++ b/services/assistant/v1-workspace-manager.html @@ -44,17 +44,12 @@
- - - -
-
- + - -
-
- - + +
- - + +
@@ -69,8 +64,8 @@

If a filename is not provided then one is automatically generated

The collection being written to can be overridden by specifying the search ids in - msg.discoveryparams.environment_id - , msg.discoveryparams.collection_id + msg.discoveryparams.environmentId + , msg.discoveryparams.collectionId and msg.discoveryparams.filename

The document to be added should be passed in as a data buffer @@ -91,14 +86,6 @@ var disdocV1 = new DiscoveryDocLoaderV1(); disdocV1.UIListeners = function () { - $('input#node-input-default-endpoint').change(function () { - var checked = $('input#node-input-default-endpoint').prop('checked') - if (checked) { - $('#node-input-service-endpoint').parent().hide(); - } else { - $('#node-input-service-endpoint').parent().show(); - } - }); } disdocV1.checkForPrepare = function () { @@ -124,11 +111,10 @@ category: 'IBM Watson', defaults: { name: {value: ''}, - environment_id: {value: ''}, - collection_id: {value: ''}, + environmentId: {value: ''}, + collectionId: {value: ''}, filename: {value: ''}, - 'default-endpoint' :{value: true}, - 'service-endpoint' :{value: 'https://gateway.watsonplatform.net/discovery/api'} + 'service-endpoint' :{value: ''} }, credentials: { username: {type:'text'}, diff --git a/services/discovery/v1-document-loader.js b/services/discovery/v1-document-loader.js index aa8fed5b..2182bdb1 100644 --- a/services/discovery/v1-document-loader.js +++ b/services/discovery/v1-document-loader.js @@ -69,14 +69,18 @@ module.exports = function (RED) { function determineSuffix(msg) { // Let's assume that if we can't determine the suffix that // its a word doc. - var ext = '.json', - ft = fileType(msg.payload); + let ext = '.json'; + if (! discoveryutils.isJsonObject(msg.payload)) { + let ext = '.json', + ft = fileType(msg.payload); - if (ft && ft.ext) { - ext = '.' + ft.ext; - } - if (isDocx(msg.payload)) { - ext = '.docx'; + if (ft && ft.ext) { + ext = '.' + ft.ext; + } + + if (isDocx(msg.payload)) { + ext = '.docx'; + } } return Promise.resolve(ext); @@ -131,20 +135,22 @@ module.exports = function (RED) { // modify as getting addJsonDocument will be deprecated messages if ('.json' === suffix) { //method = 'addJsonDocument'; - params.file = JSON.stringify(params.file); + //params.file = JSON.stringify(params.file); + + params.file = Buffer.from(JSON.stringify(params.file)); //} else { //method = 'addDocument'; } method = 'addDocument'; - discovery[method](params, function (err, response) { - if (err) { - reject(err); - } else { - msg.document = response.document ? response.document : response; + discovery[method](params) + .then((response) => { + msg.document = response.result ? response.result : response; resolve(); - } - }); + }) + .catch((err) => { + reject(err); + }); }); return p; @@ -166,7 +172,7 @@ module.exports = function (RED) { var node = this; RED.nodes.createNode(this, config); - this.on('input', function (msg) { + this.on('input', function(msg, send, done) { var message = '', fileInfo = '', fileSuffix = '', @@ -177,7 +183,7 @@ module.exports = function (RED) { apikey = sApikey || this.credentials.apikey; endpoint = sEndpoint; - if ((!config['default-endpoint']) && config['service-endpoint']) { + if (config['service-endpoint']) { endpoint = config['service-endpoint']; } @@ -223,12 +229,13 @@ module.exports = function (RED) { .then(function(){ temp.cleanup(); node.status({}); - node.send(msg); + send(msg); + done(); }) .catch(function(err){ temp.cleanup(); - payloadutils.reportError(node,msg,err); - node.send(msg); + let errMsg = payloadutils.reportError(node, msg, err); + done(errMsg); }); }); } diff --git a/services/discovery/v1-query-builder.html b/services/discovery/v1-query-builder.html index 84d8c4f5..902c5225 100644 --- a/services/discovery/v1-query-builder.html +++ b/services/discovery/v1-query-builder.html @@ -54,11 +54,6 @@

- - - -
-
@@ -275,15 +270,6 @@ } }); - $('input#node-input-default-endpoint').change(function () { - var checked = $('input#node-input-default-endpoint').prop('checked') - if (checked) { - $('#node-input-service-endpoint').parent().hide(); - } else { - $('#node-input-service-endpoint').parent().show(); - } - }); - } // The dialog is about to be shown. @@ -458,10 +444,8 @@ var k = $('#node-input-apikey').val(); var creds = {un: u, pwd: p, key: k}; - var eChecked = $('input#node-input-default-endpoint').prop('checked') - if (!eChecked) { - creds.endpoint = $('#node-input-service-endpoint').val(); - } + + creds.endpoint = $('#node-input-service-endpoint').val(); $.getJSON('watson-discovery-v1-query-builder/environments', creds ).done(function (data) { @@ -496,10 +480,9 @@ var k = $('#node-input-apikey').val(); var creds = {un: u, pwd: p, key: k}; - var eChecked = $('input#node-input-default-endpoint').prop('checked') - if (!eChecked) { - creds.endpoint = $('#node-input-service-endpoint').val(); - } + + creds.endpoint = $('#node-input-service-endpoint').val(); + creds.environment_id = disQB.environment_selected; $.getJSON('watson-discovery-v1-query-builder/collections', creds @@ -533,10 +516,9 @@ var k = $('#node-input-apikey').val(); var creds = {un: u, pwd: p, key: k}; - var eChecked = $('input#node-input-default-endpoint').prop('checked') - if (!eChecked) { - creds.endpoint = $('#node-input-service-endpoint').val(); - } + + creds.endpoint = $('#node-input-service-endpoint').val(); + creds.environment_id = disQB.environment_selected; creds.collection_id = disQB.collection_selected; @@ -731,8 +713,7 @@ queryvalue3hidden: {value: ''}, passages: {value: false}, passageshidden: {value: false}, - 'default-endpoint' :{value: true}, - 'service-endpoint' :{value: 'https://gateway.watsonplatform.net/discovery/api'} + 'service-endpoint' :{value: ''} }, credentials: { diff --git a/services/discovery/v1-query-builder.js b/services/discovery/v1-query-builder.js index e23431ca..ec4933ff 100644 --- a/services/discovery/v1-query-builder.js +++ b/services/discovery/v1-query-builder.js @@ -37,6 +37,20 @@ module.exports = function(RED) { res.json(serviceutils.checkServiceBound(SERVICE_IDENTIFIER)); }); + function processResponse(response, field) { + let reply = response; + if (response) { + if (response.result) { + if (response.result[field]) { + reply = response.result[field]; + } else { + reply = response.result; + } + } + } + return reply; + } + // API used by widget to fetch available environments RED.httpAdmin.get('/watson-discovery-v1-query-builder/environments', function(req, res) { @@ -45,13 +59,13 @@ module.exports = function(RED) { sApikey ? sApikey : req.query.key, req.query.endpoint ? req.query.endpoint : sEndpoint); - discovery.listEnvironments({}, function(err, response) { - if (err) { + discovery.listEnvironments({}) + .then((response) => { + res.json(processResponse(response,'environments')); + }) + .catch((err) => { res.json(err); - } else { - res.json(response.environments ? response.environments : response); - } - }); + }); }); // API used by widget to fetch available collections in environment @@ -61,17 +75,13 @@ module.exports = function(RED) { sApikey ? sApikey : req.query.key, req.query.endpoint ? req.query.endpoint : sEndpoint); - discovery.listCollections({ - environment_id: req.query.environment_id - }, - function(err, response) { - if (err) { - res.json(err); - } else { - res.json(response.collections ? response.collections : response); - } - } - ); + discovery.listCollections({environmentId: req.query.environment_id}) + .then((response) => { + res.json(processResponse(response,'collections')); + }) + .catch((err) => { + res.json(err); + }); }); @@ -83,18 +93,17 @@ module.exports = function(RED) { req.query.endpoint ? req.query.endpoint : sEndpoint); discovery.listCollectionFields({ - environment_id: req.query.environment_id, - collection_id: req.query.collection_id - }, - function(err, response) { - if (err) { - res.json(err); - } else { - var fieldList = discoveryutils.buildFieldList(response); - res.json(fieldList); - } - } - ); + environmentId: req.query.environment_id, + collectionId: req.query.collection_id + }) + .then((response) => { + let fieldList = discoveryutils.buildFieldList(response); + res.json(fieldList); + }) + .catch((err) => { + res.json(err); + }); + }); function Node(config) { diff --git a/services/discovery/v1.html b/services/discovery/v1.html index de6ad1c0..d26e6fa2 100644 --- a/services/discovery/v1.html +++ b/services/discovery/v1.html @@ -38,11 +38,6 @@
- - - -
-
@@ -66,6 +61,10 @@ + + + + @@ -74,24 +73,24 @@
- - + +
- - + +
- - + +
@@ -208,7 +207,7 @@

For this method the node needs an Environment ID as input.

The environment being requested can be overridden by specifying the search id - in msg.discoveryparams.environment_id + in msg.discoveryparams.environmentId

Node output :

- - - -
-
@@ -335,15 +330,6 @@ doctor.checkActionSelected(); }); - $('#node-input-default-endpoint').change(() => { - var checked = $('#node-input-default-endpoint').prop('checked') - if (checked) { - $('#node-input-service-endpoint').parent().hide(); - } else { - $('#node-input-service-endpoint').parent().show(); - } - }); - $('#node-input-srclang').change(function () { doctor.srclang_selected = $('#node-input-srclang').val(); if (doctor.models) { @@ -400,9 +386,7 @@ var e = $('#node-input-service-endpoint').val(); var creds = {un: u, pwd: p, key: k}; - if (! $('#node-input-default-endpoint').prop('checked')) { - creds.e = e; - } + creds.e = e; $.getJSON('watson-doc-translator/models/', creds) .done(function (data) { @@ -541,8 +525,7 @@ destlanghidden: {value: ''}, filename: {value: ''}, 'document-id': {value: ''}, - 'default-endpoint' :{value: true}, - 'service-endpoint' :{value: 'https://gateway.watsonplatform.net/language-translator/api'} + 'service-endpoint' :{value: ''} }, credentials: { username: {type: 'text'} diff --git a/services/language_translator/v3-doc.js b/services/language_translator/v3-doc.js index 4679a525..20aa2ed3 100644 --- a/services/language_translator/v3-doc.js +++ b/services/language_translator/v3-doc.js @@ -17,10 +17,11 @@ module.exports = function (RED) { const request = require('request'), SERVICE_IDENTIFIER = 'language-translator', - SERVICE_VERSION = '2018-05-01'; + SERVICE_VERSION = '2018-05-01', + LanguageTranslatorV3 = require('ibm-watson/language-translator/v3'), + { IamAuthenticator } = require('ibm-watson/auth'); var pkg = require('../../package.json'), - LanguageTranslatorV3 = require('watson-developer-cloud/language-translator/v3'), fs = require('fs'), fileType = require('file-type'), temp = require('temp'), @@ -54,6 +55,7 @@ module.exports = function (RED) { RED.httpAdmin.get('/watson-doc-translator/models', function (req, res) { endpoint = req.query.e ? req.query.e : sEndpoint; var lt = null, + authSettings = {}, serviceSettings = { version: SERVICE_VERSION, url: endpoint, @@ -63,24 +65,28 @@ module.exports = function (RED) { }; if (sApikey || req.query.key) { - serviceSettings.iam_apikey = sApikey ? sApikey : req.query.key; + authSettings.apikey = sApikey ? sApikey : req.query.key; } else { - serviceSettings.username = sUsername ? sUsername : req.query.un; - serviceSettings.password = sPassword ? sPassword : req.query.pwd; + authSettings.username = sUsername ? sUsername : req.query.un; + authSettings.password = sPassword ? sPassword : req.query.pwd; } + serviceSettings.authenticator = new IamAuthenticator(authSettings); lt = new LanguageTranslatorV3(serviceSettings); - lt.listModels({}, function (err, models) { - if (err) { - res.json(err); - } else { + lt.listModels({}) + .then((response) => { + let models = []; + if (response && response.result && response.result.models) { + models = response.result; + } res.json(models); - } - }); + }) + .catch((err) => { + res.json(err); + }); }); - function Node (config) { var node = this; RED.nodes.createNode(this, config); @@ -144,6 +150,30 @@ module.exports = function (RED) { return Promise.resolve(); } + function getService() { + let authSettings = {}, + serviceSettings = { + version: '2018-05-01', + headers: { + 'User-Agent': pkg.name + '-' + pkg.version + } + }; + + if (apikey) { + authSettings.apikey = apikey; + } else { + authSettings.username = username; + authSettings.password = password; + } + serviceSettings.authenticator = new IamAuthenticator(authSettings); + + if (endpoint) { + serviceSettings.url = endpoint; + } + + return new LanguageTranslatorV3(serviceSettings); + } + function buildAuthSettings () { var authSettings = {}; @@ -186,7 +216,6 @@ module.exports = function (RED) { reject('Document not found ' + response.statusCode); break; default: - console.log(body); reject('Error Invoking API ' + response.statusCode); break; } @@ -324,10 +353,25 @@ module.exports = function (RED) { } function executeGetDocument(msg) { - var docid = docID(msg); - let uriAddress = `${endpoint}/v3/documents/${docid}/translated_document?version=${SERVICE_VERSION}`; - - return executeGetRequest(uriAddress); + return new Promise(function resolver(resolve, reject){ + let lt = getService(), + docid = docID(msg); + + lt.getTranslatedDocument({documentId : docid}) + .then((response) => { + msg.payload = response; + if (response && response.result) { + msg.payload = response.result; + } + return payloadutils.checkForStream(msg); + }) + .then(() => { + resolve(msg.payload); + }) + .catch((err) => { + reject(err); + }); + }); } function executeDeleteDocument(msg) { @@ -416,7 +460,7 @@ module.exports = function (RED) { return Promise.resolve(); } - function doit(msg) { + function doit(msg, send) { let action = msg.action || config.action; translatorutils.credentialCheck(username, password, apikey) @@ -440,16 +484,16 @@ module.exports = function (RED) { .then(function(){ temp.cleanup(); node.status({}); - node.send(msg); + send(msg); }) .catch(function(err){ temp.cleanup(); payloadutils.reportError(node, msg, err); - node.send(msg); + send(msg); }); } - this.on('input', function (msg) { + this.on('input', function(msg, send, done) { // The dynamic nature of this node has caused problems with the password field. it is // hidden but not a credential. If it is treated as a credential, it gets lost when there // is a request to refresh the model list. @@ -459,7 +503,7 @@ module.exports = function (RED) { apikey = sApikey || this.credentials.apikey || config.apikey; endpoint = sEndpoint; - if ((!config['default-endpoint']) && config['service-endpoint']) { + if (config['service-endpoint']) { endpoint = config['service-endpoint']; } @@ -476,12 +520,13 @@ module.exports = function (RED) { pos = i+1; node.status({ fill: 'blue', shape: 'dot', text: `Processing document ${pos} of ${len}` }); msgClone.payload = e; - doit(msgClone); + doit(msgClone, send); }); } else { - doit(msg); + doit(msg, send); } + done(); }); } diff --git a/services/natural_language_classifier/v1.js b/services/natural_language_classifier/v1.js index 495df2d7..4af2155c 100644 --- a/services/natural_language_classifier/v1.js +++ b/services/natural_language_classifier/v1.js @@ -192,7 +192,8 @@ module.exports = function(RED) { language : config.language }; - params.trainingMetadata = JSON.stringify(meta); + params.trainingMetadata = Buffer.from(JSON.stringify(meta)); + //params.trainingMetadata = meta; if ('string' === typeof msg.payload) { diff --git a/utilities/response-utils.js b/utilities/response-utils.js index aeb81731..0085d319 100644 --- a/utilities/response-utils.js +++ b/utilities/response-utils.js @@ -37,6 +37,15 @@ class ResponseUtils { } } + static assignResultToField(msg, response, field) { + if (response && response.result) { + msg[field] = response.result; + } else { + msg[field] = response; + } + } + + } module.exports = ResponseUtils;