Skip to main content

🏝️ NusaNLP: Low-Resource NLP Toolkit for West Nusa Tenggara, Indonesia

PyPI Version Website Facebook Instagram Python 3.9+ License: MIT Tests: 147 passed Coverage: 82%

NusaNLP is an open-source Natural Language Processing (NLP) toolkit engineered specifically for the regional languages of West Nusa Tenggara (Nusa Tenggara Barat / NTB) and Bahasa Indonesia:

  1. Bahasa Sasak (sasak) — Spoken by ~3 million people across the island of Lombok.
  2. Bahasa Samawa / Sumbawa (samawa) — Spoken in Sumbawa and West Sumbawa regencies.
  3. Bahasa Mbojo / Bima (mbojo) — Spoken in Bima Regency, Bima City, and Dompu Regency.
  4. Bahasa Indonesia (indonesian) — Fully integrated with tokenization, clitic handling, stopword filtering, morphological stemming, language identification (100% test accuracy), and bilingual translation alignment.

NusaNLP is built to be production-ready, modular, extensible via a plugin language registry, and research-grade.


📦 Installation

Install NusaNLP directly from PyPI using pip:

pip install nusanlp

Optional Feature Sets

# REST API (FastAPI + Uvicorn server)
pip install "nusanlp[api]"

# Machine Learning additions (Scikit-Learn vectorizers & metrics)
pip install "nusanlp[ml]"

# Development, testing, and linting tools
pip install "nusanlp[dev]"

# All optional dependencies
pip install "nusanlp[api,ml,dev]"

From Source (For Development & Research)

git clone https://github.com/kodetr/nusanlp.git
cd nusanlp
pip install -e ".[dev]"

🚀 Quick Start

1. Unified Pipeline (with Auto-Detection)

import nusanlp
from nusanlp import Pipeline

# Initialize pipeline with automatic language detection
nlp = Pipeline(language="auto")

result = nlp.process("Tiang lalo mangan leq bale")
print(result)

Output:

{
  "language": "sasak",
  "original_text": "Tiang lalo mangan leq bale",
  "normalized_text": "tiang lalo mangan leq bale",
  "tokens": ["tiang", "lalo", "mangan", "leq", "bale"],
  "tokens_without_stopwords": ["lalo", "mangan", "bale"],
  "analysis": [
    {"word": "tiang", "root": "tiang", "prefix": null, "suffix": null, "features": []},
    {"word": "lalo", "root": "lalo", "prefix": null, "suffix": null, "features": []},
    {"word": "mangan", "root": "ang", "prefix": "m", "suffix": "an", "features": ["SUFF:an", "PREF:m"]},
    {"word": "leq", "root": "leq", "prefix": null, "suffix": null, "features": []},
    {"word": "bale", "root": "bal", "prefix": null, "suffix": "e", "features": ["SUFF:e"]}
  ],
  "pos_tags": [
    ["tiang", "NOUN"],
    ["lalo", "VERB"],
    ["mangan", "VERB"],
    ["leq", "ADP"],
    ["bale", "NOUN"]
  ]
}

2. Language Detection

Detect whether a sentence is Sasak, Samawa, Mbojo, or Indonesian:

import nusanlp

res = nusanlp.detect_language("Tiang lalo leq peken")
print(res)
# {'language': 'sasak', 'confidence': 1.0}

res_smw = nusanlp.detect_language("Kaji lalo tama ko peken ling ina")
print(res_smw)
# {'language': 'samawa', 'confidence': 1.0}

res_mbj = nusanlp.detect_language("Nahu ngaha di uma labo ita")
print(res_mbj)
# {'language': 'mbojo', 'confidence': 1.0}

3. Text Normalization

# Lowercasing, whitespace, repeated character & slang normalization
norm = nusanlp.normalize("AQ   LEKOOOOK  GATI", language="sasak")
print(norm)
# Output: "aku lekook gati"

4. Modular Tokenizer & Clitic Separation

tokens = nusanlp.tokenize("Kaji lalo-mo ko peken", language="samawa")
print(tokens)
# Output: ['Kaji', 'lalo', '-mo', 'ko', 'peken']

5. Stopword Removal

clean = nusanlp.remove_stopwords("nahu ngaha di uma labo ita", language="mbojo")
print(clean)
# Output: ['ngaha', 'uma']

6. Multilingual Dictionary Lookup

entry = nusanlp.lookup("mangan", language="sasak")
print(entry)
# {'word': 'mangan', 'language': 'sasak', 'translations': {'indonesian': 'makan'}, 'pos': 'VERB', 'lemma': 'mangan'}

entry_smw = nusanlp.lookup("balong", language="samawa")
print(entry_smw)
# {'word': 'balong', 'language': 'samawa', 'translations': {'indonesian': 'baik / bagus', 'english': 'good'}, 'pos': 'ADJ', 'lemma': 'balong'}

7. Machine Learning & TF-IDF Integration (Scikit-Learn)

NusaNLP seamlessly integrates into TfidfVectorizer and CountVectorizer, providing morphological lemmatization and low-resource stopword removal to prevent vocabulary explosion:

from sklearn.feature_extraction.text import TfidfVectorizer
import nusanlp

corpus = [
    "Tiang lalo mangan leq bale adat Sasak.",
    "Kaji mangan leq bale adat Samawa.",
    "Nahu ngaha di uma rime Mbojo."
]

# Method A: Use NusaNLP custom tokenizer callable directly
vectorizer = TfidfVectorizer(tokenizer=nusanlp.get_tfidf_tokenizer(), lowercase=False)
X = vectorizer.fit_transform(corpus)
print("TF-IDF Features:", vectorizer.get_feature_names_out())

# Method B: Preprocess texts beforehand
clean_docs = [nusanlp.preprocess_for_tfidf(doc) for doc in corpus]
# clean_docs: ['mangan bale adat sasak', 'mangan bale adat samawa', 'ngaha uma rime mbojo']

🏛️ Architecture & Project Structure

nusanlp/
│
├── src/
│   ├── nusanlp/
│   │   ├── __init__.py                 # Unified API exports
│   │   ├── core/
│   │   │   ├── pipeline.py             # Unified Pipeline engine
│   │   │   ├── language.py             # BaseLanguage & LanguageRegistry
│   │   │   ├── config.py               # Pipeline & Normalizer configs
│   │   │   └── types.py                # Pydantic models & enums
│   │   │
│   │   ├── languages/
│   │   │   ├── base.py                 # AbstractLanguageHandler
│   │   │   ├── sasak/                  # Sasak modules
│   │   │   ├── samawa/                 # Samawa (Sumbawa) modules
│   │   │   ├── mbojo/                  # Mbojo (Bima) modules
│   │   │   └── indonesian/             # Indonesian language module
│   │   │
│   │   ├── preprocessing/
│   │   │   ├── normalize.py            # Multi-language normalization
│   │   │   └── clean.py                # Text cleaning utilities
│   │   │
│   │   ├── tokenization/
│   │   │   └── tokenizer.py            # RuleBasedTokenizer
│   │   │
│   │   ├── morphology/
│   │   │   └── analyzer.py             # MorphologicalAnalyzer
│   │   │
│   │   ├── lexicon/
│   │   │   ├── dictionary.py           # Multilingual dictionary
│   │   │   └── loader.py               # JSON/CSV loaders
│   │   │
│   │   ├── language_detection/
│   │   │   ├── detector.py             # detect_language API
│   │   │   └── model.py                # N-gram Statistical Classifier
│   │   │
│   │   ├── cli/
│   │   │   └── main.py                 # CLI entry point
│   │   │
│   │   ├── api/
│   │   │   └── app.py                  # FastAPI REST API
│   │   │
│   │   └── utils/
│   │       ├── loaders.py              # Resource discovery
│   │       └── validators.py           # Pydantic data validators
│   │
│   └── sasaknlp/                       # Backward-compatibility layer
│
├── resources/
│   ├── sasak/                          # Balai Bahasa NTB lexicon & stopwords
│   ├── samawa/                         # Sumbawa lexicon & stopwords
│   └── mbojo/                          # Bima/Dompu lexicon & stopwords
│
├── datasets/
├── training/                           # Language detector training scripts
├── tests/                              # 134 automated unit tests
├── examples/                           # Usage examples
└── pyproject.toml

💻 Command Line Interface (CLI)

# Language Detection
nusanlp detect "Tiang lalo leq peken"

# Tokenize
nusanlp tokenize --lang sasak "Tiang lalo leq peken"

# Normalize
nusanlp normalize --lang mbojo "NAHU MAI DI KAMPUNG"

# Dictionary Lookup
nusanlp dictionary lookup --lang samawa "bale"

# End-to-end Process
nusanlp process --lang auto "Tiang lalo mangan leq bale" --json

🌐 REST API

Run the optional FastAPI server:

uvicorn nusanlp.api.app:app --host 127.0.0.1 --port 8000 --reload

Endpoints available:

  • POST /detect-language
  • POST /tokenize
  • POST /normalize
  • POST /process
  • GET /dictionary/{language}/{word}
  • GET /docs (Interactive Swagger UI)

🧪 Testing & Evaluation

Run test suite with pytest:

pytest tests -v

Run unified scientific evaluation benchmark across all 3 languages:

python3 scripts/evaluate_nusanlp_all.py

📊 Scientific Evaluation Highlights

NusaNLP has undergone rigorous empirical validation across 30,000 morphological pairs and 3,000 language detection sentences:

Evaluation Dimension Dataset Metric Score
Sasak Stemmer Benchmark 10k Exact Match Accuracy 93.23% (8,539 words/s)
Samawa Stemmer Benchmark 10k Exact Match Accuracy 94.63% (41,727 words/s)
Mbojo Stemmer Benchmark 10k Exact Match Accuracy 93.20% (42,028 words/s)
Language Identification Test Set 3,000 sentences Global Accuracy 99.90% (Macro-F1: 99.90%)
Pipeline Latency Authentic Sentences Mean Latency 0.046 - 0.358 ms / sentence
Downstream TF-IDF ML Multi-dialect Corpus Vocabulary Compression 14.1% feature reduction (99.4% Acc)

See the complete evaluation report in docs/laporan_evaluasi_nusanlp.md.


📈 Scientific Figures & Benchmark Visualizations

Figure 1: Morphology Accuracy & Affix Decomposition

Figure 1: Morphology Accuracy Figure 1: Exact-match stemming accuracy and affix breakdown across Sasak (93.23%), Samawa (94.63%), and Mbojo (93.20%) on 30,000 empirical evaluation pairs.

Figure 2: Dialect Performance & Cross-Dialect Robustness

Figure 2: Dialect Performance Figure 2: Morphological stemmer resilience across 11 standardized regional dialects of West Nusa Tenggara.

Figure 3: Language Identification Confusion Matrix & Classification Breakdown

Figure 3: Confusion Matrix Figure 3: Four-class normalized confusion matrix and language classification performance across 3,000 test sentences (Global Accuracy: 99.90%).

Figure 4: Pipeline Throughput & Latency Distribution

Figure 4: Pipeline Benchmark Figure 4: Computational throughput (sentences/second) and sub-millisecond execution latency across all regional language pipelines.

Figure 5: Dataset Acquisition Architecture & Corpus Pipeline

Figure 5: Dataset Acquisition Pipeline Figure 5: Multi-tier corpus engineering workflow, dictionary validation, and benchmark synthesis pipeline encompassing 959,279+ records.


📚 Datasets & Resources

  • Total Dataset Volume: 959,279 records (Sentence corpora, morphology benchmarks, language detection, and official dictionaries).
  • Official Dictionaries (Balai Bahasa NTB): 3,352 Sasak, 659 Samawa, 2,777 Mbojo entries (100% Pydantic compliant).
  • Curated Stopwords: 440 functional words (159 Sasak, 147 Samawa, 134 Mbojo).
  • See detailed documentation in datasets/README.md and docs/PANDUAN_LENGKAP.md.

📖 Citation

If you use NusaNLP in your academic work or research, please cite:

@software{nusanlp2026,
  author = {kodetr},
  title = {NusaNLP: An Open-Source Natural Language Processing Toolkit for Low-Resource Languages of West Nusa Tenggara, Indonesia},
  year = {2026},
  url = {https://github.com/kodetr/nusanlp}
}

🌐 Author & Connect

Developed and maintained by kodetr:


📄 License

Distributed under the MIT License. See LICENSE for details.

Metadata

Release files for nusanlp 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nusanlp 0.2.3
File Size Uploaded Provenance
nusanlp-0.2.3.tar.gz 604.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for nusanlp 0.2.3
File Interpreter ABI Platform
nusanlp-0.2.3-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / nusanlp-0.2.3.tar.gz

Download URL nusanlp-0.2.3.tar.gz
Size 604.5 kB
Tags Source
SHA-256 checksum
How to use checksums
995ac11bbd42a8eee0aa2d37225992e191829b55c4679709b234db74061309fe
BLAKE2b-256 checksum
How to use checksums
13b582e2c56bdc73a0fcf75d4e91f413c2ce39af9b44fb4a2b1a0e59d297709c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.0

Release files / nusanlp-0.2.3-py3-none-any.whl

Download URL nusanlp-0.2.3-py3-none-any.whl
Size 657.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f79774f96a82c37b60c2cd8864eedbcf3b8df0cd4e5d53a02bda75b514f948a3
BLAKE2b-256 checksum
How to use checksums
487e9739fb57e9e01feb05c99ae90ceea3071704508b9a3a54cc763376c1ca0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.0

Security for nusanlp 0.2.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page