Instructions to use MrBob1337/keyboard-lm-daen with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use MrBob1337/keyboard-lm-daen with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf MrBob1337/keyboard-lm-daen:F16 # Run inference directly in the terminal: llama cli -hf MrBob1337/keyboard-lm-daen:F16
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf MrBob1337/keyboard-lm-daen:F16 # Run inference directly in the terminal: llama cli -hf MrBob1337/keyboard-lm-daen:F16
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf MrBob1337/keyboard-lm-daen:F16 # Run inference directly in the terminal: ./llama-cli -hf MrBob1337/keyboard-lm-daen:F16
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf MrBob1337/keyboard-lm-daen:F16 # Run inference directly in the terminal: ./build/bin/llama-cli -hf MrBob1337/keyboard-lm-daen:F16
Use Docker
docker model run hf.co/MrBob1337/keyboard-lm-daen:F16
- LM Studio
- Jan
- vLLM
How to use MrBob1337/keyboard-lm-daen with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "MrBob1337/keyboard-lm-daen" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "MrBob1337/keyboard-lm-daen", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/MrBob1337/keyboard-lm-daen:F16
- Ollama
How to use MrBob1337/keyboard-lm-daen with Ollama:
ollama run hf.co/MrBob1337/keyboard-lm-daen:F16
- Unsloth Desktop
- Docker Model Runner
How to use MrBob1337/keyboard-lm-daen with Docker Model Runner:
docker model run hf.co/MrBob1337/keyboard-lm-daen:F16
- Lemonade
How to use MrBob1337/keyboard-lm-daen with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull MrBob1337/keyboard-lm-daen:F16
Run and chat with the model
lemonade run user.keyboard-lm-daen-F16
List all available models
lemonade list
- Atomic Chat
Bilingual Danish + English LM for FUTO Keyboard
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.
Install
- Copy
daen-xbu-q6_k.ggufanddictionary/daen_combined.dictto the phone. - Settings -> Advanced -> Models -> import the
.gguf. - Settings -> Languages -> Danish -> import
daen_combined.dictas the dictionary. - Assign the model to Danish.
Use ONE language entry, not two
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.
Quality
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.
Contents
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 |
Model
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%.
Three traps, if you are building your own
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.
Limitations
- Danish diacritics are the weak spot (10.3% vs 46.2% overall). FUTO's CHAR
alphabet is A–Z with no
<CHAR_Æ>, so the typed form folds æ/å ontoaand ø ontoowhile 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. - The dictionary is lowercase.
københavnis present,Københavnis not. Proper nouns are where problems will show first. - ~10% of dictionary entries are spellings valid in both languages and carry one merged score, which a single-locale dictionary cannot avoid.
- Swipe typing is unsupported (
xc0_swipe_typing_v1not 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. - 66M parameters is small. It beats FUTO's 36M model, but it will still miss words a larger model would get.
Licensing and attribution
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.
- Downloads last month
- 42
6-bit
8-bit
16-bit