-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdemo.js
More file actions
160 lines (148 loc) · 6.16 KB
/
demo.js
File metadata and controls
160 lines (148 loc) · 6.16 KB
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
// this API Key will only work on Algorithmia's website; get your own key at https://algorithmia.com/user#credentials
var algoClient = Algorithmia.client('sim43GD8oBTTqjwRb7/tfCO9/RV1');
var algorithms = {
autotag: '/nlp/AutoTag/1.0.1',
html2text: '/util/Html2Text/0.1.4',
scraperss: '/tags/ScrapeRSS/0.1.6',
sentiment: '/nlp/SentimentAnalysis/1.0.3',
summarizer: '/nlp/Summarizer/0.1.6'
};
/**
* once DOM is ready, update vars, set initial URL, and add handlers
*/
function init() {
setInviteCode('rss');
updateRssUrl();
requireHttp($('#rssUrl'));
};
/**
* copy URL of RSS feed from dropdown into input text
*/
function updateRssUrl() {
$('#rssUrl').val($('#rssSelector :selected').val());
}
/**
* Display error message to user; can also be used to test if error is present
* @param response (optional) response to inspect for error; if error is not present, returns immediately (nothing will be displayed)
* @param errorMessage (optional) message to display instead of the error itself
* @returns {boolean} true if there was an error
*/
function displayError(response, errorMessage) {
if(response && response.error) {
console.log(response.error);
$('#status-label').html('<span class="text-danger">' + (errorMessage?errorMessage:response.error) + '</span>');
return true;
}
return false;
}
/**
* convert a sentiment score [-1 to 1] to natural language [(very) negative / (very) positive / neutral] by quintile
* @param sentimentScore
* @returns {string}
*/
function sentimentScoreToText(sentimentScore) {
var sentimentType = 'neutral';
if (sentimentScore >= 0.2) {
sentimentType = 'positive'
} else if (sentimentScore <= -0.2) {
sentimentType = 'negative'
}
return Math.abs(sentimentScore) >= 0.4 ? 'very '+sentimentType : sentimentType;
}
/**
* scrape the RSS feed and analyze its entries
*/
var processFeed = function() {
// clear out any old results
('#results').empty();
('#status-label').empty();
$('#fetch-spinner').removeClass('hidden');
$('#rssSelector').attr('disabled','disabled');
$('#rssUrl').attr('disabled','disabled');
// query RSS scraper algorithm with selected feed URL
var feedUrl = $('#rssUrl').val();
algoClient.algo(algorithms.scraperss).pipe(feedUrl).then(function(response) {
$('#fetch-spinner').addClass('hidden');
$('#rssSelector').removeAttr('disabled');
$('#rssUrl').removeAttr('disabled');
if (displayError(response, 'Failed to load RSS feed; please check that it is a valid URL')) {return;}
$('#resultsWrapper').removeClass('hidden');
// smooth scroll to results section
$('html, body').animate({
scrollTop: $("#resultsWrapper").offset().top
}, 1000);
// process no more than 6 RSS entries
response.result.slice(0,6).forEach(processFeedEntry);
});
};
/**
* insert a section into page showing an RSS feed entry's title, generated summary & tags, and sentiment analysis
* @param entry {{url:string,title:string}} feed entry with URL and Title
*/
var processFeedEntry = function(entry) {
// create section and elements into which we will stick the results of our algorithms
var row = $('<section class="rss-result"><div class="row whitespace-none">'
+ '<div class="col-md-12 col-lg-9">'
+ '<p class="item-title">ARTICLE TITLE</p>'
+ '<h4 class="result"><a href="' + entry.url + '">' + entry.title + '</a></h4>'
+ '<p class="item-title">GENERATED SUMMARY</p>'
+ '<p class="summary"><span class="aspinner"></span></p>'
+ '<p class="item-title">GENERATED TAGS</p>'
+ '<div class="tags"><span class="aspinner"></span></div>'
+ '<p class="item-title">SENTIMENT ANALYSIS</p>'
+ '<div class="sentiment"><span class="aspinner"></span></div>'
+ '</div></section>');
$('#results').append(row);
// fetch text from the page to which this entry points, and extract summary, tags, and sentiment
algoClient.algo(algorithms.html2text).pipe(entry.url).then(function (response) {
if (displayError(response, 'Error fetching ' + entry.url + ': ' + response.error)) {
return;
}
summarizeFeedEntry(response.result, row.find('.summary:first'));
autotagFeedEntry(response.result, row.find('.tags:first'));
sentimentAnalyzeFeedEntry(response.result, row.find('.sentiment:first'));
});
};
/**
* get a summary of the entryText (via https://algorithmia.com/algorithms/nlp/Summarizer), insert into targetElement
* @param entryText full plaintext of the entry
* @param targetElement jQuery DOM element into which results should be placed
*/
function summarizeFeedEntry(entryText, targetElement) {
// call Algorithmia API for summary of text
algoClient.algo(algorithms.summarizer).pipe(entryText).then(function(response) {
if(displayError(response.error)) {return;}
targetElement.text(response.result);
});
}
/**
* extract tags from entryText (via https://algorithmia.com/algorithms/nlp/AutoTag), insert into targetElement
* @param entryText full plaintext of the entry
* @param targetElement jQuery DOM element into which results should be placed
*/
function autotagFeedEntry(entryText, targetElement) {
var topicLabels = [];
entryText = typeof(entryText)=='string'? entryText.split('\n') : [];
// call Algorithmia API for autotag analysis
algoClient.algo(algorithms.autotag).pipe(entryText).then(function(response) {
if(!displayError(response.error)) {
for (var key in response.result) {
topicLabels.push('<span class="label label-info">' + response.result[key] + '</span> ');
}
targetElement.html(topicLabels.join(''));
}
});
}
/**
* analyze sentiment of entryText (via https://algorithmia.com/algorithms/nlp/SentimentAnalysis), insert into targetElement
* @param entryText full plaintext of the entry
* @param targetElement jQuery DOM element into which results should be placed
*/
function sentimentAnalyzeFeedEntry(entryText, targetElement) {
// call Algorithmia API for sentiment analysis
algoClient.algo(algorithms.sentiment).pipe({document:entryText}).then(function(response) {
if(displayError(response)) {return;}
var sentimentScore = Math.round(response.result[0].sentiment*100)/100;
targetElement.html('<p>'+sentimentScore+' ('+sentimentScoreToText(sentimentScore)+')</p>');
});
}