compromise-typeahead
v0.3.1
Published
plugin for nlp-compromise
Downloads
9
Readme
a plugin that allows assuming a word, before it is fully-typed.
const nlp = require('compromise') //load the plugin
nlp.extend(require('compromise-typeahead'))
// a bunch of words we're expecting
const lexicon = {
bedfordshire: 'Town',
aberdeenshire: 'Town',
buckinghamshire: 'Town',
argyllshire: 'Town',
bambridgeshire: 'Town',
cheshire: 'Town',
ayrshire: 'Town',
}
// throw them in
nlp.typeahead(lexicon, { min: 3 })
// ok, create a document
let doc = nlp('i went to bucking', lexicon)
doc.has('buckinghamshire')
//true!
let m = doc.match('#Town')
console.log(m.text())
// 'bucking'
console.log(m.text('implicit'))
// 'buckinghamshire'
You can see, it just kind of pretends the word is there. It uses the same 'implicit' scheme that contractions do.
It only applies to the end of the document, for now.
In addition to assuming the word, a passed-in lexicon will also tag it automatically. If this is not required, you can simply pass-in an array of terms instead.
autoFill
words found in typeahead are available in .match()
, and visible with .text('implicit')
.
You'll notice that they do not appear in regular .text()
output though. This is done on purpose, to retain the original input. If you want the over-write the text, so the assumed words are fully-loaded, run .autoFill()
:
let words = {
july: 'Month',
august: 'Month',
september: 'Month',
}
nlp.typeahead(words, { min: 2, safe: false })
let doc = nlp('on the 5th of septem')
doc.autoFill() //boom.
doc.text()
// 'on the 5th of september',
Notes:
Typeahead is a dangerous game. Making assumptions about a user's text based on prefix, is very error-prone, especially for small-prefixes.
Great care should be taken when selecting your words for typeahead.
This tool may help in reviewing a list of potential prefix-collisions.
...ya but even then.. - it's nearly impossible to predict misunderstandings when the interpreter is being greedy.
So, heads-up.
Three things it does to decrease false-positives -
Block any overlap:
The plugin will not make predictions for any overlapping prefixes, in the given terms. if 'milan' and 'milwaukee' are both given, 'mil' will not be triggered for anything.
nlp.typeahead(['milan', 'milwaukee'])
nlp('mil').has('(milan|milwaukee)') //false
Ignore 2-char prefixes:
Prefixes shorter than 3 chars will be ignored.
you can set a lower, or higher minimum with:
nlp.typeahead(['toronto'], { min: 4 })
nlp('tor').has('toronto') //false
nlp('toro').has('toronto') //true
Block known words:
Prefixes that exist in the compromise lexicon will also be ignored.
these are assumed to be pretty common, full words.
You can disable this by passing-in safe:false
.
// 'swim' is it's own word.
nlp.typeahead(['swimsuit'])
nlp('swim').has('swimsuit') //false
nlp('swimsu').has('swimsuit') //true
// who cares - do it anyways
nlp.typeahead(['swimsuit'], { safe: false })
nlp('swim').has('swimsuit') //true
the compromise lexicon includes ~14k words, but very few common nouns. It is not meant to be a perfect-guard against prefix-collisions, like this. So please don't lean on this safe feature too-hard.
Layering prefixes carefully
you may want to conjure-up a scheme where some words are matched greedier than others.
// layer-one, quite-greedy
nlp.typeahead(['grey', 'gold', 'red'], { min: 2 })
// layer-two, a little safer
nlp.typeahead(['greyhound', 'goldendoodle', 'poodle'], { min: 3 })
// first-layer is sneaky
nlp('re').has('red') //true
// second-layer is less-sneaky
nlp('po').has('poodle') //false
nlp('gr').has('grey') //true
nlp('gre').has('(grey|greyhound)') //false (collision of two layers)
nlp('golde').has('goldendoodle') //true
Adding more matches will merge into existing prefixes, and automatically remove collisions.
If you want to get rid of them, you can set the property on the World object directly:
nlp('').world.prefixes = {} //whoosh!
See Also
- compromise-keypress - a caching plugin for on-type parsing
MIT