Skip to content

Commit a10ad42

Browse files
add support for the alchemy language API #72
1 parent bb4785a commit a10ad42

File tree

5 files changed

+232
-46
lines changed

5 files changed

+232
-46
lines changed

lib/alchemy_endpoints.json

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
{
2+
"entities" : {
3+
"url" : "/url/URLGetRankedNamedEntities",
4+
"text" : "/text/TextGetRankedNamedEntities",
5+
"html" : "/html/HTMLGetRankedNamedEntities"
6+
},
7+
8+
"keywords": {
9+
"url" : "/url/URLGetRankedKeywords",
10+
"text" : "/text/TextGetRankedKeywords",
11+
"html" : "/html/HTMLGetRankedKeywords"
12+
},
13+
14+
"concepts": {
15+
"url" : "/url/URLGetRankedKeywords",
16+
"text" : "/text/TextGetRankedKeywords",
17+
"html" : "/html/HTMLGetRankedKeywords"
18+
},
19+
20+
"sentiment": {
21+
"url" : "/url/URLGetTextSentiment",
22+
"text" : "/text/TextGetTextSentiment",
23+
"html" : "/html/HTMLGetTextSentiment"
24+
},
25+
26+
"sentiment_targeted": {
27+
"url" : "/url/URLGetTargetedSentiment",
28+
"text" : "/text/TextGetTargetedSentiment",
29+
"html" : "/html/HTMLGetTargetedSentiment"
30+
},
31+
32+
"category": {
33+
"url" : "/url/URLGetRankedConcepts",
34+
"text" : "/text/TextGetRankedConcepts",
35+
"html" : "/html/HTMLGetRankedConcepts"
36+
},
37+
38+
"relations": {
39+
"url" : "/url/URLGetRelations",
40+
"text" : "/text/TextGetRelations",
41+
"html" : "/html/HTMLGetRelations"
42+
},
43+
44+
"language": {
45+
"url" : "/url/URLGetLanguage",
46+
"text" : "/text/TextGetLanguage",
47+
"html" : "/html/HTMLGetLanguage"
48+
},
49+
50+
"text": {
51+
"url" : "/url/URLGetText",
52+
"html" : "/html/HTMLGetText"
53+
},
54+
55+
"text_raw": {
56+
"url" : "/url/URLGetRawText",
57+
"html" : "/html/HTMLGetRawText"
58+
},
59+
60+
"authors": {
61+
"url" : "/url/URLGetAuthors",
62+
"html" : "/html/HTMLGetAuthors"
63+
},
64+
65+
"feeds": {
66+
"url" : "/url/URLGetFeedLinks",
67+
"html" : "/html/HTMLGetFeedLinks"
68+
},
69+
70+
"microformats": {
71+
"url" : "/url/URLGetMicroformatData",
72+
"html" : "/html/HTMLGetMicroformatData"
73+
},
74+
75+
"taxonomy": {
76+
"url" : "/url/URLGetRankedTaxonomy",
77+
"text" : "/text/TextGetRankedTaxonomy",
78+
"html" : "/html/HTMLGetRankedTaxonomy"
79+
},
80+
81+
"combined": {
82+
"url" : "/url/URLGetCombinedData",
83+
"text" : "/text/TextGetCombinedData",
84+
"html" : "/html/HTMLGetCombinedData"
85+
},
86+
87+
"image": {
88+
"url" : "/url/URLGetImage"
89+
},
90+
91+
"image_keywords": {
92+
"url" : "/url/URLGetRankedImageKeywords",
93+
"image" : "/image/ImageGetRankedImageKeywords"
94+
},
95+
96+
"image_face_tag": {
97+
"url" : "/url/URLGetRankedImageFaceTags",
98+
"image" : "/image/ImageGetRankedImageFaceTags"
99+
}
100+
}

lib/helper.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ module.exports = {
4747
*/
4848
isHTML: function (text){
4949
return /<[a-z][\s\S]*>/i.test(text);
50-
}
50+
},
51+
52+
/**
53+
* Returns the first match from formats that is key the params map
54+
* otherwise null
55+
* @param {Object} params The parameters
56+
* @param {Array} requires The keys we want to check
57+
*/
58+
getFormat: function(params, formats) {
59+
if (!formats || !params)
60+
return null;
5161

62+
for(var i = 0; i < formats.length; i++) {
63+
if (formats[i] in params)
64+
return formats[i];
65+
};
66+
return null;
67+
}
5268
};

lib/requestwrapper.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,12 @@ function createRequest(parameters, callback) {
106106

107107
if (typeof(options.api_key) !== 'undefined') {
108108
// Alchemy uses the apikey(a.k.a api_key) as query parameter
109-
if (options.alchemy)
110-
options.qs.apikey = options.api_key;
111-
else
109+
if (options.alchemy){
110+
options.qs = extend({ apikey : options.api_key }, options.qs);
111+
} else {
112112
// IBM Watson uses Basic auth
113113
options.headers['Authorization'] = 'Basic ' + options.api_key;
114+
}
114115
delete options.api_key;
115116
}
116117

services/alchemy_language/v1.js

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -18,62 +18,121 @@
1818

1919
var extend = require('extend');
2020
var requestFactory = require('../../lib/requestwrapper');
21-
var pick = require('object.pick');
22-
var omit = require('object.omit');
23-
var isStream = require('isstream');
21+
var endpoints = require('../../lib/alchemy_endpoints.json');
22+
var helper = require('../../lib/helper');
23+
24+
function createRequest(method) {
25+
return function(_params, callback ) {
26+
var params = _params || {};
27+
var accepted_formats = Object.keys(endpoints[method]);
28+
var format = helper.getFormat(params, accepted_formats);
29+
30+
if (format === null) {
31+
callback(new Error('Missing required parameters: ' +
32+
accepted_formats.join(', ') +
33+
' needs to be specified'));
34+
return;
35+
}
36+
37+
var parameters = {
38+
options: {
39+
url: endpoints[method][format],
40+
method: 'POST',
41+
json: true,
42+
path: params,
43+
form: extend({outputMode: 'json'}, params) // change default output to json
44+
},
45+
defaultOptions: this._options
46+
};
47+
return requestFactory(parameters, callback);
48+
};
49+
}
2450

2551
function AlchemyLanguage(options) {
2652
// Default URL
2753
var serviceDefaults = {
2854
url: 'https://access.alchemyapi.com/calls',
2955
alchmemy: true
3056
};
31-
32-
this.paths = {
33-
text: 'text/TextGetRankedNamedEntities',
34-
url: 'url/URLGetRankedNamedEntities',
35-
html: 'html/HTMLGetRankedNamedEntities'
36-
};
37-
3857
// Replace default options with user provided
3958
this._options = extend(serviceDefaults, options);
4059
}
4160

4261
/**
4362
* Extracts a grouped, ranked list of named entities (people, companies,
44-
* organizations, etc.) from within a text, url or html.
63+
* organizations, etc.) from text, a URL or HTML.
4564
*/
46-
AlchemyLanguage.prototype.entities = function(_params, callback) {
47-
var params = _params || {};
48-
var path = null;
49-
50-
if (typeof(params.text) === 'undefined' &&
51-
typeof(params.url) === 'undefined' &&
52-
typeof(params.html) === 'undefined') {
53-
callback(new Error('Missing required parameters: either text, ' +
54-
'url or html needs to be specified'));
55-
return;
56-
}
57-
58-
if (typeof(params.text) !== 'undefined')
59-
path = '/text/TextGetRankedNamedEntities';
60-
else if (typeof(params.url) !== 'undefined')
61-
path = '/url/URLGetRankedNamedEntities';
62-
else
63-
path = '/url/HTMLGetRankedNamedEntities';
64-
65-
var parameters = {
66-
options: {
67-
url: path,
68-
method: 'GET',
69-
json: true,
70-
path: params,
71-
qs: extend({outputMode: 'json'}, params) // change default output to json
72-
},
73-
requiredParams: ['text'],
74-
defaultOptions: this._options
75-
};
76-
return requestFactory(parameters, callback);
65+
AlchemyLanguage.prototype.entities = createRequest('entities');
66+
67+
/**
68+
* Extracts the keywords from text, a URL or HTML.
69+
*/
70+
AlchemyLanguage.prototype.keywords = createRequest('keywords');
71+
72+
/**
73+
* Tags the concepts from text, a URL or HTML.
74+
*/
75+
AlchemyLanguage.prototype.concepts = createRequest('concepts');
76+
77+
/**
78+
* Calculates the sentiment for text, a URL or HTML.
79+
*/
80+
AlchemyLanguage.prototype.sentiment = function(params, callback) {
81+
var service = (params && params.target) ? 'sentiment' : 'sentiment_targeted';
82+
return createRequest(service).call(this, params, callback);
7783
};
84+
/**
85+
* Extracts the cleaned text (removes ads, navigation, etc.) for a URL or HTML.
86+
* if raw = true, extracts the cleaned text (removes ads, navigation, etc.).
87+
*/
88+
AlchemyLanguage.prototype.text = function(params, callback) {
89+
var service = (params && params.raw) ? 'text_raw' : 'text';
90+
return createRequest(service).call(this, params, callback);
91+
};
92+
93+
/**
94+
* Extracts the authors from a URL or HTML.
95+
*/
96+
AlchemyLanguage.prototype.authors = createRequest('authors');
97+
98+
/**
99+
* Detects the language for text, a URL or HTML.
100+
*/
101+
AlchemyLanguage.prototype.language = createRequest('language');
102+
103+
/**
104+
* Extracts the title for a URL or HTML.
105+
*/
106+
AlchemyLanguage.prototype.title = createRequest('title');
107+
108+
/**
109+
* Extracts the relations for text, a URL or HTML.
110+
*/
111+
AlchemyLanguage.prototype.relations = createRequest('relations');
112+
113+
/**
114+
* Categorizes the text for text, a URL or HTML.
115+
*/
116+
AlchemyLanguage.prototype.category = createRequest('category');
117+
118+
/**
119+
* Detects the RSS/ATOM feeds for a URL or HTML.
120+
*/
121+
AlchemyLanguage.prototype.feeds = createRequest('category');
122+
123+
/**
124+
* Parses the microformats for a URL or HTML.
125+
*/
126+
AlchemyLanguage.prototype.microformats = createRequest('microformats');
127+
128+
/**
129+
* Categorized through the taxonomy call for text, HTML, or a URL.
130+
*/
131+
AlchemyLanguage.prototype.taxonomy = createRequest('taxonomy');
132+
133+
/**
134+
* Categorized through the taxonomy call for text, HTML, or a URL.
135+
*/
136+
AlchemyLanguage.prototype.combined = createRequest('combined');
78137

79138
module.exports = AlchemyLanguage;

test/test.wrapper.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
var assert = require('assert');
44
var watson = require('../lib/index');
5+
var helper = require('../lib/helper');
56

67
describe('wrapper', function() {
78

@@ -136,4 +137,13 @@ describe('wrapper', function() {
136137
assert.equal(service._options.bar, 'foo');
137138
});
138139

140+
it('should detect the alchemy format', function() {
141+
assert.equal(null, helper.getFormat());
142+
assert.equal(null, helper.getFormat(null));
143+
assert.equal(null, helper.getFormat(null, null));
144+
assert.equal(null, helper.getFormat({}, null));
145+
assert.equal(null, helper.getFormat({ foo:'foo', bar:'bar'}, null));
146+
assert.equal('foo', helper.getFormat({ foo:'foo'}, ['foo']));
147+
assert.equal('bar', helper.getFormat({ foo:'foo', bar:'bar'}, ['bar', 'foo']));
148+
});
139149
});

0 commit comments

Comments
 (0)