Language identification for Ghanaian and West African speech, over IPA phonemes
# ghana-speech-id
Language identification for 41 Ghanaian and West African languages.
Speech goes through
Omnilingual ASR, which turns audio
into text; this library says which language the text is in.
```
audio ──[sherpa-onnx + omniASR CTC]──▶ transcript ──[this]──▶ language
```
CPU only, 8.2 MB, about 0.06 ms per classification. The inference core is C++ with a C API,
so there is no Python on the device.
```sh
pip install ghana-speech-id
```
**How the model behaves, what it scores and where it fails** is on the
model card. This file is about
using it.
## Quick start
The head classifies text and cannot read audio, so it needs a recogniser in front of it.
Both come from the same repo:
```python
import soundfile as sf
import sherpa_onnx
from ghana_speech_id import GhanaSpeechId
model, tokens = GhanaSpeechId.download_recogniser() # omniASR, 279 MB, once
rec = sherpa_onnx.OfflineRecognizer.from_omnilingual_asr_ctc(model=model, tokens=tokens)
lid = GhanaSpeechId.load() # the head, 8.2 MB
wav, sr = sf.read("clip.wav", dtype="float32")
s = rec.create_stream()
s.accept_waveform(sr, wav)
rec.decode_stream(s)
print(lid.classify(s.result.text)) # Ewe_ewe (0.50)
```
`load()` pulls only the head. The recogniser is downloaded when you ask for it and not
before, so a process that already has transcripts never fetches 279 MB it will not use.
There is one head and nothing to configure.
`classify()` returns `None` when no n-gram matched, meaning there was no basis for a
decision. Report that as unknown rather than naming whichever language scored least badly.
```python
p = lid.classify(text)
if p is None:
print("unknown")
else:
print(p.language, p.confidence, p.margin) # margin = top-1 minus top-2
```
**The head is closed-set.** It always names one of its 41 languages, including for speech in
a language it has never seen. `margin` is the signal to threshold on if you need to reject
those — a weak one, so read the model card b …