Skip to content

Repository files navigation

yake-ts

npm version types CI license

Text in, ranked keywords out. 🔑

yake-ts implements YAKE — an unsupervised keyword extractor that scores candidate phrases from statistics of one document alone: word frequency, casing, position, spread across sentences, and co-occurrence. No model, no corpus, no training, no network call.

import { extractKeywords } from "yake-ts";

extractKeywords("fix flaky auth test in login flow")[0].keyword;
// "fix flaky auth"

One function, zero runtime dependencies, 5.7 kB

gzipped including the English stopword list. 33 more languages are separate imports you only pay for if you use them.

Code snippets, the API tables, the language list, and the bundle size above are generated from the real source/build output, not typed by hand — see scripts/docs/sync-readme.ts.

Picking a package

Several JS keyword extractors exist and they solve genuinely different problems:

Package What you get What it costs
yake-ts YAKE scores from a single call; English inline, 33 languages opt-in; ESM, edge/browser-safe young and unproven; Levenshtein-only dedup; no CJK segmentation
@ade_oshineye/yaket the same algorithm, plus scorer/tokenizer hooks, CLI, highlighter, Bobbin adapter, Python-parity + Cloudflare test lanes, benchmarks ~370 kB unpacked, all 34 stopword sets reachable through one API; Node 20+; a much bigger API to learn
yake-wasm YAKE in Rust/WASM; fast on long documents; drops n-gram substrings so "data science" wins over "data" a WASM init step in your bundler; stopwords are English-only and not configurable; last published 2022
retext-keywords part-of-speech-aware keywords and keyphrases inside a unified pipeline needs unified + retext + retext-pos; ~5 dependencies; results come back as stems on a vfile
keyword-extractor stopword removal in 20 languages, battle-tested (~220k downloads/week) no ranking — you get a filtered word list, not keywords ordered by importance

Short version: keyword-extractor if you only need stopwords gone, retext-keywords if you are already in the unified ecosystem, yaket if you need the extension points or upstream parity, yake-ts if you want YAKE's ranking in the smallest possible bundle with one import.

For POS tagging, NER, or CJK word segmentation, use a real NLP stack (spaCy, wink-nlp) — none of the above do that.

What's new

Version Highlights
1.2.0 Tiny, dependency-free YAKE keyword extractor—one function, 34 languages, zero classes
0.1.0 Initial release — extractKeywords, zero-dependency YAKE, English bundled + 33 more languages as subpath imports

Full history in CHANGELOG.md.

Install

npm install yake-ts   # bun / pnpm / yarn all fine

Quick start

import { extractKeywords } from "yake-ts";

const keywords = extractKeywords("fix flaky auth test in login flow");
// [
//   { keyword: "fix flaky auth", normalized: "fix flaky auth", score: 0.017,
//     ngramSize: 3, occurrences: 1, sentenceIds: [0] },
//   ...
// ]

Results come back sorted, best first. Typical uses: tagging notes or CMS entries, naming a chat session from its first message, enriching search/RAG chunks without an LLM call.

The rules

Three things, and you've seen the whole tool.

1 · Lower score wins. score is a cost, not a relevance percentage. The list is already sorted ascending, so [0] is the strongest keyword — don't re-sort it descending.

2 · Everything happens per call. Scores come from the input text alone, so there is nothing to load, warm up, or reuse between calls. Pass a whole document rather than one sentence at a time: YAKE's position and spread features need more than one sentence to say anything.

3 · A language is a stopword list, not a tokenizer. Pass another language's set via the stopwords option and phrase detection adapts; word splitting stays the same Unicode word-boundary scan. Fine for space-delimited scripts, not for unsegmented Chinese or Japanese — see Languages.

API

extractKeywords(text: string, options?: YakeTsOptions): Keyword[]

Options

Field Type Default Description
maxNgramSize? number 3 Max words per candidate keyword phrase.
windowSize? number 1 Co-occurrence window size for the relatedness feature.
dedupeThreshold? number 0.9 Similarity ceiling above which a candidate is dropped as a near-duplicate. 1 disables dedup.
limit? number 10 Max number of keywords to return.
stopwords? Iterable bundled English Stopwords to use. For other languages, import STOPWORDS from yake-ts/stopwords/<code> (e.g. yake-ts/stopwords/fr) and pass it here — each language is its own subpath export so you only pay for the ones you use. Or pass a fully custom set.

Keyword

Field Type Default Description
keyword string Surface form as it appeared in the source text.
normalized string Lowercased form used for matching/deduplication.
score number YAKE score — lower is more relevant.
ngramSize number Number of words in the phrase.
occurrences number How many times the phrase occurred in the text.
sentenceIds number[] Zero-based indices of sentences the phrase occurs in, ascending.

Languages

English is bundled and used by default. 33 more ship as stopword-only subpath exports, so a consumer who never imports one pays zero bytes for it:

import { extractKeywords } from "yake-ts";
import { STOPWORDS as FRENCH } from "yake-ts/stopwords/fr";

extractKeywords("le chat est sur la table", { stopwords: FRENCH });

Available codes: ar, bg, br, cz, da, de, el, es, et, fa, fi, fr, hi, hr, hu, hy, id, it, ja, lt, lv, nl, no, pl, pt, ro, ru, sk, sl, sv, tr, uk, zh (vendored from @ade_oshineye/yaket's stopword bundle)

Adding your own words on top of a bundled list. Every language, including English, is a plain yake-ts/stopwords/<code> subpath export — yake-ts/stopwords/en works the same as /fr. Spread it into a Set with your own additions; this only imports the one list you name, so it costs nothing beyond what you were already paying:

import { STOPWORDS as EN } from "yake-ts/stopwords/en";

extractKeywords(text, { stopwords: new Set([...EN, "widget", "wigl"]) });

CJK needs pre-segmentation. Tokenization is a Unicode word-boundary scan, so Chinese and Japanese text — which has no spaces between words — comes back as one run-on token per script run, and the zh/ja stopword lists can't fix that. Segment it yourself (e.g. with Intl.Segmenter) and space-join the result before calling extractKeywords.

Limitations

  • Not byte-for-byte upstream YAKE. It is a port of a port: the algorithm core comes from @ade_oshineye/yaket, vendored rather than depended on, which itself documents drift from Python YAKE's segtok tokenizer. Expect the same top keywords, not identical float scores.
  • Dedup is Levenshtein similarity only, where yaket lets you choose seqm, levs, or jaro. Good enough for short candidate phrases; if you need Python's seqm behavior, use yaket.
  • Single documents only. No corpus statistics, no TF-IDF across a collection, no topic modeling.
  • Short input gives thin results. A five-word title has almost no statistics to score.
  • No lemmatization or POS filtering, so plural and singular forms rank as separate candidates.

Need something this doesn't do? Open an issue — feature requests welcome.

Credits

The algorithm is from the YAKE paper: Campos, Mangaravite, Pasquali, Jorge, Nunes, Jatowt, YAKE! Keyword Extraction from Single Documents using Multiple Local Features, Information Sciences 509 (2020), 257–289 — 10.1016/j.ins.2019.09.013. Reference implementation: LIAAD/yake.

Development

bun install
bun run test         # bun test
bun run typecheck    # tsc --noEmit
bun run build        # vite → dist/
bun run format       # biome check --write

License

MIT © jayF0x

About

Tiny, dependency-free YAKE keyword extractor — no classes, no caching, one pure function. English bundled, 33 more languages as opt-in imports.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages