NLP & Tokenization¶
The olaverse.nlp module is the core of the SDK β production-ready tools for African language text processing, detection, diacritization, tokenization, and preprocessing.
pip install olaverse # all NLP tools included (no GPU required)
pip install olaverse[deeplearning] # adds LIDNeural5/LIDNeural25/LIDNeural5_1, diacnet-1.0/1.1, diactag-1.0
pip install olaverse[onnx] # adds the int8 diactag-1.0 backend
pip install olaverse[lid] # adds LIDLite25 (fastText, 25 languages)
pip install olaverse[retrieval] # adds Reranker, Embedder
Language Detection¶
Two models cover the same 5 languages at very different scales. Pick based on your latency and accuracy requirements.
- 1.1 MB JSON model
- 0.014 ms per sentence
- 98.12% macro accuracy
- TF-IDF + Logistic Regression
- Pure Python β no torch, no transformers
- 484 MB β XLM-RoBERTa 125M
- 13.3 ms per sentence (CPU/GPU)
- 98.96% macro accuracy
- Fine-tuned on castorini/afriberta_large
- Requires
olaverse[deeplearning]
LIDLite5¶
Model Card: olaverse/lid-lite-5
from olaverse import LIDLite5, detect_language
# Class interface
detector = LIDLite5()
detector.predict("Bawo ni, se daadaa ni?") # β 'yor'
detector.predict("Sannu, yaya kake?") # β 'hau'
detector.predict("How far, wetin dey happen?") # β 'pcm'
# Probability distribution over all 5 classes
detector.predict_proba("Kedu, α» dα» mma?")
# β {'eng': 0.037, 'hau': 0.024, 'ibo': 0.807, 'pcm': 0.021, 'yor': 0.112}
# Quick one-liner
detect_language("E kaaro, bawo ni?") # β 'yor'
olaverse.nlp.LIDLite5 ¶
Lightweight, zero-dependency TF-IDF + Logistic Regression Language Detector for 5 languages: Yoruba ('yor'), Hausa ('hau'), Igbo ('ibo'), Pidgin ('pcm'), and English ('eng').
olaverse.nlp.detect_language ¶
Detect the language of the given text using LIDLite5. Returns: 'yor' (Yoruba), 'hau' (Hausa), 'ibo' (Igbo), 'pcm' (Pidgin), or 'eng' (English).
LIDNeural5¶
Model Card: olaverse/lid-neural-5
from olaverse import LIDNeural5
detector = LIDNeural5()
detector.load() # downloads once from Hugging Face, cached after first run
detector.predict("Kedu ka α» mere today?") # β 'ibo'
detector.predict("αΊΈ kÑà Ñrα»Μ, αΊΉ kÑà bα»Μ") # β 'yor'
probs = detector.predict_proba("How far, wetin dey happen?")
# β {'pcm': 0.991, 'eng': 0.006, 'ibo': 0.001, 'hau': 0.001, 'yor': 0.001}
Batch Inference¶
predict_batch and predict_proba_batch run a single batched forward pass β much faster than calling predict() in a loop over a dataset.
texts = ["Bawo ni?", "Kedu α» dα»?", "How far?", "Sannu dai."]
# Returns a list of predicted language codes
langs = detector.predict_batch(texts)
# β ['yor', 'ibo', 'pcm', 'hau']
# Returns a list of probability dicts β one per input
probs = detector.predict_proba_batch(["Bawo ni?", "Kedu?"])
# β [
# {'yor': 0.991, 'eng': 0.005, ...},
# {'ibo': 0.987, 'eng': 0.008, ...},
# ]
Per-language accuracy:
| Language | Precision | Recall | F1-Score |
|---|---|---|---|
Yoruba (yor) |
99.60% | 99.60% | 99.60% |
Hausa (hau) |
99.60% | 99.20% | 99.40% |
Igbo (ibo) |
98.79% | 98.20% | 98.50% |
Nigerian Pidgin (pcm) |
99.20% | 98.80% | 99.00% |
English (eng) |
97.63% | 99.00% | 98.31% |
| Overall (Macro) | 98.96% |
olaverse.nlp.LIDNeural5 ¶
Bases: _HFSequenceClassifierLID
High-accuracy transformer-based language identifier for 5 Nigerian languages.
Base Model: castorini/afriberta_large (XLM-RoBERTa, 125M parameters) Fine-tuned on: Yoruba ('yor'), Hausa ('hau'), Igbo ('ibo'), Pidgin ('pcm'), English ('eng') Validation accuracy: 98.96% macro-F1
Requires: pip install olaverse[deeplearning]
LIDLite25 / LIDNeural25 β 25-language identification¶
New in v0.1.5
Beyond the 5 core Nigerian languages, LIDLite25 and LIDNeural25 cover 25 languages spanning Africa, Europe, and Asia β for products that need broader coverage than Yoruba/Hausa/Igbo/Pidgin/English.
Model Cards: olaverse/lid-lite-25 Β· olaverse/lid-neural-25.1 Β· olaverse/lid-neural-25.2
Both come in two checkpoints, tuned for different input lengths β pick the variant= that matches your traffic:
variant= |
Use for |
|---|---|
"passages" |
Documents, articles, paragraph-length text |
"questions" (default) |
Search queries, chat messages, short user input |
LIDLite25 is a CPU-only fastText classifier (sub-millisecond, ~5-10MB per checkpoint); LIDNeural25 is an XLM-RoBERTa-base sequence classifier β higher accuracy on short text (98.2% vs 97.3%), at the cost of needing transformers/torch.
pip install olaverse[lid] # LIDLite25 (fastText)
pip install olaverse[deeplearning] # LIDNeural25 (transformers)
from olaverse import LIDLite25, LIDNeural25
lite = LIDLite25(variant="questions")
lite.predict("What causes ocean tides?") # β 'eng'
neural = LIDNeural25(variant="questions")
neural.load()
neural.predict_proba("What causes ocean tides?")
# β {'eng': 0.999, 'fra': 0.0003, ...}
Zulu/Xhosa confusion on short text
Both models score noticeably lower on Zulu/Xhosa short-text classification (F1 ~0.77-0.79) than every other language (β₯0.98) β the two languages are closely related with substantial shared vocabulary. This holds across both architectures, so treat predictions between these two specifically with reduced confidence on short input.
olaverse.nlp.LIDLite25 ¶
Lightweight, CPU-only fastText language identifier for 25 languages. Sub-millisecond inference, ~5-10MB per checkpoint, no GPU required.
Two checkpoints for two input lengths (variant=): "passages" β long-form text (documents, articles) "questions" β short text (queries, chat messages) [default]
For higher accuracy at the cost of needing transformers/torch, see LIDNeural25.
Requires: pip install olaverse[lid]
olaverse.nlp.LIDNeural25 ¶
Bases: _HFSequenceClassifierLID
Transformer-based (XLM-RoBERTa, 125M parameters) language identifier for 25 languages β higher accuracy than LIDLite25, especially on short text, at the cost of needing transformers/torch.
Two checkpoints for two input lengths (variant=): "passages" β lid-neural-25.1, long-form text (documents, articles) "questions" β lid-neural-25.2, short text (queries, chat messages) [default]
Requires: pip install olaverse[deeplearning]
LIDNeural5_1 β Nigerian-only, no English fallback¶
Model Card: olaverse/lid-neural-5.1
A compact (~31M parameter) classifier built on mist-encoder-base-ng, covering only the 4 main Nigerian languages β no English/"other" class.
from olaverse import LIDNeural5_1
detector = LIDNeural5_1()
detector.predict("Ina kwana?") # β 'Hausa'
No English class
Out-of-set input (English or any other language) will be confidently mislabelled, most often as Nigerian Pidgin. If your input may include English, use LIDLite25/LIDNeural25/LIDNeural5 instead β this model always picks one of the four Nigerian languages.
olaverse.nlp.LIDNeural5_1 ¶
Bases: _HFSequenceClassifierLID
Compact language identifier for the 4 main Nigerian languages, built as a classification head on olaverse/mist-encoder-base-ng (ModernBERT, ~31M parameters).
Labels: 'Hausa', 'Yoruba', 'Igbo', 'Nigerian Pidgin'.
No English/'other' class β out-of-set languages (e.g. English) will be confidently mislabelled, most often as Nigerian Pidgin. Use LIDLite25 or LIDNeural25 instead if inputs may include English or other non-Nigerian languages.
Requires: pip install olaverse[deeplearning]
Diacritization¶
DiacNet and DiacTag restore tones and diacritical marks stripped from text β the critical front-end step for TTS, language learning, and NLP accuracy. The small DiacNet models cover Yoruba and Igbo with no extras; diacnet-1.0/1.1 and diactag-1.0 cover 10 languages each.
For new work prefer diactag-1.0: it classifies each character instead of generating text, so it cannot alter your input beyond adding marks, and it wins on 9 of 10 languages.
Available Models¶
| Model ID | Language | Method | Speed | Accuracy | Size |
|---|---|---|---|---|---|
diacnet-yor-viterbi |
Yoruba | Viterbi n-gram | β‘ Fast | Good | ~7 MB |
diacnet-yor-db |
Yoruba (dot-below only) | KNN backoff | β‘ Fast | Dot-below focused | ~2 MB |
diacnet-yor |
Yoruba | BiLSTM | Medium | 93.35% char | 2.4 MB |
diacnet-yor-x |
Yoruba (full) | XLM-RoBERTa | Slow | 82.46% word | 503 MB |
diacnet-ig |
Igbo | KNN backoff | β‘ Fast | Good | ~3 MB |
diacnet-1.0 |
10 languages (see below) | ByT5 seq2seq | Slow | ~0.02 median CER | ~300 MB |
diacnet-1.1 |
10 languages | ByT5 seq2seq | Slow | 0.0002β0.2006 DER | ~1.1 GB |
diactag-1.0 |
10 languages | character tagger | β‘ 244 chars/s CPU | 0.0132 DER, 1.0 compliance | 150 MB / 38 MB int8 |
Quick Functions¶
from olaverse import diacritize_yoruba, diacritize_yoruba_dot_below, diacritize_igbo
# Yoruba β full tonal diacritics (Viterbi, fast)
diacritize_yoruba("Ojo lo si oja lana")
# β 'ΓjΓ³ lα» sΓ α»jΓ lana'
# Yoruba β dot-below vowels only (KNN)
diacritize_yoruba_dot_below("Ojo lo si oja")
# β 'α»jα» lo si α»ja'
# Igbo
diacritize_igbo("Kedu ka i mere")
# β 'Kedα»₯ ka α» mere'
Unified Diacritizer Class¶
Use Diacritizer when you need to choose a specific model, switch between neural backends, or process mixed-language input.
from olaverse.nlp import Diacritizer
# Default: fast Viterbi for Yoruba
d = Diacritizer(model="diacnet-yor-viterbi")
d.restore("Ojo lo si oja lana")
# β 'ΓjΓ³ lα» sΓ α»jΓ lana'
# High-accuracy neural (requires olaverse[deeplearning])
d_neural = Diacritizer(model="diacnet-yor-x")
d_neural.restore("Ojo lo si oja lana")
Auto-routing (model="auto") β New in v0.1.4¶
Set model="auto" to skip manual language selection. LIDLite5 detects the language on each call and routes to the correct backend β Yoruba β diacnet-yor-viterbi, Igbo β diacnet-ig. Both LIDLite5 and the target diacritizer are lazy-loaded on first use.
from olaverse.nlp import Diacritizer
d = Diacritizer(model="auto")
# Yoruba text β routes to diacnet-yor-viterbi
d.restore("Ojo lo si oja lana")
# β 'ΓjΓ³ lα» sΓ α»jΓ lana'
# Igbo text β routes to diacnet-ig
d.restore("Kedu ka i mere")
# β 'Kedα»₯ ka α» mere'
diacnet-1.0 β multilingual, 10 languages (New in v0.1.5)¶
Model Card: olaverse/diacnet-1.0
A single joint ByT5 model that restores diacritics across 10 languages β Yoruba, Igbo, Hausa, Vietnamese, Polish, Turkish, Portuguese, Spanish, French, and Italian β selected via the lang= argument, no separate per-language model or upstream LID step required.
from olaverse.nlp import Diacritizer
d = Diacritizer(model="diacnet-1.0", lang="fr")
d.restore("Le cafe est tres chaud, mais il prefere le the.")
# β 'Le cafΓ© est trΓ¨s chaud, mais il prΓ©fΓ¨re le thΓ©.'
d_yo = Diacritizer(model="diacnet-1.0", lang="yo")
d_yo.restore("se eranko naa si gbo o?")
# β 'αΉ£Γ© αΊΉranko nÑà sΓ¬ gbα»Μ α»?'
Supported lang= codes: "yo", "vi", "ig", "ha", "pl", "tr", "pt", "es", "fr", "it".
Long text is segmented automatically. diacnet-1.0 was trained on
sentence-length input (median 58 bytes), so multi-sentence text is split on
sentence boundaries, restored a sentence at a time, and rejoined. Without this,
a 358-character French paragraph comes back at 235 characters β truncated
mid-sentence with the tail dropped.
Diacritizer(model="diacnet-1.0", lang="fr") # segments (default)
Diacritizer(model="diacnet-1.0", lang="fr", split_sentences=False) # one pass
Diacritizer(model="diacnet-1.0", lang="fr", splitter=my_splitter) # your own
Very short fragments still degenerate
Single words fall below the trained input length, and the model rewrites rather than annotates:
| Input | lang= |
Output |
|---|---|---|
"el nino" |
es |
'el niΓ±o\nel niΓ±o\nel niΓ±oβ¦' (repetition loop) |
"je nai pas" |
fr |
'je nai pas pas je nai pas pasβ¦' (repetition loop) |
"cafe" |
fr |
'cafαΊΉΜ' (Yoruba dot-below on a French word) |
"nino" |
es |
'niΓ±os' (inflection changed) |
"pho" |
vi |
'phα»i>' (wrong word + stray character) |
"citta" |
it |
'cittΓ ?' (punctuation invented) |
Pass whole sentences with their punctuation. It also restores diacritics
only β it does not insert apostrophes, so "cest fini" does not become
"c'est fini".
Yoruba is the hardest language for this model
Yoruba's median CER (0.110) is nearly 3x the next-highest language β genuine tonal ambiguity (the same base letters can carry multiple valid tone patterns), not a model weakness. For Yoruba specifically, the dedicated diacnet-yor-viterbi/diacnet-yor-x models above may perform better; diacnet-1.0's advantage is breadth (10 languages, one model), not peak Yoruba accuracy.
diacnet-1.1 β same architecture, larger corpus (New in v0.3.0)¶
Model Card: olaverse/diacnet-1.1
Retrained on a much larger web-sourced corpus. A large improvement on Vietnamese
(0.1264 β 0.0460 DER), Turkish (0.0447 β 0.0068), Polish (0.0357 β 0.0058) and
Italian (0.0015 β 0.0002); a regression on Yoruba (0.1554 β 0.2006), because the
larger corpus is mostly under-tone-marked and the model learned to omit marks
too. It takes the same lang=, split_sentences= and splitter= arguments as
diacnet-1.0.
d = Diacritizer(model="diacnet-1.1", lang="vi")
d.restore("Toi khong biet tieng Viet")
# β 'TΓ΄i khΓ΄ng biαΊΏt tiαΊΏng Viα»t'
diactag-1.0 β per-character tagger, 10 languages (New in v0.3.0)¶
Model Card: olaverse/diactag-1.0 Β· Full guide: DiacTag β
Classifies each character into a diacritic transformation instead of generating
output text. It has no mechanism for changing, inserting or deleting a base
character, so strip(output) == strip(input) holds by construction β asserted on
every call. 37.6M parameters against 580M, and it beats diacnet-1.1 on 9 of 10
languages (Yoruba 0.2006 β 0.0836 DER, Hausa 0.0593 β 0.0041).
from olaverse.nlp import Diacritizer
d = Diacritizer(model="diactag-1.0", lang="yo")
d.restore("se eranko naa si gbo o?")
# β 'αΉ£Γ© αΊΉranko nÑà sΓ¬ gbα»Μ α»?'
lang= takes ISO-639-1 ("yo") or ISO-639-3 ("yor"). Omit it and the
model's own LID head detects the language, at a cost of ~0.0001 DER:
d = Diacritizer(model="diactag-1.0")
d.restore("Co ay rat dam dang") # β 'CΓ΄ αΊ₯y rαΊ₯t ΔαΊ£m Δang'
d.detect_language("Lodz jest piekna") # β ('pol', 0.9999)
Per-character confidence and abstention. Characters below min_confidence
are left exactly as the caller typed them. At 0.9, ~97% of characters are
restored at 99.6% accuracy and the rest are flagged. The threshold is also a
per-call argument, so one loaded model serves several pipelines.
d = Diacritizer(model="diactag-1.0", lang="yor", min_confidence=0.9)
text, details = d.restore("se eranko naa", return_details=True)
review = [c for c in details if c.confidence < 0.9]
# each detail: .char, .confidence, .abstained, .protected
CPU serving. onnx=True loads the int8 export β 3x faster, 4x smaller, with
language auto-detection intact, and compliance stays 1.0000 because the
guarantee is architectural rather than a property of numeric precision.
device= selects "cpu", "cuda" or "mps" on the PyTorch backend.
Lexicon reranking (use_lexicon=True, off by default) rescores predicted
non-words against attested spellings of the same stripped form. Measure it on
your data before enabling it: on diacbench it cuts non-word outputs by 27% but
raises YorΓΉbΓ‘ DER by 15% (0.0836 β 0.0961), because density gating shrank the
YorΓΉbΓ‘ lexicon to 18,436 forms β so "not in the lexicon" often means "rare word
we didn't keep", and correct output gets overwritten. See
DiacTag β Lexicon reranking.
Differences from the diacnet models
- No sentence splitting needed. Documents are handled with overlapping
sliding windows, so
split_sentences=/splitter=do not apply. - URLs, emails,
@handlesandCONSTANT_NAMESpass through untouched, and marks already in the input are never silently deleted. - It cannot fix typos. Insertions and deletions are impossible by construction β that is the price of the guarantee.
- ONNX exports predating 2026-08-04 have no LID head. The SDK reads
the capability off the graph, so against one of those
lang=is required and calling without it raises rather than silently assuming Yoruba.
olaverse.nlp.Diacritizer ¶
Diacritizer(model: str = 'diacnet-yor-viterbi', lang: str = None, split_sentences: bool = True, splitter: callable = None, min_confidence: float = 0.0, use_lexicon: bool = False, onnx: bool = False, device: str = 'cpu')
Unified interface for restoring diacritics in African languages.
Pass a model ID to use a specific backend, or model="auto" to detect
the language automatically and route to the appropriate diacritizer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
One of:
|
'diacnet-yor-viterbi'
|
lang
|
str
|
Target language for the multilingual models. One of
|
None
|
split_sentences
|
bool
|
|
True
|
splitter
|
callable
|
|
None
|
min_confidence
|
float
|
|
0.0
|
use_lexicon
|
bool
|
|
False
|
onnx
|
bool
|
|
False
|
device
|
str
|
|
'cpu'
|
Methods:¶
detect_language ¶
Identify the language of text. "diactag-1.0" only β it is the
only model with a language-identification head of its own.
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
Tuple[str, float]
|
|
restore ¶
restore(text: str, lang: str = None, min_confidence: float = None, return_details: bool = False) -> Union[str, Tuple[str, List]]
Restore diacritics in the given text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Plain text (tones/diacritics stripped or missing). |
required |
lang
|
str
|
Per-call language override for the multilingual models, replacing the one given at construction. |
None
|
min_confidence
|
float
|
|
None
|
return_details
|
bool
|
|
False
|
Returns:
| Type | Description |
|---|---|
Union[str, Tuple[str, List]]
|
Union[str, Tuple[str, List]]: the restored text, or |
olaverse.nlp.DiacTagDecoder ¶
DiacTagDecoder(model_name: str = 'olaverse/diactag-1.0', ckpt: str = _DIACTAG_DEFAULT_CKPT, device: str = 'cpu', min_confidence: float = 0.0, use_lexicon: bool = False, onnx: bool = False)
diactag-1.0 diacritic restoration (per-character tagger) β 10 languages.
Unlike the seq2seq diacnet line, this model classifies each character
into a diacritic transformation instead of generating output text. It has no
mechanism for changing, inserting or deleting a base character, so::
strip_diacritics(output) == strip_diacritics(input)
holds by construction. The invariant is asserted on every call rather than assumed, and it survives int8 quantisation because it is a property of the architecture, not of numeric precision.
What that buys over diacnet-1.1: no text corruption, per-character
calibrated confidence, built-in language detection, and 37.6M parameters
against 580M β CPU serving is the default rather than a compromise. What it
costs: the model cannot fix a typo, because fixing one would mean inserting
or deleting a character.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_name
|
str
|
Hugging Face repo id. |
'olaverse/diactag-1.0'
|
ckpt
|
str
|
Checkpoint filename in the repo. Ignored when |
_DIACTAG_DEFAULT_CKPT
|
device
|
str
|
|
'cpu'
|
min_confidence
|
float
|
Abstention threshold in [0, 1]. Characters the model is
less sure about than this are left exactly as the caller typed
them. |
0.0
|
use_lexicon
|
bool
|
Rerank predicted non-words against attested spellings of the same stripped form. Conservative β it only ever chooses among forms seen in the corpus. Measure it on your data before enabling it: on diacbench it cuts non-word outputs by 27% but raises Yoruba DER by 15% (0.0836 -> 0.0961), because the density gating that keeps the lexicon clean shrank the Yoruba vocabulary to 18,436 forms, so "not in the lexicon" often means "rare or inflected word we didn't keep" and correct output gets overwritten. Off by default. |
False
|
onnx
|
bool
|
Load the int8 ONNX export instead of the PyTorch checkpoint β
3x faster and 4x smaller on CPU for +0.03pp DER, and the strip
guarantee survives quantisation because it is architectural.
Language auto-detection works here too, matching the PyTorch
head; against an export predating the LID head, |
False
|
Methods:¶
normalize_language ¶
Map a language code to the ISO-639-3 form the model uses, raising on
anything it does not support. None passes through and means
"detect it".
detect_language ¶
Identify the language of text with the model's own LID head.
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
Tuple[str, float]
|
|
decode ¶
decode(text: str, lang: str = None, min_confidence: float = None, return_details: bool = False) -> Union[str, Tuple[str, List]]
Restore diacritics.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input text. Documents are handled directly β the model slides an overlapping window and keeps only the centre of each, so every character is predicted with context on both sides. |
required |
lang
|
str
|
ISO-639-3 or ISO-639-1 code. |
None
|
min_confidence
|
float
|
Per-call override of the abstention threshold. |
None
|
return_details
|
bool
|
Also return a list of per-character results
( |
False
|
Returns:
| Type | Description |
|---|---|
Union[str, Tuple[str, List]]
|
Union[str, Tuple[str, List]]: the restored text, or |
Tokenization β OTK-BPE-50k¶
Model Card: olaverse/otk-bpe-50k
Byte-Level BPE tokenizers trained on dedicated corpora for each Nigerian language. 0% out-of-vocabulary tokens via raw UTF-8 byte fallback.
Why OTK-BPE?¶
General-purpose tokenizers like GPT-4's cl100k tokenize African languages character-by-character, blowing up sequence lengths and wasting context. OTK-BPE-50k learns proper subwords from native text:
| Model | Language | Vocab | Efficiency vs GPT-4 |
|---|---|---|---|
otk-bpe-50k-yo |
Yoruba | 50,000 | 63% fewer tokens |
otk-bpe-50k-ig |
Igbo | 50,000 | ~60% fewer tokens |
otk-bpe-50k-ha |
Hausa | 50,000 | ~58% fewer tokens |
otk-bpe-50k-pcm |
Nigerian Pidgin | 50,000 | ~55% fewer tokens |
otk-bpe-50k-naija |
Unified (all 4) | 50,000 | Balanced |
Usage¶
from olaverse import Tokenizer
# Load by language code
tok_yo = Tokenizer("yo") # Yoruba
tok_ig = Tokenizer("ig") # Igbo
tok_ha = Tokenizer("ha") # Hausa
tok_pcm = Tokenizer("pcm") # Nigerian Pidgin
tok_all = Tokenizer("naija") # Unified
# Encode / decode
ids = tok_yo.encode("αΊΈ kΓΊ Γ bα»Μ")
print(ids) # β [124, 381]
print(tok_yo.decode(ids)) # β 'αΊΈ kΓΊ Γ bα»Μ'
# For fine-tuning / dataset preparation
sentences = ["Bawo ni?", "Se daadaa ni?", "Mo dupe."]
all_ids = [tok_yo.encode(s) for s in sentences]
olaverse.nlp.Tokenizer ¶
A unified BPE Tokenizer for African languages.
Nigerian family (fixed 50k vocab): 'yoruba'/'yo', 'igbo'/'ig', 'hausa'/'ha', 'pidgin'/'pcm', and 'naija' (unified).
Multilingual family (50k/100k/150k vocab, see olaverse/otk-bpe): 'sw-50k', 'sw-100k', 'sw-150k' (Swahili); 'kin-50k', 'kin-100k', 'kin-150k' (Kinyarwanda); 'merged-50k', 'merged-100k', 'merged-150k' (French + Kinyarwanda + English + Swahili).
Tokenization β OTK-BPE (Multilingual) (New in v0.1.5)¶
Model Card: olaverse/otk-bpe
A companion tokenizer family for Swahili, Kinyarwanda, and a merged French + Kinyarwanda + English + Swahili vocabulary β each available at three vocab sizes. Same Tokenizer class, different lang= values.
lang= |
Languages | Vocab sizes |
|---|---|---|
sw-50k / sw-100k / sw-150k |
Swahili | 50k / 100k / 150k |
kin-50k / kin-100k / kin-150k |
Kinyarwanda | 50k / 100k / 150k |
merged-50k / merged-100k / merged-150k |
French + Kinyarwanda + English + Swahili | 50k / 100k / 150k |
150k is the recommended default β fertility and entity-handling both improve monotonically from 50k β 100k β 150k in every benchmark on the model card, with no exceptions. Step down only if embedding-table size is a hard constraint.
from olaverse import Tokenizer
tok = Tokenizer("sw-150k")
ids = tok.encode("Habari yako? Leo ni siku nzuri sana π")
tok.decode(ids)
# β 'Habari yako? Leo ni siku nzuri sana π'
tok_merged = Tokenizer("merged-150k") # French + Kinyarwanda + English + Swahili
Text Normalization (TTS)¶
TTSNormalizer converts raw text into a form suitable for speech synthesis β expanding numbers, abbreviations, and punctuation into their spoken equivalents.
from olaverse import TTSNormalizer
# Yoruba normalization
norm = TTSNormalizer(lang="yo")
norm.normalize("Dr. Ade lo si oja lana")
# β 'Dα»ΜkΓtΓ Ade lo si oja lana'
norm.normalize("O san β¦1,200")
# β 'O san α»Μkan αΊΉgbαΊΉΜrΓΊn mΓ©jΓ¬'
# Igbo normalization
norm_ig = TTSNormalizer(lang="ig")
norm_ig.normalize("Prof. Obi ra ulo")
# β 'Purofesα» Obi ra ulo'
olaverse.nlp.TTSNormalizer ¶
Normalizes text for TTS processing by expanding numbers, abbreviations, and symbols into their spoken equivalents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lang
|
str
|
Target language. One of |
'yo'
|
Methods:¶
expand_abbreviations ¶
Expand abbreviations to their spoken forms.
expand_numbers ¶
Expand digit characters to spoken words (digit-by-digit).
normalize ¶
Run the full normalization pipeline: abbreviations β numbers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Raw input text. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Normalized text ready for phonetic processing. |
Nigerian Pidgin Normalization β NaijaNormalizer¶
NaijaNormalizer is a Pidgin-specific TTS normalizer built on top of TTSNormalizer. It adds a pre-processing step that expands informal Pidgin spellings β SMS shorthand, phonetic spellings, loan abbreviations β before running the standard abbreviation and number expansion.
from olaverse import NaijaNormalizer
norm = NaijaNormalizer()
# Informal spellings expanded first, then standard normalization
norm.normalize("Oga, 2moro na Sunday. Call am nd tell am 2 come.")
# β 'Oga, tomorrow na Sunday. Call am and tell am to come.'
norm.normalize("e don finish. tnx 4 d help, u r d best!")
# β 'e don finish. thanks for the help, you are the best!'
# normalize_informal() only β skip abbreviations/number expansion
norm.normalize_informal("dis tin dey hard nd i no sabi wetin 2 do")
# β 'this tin dey hard and i no sabi wetin to do'
Informal expansion map includes (35+ entries):
| Input | Output | Input | Output |
|---|---|---|---|
2moro |
tomorrow | 2day |
today |
b4 |
before | 4 |
for |
dis |
this | dat |
that |
nd / n |
and | u |
you |
pls |
please | tnx |
thanks |
lol |
laugh | smh |
sigh |
jst |
just | wat |
what |
wen |
when | hw |
how |
olaverse.nlp.NaijaNormalizer ¶
Bases: TTSNormalizer
Extended text normalizer for Nigerian Pidgin English (Naija / pcm).
Inherits the full TTSNormalizer pipeline and adds Pidgin-specific
informal spelling normalization β collapsing common alternate spellings
to a canonical spoken form before TTS processing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canonical
|
bool
|
If |
True
|
Example::
from olaverse.nlp import NaijaNormalizer
norm = NaijaNormalizer()
norm.normalize("Oga, e don finish. Call am 2moro.")
# β 'Oga, e don finish. Call am tomorrow.'
Methods:¶
normalize_informal ¶
Collapse Pidgin informal spellings to canonical spoken forms.
normalize ¶
Full normalization pipeline for Pidgin: informal spellings β abbreviations β numbers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Raw Pidgin input text. |
required |
Returns:
| Type | Description |
|---|---|
str
|
TTS-ready normalized text. |
Stopwords¶
The stopwords module provides curated stopword sets for all 4 Nigerian languages, ready for use in NLP pipelines, TF-IDF vectorizers, and preprocessing workflows.
from olaverse import (
YORUBA_STOPWORDS, IGBO_STOPWORDS, HAUSA_STOPWORDS, PIDGIN_STOPWORDS,
get_stopwords, filter_stopwords,
)
Available Sets¶
| Constant | Language | Example words |
|---|---|---|
YORUBA_STOPWORDS |
Yoruba | mo, mi, o, ni, nΓ, fun, lati, ati, tabi, sugbon, αΉ£ugbα»n |
IGBO_STOPWORDS |
Igbo | m, mu, gi, gα», ya, anyi, anyα», ka, na, nke |
HAUSA_STOPWORDS |
Hausa | ni, kai, ke, shi, ita, mu, ku, su, da, ko, amma |
PIDGIN_STOPWORDS |
Nigerian Pidgin | i, you, him, na, be, go, don, dey, de, wey, sey |
All sets are frozenset β safe to use in in membership tests and set operations.
Usage¶
# Direct membership test
"ni" in YORUBA_STOPWORDS # β True
"atal" in IGBO_STOPWORDS # β False
# Retrieve by language code
get_stopwords("yor") # β YORUBA_STOPWORDS (also accepts "yo")
get_stopwords("ibo") # β IGBO_STOPWORDS (also accepts "ig")
get_stopwords("hau") # β HAUSA_STOPWORDS (also accepts "ha")
get_stopwords("pcm") # β PIDGIN_STOPWORDS
get_stopwords("eng") # β frozenset of common English stopwords
# Filter a tokenized sentence
tokens = ["Bawo", "ni", "Ade", "ati", "Sade", "dara"]
filter_stopwords(tokens, "yor")
# β ['Bawo', 'Ade', 'Sade', 'dara']
# Works with any iterable
filter_stopwords(iter(["dem", "dey", "Lagos", "for", "here"]), "pcm")
# β ['Lagos']
Using with scikit-learn¶
from olaverse import get_stopwords
from sklearn.feature_extraction.text import TfidfVectorizer
yoruba_docs = ["Bawo ni Ade?", "Sade dara pupo", "Mo feran onje Yoruba"]
stop = list(get_stopwords("yor"))
vec = TfidfVectorizer(stop_words=stop)
X = vec.fit_transform(yoruba_docs)
Text Preprocessing & Cleaning¶
PII Masking¶
from olaverse import mask_pii
mask_pii("Contact me at support@olaverse.co.uk or call +1-800-555-0199")
# β 'Contact me at [EMAIL] or call [PHONE]'
mask_pii("My card is 4111-1111-1111-1111 and SSN 123-45-6789")
# β 'My card is [CREDIT_CARD] and SSN [SSN]'
olaverse.nlp.mask_pii ¶
Mask general Personally Identifiable Information (PII) globally. Replaces Emails, Credit Cards, Social Security Numbers (SSN), and Phone numbers.
Text Cleaning¶
from olaverse import clean_text
clean_text("Visit <a href='https://olaverse.co.uk'>our site</a> today!")
# β 'Visit our site today!'
clean_text("Check https://example.com for details. Multiple spaces.")
# β 'Check for details. Multiple spaces.'
# Keep URLs
clean_text("Visit https://olaverse.co.uk", remove_urls=False)
# β 'Visit https://olaverse.co.uk'
olaverse.nlp.clean_text ¶
General text cleaning utility. Strips extra whitespaces, and optionally removes URLs and HTML tags.
Retrieval (New in v0.1.5)¶
Two-piece toolkit for building RAG/search pipelines: a cross-encoder Reranker for the second stage, and a Nigerian-language Embedder for semantic search and cross-lingual retrieval.
Reranker¶
Model Cards: olaverse/mist-reranker-150m Β· olaverse/mist-reranker-22.7M
Scores (query, passage) pairs to re-sort the top-k candidates from a first-stage retriever (BM25 or a bi-encoder).
size= |
Model | Params | Best for |
|---|---|---|---|
"150m" |
mist-reranker-150m | ~150M | Best QA/fact accuracy (ModernBERT-base) |
"22.7m" (default) |
mist-reranker-22.7M | ~22.7M | Smaller/faster, MiniLM-L6 backbone |
from olaverse import Reranker
reranker = Reranker(size="22.7m")
reranker.rank("who wrote hamlet", [
"Hamlet is a tragedy written by William Shakespeare.",
"The capital of France is Paris.",
])
# β [(0, 0.915...), (1, 0.301...)] # (original_index, score), best-first
reranker.score("who wrote hamlet", ["Hamlet is a tragedy by Shakespeare."])
# β [0.912...]
Both models are English-only; Reranker auto-handles their different output head shapes (a single relevance score vs. 2-class logits).
olaverse.nlp.Reranker ¶
Cross-encoder reranker for the second stage of a RAG / search pipeline.
Scores (query, passage) pairs to re-sort the top-k candidates from a first-stage retriever (BM25 or a bi-encoder).
Models (size=): "150m" β mist-reranker-150m (ModernBERT-base, English, best QA/fact accuracy) "22.7m" β mist-reranker-22.7M (MiniLM-L6, English, smaller/faster) [default]
Requires: pip install olaverse[retrieval]
Quick start
reranker = Reranker(size="22.7m") reranker.rank("who wrote hamlet", [ ... "Hamlet is a tragedy written by William Shakespeare.", ... "The capital of France is Paris.", ... ]) [(0, 0.98...), (1, 0.01...)]
Methods:¶
score ¶
Score a query against a list of passages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The search query. |
required |
passages
|
list
|
List of candidate passage strings. |
required |
Returns:
| Type | Description |
|---|---|
list
|
list[float]: relevance scores, one per passage, same order as input. |
rank ¶
Rank passages by relevance to the query, descending.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The search query. |
required |
passages
|
list
|
List of candidate passage strings. |
required |
Returns:
| Type | Description |
|---|---|
list
|
list[tuple[int, float]]: (original_index, score) pairs, best-first. |
Embedder¶
Model Card: olaverse/naija-embed-base
Cross-lingual sentence embeddings for Hausa, Yoruba, and Igbo β contrastively fine-tuned from mist-encoder-base-ng. Useful for cross-lingual retrieval (e.g. Hausa query β Yoruba document), semantic search, clustering, and deduplication.
from olaverse import Embedder
embedder = Embedder()
vecs = embedder.encode(["bawo ni", "sannu"])
embedder.similarity(vecs[0], vecs[1])
No Nigerian Pidgin support
The underlying translation model used for training only outputs Hausa/Yoruba/Igbo β Pidgin (pcm) is not covered.
olaverse.nlp.Embedder ¶
Cross-lingual sentence embeddings for Nigerian languages (Hausa, Yoruba, Igbo).
Wraps olaverse/naija-embed-base β contrastively fine-tuned from olaverse/mist-encoder-base-ng on synthetic parallel pairs. Mean pooling, cosine similarity. Useful for cross-lingual retrieval, semantic search, clustering, and deduplication over Nigerian-language text.
Note: does not cover Nigerian Pidgin (pcm) β the base model only supports ha/yo/ig.
Requires: pip install olaverse[retrieval]
Quick start
embedder = Embedder() vecs = embedder.encode(["bawo ni", "sannu"]) embedder.similarity(vecs[0], vecs[1])
Methods:¶
encode ¶
Encode a string or list of strings into embedding vector(s).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
texts
|
str | list[str]
|
A string, or list of strings. |
required |
**kwargs
|
object
|
Passed through to SentenceTransformer.encode(). |
{}
|
Returns:
| Type | Description |
|---|---|
'numpy.ndarray'
|
numpy.ndarray: embedding vector(s). |