Skip to content

Commit 5cabda6

Browse files
Merge pull request watson-developer-cloud#103 from watson-developer-cloud/dev
added visual insights and the new events call to tradeoff analytics
2 parents 15972a4 + 4ce903a commit 5cabda6

File tree

4 files changed

+116
-83
lines changed

4 files changed

+116
-83
lines changed

services/alchemy_vision/v1.js

Lines changed: 22 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ var requestFactory = require('../../lib/requestwrapper');
2121
var endpoints = require('../../lib/alchemy_endpoints.json');
2222
var helper = require('../../lib/helper');
2323
var isStream = require('isstream');
24-
var pick = require('object.pick');
2524
var omit = require('object.omit');
2625
var fs = require('fs');
2726

@@ -54,18 +53,33 @@ function createRequest(method) {
5453
' needs to be specified'));
5554
return;
5655
}
56+
// always return json
57+
params.outputMode = 'json';
5758

5859
var parameters = {
5960
options: {
6061
url: endpoints[method][format],
61-
method: 'POST',
62-
json: true,
63-
qs: extend({outputMode: 'json'}, params) // change default output to json
62+
method: 'POST'
6463
},
6564
defaultOptions: this._options
6665
};
6766

68-
return requestFactory(parameters, errorFormatter(callback));
67+
if (!params.image || !isStream(params.image)) {
68+
// url or base64 images are considered 'not-raw'
69+
params.imagePostMode = 'not-raw';
70+
// send the parameters as form url-encoded
71+
parameters.options.form = params;
72+
return requestFactory(parameters, errorFormatter(callback));
73+
} else {
74+
params.imagePostMode = 'raw';
75+
// send the parameters as query parameters
76+
parameters.options.qs = omit(params,['image']);
77+
// add the content-length to the headers
78+
parameters.options.headers = {
79+
'Content-Length': fs.statSync(params.image.path).size
80+
};
81+
return params.image.pipe(requestFactory(parameters, errorFormatter(callback)));
82+
}
6983
};
7084
}
7185

@@ -81,86 +95,16 @@ function AlchemyVision(options) {
8195
/**
8296
* Extracts images from a URL or html
8397
*/
84-
AlchemyVision.prototype.getImageLinks = function(_params, callback ) {
85-
var params = _params || {};
86-
var accepted_formats = Object.keys(endpoints['image_link']);
87-
var format = helper.getFormat(params, accepted_formats);
88-
89-
if (format === null) {
90-
callback(new Error('Missing required parameters: ' + accepted_formats.join(', ') + ' needs to be specified'));
91-
return;
92-
}
93-
94-
var parameters = {
95-
options: {
96-
url: endpoints['image_link'][format],
97-
method: 'POST',
98-
json: true,
99-
qs: extend({}, params,{outputMode: 'json'}) // change default output to json
100-
},
101-
defaultOptions: this._options
102-
};
103-
104-
return requestFactory(parameters, errorFormatter(callback));
105-
};
98+
AlchemyVision.prototype.getImageLinks = createRequest('image_link');
10699

107100
/**
108101
* Tags image with keywords
109102
*/
110-
AlchemyVision.prototype.getImageKeywords = function(_params, callback) {
111-
var params = extend({}, _params);
112-
var accepted_formats = Object.keys(endpoints['image_keywords']);
113-
var format = helper.getFormat(params, accepted_formats);
114-
115-
if (format === null) {
116-
callback(new Error('Missing required parameters: ' + accepted_formats.join(', ') + ' needs to be specified'));
117-
return;
118-
}
119-
120-
var parameters = {
121-
options: {
122-
url: endpoints['image_keywords'][format],
123-
method: 'POST',
124-
json: true,
125-
qs: {outputMode: 'json'} // change default output to json
126-
},
127-
defaultOptions: this._options
128-
};
129-
130-
if (typeof(params.image) !== 'undefined') {
131-
132-
// check if image is stream or string
133-
if ((typeof(params.image) !== 'string') && !isStream(params.image)) {
134-
callback(new Error('Invalid arguments: image needs to be a stream or base64'));
135-
return;
136-
}
137-
138-
if (isStream(params.image)) {
139-
params.imagePostMode = 'raw';
140-
// handle raw images
141-
parameters.options.body = params.image;
142-
143-
} else {
144-
params.imagePostMode = 'not-raw';
145-
parameters.options.formData = params;
146-
}
147-
} else {
148-
parameters.options.formData = params;
149-
}
150-
151-
return requestFactory(parameters, errorFormatter(callback));
152-
};
103+
AlchemyVision.prototype.getImageKeywords = createRequest('image_keywords');
153104

154105
/**
155106
* Face detection and Recognition
156107
*/
157-
AlchemyVision.prototype.recognizeFaces = function(_params, callback) {
158-
var params = _params || {};
159-
160-
if (params.image && typeof(params.image) !== 'string')
161-
params.imagePostMode = 'raw';
162-
163-
return createRequest('image_recognition').call(this, params, callback);
164-
};
108+
AlchemyVision.prototype.recognizeFaces = createRequest('image_recognition');
165109

166110
module.exports = AlchemyVision;

services/tradeoff_analytics/v1.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
var extend = require('extend');
2020
var requestFactory = require('../../lib/requestwrapper');
21+
var omit = require('object.omit');
2122

2223
function TradeoffAnalytics(options) {
2324
// Default URL
@@ -39,19 +40,51 @@ function TradeoffAnalytics(options) {
3940
* @param {String} params.subject Name of the decision problem
4041
* @param {String} params.options A list of options. Typically, the rows in a
4142
* table representation of your data
43+
* @param {String} params.metadataHeader Value of the x-watson-metadata header to be forwarded
44+
* for analytics purposes
4245
*/
4346
TradeoffAnalytics.prototype.dilemmas = function(params, callback) {
47+
params = params || {};
48+
4449
var parameters = {
4550
options: {
4651
method: 'POST',
4752
url: '/v1/dilemmas',
48-
body: params,
49-
json: true,
53+
body: omit(params,['metadata_header']),
54+
headers: {
55+
'x-watson-metadata' : params.metadata_header
56+
},
57+
json: true
5058
},
5159
requiredParams: ['columns', 'subject', 'options'],
5260
defaultOptions: this._options
5361
};
5462
return requestFactory(parameters, callback);
5563
};
5664

65+
/**
66+
* Forward events from the Tradeoff Analytics widget to the service
67+
*
68+
* @param {String} params - the array of events to forward to the service
69+
* @param {String} params.metadataHeader Value of the x-watson-metadata header to be forwarded
70+
* for analytics purposes
71+
*/
72+
TradeoffAnalytics.prototype.events = function(params, callback) {
73+
params = params || {};
74+
75+
var parameters = {
76+
options: {
77+
method: 'POST',
78+
url: '/v1/events',
79+
body: omit(params,['metadata_header']),
80+
headers: {
81+
'x-watson-metadata' : params.metadata_header
82+
},
83+
json: true
84+
},
85+
defaultOptions: this._options
86+
};
87+
return requestFactory(parameters, callback);
88+
};
89+
5790
module.exports = TradeoffAnalytics;

test/resources/ta_events.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[{
2+
"widget_instance_uuid" : "e8d263d9-a0a7-43f4-81cf-2767ad246cb5",
3+
"widget_show_uuid" : null,
4+
"dilemma_call_uuid" : null,
5+
"event_number" : 0,
6+
"category" : "widget",
7+
"action" : "started",
8+
"object" : "basic",
9+
"value" : {
10+
"optionHighlighting" : false,
11+
"favorites" : true,
12+
"favoritesTab" : false,
13+
"optionDetails" : true,
14+
"filters" : true,
15+
"filterHistogram" : false,
16+
"objectivesOnly" : true,
17+
"optimalsList" : true,
18+
"autoExcludedList" : true,
19+
"incompleteList" : true,
20+
"tradeoffAnalyzer" : true,
21+
"undoRedo" : false,
22+
"exploreViz" : "both",
23+
"questionEditor" : "editableNoToggle",
24+
"bidiTextDir" : "auto",
25+
"analytics" : "MetadataAndEvents"
26+
},
27+
"timestamp" : 1442414658641
28+
}]

test/test.tradeoff_analytics.v1.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33
var assert = require('assert');
44
var watson = require('../lib/index');
55
var nock = require('nock');
6+
var extend = require('extend');
67

78
describe('tradeoff_analytics', function() {
89

910
var noop = function() {};
1011

1112
var service_request = require('./resources/dilemma_problem');
13+
var events_request = require('./resources/ta_events');
1214

1315
var service_response = {};
1416

1517
var service_path = '/v1/dilemmas';
16-
18+
var events_path = '/v1/events';
19+
1720
var service = {
1821
username: 'batman',
1922
password: 'bruce-wayne',
@@ -27,6 +30,11 @@ describe('tradeoff_analytics', function() {
2730
.persist()
2831
.post(service_path, service_request)
2932
.reply(200, service_response);
33+
nock(service.url)
34+
.persist()
35+
.post(events_path, events_request)
36+
.reply(200);
37+
3038
});
3139

3240
after(function() {
@@ -43,13 +51,33 @@ describe('tradeoff_analytics', function() {
4351
tradeoff_analytics.dilemmas({}, missingParameter);
4452
tradeoff_analytics.dilemmas(null, missingParameter);
4553
tradeoff_analytics.dilemmas(undefined, missingParameter);
54+
55+
tradeoff_analytics.events({}, missingParameter);
56+
tradeoff_analytics.events(null, missingParameter);
57+
tradeoff_analytics.events(undefined, missingParameter);
4658
});
47-
59+
4860
it('should generate a valid payload', function() {
49-
var req = tradeoff_analytics.dilemmas(service_request, noop);
61+
var params = extend({}, service_request);
62+
params.metadata_header = 'test_header_content';
63+
var req = tradeoff_analytics.dilemmas(params, noop);
5064
var body = new Buffer(req.body).toString('ascii');
5165
assert.equal(req.uri.href, service.url + service_path);
5266
assert.equal(body, JSON.stringify(service_request));
67+
assert.notEqual(body, JSON.stringify(params));
68+
assert.equal(req.headers['x-watson-metadata'], params.metadata_header);
69+
assert.equal(req.method, 'POST');
70+
});
71+
72+
it('should forward the events correctly', function() {
73+
var params = extend({}, events_request);
74+
params.metadata_header = 'test_header_content';
75+
var req = tradeoff_analytics.events(params, noop);
76+
var body = new Buffer(req.body).toString('ascii');
77+
assert.equal(req.uri.href, service.url + events_path);
78+
assert.equal(body, JSON.stringify(events_request));
79+
assert.notEqual(body, JSON.stringify(params));
80+
assert.equal(req.headers['x-watson-metadata'], params.metadata_header);
5381
assert.equal(req.method, 'POST');
5482
});
5583

0 commit comments

Comments
 (0)