compromise README

The project's README from github.com/spencermountain/compromise. As one markdown file: README.md.

compromise
modest natural language processing
npm install compromise
by Spencer Kelly and many contributors
french • german • italian • spanish
don't you find it strange,
    how easy text is to make,

     ↬ᔐᖜ↬   and how hard it is to actually parse and use?

compromise tries its best to turn text into data.
it makes limited and sensible decisions.
it's not as smart as you'd think.
import nlp from 'compromise'

let doc = nlp('she sells seashells by the seashore.')
doc.verbs().toPastTense()
doc.text()
// 'she sold seashells by the seashore.'
don't be fancy, at all:
if (doc.has('simon says #Verb')) {
  return true
}
grab parts of the text:
let doc = nlp(entireNovel)
doc.match('the #Adjective of times').text()
// "the blurst of times?"
match docs

and get data:

import plg from 'compromise-speech'
nlp.extend(plg)

let doc = nlp('Milwaukee has certainly had its share of visitors..')
doc.compute('syllables')
doc.places().json()
/*
[{
  "text": "Milwaukee",
  "terms": [{
    "normal": "milwaukee",
    "syllables": ["mil", "wau", "kee"]
  }]
}]
*/
json docs

avoid the problems of brittle parsers:

let doc = nlp("we're not gonna take it..")

doc.has('gonna') // true
doc.has('going to') // true (implicit)

// transform
doc.contractions().expand()
doc.text()
// 'we are not going to take it..'
contraction docs

and whip stuff around like it's data:

let doc = nlp('ninety five thousand and fifty two')
doc.numbers().add(20)
doc.text()
// 'ninety five thousand and seventy two'
number docs

-because it actually is-

let doc = nlp('the purple dinosaur')
doc.nouns().toPlural()
doc.text()
// 'the purple dinosaurs'
noun docs

Use it on the client-side:

<script src="https://unpkg.com/compromise"></script>
<script>
  var doc = nlp('two bottles of beer')
  doc.numbers().minus(1)
  document.body.innerHTML = doc.text()
  // 'one bottle of beer'
</script>

or likewise:

import nlp from 'compromise'

var doc = nlp('London is calling')
doc.verbs().toNegative()
// 'London is not calling'

compromise is ~250kb (minified):

it's pretty fast. It can run on keypress:

it works mainly by conjugating all forms of a basic word list.

The final lexicon is ~14,000 words:

you can read more about how it works, here. it's weird.

okay -

compromise/one

A tokenizer of words, sentences, and punctuation.

import nlp from 'compromise/one'

let doc = nlp("Wayne's World, party time")
let data = doc.json()
/* [{
  normal:"wayne's world party time",
    terms:[{ text: "Wayne's", normal: "wayne" },
      ...
      ]
  }]
*/
tokenizer docs

compromise/one splits your text up, wraps it in a handy API,

/one is quick - most sentences take a 10th of a millisecond.

It can do ~1mb of text a second - or 10 wikipedia pages.

Infinite jest takes 3s.

You can also parallelize, or stream text to it with compromise-speed.

compromise/two

A part-of-speech tagger, and grammar-interpreter.

import nlp from 'compromise/two'

let doc = nlp("Wayne's World, party time")
let str = doc.match('#Possessive #Noun').text()
// "Wayne's World"
tagger docs

compromise/two automatically calculates the very basic grammar of each word.

this is more useful than people sometimes realize.

Light grammar helps you write cleaner templates, and get closer to the information.

compromise has 83 tags, arranged in a handsome graph.

#FirstName → #Person → #ProperNoun → #Noun

you can see the grammar of each word by running doc.debug()

you can see the reasoning for each tag with nlp.verbose('tagger').

if you prefer Penn tags, you can derive them with:

let doc = nlp('welcome thrillho')
doc.compute('penn')
doc.json()

compromise/three

Phrase and sentence tooling.

import nlp from 'compromise/three'

let doc = nlp("Wayne's World, party time")
let str = doc.people().normalize().text()
// "wayne"
selection docs

compromise/three is a set of tooling to zoom into and operate on parts of a text.

.numbers() grabs all the numbers in a document, for example - and extends it with new methods, like .subtract().

When you have a phrase, or group of words, you can see additional metadata about it with .json()

let doc = nlp('four out of five dentists')
console.log(doc.fractions().json())
/*[{
    text: 'four out of five',
    terms: [ [Object], [Object], [Object], [Object] ],
    fraction: { numerator: 4, denominator: 5, decimal: 0.8 }
  }
]*/
let doc = nlp('$4.09CAD')
doc.money().json()
/*[{
    text: '$4.09CAD',
    terms: [ [Object] ],
    number: { prefix: '$', num: 4.09, suffix: 'cad'}
  }
]*/

🤖 For AI agents & LLMs

Plain-text, copy-paste docs that render without JavaScript live in this repo:

API

Compromise/one

Output
Utils
Accessors
Match

(match methods use the match-syntax.)

compromise (spencermountain/compromise)

named-entity-recognition
Searching Database…

What is this?Compromise is a lightweight JavaScript natural-language processing library that parses text into structured data: tokenizing words and sentences, tagging part-of-speech, and letting you query phrases like numbers, names, or dates.
Is it a framework or a library?It is a library you import into a JS project, built as three layered pieces: 'one' for tokenization, 'two' for part-of-speech tagging/grammar, and 'three' for phrase and sentence tooling.
How do I add it to a project?Install it with npm, then call nlp(text) to get a document you can query and transform.
Do I need Python or any other runtime first?No, it's pure JavaScript with a few small npm dependencies (efrt, grad-school, suffix-thumb) and requires Node 12 or newer if used server-side.
Is tagging accurate or just a quick heuristic?It leans on a basic word list and lightweight heuristics rather than a trained model, so tagging is fast but approximate; you can inspect confidence with .confidence() or debug with doc.debug().
Does it run in the browser or only Node?It runs anywhere JavaScript runs, including in the browser on keypress events, since it has no native dependencies.
How fast is it?compromise/one can tokenize about 1mb of text per second (roughly 10 Wikipedia pages), with most sentences parsed in a tenth of a millisecond; Infinite Jest takes about 3 seconds.
How does the grammar tagging work?compromise/two assigns each word one of 83 part-of-speech tags arranged in a hierarchy (e.g. #FirstName to #Person to #ProperNoun to #Noun), which helps extract clean data from text.
Can I extract specific things like numbers or dates from text?Yes, compromise/three adds phrase-level tooling such as .numbers() to grab all numbers in a document, plus methods like .subtract() and .json() for metadata on matched phrases.
Size
62.1 MB
Stars
12.2K
Age
15y
Commits · 90 Days