node-red-contrib-fuzzywuzzy
Version:
Fuzzy string matching for node red. Can be used for intent recognition.
68 lines (58 loc) • 2.16 kB
JavaScript
fuzz = require('fuzzball');
module.exports = function(RED) {
function FuzzyWuzzyNode(config) {
RED.nodes.createNode(this, config);
const node = this;
// creates choice array from input string
function makeChoices (choices) {
const output = choices.split('\n').map( (line,i) => {
if (line.includes(":")) {
let [ key, val ] = line.split(":");
return {
key: key,
val: val
}
} else {
return {
key: i,
val: line
}
}
}).filter( (p) => p.val.length > 0) // filter empty lines
return output;
}
let keyChoicePairs = config.inputOptions == 'message' ? [] : makeChoices(config.choices);
const scorer = fuzz[config.scorer]
const options = {
wildcards : "*",
returnObjects : true,
cutoff : Number(config.cutoff),
limit: Number(config.limit),
scorer : scorer
}
node.on('input', function(msg) {
if (config.inputOptions == 'message' && 'choices' in msg) {
try {
keyChoicePairs = makeChoices(msg.choices);
} catch(err) {
node.error("Could not load choices from msg.choices", msg)
return
}
}
if (typeof msg.payload !== "string") {
return
}
let choices = keyChoicePairs.map((p) => p.val.toLowerCase())
const results = fuzz.extract(msg.payload.toLowerCase(), choices, options)
// map back keys to results
const resultsWithKeys = results.map( (res) => {
res.key = keyChoicePairs[res.key].key
res.input = msg.payload
return res
})
msg.payload = resultsWithKeys
node.send([{...msg, payload: resultsWithKeys.length > 0 && resultsWithKeys[0].key , match: resultsWithKeys.length > 0 && resultsWithKeys[0] }, {...msg, payload: resultsWithKeys }])
});
}
RED.nodes.registerType("fuzzy-match", FuzzyWuzzyNode)
}