YAML Metadata Warning:The pipeline tag "text2text-generation" is not in the official list: text-classification, token-classification, table-question-answering, question-answering, zero-shot-classification, translation, summarization, feature-extraction, text-generation, fill-mask, sentence-similarity, text-to-speech, text-to-audio, automatic-speech-recognition, audio-to-audio, audio-classification, audio-text-to-text, voice-activity-detection, depth-estimation, image-classification, object-detection, image-segmentation, text-to-image, image-to-text, image-to-image, image-to-video, unconditional-image-generation, video-classification, reinforcement-learning, robotics, tabular-classification, tabular-regression, tabular-to-text, table-to-text, multiple-choice, text-ranking, text-retrieval, time-series-forecasting, text-to-video, image-text-to-text, image-text-to-image, image-text-to-video, visual-question-answering, document-question-answering, zero-shot-image-classification, graph-ml, mask-generation, zero-shot-object-detection, text-to-3d, image-to-3d, image-feature-extraction, video-text-to-text, keypoint-detection, visual-document-retrieval, any-to-any, video-to-video, other
gl-keyboard-correction
Spelling & sentence correction for mobile keyboards. 13.5M params trained
from scratch, shipped as int8 ONNX (27MB total), ~25ms per sentence on 2 CPU
threads. Also includes lexicons.json: frequency-ranked wordlists and
next-word tables for 10 locales.
Don't use it for Japanese. It makes Japanese text worse.
Run the correction model
pip install onnxruntime sentencepiece numpy huggingface_hub
import numpy as np, onnxruntime as ort, sentencepiece as spm
from huggingface_hub import hf_hub_download
repo = "Loke-60000/gl-keyboard-correction"
enc = ort.InferenceSession(hf_hub_download(repo, "gec-encoder-int8.onnx"))
dec = ort.InferenceSession(hf_hub_download(repo, "gec-decoder-int8.onnx"))
sp = spm.SentencePieceProcessor(model_file=hf_hub_download(repo, "spm.model"))
MAX_LEN = 96 # fixed shapes; pad=0, bos=2, eos=3
def correct(text, lang): # lang: en fr de es it pt_br ru ar ko ja
src = np.zeros((1, MAX_LEN), dtype=np.int64)
ids = [sp.piece_to_id(f"<{lang}>")] + sp.encode(text)
src[0, :len(ids)] = ids[:MAX_LEN]
memory = enc.run(None, {"src": src})[0]
tgt = np.zeros((1, MAX_LEN), dtype=np.int64)
tgt[0, 0] = 2
out = []
for pos in range(min(len(ids) + 8, MAX_LEN - 1)):
logits = dec.run(None, {"tgt": tgt, "pos": np.array([pos], dtype=np.int64),
"memory": memory, "src": src})[0]
nxt = int(logits[0].argmax())
if nxt == 3:
break
tgt[0, pos + 1] = nxt
out.append(nxt)
return sp.decode(out)
print(correct("i cant beleive its alredy friday", "en"))
print(correct("das waere schoen, vielen dank fuer alles", "de"))
Use the wordlists
import json
from huggingface_hub import hf_hub_download
lex = json.load(open(hf_hub_download("Loke-60000/gl-keyboard-correction", "lexicons.json")))
print(lex["en-US"][:10]) # words ranked by frequency
print(lex["_nextWords"]["en-US"]["thank"]) # next-word prediction
Deploying on phones
Numbers below are from a real Android integration, measured on device-class ART (emulator) and a JVM benchmark. Phone CPUs scale roughly 3-5x slower than the JVM figures.
Parse lexicons.json once per process, on a background thread, and build
your suggestion index there too. Parsing the 4.4MB JSON costs ~236 ms and
index building ~403 ms; doing both synchronously on every text-field focus
freezes the UI for ~640 ms per focus and 1.5-2 s on cold open. Keep one
parsed copy: re-parsing the same file for abbreviations or Japanese
conversions adds ~470 ms more.
Per-keystroke suggest over the 20,787-word en-US list (JVM):
| query | latency |
|---|---|
| w (1 char) | 0.27 ms |
| he | 0.25 ms |
| beleive | 1.4 ms |
| misunderstannd | 2.6 ms |
For the ONNX model: run it only when a sentence is committed, never per
keystroke. Create the two OrtSessions once and reuse them for the process
lifetime; session creation is the expensive part, inference is ~25 ms.
Surface the result as a tappable suggestion, never a silent rewrite, and
show nothing when the output equals the input.
Training data: OPUS OpenSubtitles v2018 (Lison & Tiedemann, 2016). No subtitle text is included in these files.