-
Notifications
You must be signed in to change notification settings - Fork 0
/
backdrop.js
165 lines (148 loc) · 5.64 KB
/
backdrop.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
var indico = require('indico.io');
var btoa = require('btoa');
var Q = require('q');
var request = require('request-promise');
var wikipedia = require('wikipedia-js');
indico.apiKey = '37486d14726ba66828c08209e66e241c';
var NUM_IMAGES = 3;
var NUM_NEWS_ARTICLES = 5;
var NUM_TEXT_TAGS = 3;
function backdrop (text) {
backdrop = {'original text': text};
// Get keywords from text, then hit Bing News API
var newsPromise = indico.keywords(text).then(function(keywords) {
backdrop['keywords'] = keywords;
return keywords;
}).then(bingNews)
.then(function(news) {
backdrop['news'] = news;
}).catch(console.warn);
// Get named entities, then hit wiki summary and Bing Image API for each named entity
var namedEntsPromise = indico.named_entities(text).then(function(namedEnts) {
backdrop['named_entities'] = namedEnts;
return Object.keys(namedEnts);
}).then(function(entities) {
var deferred = Q.defer();
var allPromises = [];
// Grab wiki-summary and bing images for each entity
entities.forEach(function(entity) {
allPromises.push(allInfoForNamedEnt(entity))
});
// Only fulfill promise once all info for all entities is returned
Q.all(allPromises).then(function(allInfo) {
deferred.resolve(allInfo);
}).catch(deferred.reject);
return deferred.promise;
// allInfo contains lists of {entity -> {images: ..., summary...}}
}).then(function(allInfo) {
for (var i = 0; i < allInfo.length; ++i) {
var entity = Object.keys(allInfo[i])[0];
backdrop[entity] = {};
Object.keys(allInfo[i][entity]).forEach(function (info) {
backdrop[entity][info] = allInfo[i][entity][info];
});
}
}).catch(console.warn);
// Get text tags
var textTagsPromise = indico.textTags(text, {top_n: NUM_TEXT_TAGS}).then(function(tags) {
backdrop['textTags'] = tags;
}).catch(console.warn);
// Wait for all information to be gathered, then return it all
var deferred = Q.defer();
var allPromises = Q.all([newsPromise, namedEntsPromise, textTagsPromise]);
allPromises.then(function(res) {
deferred.resolve(backdrop);
}).catch(deferred.reject);
return deferred.promise;
};
// Takes in an entity and returns all relevant information for
// that entity as a map {entity: {image: ..., summary: ..., etc.}}
function allInfoForNamedEnt(entity) {
var deferred = Q.defer();
var allInfo = {};
allInfo[entity] = {};
Q.all([bingImages(entity), wikiSummary(entity)]).then(function (info) {
allInfo[entity]['images'] = info[0];
allInfo[entity]['summary'] = info[1];
deferred.resolve(allInfo);
}).catch(deferred.reject);
return deferred.promise;
}
// Returns promise that when fulfilled will return all relevant
// bing images for the given keyword
function bingImages(keyword) {
var deferred = Q.defer();
var url = constructBingUrl([keyword], 'Image');
bingOptions = bingReqOptions(url);
request(bingOptions).then(function(body) {
var images = [];
for (var i = 0; i < NUM_IMAGES; ++i) {
var result = body['d']['results'][i];
var full_image = result['MediaUrl'];
var thumbnail = result['Thumbnail']['MediaUrl'];
images.push({'full_image': full_image,
'thumbnail':thumbnail});
}
deferred.resolve(images);
}).catch(deferred.reject);
return deferred.promise;
}
// Returns promise that when fulfilled will return all relevant
// news to the given keywords
function bingNews(keywords) {
// Ignore weights for now, and only take two keywords because Bing
// API seems to not send full results often for 3 keywords
var deferred = Q.defer();
var keywords = Object.keys(keywords).slice(0, 2);
var url = constructBingUrl(keywords, 'News');
var bingOptions = bingReqOptions(url);
request(bingOptions).then(function(body) {
var newsArticles = [];
var numArticlesReturned = Object.keys(body['d']['results']).length;
for (var i = 0; i < NUM_NEWS_ARTICLES && i < numArticlesReturned; ++i) {
var result = body['d']['results'][i];
var title = result['Title'];
var url = result['Url'];
newsArticles.push({'title': title, 'url': url});
}
deferred.resolve(newsArticles);
}).catch(deferred.reject);
return deferred.promise;
}
// returns a bing search url for the given keywords
// Example media types are 'News', 'Image', etc.
function constructBingUrl(keywords, mediaType) {
var hackedUrl = 'https://api.datamarket.azure.com/Bing/Search/v1/' + mediaType + '?Query=' + "%27";
keywords.forEach(function(word) {
hackedUrl += word + '%27';
});
hackedUrl += '&$format=json';
return hackedUrl;
}
// Returns the necessary bing options (headers + API key) to
// pass along for get requests
function bingReqOptions(url) {
bingOptions = {
url: url,
method: 'GET',
headers: { //We can define headers too
'Authorization': 'Basic ' + btoa('AccountKey:QN98hNEWbua9ag8YDVPodtOHXHoHzPRMLlDnwvWW9lk'),
'Accept': 'application/json'
},
json: true
}
return bingOptions;
}
// returns a wikipedia summary for the given entity
function wikiSummary(entity) {
var deferred = Q.defer();
var options = {query: entity, format: "html", summaryOnly: true};
wikipedia.searchArticle(options, function(err, html) {
if(err) {
deferred.reject(err);
}
deferred.resolve(html);
});
return deferred.promise;
}
module.exports = backdrop;