First draft of toxic-comments

This commit is contained in:
Chi Vinh Le
2017-09-06 22:11:48 +07:00
parent fea5f75aa6
commit 6f82fd76f5
32 changed files with 298 additions and 491 deletions
@@ -0,0 +1,6 @@
const apiKey = process.env.TALK_PERSPECTIVE_API_KEY;
if(!apiKey) {
throw new Error('Please set the TALK_PERSPECTIVE_API_KEY environment variable to use the toxic-comments plugin. Visit https://www.perspectiveapi.com/ to request API access.');
}
module.exports = apiKey;
@@ -0,0 +1,3 @@
module.exports = {
TOXICITY_THRESHOLD: 0.8,
};
@@ -0,0 +1,15 @@
const {APIError} = require('../../../errors');
const ErrNoComment = new APIError('Comment must be provided', {
status: 400,
});
const ErrToxic = new APIError('Comment is toxic', {
status: 400,
translation_key: 'COMMENT_IS_TOXIC',
});
module.exports = {
ErrNoComment,
ErrToxic,
};
@@ -0,0 +1,37 @@
const perspective = require('./perspective');
const {ADD_COMMENT_TAG} = require('../../../perms/constants');
const {ErrToxic} = require('./errors');
const {TOXICITY_THRESHOLD} = require('./constants');
module.exports = {
Comment: {
tags: {
post(comment, input, {user}, _info, result) {
if (comment.metadata.perspective && user && user.can(ADD_COMMENT_TAG)) {
return result.concat({tag: {name: 'TOXIC', created_at: new Date()}});
}
return result;
}
},
},
RootMutation: {
createComment: {
async pre(_, {input}, _context, _info) {
// Don't call out to perspective when running tests.
if (process.env.NODE_ENV === 'test') {
return;
}
const apiKey = require('./apiKey');
const scores = await perspective.getScores(apiKey, input.body);
if (input.checkToxicity && scores.SEVERE_TOXICITY.summaryScore > TOXICITY_THRESHOLD) {
throw ErrToxic;
}
input.metadata = Object.assign({}, input.metadata, {
perspective: scores,
});
},
},
},
};
@@ -0,0 +1,37 @@
const fetch = require('node-fetch');
const API_ENPOINT = 'https://commentanalyzer.googleapis.com/v1alpha1';
async function getScores(apiKey, text) {
const response = await fetch(`${API_ENPOINT}/comments:analyze?key=${apiKey}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
comment: {
text,
},
// TODO: support other languages.
languages: ['en'],
requestedAttributes: {
TOXICITY: {},
SEVERE_TOXICITY: {},
}
}),
});
const data = await response.json();
return {
TOXICITY: {
summaryScore: data.attributeScores.TOXICITY.summaryScore.value
},
SEVERE_TOXICITY: {
summaryScore: data.attributeScores.SEVERE_TOXICITY.summaryScore.value
},
};
}
module.exports = {
getScores,
};
@@ -1,56 +1,33 @@
const http = require('axios');
const boom = require('express-boom');
const bodyParser = require('body-parser');
const perspective = require('./perspective');
const {ErrNoComment} = require('./errors');
module.exports = (router) => {
const key = process.env.TALK_PERSPECTIVE_API_KEY;
if(!key) {
throw new Error('Please set the TALK_PERSPECTIVE_API_KEY environment variable to use the toxic-comments plugin. Visit https://www.perspectiveapi.com/ to request API access.');
}
router.use(boom());
router.use(bodyParser.text());
/**
* POST /api/v1/toxicity/score
* args:
* - provide the comment in the request body
*/
router.post('/api/v1/toxicity/score', (req, res) => {
var comment = req.body;
if(comment) {
var body = {
comment: {
text: comment,
},
languages: ["en"],
requestedAttributes: {
TOXICITY: {}
}
};
var headers = {
'Content-Type': 'application/json',
};
http.post(
'https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key='+key,
body)
.then(function(response) {
var data = response.data;
var score = {
comment: comment,
score: data.attributeScores.TOXICITY.summaryScore.value
}
return res.json(score);
})
.catch(function(err) {
console.log(err);
res.boom.badRequest('The Perspective API returned an error. Please check the server logs for details.');
})
router.post('/api/v1/toxicity/score', async (req, res, next) => {
const apiKey = process.env.TALK_PERSPECTIVE_API_KEY;
if(!apiKey) {
throw new Error('Please set the TALK_PERSPECTIVE_API_KEY environment variable to use the toxic-comments plugin. Visit https://www.perspectiveapi.com/ to request API access.');
}
else {
res.boom.badRequest('No comment provided');
const {comment} = req.body;
if(!comment) {
return next(ErrNoComment);
}
try {
const scores = await perspective.getScores(apiKey, comment);
return res.json({
comment,
score: scores.SEVERE_TOXICITY.summaryScore,
});
} catch(err) {
return next(err);
}
});
@@ -0,0 +1,4 @@
input CreateCommentInput {
checkToxicity: Boolean
}