diff --git a/analysis/mlsentiment/locales/en-US/mlsentiment.html b/analysis/mlsentiment/locales/en-US/mlsentiment.html
index 8e9f5c9d..b17242f8 100644
--- a/analysis/mlsentiment/locales/en-US/mlsentiment.html
+++ b/analysis/mlsentiment/locales/en-US/mlsentiment.html
@@ -4,14 +4,16 @@
Outputs
- sentiment object
- - contains the resulting AFINN-111 sentiment.
+ - contains the resulting AFINN-165 sentiment.
- sentiment.score number
- the sentiment score.
Inputs
- words object
- - an object of words and scores to override or add words can be supplied -
{ word:score,... }
.
+ - besides sending a raw string in msg.payload, an object of words and scores to override or add words can be supplied -
{ word:score,... }
.
+ - tokens object
+ - a `tokens` object allows custom tokenizers which may be required by some languages -
{ ['世界',...] }
.
- lang string
diff --git a/analysis/mlsentiment/locales/ja/mlsentiment.html b/analysis/mlsentiment/locales/ja/mlsentiment.html
index ae7b5fa7..cfeee6ad 100644
--- a/analysis/mlsentiment/locales/ja/mlsentiment.html
+++ b/analysis/mlsentiment/locales/ja/mlsentiment.html
@@ -4,17 +4,19 @@
出力
- sentiment オブジェクト
- - AFINN-111による感情分析の結果
+ - AFINN-165による感情分析の結果
- sentiment.score 数値
- 感情分析スコア
入力
- - overrides オブジェクト
+ - words オブジェクト
- 単語スコアの上書きをするためのオブジェクト -
{ word:score,... }
+ - tokens object
+ - 一部の言語で必要となるカスタム トークナイザーが可能になります -
{ ['世界',...] }
.
詳細
ゼロ以上のスコアはポジティブ、ゼロ以下はネガティブを意味します。
スコアの範囲は通常-5から+5ですが、より大きかったり小さかったりすることもあります。
詳細はthe Multilang-Sentiment docs hereを参照してください。
-
+
\ No newline at end of file
diff --git a/analysis/mlsentiment/mlsentiment.js b/analysis/mlsentiment/mlsentiment.js
index f9bb85fa..b35051af 100644
--- a/analysis/mlsentiment/mlsentiment.js
+++ b/analysis/mlsentiment/mlsentiment.js
@@ -1,28 +1,25 @@
-module.exports = function(RED) {
+module.exports = function (RED) {
"use strict";
var multilangsentiment = require('multilang-sentiment');
function MultiLangSentimentNode(n) {
- RED.nodes.createNode(this,n);
+ RED.nodes.createNode(this, n);
this.lang = n.lang;
- this.property = n.property||"payload";
+ this.property = n.property || "payload";
var node = this;
- this.on("input", function(msg) {
- var value = RED.util.getMessageProperty(msg,node.property);
+ this.on("input", function (msg) {
+ var value = RED.util.getMessageProperty(msg, node.property);
if (value !== undefined) {
- if (msg.hasOwnProperty("overrides")) {
- msg.extras = msg.overrides;
- delete msg.overrides;
- }
- multilangsentiment(value, node.lang || msg.lang || 'en', {words: msg.extras || null}, function (err, result) {
+ multilangSentiment(value, node.lang || msg.lang || 'en', { 'words': msg.words || null, 'tokens': msg.tokens || null }, function (err, result) {
msg.sentiment = result;
+ msg.sentiment.comparative = msg.sentiment.score / msg.sentiment.tokens.length; // temporarily addresses an issue in v2.0.0: https://github.com/marcellobarile/multilang-sentiment/issues/10
node.send(msg);
});
}
else { node.send(msg); } // If no matching property - just pass it on.
});
}
- RED.nodes.registerType("mlsentiment",MultiLangSentimentNode);
+ RED.nodes.registerType("mlsentiment", MultiLangSentimentNode);
}
diff --git a/analysis/mlsentiment/package.json b/analysis/mlsentiment/package.json
index 7b54370c..d3b3f3f3 100644
--- a/analysis/mlsentiment/package.json
+++ b/analysis/mlsentiment/package.json
@@ -1,19 +1,25 @@
{
- "name" : "node-red-node-multilang-sentiment",
- "version" : "0.1.0",
- "description" : "A Node-RED node that uses the AFINN-165 wordlists for sentiment analysis of words translated into multiple languages including emojis.",
- "dependencies" : {
- "multilang-sentiment" : "^1.2.0"
+ "name": "node-red-node-multilang-sentiment",
+ "version": "0.2.0",
+ "description": "A Node-RED node that uses the AFINN-165 wordlists for sentiment analysis of words translated into multiple languages including emoji.",
+ "dependencies": {
+ "multilang-sentiment": "^2.0.0"
},
- "repository" : {
- "type":"git",
- "url":"https://github.com/node-red/node-red-nodes.git",
- "directory" : "tree/master/analysis/mlsentiment"
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/node-red/node-red-nodes.git",
+ "directory": "tree/master/analysis/mlsentiment"
},
"license": "Apache-2.0",
- "keywords": [ "node-red", "sentiment", "anaylsis", "AFINN" ],
- "node-red" : {
- "nodes" : {
+ "keywords": [
+ "node-red",
+ "sentiment",
+ "anaylsis",
+ "AFINN",
+ "emoji"
+ ],
+ "node-red": {
+ "nodes": {
"mlsentiment": "mlsentiment.js"
}
},
@@ -21,5 +27,8 @@
"name": "Dave Conway-Jones",
"email": "ceejay@vnet.ibm.com",
"url": "http://nodered.org"
- }
-}
+ },
+ "contributors" : [
+ "Chuan Khoo (https://chuank.com)"
+ ]
+}
\ No newline at end of file
diff --git a/test/analysis/mlsentiment/mlsentiment_spec.js b/test/analysis/mlsentiment/mlsentiment_spec.js
index 876026c4..ec64428b 100644
--- a/test/analysis/mlsentiment/mlsentiment_spec.js
+++ b/test/analysis/mlsentiment/mlsentiment_spec.js
@@ -18,118 +18,118 @@ var should = require("should");
var sentimentNode = require("../../../analysis/mlsentiment/mlsentiment.js");
var helper = require("node-red-node-test-helper");
-describe('mlsentiment Node', function() {
+describe('mlsentiment Node', function () {
- before(function(done) {
+ before(function (done) {
helper.startServer(done);
});
- after(function(done) {
+ after(function (done) {
helper.stopServer(done);
});
- afterEach(function() {
+ afterEach(function () {
helper.unload();
});
- it('should be loaded', function(done) {
- var flow = [{id:"sentimentNode1", type:"mlsentiment", name: "sentimentNode" }];
- helper.load(sentimentNode, flow, function() {
+ it('should be loaded', function (done) {
+ var flow = [{ id: "sentimentNode1", type: "mlsentiment", name: "sentimentNode" }];
+ helper.load(sentimentNode, flow, function () {
var sentimentNode1 = helper.getNode("sentimentNode1");
sentimentNode1.should.have.property('name', 'sentimentNode');
done();
});
});
- it('should pass on msg if no payload', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",wires:[["jn2"]]},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should pass on msg if no payload', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
msg.should.not.have.property('sentiment');
msg.topic.should.equal("pass on");
done();
});
var testString = 'good, great, best, brilliant';
- jn1.receive({topic:"pass on"});
+ jn1.receive({ topic: "pass on" });
});
});
- it('should add a positive score for good words', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",wires:[["jn2"]]},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should add a positive score for good words', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
try {
msg.should.have.property('sentiment');
msg.sentiment.should.have.property('score');
msg.sentiment.score.should.be.a.Number();
msg.sentiment.score.should.be.above(10);
done();
- } catch(err) {
+ } catch (err) {
done(err);
}
});
var testString = 'good, great, best, brilliant';
- jn1.receive({payload:testString});
+ jn1.receive({ payload: testString });
});
});
- it('should add a positive score for good words (in French)', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",wires:[["jn2"]],lang:"fr"},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should add a positive score for good words (in French)', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", wires: [["jn2"]], lang: "fr" },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
try {
msg.should.have.property('sentiment');
msg.sentiment.should.have.property('score');
msg.sentiment.score.should.be.a.Number();
msg.sentiment.score.should.be.above(5);
done();
- } catch(err) {
+ } catch (err) {
done(err);
}
});
var testString = 'bon, belle, don du ciel, brillant';
- jn1.receive({payload:testString});
+ jn1.receive({ payload: testString });
});
});
- it('should add a positive score for good words - alternative property', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",property:"foo",wires:[["jn2"]]},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should add a positive score for good words - alternative property', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", property: "foo", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
try {
msg.should.have.property('sentiment');
msg.sentiment.should.have.property('score');
msg.sentiment.score.should.be.a.Number();
msg.sentiment.score.should.be.above(10);
done();
- } catch(err) {
+ } catch (err) {
done(err);
}
});
var testString = 'good, great, best, brilliant';
- jn1.receive({foo:testString});
+ jn1.receive({ foo: testString });
});
});
- it('should add a negative score for bad words', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",wires:[["jn2"]]},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should add a negative score for bad words', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
msg.should.have.property('sentiment');
msg.sentiment.should.have.property('score');
msg.sentiment.score.should.be.a.Number();
@@ -137,17 +137,17 @@ describe('mlsentiment Node', function() {
done();
});
var testString = 'bad, horrible, negative, awful';
- jn1.receive({payload:testString});
+ jn1.receive({ payload: testString });
});
});
- it('should add a negative score for bad words - alternative property', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",property:"foo",wires:[["jn2"]]},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should add a negative score for bad words - alternative property', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", property: "foo", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
msg.should.have.property('sentiment');
msg.sentiment.should.have.property('score');
msg.sentiment.score.should.be.a.Number();
@@ -155,17 +155,17 @@ describe('mlsentiment Node', function() {
done();
});
var testString = 'bad, horrible, negative, awful';
- jn1.receive({foo:testString});
+ jn1.receive({ foo: testString });
});
});
- it('should allow you to override word scoring', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",wires:[["jn2"]]},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should allow you to override word scoring', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
msg.should.have.property('sentiment');
msg.sentiment.should.have.property('score');
msg.sentiment.score.should.be.a.Number();
@@ -173,18 +173,18 @@ describe('mlsentiment Node', function() {
done();
});
var testString = 'sick, wicked';
- var overrides = {'sick': 10, 'wicked': 10 };
- jn1.receive({payload:testString,overrides:overrides});
+ var wordOverrides = { 'sick': 10, 'wicked': 10 };
+ jn1.receive({ payload: testString, words: wordOverrides });
});
});
- it('should allow you to override word scoring - alternative property', function(done) {
- var flow = [{id:"jn1",type:"mlsentiment",property:"foo",wires:[["jn2"]]},
- {id:"jn2", type:"helper"}];
- helper.load(sentimentNode, flow, function() {
+ it('should allow you to override word scoring - alternative property', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", property: "foo", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
- jn2.on("input", function(msg) {
+ jn2.on("input", function (msg) {
msg.should.have.property('sentiment');
msg.sentiment.should.have.property('score');
msg.sentiment.score.should.be.a.Number();
@@ -192,8 +192,46 @@ describe('mlsentiment Node', function() {
done();
});
var testString = 'sick, wicked';
- var overrides = {'sick': 10, 'wicked': 10 };
- jn1.receive({foo:testString,overrides:overrides});
+ var wordOverrides = { 'sick': 10, 'wicked': 10 };
+ jn1.receive({ foo: testString, words: wordOverrides });
+ });
+ });
+
+ it('should allow you to use custom tokens', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
+ var jn1 = helper.getNode("jn1");
+ var jn2 = helper.getNode("jn2");
+ jn2.on("input", function (msg) {
+ msg.should.have.property('sentiment');
+ msg.sentiment.should.have.property('score');
+ msg.sentiment.score.should.be.a.Number();
+ msg.sentiment.score.should.equal(-3);
+ done();
+ });
+ var testString = '世界就是一个疯子的囚笼';
+ var tokenOverrides = ['世界', '就', '是', '一个', '疯子', '的', '囚笼'];
+ jn1.receive({ payload: testString, tokens: tokenOverrides });
+ });
+ });
+
+ it('should allow you to use custom tokens - alternative property', function (done) {
+ var flow = [{ id: "jn1", type: "mlsentiment", property: "foo", wires: [["jn2"]] },
+ { id: "jn2", type: "helper" }];
+ helper.load(sentimentNode, flow, function () {
+ var jn1 = helper.getNode("jn1");
+ var jn2 = helper.getNode("jn2");
+ jn2.on("input", function (msg) {
+ msg.should.have.property('sentiment');
+ msg.sentiment.should.have.property('score');
+ msg.sentiment.score.should.be.a.Number();
+ msg.sentiment.score.should.equal(-3);
+ done();
+ });
+ var testString = '世界就是一个疯子的囚笼';
+ var tokenOverrides = ['世界', '就', '是', '一个', '疯子', '的', '囚笼'];
+ jn1.receive({ foo: testString, tokens: tokenOverrides });
});
});