indickit 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -19
- package/dist/deromanize.js +1129 -0
- package/dist/phonetic-search.js +1329 -0
- package/dist/phonetic.js +85 -16
- package/dist/romanize.js +1 -1
- package/dist/types/js/deromanize.d.ts +57 -0
- package/dist/types/js/phonetic-search.d.ts +104 -0
- package/dist/types/js/phonetic.d.ts +14 -0
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
Small, exact utilities for text in the languages of India, in Go and
|
|
4
4
|
TypeScript. They fix the places where ordinary string code goes wrong on
|
|
5
5
|
Indian text: a search that misses a word because it is spelled, encoded or
|
|
6
|
-
inflected another way, a letter count that cuts a letter in two,
|
|
7
|
-
that must be written in Latin letters
|
|
6
|
+
inflected another way, a letter count that cuts a letter in two, a name
|
|
7
|
+
that must be written in Latin letters, and Latin typing that must be written
|
|
8
|
+
in an Indian script.
|
|
8
9
|
|
|
9
10
|
```
|
|
10
11
|
stem किताब किताबें किताबों → किताब
|
|
11
12
|
phonetic राम ರಾಮ രാമ ராம رام Ram → rn
|
|
12
13
|
segment ಲಕ್ಷ್ಮಿ → ಲ ಕ್ಷ್ಮಿ
|
|
13
14
|
romanize लक्ष्मी ലക്ഷ്മി லக்ஷ்மி → lakshmi
|
|
15
|
+
deromanize namaste → नमस्ते
|
|
14
16
|
```
|
|
15
17
|
|
|
16
18
|
Each utility gives the same output in Go and in TypeScript, and each was
|
|
@@ -24,8 +26,47 @@ measured on data that its rules were never built on.
|
|
|
24
26
|
| let a search for किताब also find किताबों | `normalize`, then `stem` |
|
|
25
27
|
| let a search for हिन्दी also find हिंदी, and keep words whole | `fold` |
|
|
26
28
|
| find a person's name typed in another script | `phonetic` |
|
|
29
|
+
| find a name in a long list, as people write it (titles, initials), or in running text | `phonetic-search` |
|
|
27
30
|
| count letters, cut at a length, or move a cursor | `segment` |
|
|
28
31
|
| write a name or a text in Latin letters (लक्ष्मी → lakshmi) | `romanize` |
|
|
32
|
+
| write Latin typing in an Indian script (namaste → नमस्ते) | `deromanize` |
|
|
33
|
+
|
|
34
|
+
## Languages
|
|
35
|
+
|
|
36
|
+
The 22 languages of the Eighth Schedule. `normalize`, `fold`, `segment` and
|
|
37
|
+
`phonetic` read every script below, so they serve every language; the
|
|
38
|
+
others hold tables for some languages only.
|
|
39
|
+
|
|
40
|
+
| Language | Code | Script | `stem` | `phonetic-search` | `romanize` | `deromanize` |
|
|
41
|
+
|---|---|---|---|---|---|---|
|
|
42
|
+
| Assamese | `as` | Bengali-Assamese | ✓ | ✓ | words, names | words, names |
|
|
43
|
+
| Bengali | `bn` | Bengali-Assamese | ✓ | ✓ | words, names | words, names |
|
|
44
|
+
| Bodo | `brx` | Devanagari | – | ✓ | words | words |
|
|
45
|
+
| Dogri | `doi` | Devanagari | – | ✓ | words | words |
|
|
46
|
+
| Gujarati | `gu` | Gujarati | ✓ | ✓ | words, names | words, names |
|
|
47
|
+
| Hindi | `hi` | Devanagari | ✓ | ✓ | words, names | words, names |
|
|
48
|
+
| Kannada | `kn` | Kannada | ✓ | ✓ | words, names | words, names |
|
|
49
|
+
| Kashmiri | `ks` | Perso-Arabic | – | ✓ | words, names | words, names |
|
|
50
|
+
| Konkani | `gom` | Devanagari | – | ✓ | words, names | words, names |
|
|
51
|
+
| Maithili | `mai` | Devanagari | – | ✓ | words, names | words, names |
|
|
52
|
+
| Malayalam | `ml` | Malayalam | ✓ | ✓ | words, names | words, names |
|
|
53
|
+
| Manipuri | `mni` | Meetei Mayek | – | ✓ | words, names | words, names |
|
|
54
|
+
| Marathi | `mr` | Devanagari | ✓ | ✓ | words, names | words, names |
|
|
55
|
+
| Nepali | `ne` | Devanagari | ✓ | ✓ | words, names | words, names |
|
|
56
|
+
| Odia | `or` | Odia | – | ✓ | words, names | words, names |
|
|
57
|
+
| Punjabi | `pa` | Gurmukhi | ✓ | ✓ | words, names | words, names |
|
|
58
|
+
| Sanskrit | `sa` | Devanagari | ✓ | ✓ | words, names | words, names |
|
|
59
|
+
| Santali | `sat` | Ol Chiki | – | keys only | names | names |
|
|
60
|
+
| Sindhi | `sd` | Perso-Arabic | – | ✓ | words, names | words, names |
|
|
61
|
+
| Tamil | `ta` | Tamil | ✓ | ✓ | words, names | words, names |
|
|
62
|
+
| Telugu | `te` | Telugu | ✓ | ✓ | words, names | words, names |
|
|
63
|
+
| Urdu | `ur` | Perso-Arabic | ✓ | ✓ | words, names | words, names |
|
|
64
|
+
|
|
65
|
+
"words" and "names" are the two modes of `romanize` and `deromanize`. In
|
|
66
|
+
`deromanize`, the names mode of Bodo and Dogri uses their words tables.
|
|
67
|
+
Santali has no words tables: no dataset of Santali words in Latin letters
|
|
68
|
+
was found. `phonetic-search` in Santali ranks by the keys alone. Measured
|
|
69
|
+
quality differs by language; see `docs/` for each utility.
|
|
29
70
|
|
|
30
71
|
## Install
|
|
31
72
|
|
|
@@ -45,25 +86,28 @@ deno add npm:indickit
|
|
|
45
86
|
|
|
46
87
|
The package is ES modules only; `require()` works from Node 20.19. In
|
|
47
88
|
TypeScript, set `moduleResolution` to `nodenext` or `bundler`; the old
|
|
48
|
-
`node10` cannot find the
|
|
89
|
+
`node10` cannot find the utilities.
|
|
49
90
|
|
|
50
91
|
In a browser, with no build step:
|
|
51
92
|
|
|
52
93
|
```js
|
|
53
|
-
import { normalize } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.
|
|
54
|
-
import { stem } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.
|
|
55
|
-
import { match } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.
|
|
56
|
-
import { segment } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.
|
|
57
|
-
import { load } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.
|
|
94
|
+
import { normalize } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.8.0/dist/normalize.js";
|
|
95
|
+
import { stem } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.8.0/dist/stem.js";
|
|
96
|
+
import { match } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.8.0/dist/phonetic.js";
|
|
97
|
+
import { segment } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.8.0/dist/segment.js";
|
|
98
|
+
import { load } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.8.0/dist/romanize.js";
|
|
99
|
+
import { loadSearch } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.8.0/dist/phonetic-search.js";
|
|
100
|
+
import { load as loadDeromanize } from "https://cdn.jsdelivr.net/gh/micahchoo/indickit@v0.8.0/dist/deromanize.js";
|
|
58
101
|
```
|
|
59
102
|
|
|
60
103
|
Each utility is its own file, so a page loads only the rules it uses.
|
|
61
104
|
`romanize` also loads one language's tables when you ask for them (0.2–1.8
|
|
62
|
-
MB)
|
|
105
|
+
MB), `deromanize` one language's tables and word list (0.3–3.1 MB), and
|
|
106
|
+
`phonetic-search` one language's table (2–6 KB). The npm package carries no tables: `load()` reads them beside the
|
|
63
107
|
module (a jsDelivr or GitHub-tag install), else from jsDelivr at the same
|
|
64
108
|
version. Offline, pass your own `fetch`. In Go, `go get` downloads the
|
|
65
|
-
tables of every language once (14 MB); a
|
|
66
|
-
it imports.
|
|
109
|
+
tables of every language once (`romanize` 14 MB, `deromanize` 52 MB); a
|
|
110
|
+
program carries only the languages it imports.
|
|
67
111
|
|
|
68
112
|
## Recipes
|
|
69
113
|
|
|
@@ -147,6 +191,26 @@ Equal keys mean "sounds alike", not "the same person". Before you merge two
|
|
|
147
191
|
records, weigh the evidence: a shared rare name says more than a shared
|
|
148
192
|
common one.
|
|
149
193
|
|
|
194
|
+
### Search a list of names
|
|
195
|
+
|
|
196
|
+
`phonetic-search` uses the keys to find candidates, and a scorer learned
|
|
197
|
+
from data to rank them from 0 to 100. It finds names as people write them,
|
|
198
|
+
with titles, initials and joined words, and names in running text.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { loadSearch, THRESHOLDS } from "indickit/phonetic-search";
|
|
202
|
+
|
|
203
|
+
const s = await loadSearch("hi"); // fetches the Hindi table (3 KB)
|
|
204
|
+
const ix = s.index(["नरेश मोदी", "नरेंद्र मोदी", "मनमोहन सिंह"]);
|
|
205
|
+
ix.search("Narendra Modi", THRESHOLDS.names); // [{ name: 1, score: 100 }]
|
|
206
|
+
ix.search("Manmohan Singh", THRESHOLDS.names); // [{ name: 2, score: 96 }]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Use the threshold for your task: `THRESHOLDS.names` (74) for a list of
|
|
210
|
+
people, `THRESHOLDS.villages` (72) for place names, `THRESHOLDS.text_10`
|
|
211
|
+
(80) or `text_20` (70) with `s.index(words, "text")` for a name among the
|
|
212
|
+
words of a text. A score is relative to the other candidates of its search.
|
|
213
|
+
|
|
150
214
|
### Count and cut letters
|
|
151
215
|
|
|
152
216
|
A cursor, a backspace, a letter count and a cut at a length limit must
|
|
@@ -189,6 +253,34 @@ import (
|
|
|
189
253
|
romanize.Word("लक्ष्मी", "hi", romanize.Words, 2) // [lakshmi laxmi]
|
|
190
254
|
```
|
|
191
255
|
|
|
256
|
+
### Write Latin typing in an Indian script
|
|
257
|
+
|
|
258
|
+
`deromanize` is the reverse: it gives a ranked list of native spellings for
|
|
259
|
+
a Latin-typed word, most likely first. It writes every word it is given in
|
|
260
|
+
the Indian script, English words too: in mixed text, find each word's
|
|
261
|
+
language first.
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
import { load } from "indickit/deromanize";
|
|
265
|
+
|
|
266
|
+
const hi = await load("hi"); // fetches the Hindi tables and word list
|
|
267
|
+
hi.word("namaste", 1); // ["नमस्ते"]
|
|
268
|
+
hi.text("bharat ke pradhanmantri"); // "भारत के प्रधानमंत्री"
|
|
269
|
+
const ur = await load("ur", "names");
|
|
270
|
+
ur.word("ahmad", 1); // ["احمد"]
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
In Go:
|
|
274
|
+
|
|
275
|
+
```go
|
|
276
|
+
import (
|
|
277
|
+
"github.com/micahchoo/indickit/deromanize"
|
|
278
|
+
_ "github.com/micahchoo/indickit/deromanize/lang/hi"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
deromanize.Word("namaste", "hi", deromanize.Words, 1) // [नमस्ते]
|
|
282
|
+
```
|
|
283
|
+
|
|
192
284
|
### The same in Go
|
|
193
285
|
|
|
194
286
|
```go
|
|
@@ -202,6 +294,7 @@ import (
|
|
|
202
294
|
normalize.Text("അവന്\u200d", "ml") // "അവൻ"
|
|
203
295
|
stem.Stem(normalize.Text("किताबों", "hi"), "hi") // किताब
|
|
204
296
|
phonetic.Match("Mohanlal", "മോഹൻലാൽ") // true
|
|
297
|
+
phonetic.NewIndex(names, "hi", phonetic.ProfileNames).Search("Narendra Modi", phonetic.Thresholds["names"])
|
|
205
298
|
segment.Segment("ಲಕ್ಷ್ಮಿ") // [ಲ ಕ್ಷ್ಮಿ]
|
|
206
299
|
```
|
|
207
300
|
|
|
@@ -217,11 +310,18 @@ segment.Segment("ಲಕ್ಷ್ಮಿ") // [ಲ ಕ್ಷ
|
|
|
217
310
|
| `phonetic.NameKeys(name)` | `nameKeys(name)` | the keys of a whole name; index these |
|
|
218
311
|
| `phonetic.Match(a, b)` | `match(a, b)` | same word count, and each pair of words shares a key |
|
|
219
312
|
| `phonetic.Words(name)` | `words(name)` | the words, split as the others split them |
|
|
313
|
+
| `phonetic.JoinedKeys(name)` | `joinedKeys(name)` | the keys of the name with its words joined (8+ classes) |
|
|
314
|
+
| `phonetic.NewIndex(names, lang, profile)` | `(await loadSearch(lang)).index(names, profile?)` | names keyed once for searching |
|
|
315
|
+
| `ix.Search(query, threshold)` | `ix.search(query, threshold?)` | the names scoring at least threshold, best first |
|
|
316
|
+
| `phonetic.Score(query, names, lang, profile)` | `(await loadSearch(lang)).score(query, names, profile?)` | one score (0..100) per candidate |
|
|
220
317
|
| `segment.Segment(s)` | `segment(text)` | the letters, in order; joined, they give the text back |
|
|
221
318
|
| `segment.Count(s)` | `count(text)` | how many letters a reader sees |
|
|
222
319
|
| `romanize.Word(w, lang, mode, n)` | `(await load(lang, mode)).word(w, n?)` | up to n spellings, most likely first |
|
|
223
320
|
| `romanize.Text(s, lang, mode)` | `(await load(lang, mode)).text(text)` | each word of the language's script in Latin letters |
|
|
224
321
|
| `romanize.Languages(mode)` | `languages(mode)` | the languages with tables (Go: those imported) |
|
|
322
|
+
| `deromanize.Word(latin, lang, mode, n)` | `(await load(lang, mode)).word(latin, n?)` | up to n native spellings, most likely first |
|
|
323
|
+
| `deromanize.Text(s, lang, mode)` | `(await load(lang, mode)).text(text)` | each run of Latin letters in the language's script |
|
|
324
|
+
| `deromanize.Languages(mode)` | `languages(mode)` | the languages with tables (Go: those imported) |
|
|
225
325
|
|
|
226
326
|
Three things hold for all of them:
|
|
227
327
|
|
|
@@ -246,19 +346,30 @@ other tools tried and each weak spot are in `docs/`.
|
|
|
246
346
|
|---|---|---|---|---|
|
|
247
347
|
| `normalize` | makes 88.1% of look-alike spellings equal, and changes the look of no word | Indic NLP Library: 82.4%, and changes 0.68% of words | 14 KB | [docs/normalize.md](docs/normalize.md) |
|
|
248
348
|
| `stem` | finds 6–15 points more of the right sentences than exact search, in 13 languages | ahead in 5 languages, level in 2, a trade in 4, behind in Nepali | 3 KB | [docs/stem.md](docs/stem.md) |
|
|
249
|
-
| `phonetic` | finds the right person 84% of the time, in 21 languages, on clean names; 42% on a real roster as written (70% with titles and initials removed) | romanize + Soundex: 23% in Tamil, 70% in Hindi; cannot read Urdu |
|
|
349
|
+
| `phonetic` | finds the right person 84% of the time, in 21 languages, on clean names; 42% on a real roster as written (70% with titles and initials removed); with `phonetic-search`, 86% of a real roster as written and 85% of villages | romanize + Soundex: 23% in Tamil, 70% in Hindi; cannot read Urdu; ICU + fuzzy match: 78% and 65% | 5 KB | [docs/phonetic.md](docs/phonetic.md) |
|
|
250
350
|
| `segment` | cuts 0.05% of Kannada words wrongly | `Intl.Segmenter`: 50.3% | 9 KB | [docs/segment.md](docs/segment.md) |
|
|
251
351
|
| `romanize` | writes 48.9% of the words of running text as people typed them, in 11 languages; 71.3% of names (tables: 0.2–1.8 MB a language) | IndicXlit (Python, a 119 MB model): 37.9% and 49.0% | 5 KB | [docs/romanize.md](docs/romanize.md) |
|
|
352
|
+
| `deromanize` | writes the right word first for 87.1% of the words of Hindi news typed in Latin, and in four for 97.4%; 69.7% of names in 19 languages (tables: 0.3–3.1 MB a language) | IndicXlit: 86.1%, 89.7% and 66.4%; behind on rare words out of context | 20 KB | [docs/deromanize.md](docs/deromanize.md) |
|
|
252
353
|
|
|
253
354
|
(Browser files are gzipped.)
|
|
254
355
|
|
|
356
|
+
`romanize` is also ahead of every tool tried that runs without a neural model. The
|
|
357
|
+
best of them, indic-trans (about 200 MB), gives 34.7% on running text against
|
|
358
|
+
51.2%, on the development data; it is ahead only in Urdu. See
|
|
359
|
+
[docs/romanize.md](docs/romanize.md).
|
|
360
|
+
|
|
255
361
|
## Limits
|
|
256
362
|
|
|
363
|
+
- **`deromanize` writes English words in the Indian script too.** About 8%
|
|
364
|
+
of the words of romanized Hinglish are English; find each word's language
|
|
365
|
+
first. On rare words out of context it is 10 points behind IndicXlit. See
|
|
366
|
+
[docs/deromanize.md](docs/deromanize.md).
|
|
257
367
|
- **Only HarfBuzz was tested** for "looks the same" (`normalize`,
|
|
258
368
|
`segment`). Windows and Apple draw text with their own engines.
|
|
259
|
-
-
|
|
260
|
-
initials before you key a name
|
|
261
|
-
wrong matches. See
|
|
369
|
+
- **The `phonetic` key expects clean names.** Remove titles (Shri, Smt.)
|
|
370
|
+
and initials before you key a name, or use `phonetic-search`. On one-word
|
|
371
|
+
place names the key alone returns many wrong matches. See
|
|
372
|
+
[docs/phonetic.md](docs/phonetic.md).
|
|
262
373
|
- **Tamil is the weakest language** for `phonetic` (76%), and `stem` is
|
|
263
374
|
behind Snowball's recall in Tamil.
|
|
264
375
|
- **`stem` does not help passage search in Hindi or Punjabi.** Short
|
|
@@ -294,21 +405,32 @@ Each utility's own weak spots are at the end of its file in `docs/`.
|
|
|
294
405
|
Every table and switch of a utility is in its rules file
|
|
295
406
|
(`normalize/rules.json`, `stem/rules.json`, `phonetic/rules.json`,
|
|
296
407
|
`segment/rules.json`; `romanize/rules.json` and its tables in
|
|
297
|
-
`romanize/lang
|
|
408
|
+
`romanize/lang/`; `deromanize/rules.json` and its tables and word lists in
|
|
409
|
+
`deromanize/lang/`; `phonetic-search`'s tables in `phonetic/scorer/`); the
|
|
410
|
+
Go and TypeScript code is a short loop over it.
|
|
298
411
|
Both are checked against a conformance file of inputs with the outputs that
|
|
299
412
|
a reference implementation gave them: 345,276 inputs for `normalize`,
|
|
300
413
|
418,665 for `stem`, 195,994 for `phonetic`, 858,654 for `segment`, 2,397
|
|
301
|
-
for `romanize`
|
|
302
|
-
(`*/testdata
|
|
414
|
+
for `romanize`, 2,818 for `deromanize`, and 1,021 search rows for
|
|
415
|
+
`phonetic-search` (`*/testdata/*conformance.jsonl.gz`). A change that makes any one disagree
|
|
303
416
|
on any input fails the build.
|
|
304
417
|
|
|
305
418
|
## Credits and licence
|
|
306
419
|
|
|
307
420
|
MIT. The test words are Wikidata labels (CC0). The rules were tuned on
|
|
308
421
|
Wikidata and PIB Parallel (Press Information Bureau releases), and checked
|
|
309
|
-
on AI4Bharat's Aksharantar and on Wikipedia text
|
|
422
|
+
on AI4Bharat's Aksharantar and on Wikipedia text. No text of theirs ships
|
|
423
|
+
here, except `deromanize`'s word counts (below).
|
|
310
424
|
`normalize` and `segment` were checked in fonts by Google (Noto), Ek Type
|
|
311
425
|
(Anek), SIL, SMC and others. `stem`'s endings were mined from PIB text;
|
|
312
426
|
Wiktionary's inflection tables (CC BY-SA), Universal Dependencies
|
|
313
427
|
treebanks and FLORES+ (CC BY-SA) were used only to measure them. It was
|
|
314
428
|
compared with Snowball, Lucene and the Indic NLP Library.
|
|
429
|
+
|
|
430
|
+
`romanize` and `deromanize` learned from AI4Bharat's Aksharantar (CC BY for
|
|
431
|
+
its hand-collected pairs, CC0 for its mined pairs), Wikidata labels (CC0),
|
|
432
|
+
and IndicXlit's romanizations (MIT) of frequent Wikipedia words.
|
|
433
|
+
`deromanize`'s tables hold word lists: counts of the words of Wikipedia
|
|
434
|
+
(text CC BY-SA 4.0) and, for Bodo and Dogri, of IndicCorp v2 (CC0). Both
|
|
435
|
+
were measured against IndicXlit, on Google's Dakshina (CC BY-SA 4.0) and,
|
|
436
|
+
for `deromanize`, on COMI-LINGUA (CC BY 4.0), used only to measure.
|