Downloads · 30 days
77
60% of all-time downloads
MrBob1337/keyboard-lm-daen
keyboard-lm-daen is a text generation model from MrBob1337. Use it when you need the model to write or continue text. It is set up for gguf. The card lists the license as cc-by-sa-4.0.
A drop-in GGUF for FUTO Keyboard, trained from scratch to handle Danish and English in one model, plus the combined dictionary that makes mixed-language typing actually work.
Downloads · 30 days
77
60% of all-time downloads
All-time downloads
129
Public
Repo size
259 MB
Likes
0
Public
Click a slice to open those files.
.gguf258 MB · 98%
From the Hugging Face model README
A drop-in GGUF for FUTO Keyboard, trained from scratch to handle Danish and English in one model, plus the combined dictionary that makes mixed-language typing actually work.
FUTO's shipped transformer is English-only (issue #1212). Danish falls back to the AOSP dictionary path while the transformer sits idle or fights you. This replaces it without forking the app.
daen-xbu-q6_k.gguf and dictionary/daen_combined.dict to the phone..gguf.daen_combined.dict as the
dictionary.This is the part that matters, and it is not obvious.
LanguageModelFacilitator.kt:194 refuses to run the transformer whenever the
most-confident locale differs from the locale the model was loaded under:
if(dictionaryFacilitator.mostConfidentLocale != languageModel?.locale) return null
With Danish and English both enabled, FUTO keeps a DictionaryGroup per
language and shifts confidence toward whichever dictionary recognises your
recent words. Type English on the Danish subtype and the transformer goes
completely silent — exactly on the mixed-language input a bilingual model
exists for. No model can fix this; the gate is upstream of the model.
So: enable Danish only, and give it the bilingual dictionary here. One dictionary group means the most-confident locale is always the primary locale, the gate never fires, and the dictionary still validates English words so they are not autocorrected into Danish.
A .dict declares its own locale in its header and FUTO does not cross-check
it, which is what lets one file serve both languages.
Note: with a single locale, FUTO stops forcing transformerWeight = 1.0 and
uses your own setting, which defaults to 3.4 in favour of the dictionary.
If suggestions feel too dictionary-driven, lower it under Settings -> Advanced.
Next-token accuracy against FUTO's own English model, same eval, its own tokenizer for each:
| Tatoeba en | C4 validation | |||
|---|---|---|---|---|
| top-1 | top-5 | top-1 | top-5 | |
FUTO ml4 (36M, en-only) | 13.5% | 44.3% | 16.6% | 47.2% |
| this model (66M, da+en) | 31.6% | 52.9% | 30.9% | 52.8% |
Held-out perplexity: 28.05 English (C4 validation), 39.02 Danish
(FineWeb-2 dan_Latn). Neither was in training.
<XBU> autocorrect, held-out Tatoeba, exact-match on the intended word:
| Danish | Danish (æøå) | English | |
|---|---|---|---|
| FUTO's default noise | 46.2% | 10.3% | 51.5% |
| light noise | 61.1% | 19.6% | 65.6% |
The base model scores 0% on these — the protocol is entirely learned by the LoRA. Danish words needing a restored diacritic are the weak spot; see Limitations.
daen-xbu-q6_k.gguf | 55 MB, ship this |
daen-xbu-q8_0.gguf | 71 MB, 0.25% better perplexity |
daen-xbu-f16.gguf | 132 MB, for requantizing |
dictionary/daen_combined.dict | 145,618 entries, da+en, locale=da |
dictionary/daen_combined.txt | the word list, to rebuild without a corpus |
tokenizer/daen_keyboard.model | SentencePiece BPE, 15,008 |
scripts/ | the whole pipeline, corpus to GGUF |
FINDINGS.md | build log, including what went wrong |
12 layers x 512 hidden, 8 heads, 2048 FFN, 512 context, ~66M parameters.
Llama architecture. 15,008-token SentencePiece BPE with
treat_whitespace_as_suffix=true (FUTO's inverted_space) and the
<XBU>/<XBC>/<XEC>/<CHAR_A..Z> autocorrect specials.
Trained from scratch for 53,000 steps over 6.95B tokens at 70% English / 30%
Danish, annealed to 45% Danish for the last 9,000 steps after per-language
evaluation showed Danish regressing. Then a rank-32 LoRA for the <XBU>
autocorrect protocol, mixing Tatoeba-derived correction data 50/50 with the
original corpus.
That replay ratio is not optional. Training the LoRA on the task data alone taught the protocol well and cost +70% English / +77% Danish perplexity — fluent at autocorrect, materially worse at the next-word prediction that runs on every keystroke. With replay the cost is ~6%.
Permute Q and K. HF rotates halves of the head dimension; llama.cpp rotates
adjacent pairs. q_proj/k_proj must be interleaved during conversion or RoPE
reads the wrong element of every pair. The model still emits fluent-looking
function words, so it reads as poor quality rather than a broken tensor layout.
12_check_gguf_parity.py compares every tensor against the source weights;
metadata validation cannot catch this.
Set remove_extra_whitespaces=False when training the tokenizer. It
defaults to True, which strips the trailing space, so "thank you very "
encodes as ['thank ', 'you ', 'ver', 'y']. The model can then only finish the
current word or punctuate — it can never predict the next one. FUTO's own
tokenizer sets it False.
keyboardlm.features is only read at import and for display, never at
runtime. Declaring xbu_char_autocorrect_v1 char_embed_mixing_v1 is enough;
omitting base_v1 and inverted_space changes nothing functionally.
<CHAR_Æ>, so the typed form folds æ/å onto a and
ø onto o while the truth keeps its diacritic. Half the training cases drop
the letter instead of folding, which is often unrecoverable. Whether FUTO's
native side drops or folds is not observable from outside the app.københavn is present, København is not.
Proper nouns are where problems will show first.xc0_swipe_typing_v1 not declared); it falls
back to FUTO's built-in model. Keep æøå off the main layout layer — the
built-in swipe model degrades with extra main-layer keys.Model weights, tokenizer and dictionary: CC-BY-SA-4.0, because Danish Dynaword includes CC-BY-SA-4.0 subcorpora. Whether share-alike reaches model weights is legally unsettled; this honours the strictest input licence rather than betting it does not apply.
Scripts: MIT. Parts are adapted from
jblechert/keyboard-lm-de
(MIT, Copyright (c) 2025 Janis Blechert) — see
scripts/LICENSE-keyboard-lm-de-MIT. That project worked out FUTO's
undocumented GGUF contract and this would have been far harder without it.
Training data:
| Source | Licence |
|---|---|
| Danish Dynaword | CC-0 / CC-BY-SA-4.0 / CC-BY-4.0 / Apache-2.0 / MIT by subcorpus |
C4 en | ODC-By |
| Tatoeba da + en | CC-BY-2.0 |
FineWeb-2 dan_Latn | ODC-By (evaluation only) |
FUTO Keyboard is Apache-2.0. The dictionary was compiled with dicttool from
futo-org/android-keyboard; no FUTO code is redistributed here.
Not affiliated with or endorsed by FUTO.