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 }); }); });