typeling 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- typeling-0.1.0/LICENSE +202 -0
- typeling-0.1.0/NOTICE +46 -0
- typeling-0.1.0/PKG-INFO +281 -0
- typeling-0.1.0/README.md +252 -0
- typeling-0.1.0/pyproject.toml +45 -0
- typeling-0.1.0/setup.cfg +4 -0
- typeling-0.1.0/tests/test_kernel.py +84 -0
- typeling-0.1.0/tests/test_keyboard.py +71 -0
- typeling-0.1.0/tests/test_lm.py +92 -0
- typeling-0.1.0/typeling/__init__.py +6 -0
- typeling-0.1.0/typeling/__main__.py +4 -0
- typeling-0.1.0/typeling/demo.py +300 -0
- typeling-0.1.0/typeling/en.bin +0 -0
- typeling-0.1.0/typeling/keyboard.py +43 -0
- typeling-0.1.0/typeling/lm.py +370 -0
- typeling-0.1.0/typeling/model.py +209 -0
- typeling-0.1.0/typeling/predictor.py +158 -0
- typeling-0.1.0/typeling/text.py +66 -0
- typeling-0.1.0/typeling/user.py +87 -0
- typeling-0.1.0/typeling.egg-info/PKG-INFO +281 -0
- typeling-0.1.0/typeling.egg-info/SOURCES.txt +23 -0
- typeling-0.1.0/typeling.egg-info/dependency_links.txt +1 -0
- typeling-0.1.0/typeling.egg-info/entry_points.txt +2 -0
- typeling-0.1.0/typeling.egg-info/requires.txt +4 -0
- typeling-0.1.0/typeling.egg-info/top_level.txt +1 -0
typeling-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
typeling-0.1.0/NOTICE
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Typeling
|
|
2
|
+
Copyright 2026 The Typeling Authors
|
|
3
|
+
|
|
4
|
+
The source code is licensed under the Apache License, Version 2.0; see LICENSE.
|
|
5
|
+
|
|
6
|
+
The model file typeling/en.bin consists of n-gram probabilities (pruned and quantized)
|
|
7
|
+
computed from the datasets below. It is licensed under the Open Data Commons Attribution
|
|
8
|
+
License (ODC-By) v1.0 (https://opendatacommons.org/licenses/by/1-0/). Please retain the
|
|
9
|
+
following attributions when redistributing or using the model:
|
|
10
|
+
|
|
11
|
+
- FineWeb (HuggingFaceFW/fineweb), Hugging Face — ODC-By 1.0; use is also subject to the
|
|
12
|
+
Common Crawl Terms of Use
|
|
13
|
+
https://huggingface.co/datasets/HuggingFaceFW/fineweb
|
|
14
|
+
- SODA (allenai/soda), Kim et al. 2022, "SODA: Million-scale Dialogue Distillation with Social
|
|
15
|
+
Commonsense Contextualization" — CC BY 4.0
|
|
16
|
+
https://huggingface.co/datasets/allenai/soda
|
|
17
|
+
- WildChat-1M (allenai/WildChat-1M), Zhao et al. 2024, "WildChat: 1M ChatGPT Interaction Logs in
|
|
18
|
+
the Wild" — ODC-By 1.0
|
|
19
|
+
https://huggingface.co/datasets/allenai/WildChat-1M
|
|
20
|
+
- OpenAssistant Conversations Release 2 (OpenAssistant/oasst2), LAION — Apache License 2.0
|
|
21
|
+
https://huggingface.co/datasets/OpenAssistant/oasst2
|
|
22
|
+
- Ubuntu IRC logs (https://irclogs.ubuntu.com), released into the Public Domain, as packaged by
|
|
23
|
+
the Common Pile v0.1 (common-pile/ubuntu_irc_filtered), Kandpal et al. 2025
|
|
24
|
+
https://huggingface.co/datasets/common-pile/ubuntu_irc_filtered
|
|
25
|
+
|
|
26
|
+
The language model Typeling-25M (https://huggingface.co/ScarletKc/Typeling-25M), used by
|
|
27
|
+
typeling/lm.py and distributed separately, is licensed under the Apache License, Version 2.0. It
|
|
28
|
+
is SupraLabs/Supra2-Medium-Base (Apache License 2.0,
|
|
29
|
+
https://huggingface.co/SupraLabs/Supra2-Medium-Base) further trained on the datasets above.
|
|
30
|
+
|
|
31
|
+
The words that the model never suggests by default are taken from the List of Dirty, Naughty,
|
|
32
|
+
Obscene, and Otherwise Bad Words — CC BY 4.0
|
|
33
|
+
https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words
|
|
34
|
+
|
|
35
|
+
Likely misspellings are identified with word lists generated from the English Speller Database
|
|
36
|
+
(ESDB, formerly SCOWL), https://github.com/en-wl/wordlist, under the following notice:
|
|
37
|
+
|
|
38
|
+
Copyright 2000-2026 by Kevin Atkinson
|
|
39
|
+
|
|
40
|
+
Permission to use, copy, modify, distribute, and sell any part of the English
|
|
41
|
+
Speller Database (ESDB, previously known as SCOWLv2), or word lists
|
|
42
|
+
created from it, is hereby granted without fee, provided that the above
|
|
43
|
+
copyright notice appears in all copies and that both the above copyright
|
|
44
|
+
notice and this notice appear in supporting documentation. Kevin Atkinson
|
|
45
|
+
makes no representations about the suitability of this database for any
|
|
46
|
+
purpose. It is provided "as is" without express or implied warranty.
|
typeling-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: typeling
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Offline English typing prediction: completes the current word, predicts the next one and fixes typos; a pure-Python n-gram kernel and an optional small language model.
|
|
5
|
+
Author: scarletkc
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/scarletkc/typeling
|
|
8
|
+
Project-URL: Source, https://github.com/scarletkc/typeling
|
|
9
|
+
Project-URL: Issues, https://github.com/scarletkc/typeling/issues
|
|
10
|
+
Keywords: autocomplete,word prediction,next-word prediction,language model,kneser-ney,n-gram,typo correction
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Natural Language :: English
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
21
|
+
Requires-Python: >=3.13
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
License-File: NOTICE
|
|
25
|
+
Provides-Extra: lm
|
|
26
|
+
Requires-Dist: torch>=2.7; extra == "lm"
|
|
27
|
+
Requires-Dist: transformers>=5; extra == "lm"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# Typeling
|
|
31
|
+
|
|
32
|
+
Offline English typing prediction: completes the word being typed, predicts the next word and fixes typos.
|
|
33
|
+
|
|
34
|
+
The `typeling` package has two predictors with the same interface:
|
|
35
|
+
|
|
36
|
+
- `typeling.Predictor`: a dependency-free n-gram kernel in pure Python with a bundled 5 MB model.
|
|
37
|
+
- `typeling.lm.LMPredictor`: the typing decoder for [Typeling-25M](https://huggingface.co/ScarletKc/Typeling-25M),
|
|
38
|
+
a 25M-parameter transformer language model trained for typing, with typo repair (optional extra
|
|
39
|
+
`typeling[lm]`: PyTorch and Transformers).
|
|
40
|
+
|
|
41
|
+
Training and evaluation of the language model are in `lm/`; see [docs/model-plan.md](docs/model-plan.md) for the plan,
|
|
42
|
+
the experiments and their results.
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **Offline and private.** No network access at runtime (the language model is downloaded once); what the user types
|
|
47
|
+
never leaves the machine.
|
|
48
|
+
- **Pure Python, no dependencies.** The n-gram kernel uses only the standard library (Python 3.13+).
|
|
49
|
+
- **Small and fast.** The bundled n-gram model is at most 5 MB, loads in milliseconds and answers a keystroke in tens
|
|
50
|
+
of microseconds; the language model answers in tens of milliseconds on a laptop CPU.
|
|
51
|
+
- **Completion and prediction.** Completes the current word (`Let me kn` → `ow`) and predicts the next one after a
|
|
52
|
+
space (`Thank you so ` → `much`), as ghost text or as a bar of candidates.
|
|
53
|
+
- **Typo repair.** With the language model, mistyped words are corrected from keyboard errors (`See you tomm` →
|
|
54
|
+
*tomorrow*, `What do you thnik` → *think*).
|
|
55
|
+
- **Natural output.** Handles contractions such as *I'm* and *don't* and restores casing (*I*, *English*, sentence
|
|
56
|
+
starts, ALL-CAPS input).
|
|
57
|
+
- **Learns locally.** Adapts to the user's own words and phrases and stores them in a local JSON file.
|
|
58
|
+
- **Unobtrusive.** Ghost text is shown only above a confidence threshold, offensive words are not suggested by
|
|
59
|
+
default, and common misspellings found in real typing (*recieve*, *definately*) are never suggested.
|
|
60
|
+
- **Permissively licensed data.** The model is built only from openly licensed corpora (ODC-By, CC BY, Apache-2.0).
|
|
61
|
+
|
|
62
|
+
## Quick start
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install typeling # n-gram kernel, no dependencies
|
|
66
|
+
pip install "typeling[lm]" # plus the language model decoder (PyTorch, Transformers)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Python API
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from typeling import Predictor
|
|
73
|
+
|
|
74
|
+
p = Predictor()
|
|
75
|
+
p.suggest("Let me kn") # 'ow' ghost text to display after the cursor
|
|
76
|
+
p.suggest("Thank you so ") # 'much' after a space, the next word is predicted
|
|
77
|
+
p.suggest("Hello,") # '' nothing is shown when no confident suggestion exists
|
|
78
|
+
p.topk("I'll see you ", 3) # [(word, probability), ...] best full words, ignoring the display thresholds
|
|
79
|
+
|
|
80
|
+
p = Predictor(user="path/to/user.json") # enable persistent learning
|
|
81
|
+
p.learn("Our project is called Zorblaxa.")
|
|
82
|
+
p.suggest("I love Zorb") # 'laxa' learned words are suggested too
|
|
83
|
+
p.save() # write the user model back to user.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`suggest(text)` and `topk(text, k)` take the text before the cursor. `Predictor` also accepts `model` (path to an
|
|
87
|
+
alternative model file) and the keyword-only options `next_threshold` (default 0.3), `complete_threshold` (0.3),
|
|
88
|
+
`cache_weight` (0.1), `allow_blocked` (False) and `use_context` (True).
|
|
89
|
+
|
|
90
|
+
With the language model:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from typeling.lm import LMPredictor
|
|
94
|
+
|
|
95
|
+
p = LMPredictor() # downloads ScarletKc/Typeling-25M once; or a repo id / local directory
|
|
96
|
+
p.topk("See you tomm", 3) # [('tomorrow', ...), ...] corrections are candidates too
|
|
97
|
+
p.suggest("Let me kn") # 'ow' ghost text only extends what was typed
|
|
98
|
+
p.topk("I'm going to ", 5) # the top 3 are exact, further candidates are best effort
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`LMPredictor(model, user)` takes the same user model file as `Predictor`, with the same `learn()` and `save()`. It
|
|
102
|
+
also accepts `device` (`"cpu"` or `"cuda"`, default: CUDA if available), `typo_weight` (default 0.003, 0 turns typo
|
|
103
|
+
repair off), `ngram_weight` (0.1, share of the n-gram model in the probabilities), `context_chars` (1000),
|
|
104
|
+
`beam` (8), `allow_blocked` and the display thresholds.
|
|
105
|
+
|
|
106
|
+
### Terminal demo
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python -m typeling # or: typeling
|
|
110
|
+
python -m typeling --lm # use Typeling-25M (needs typeling[lm]); --lm DIR for a local model
|
|
111
|
+
python -m typeling --no-learn # do not learn or save your words
|
|
112
|
+
python -m typeling --bench # measure per-keystroke latency
|
|
113
|
+
echo "I wan" | python -m typeling # pipe mode: prints "I wan[t]"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The line shows the best suggestion as grey ghost text; the bar below it shows the top candidates.
|
|
117
|
+
|
|
118
|
+
| Key | Action |
|
|
119
|
+
|---|---|
|
|
120
|
+
| Tab / Right | accept the highlighted candidate (the first one by default; it replaces a mistyped word) |
|
|
121
|
+
| Up / Down | move the highlight in the candidate bar |
|
|
122
|
+
| Esc | hide the suggestions |
|
|
123
|
+
| Ctrl+W | delete the previous word |
|
|
124
|
+
| Enter | new line (the finished line is learned unless `--no-learn` is given) |
|
|
125
|
+
| Ctrl+C | quit |
|
|
126
|
+
|
|
127
|
+
Learned words are stored in `~/.typeling/user.json` (used by both models) and saved on exit.
|
|
128
|
+
|
|
129
|
+
## How it works
|
|
130
|
+
|
|
131
|
+
- **Tokenizer** (`text.py`): words (with inner apostrophes), numbers, sentence boundaries, commas and other
|
|
132
|
+
punctuation. Training and runtime share the same rules.
|
|
133
|
+
- **Language model** (`model.py`): an interpolated modified Kneser-Ney trigram model over a 60,000-word vocabulary,
|
|
134
|
+
pruned with the weighted-difference criterion (Seymore & Rosenfeld) to fit a 5 MB budget, with probabilities
|
|
135
|
+
quantized to one byte. Words are stored alphabetically, so all completions of a prefix form one contiguous id
|
|
136
|
+
range. The binary format is documented at the top of `model.py`.
|
|
137
|
+
- **Scoring** (`predictor.py`): the n-gram probability is mixed with a document cache (words used earlier in the same
|
|
138
|
+
text) and the user model (`user.py`, unigram and bigram counts of what the user typed), whose weight grows as more
|
|
139
|
+
text is learned.
|
|
140
|
+
- **Display**: a next-word prediction is shown only if its probability is at least `next_threshold`; a completion
|
|
141
|
+
only if its probability given the typed prefix is at least `complete_threshold`.
|
|
142
|
+
- **Spelling filter**: the chat corpora contain real typos, so at build time every vocabulary word that is missing
|
|
143
|
+
from a speller dictionary (and from a short list of internet slang such as *lol*, *idk*, *tbh*), is usually written
|
|
144
|
+
in lowercase, and is one edit (two for words of 8+ letters) away from a dictionary word at least 20 times as common
|
|
145
|
+
is marked as a misspelling. Such words still serve as context but are never suggested.
|
|
146
|
+
|
|
147
|
+
## Evaluation
|
|
148
|
+
|
|
149
|
+
`bench/eval.py` simulates typing the held-out dev split of each corpus (created by `uv run training/build.py fetch`)
|
|
150
|
+
and reports how much the suggestions help. For each word it "types" 0, 1, 2, ... letters; when the top suggestion is
|
|
151
|
+
the target word and passes the display threshold, the simulated user accepts it with one keystroke (ghost text);
|
|
152
|
+
with a candidate bar, the user picks the target with one keystroke as soon as it is among the top 3. `lm/eval.py`
|
|
153
|
+
runs the same simulation on the language model, and `--typos` repeats it with every word mistyped.
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
python bench/eval.py # dev split, all sources
|
|
157
|
+
python bench/eval.py --limit 2000 --sources soda fineweb --no-save # quick run
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| Option | Meaning |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `--limit N` | at most N target words per source (default 20000, 0 = no limit) |
|
|
163
|
+
| `--sources ...` | corpora to evaluate (default: soda wildchat oasst2 irc fineweb) |
|
|
164
|
+
| `--model PATH` | evaluate another model file |
|
|
165
|
+
| `--no-context` | ablation: ignore the context (typed letters and word frequency only) |
|
|
166
|
+
| `--learn` | call `learn()` after each segment to simulate user learning |
|
|
167
|
+
| `--cache W` | override the cache weight |
|
|
168
|
+
| `--grid` | also print KSR / precision for a grid of display thresholds |
|
|
169
|
+
| `--final` | use the sealed test split (final comparisons only) |
|
|
170
|
+
| `--note TEXT` | note stored with the results |
|
|
171
|
+
| `--no-save` | do not append the results to `bench/results.jsonl` |
|
|
172
|
+
|
|
173
|
+
| Metric | Definition |
|
|
174
|
+
|---|---|
|
|
175
|
+
| KSR | keystroke savings rate with ghost text: 1 − keystrokes used / letters in the target words |
|
|
176
|
+
| Precision | share of displayed suggestions that were accepted |
|
|
177
|
+
| Shown | suggestions displayed per word |
|
|
178
|
+
| KSR@3 | keystroke savings rate with a bar of the top 3 candidates, always shown |
|
|
179
|
+
| acc@i | share of words whose top candidate is correct after typing i letters (acc@0 = next-word accuracy) |
|
|
180
|
+
| top3@i | share of words among the top 3 candidates after typing i letters |
|
|
181
|
+
| OOV | share of words missing from the model vocabulary |
|
|
182
|
+
|
|
183
|
+
Results are reported per source and pooled into *chat* (SODA, WildChat, oasst2), *casual* (Ubuntu IRC) and
|
|
184
|
+
*writing* (FineWeb).
|
|
185
|
+
|
|
186
|
+
## Results
|
|
187
|
+
|
|
188
|
+
**Typeling-25M against the n-gram kernel**, on the sealed test split (2,000 words per source; KSR with ghost text /
|
|
189
|
+
KSR@3 with a bar of 3 candidates):
|
|
190
|
+
|
|
191
|
+
| Domain | n-gram, bundled 5 MB | n-gram, unpruned 23 MB | Typeling-25M |
|
|
192
|
+
|---|---|---|---|
|
|
193
|
+
| chat (SODA, WildChat, oasst2) | 31.6% / 48.8% | 34.1% / 50.6% | **43.1% / 58.0%** |
|
|
194
|
+
| casual (Ubuntu IRC) | 22.7% / 38.9% | 24.4% / 40.4% | **29.8% / 46.8%** |
|
|
195
|
+
| writing (FineWeb) | 22.3% / 40.6% | 23.9% / 41.5% | **32.4% / 49.9%** |
|
|
196
|
+
|
|
197
|
+
With every word of 3+ letters mistyped, chat KSR drops from 32.1% to 22.7% with the n-gram kernel and from 44.5% to
|
|
198
|
+
40.1% with Typeling-25M, which repairs the errors (86% of the mistyped words end correct, against 48%). Next-word
|
|
199
|
+
accuracy, typo results per domain, latency and training details are in the
|
|
200
|
+
[model card](https://huggingface.co/ScarletKc/Typeling-25M) and [docs/model-plan.md](docs/model-plan.md).
|
|
201
|
+
|
|
202
|
+
**The n-gram kernel** on the dev split, bundled 5.00 MB model, default thresholds (next word 0.3, completion 0.3),
|
|
203
|
+
20,000 target words per source (oasst2: all 9,251), measured with `python bench/eval.py`:
|
|
204
|
+
|
|
205
|
+
| Domain | Source | KSR | Precision | Shown | KSR@3 | acc@0 | top3@0 | top3@1 | top3@2 | OOV |
|
|
206
|
+
|---|---|---|---|---|---|---|---|---|---|---|
|
|
207
|
+
| chat | SODA | 37.3% | 58.3% | 1.44 | 54.5% | 28.6% | 46.6% | 80.8% | 89.6% | 0.3% |
|
|
208
|
+
| chat | WildChat | 30.3% | 47.8% | 1.59 | 46.7% | 21.3% | 32.4% | 59.4% | 69.5% | 2.0% |
|
|
209
|
+
| chat | oasst2 | 26.2% | 46.4% | 1.62 | 44.3% | 18.1% | 30.3% | 61.3% | 72.4% | 1.3% |
|
|
210
|
+
| casual | Ubuntu IRC | 22.8% | 43.8% | 1.58 | 39.6% | 13.8% | 24.5% | 54.9% | 69.6% | 1.7% |
|
|
211
|
+
| writing | FineWeb | 23.1% | 43.2% | 1.68 | 41.7% | 14.3% | 23.8% | 51.1% | 64.4% | 2.9% |
|
|
212
|
+
| **chat** | pooled | **32.1%** | **51.5%** | 1.54 | **49.1%** | | | | | |
|
|
213
|
+
| **casual** | pooled | **22.8%** | **43.8%** | 1.58 | **39.6%** | | | | | |
|
|
214
|
+
| **writing** | pooled | **23.1%** | **43.2%** | 1.68 | **41.7%** | | | | | |
|
|
215
|
+
|
|
216
|
+
- **Context matters.** With `--no-context` (typed letters and word frequency only), KSR with every suggestion shown
|
|
217
|
+
drops to 15.3% (chat), 13.8% (casual) and 14.4% (writing), and next-word accuracy to about 2%.
|
|
218
|
+
- **Thresholds trade savings for precision.** Lowering both thresholds to 0.15 raises chat KSR to 34.9% at 41%
|
|
219
|
+
precision; raising them to 0.5 gives 27.9% at 65%. `python bench/eval.py --grid` prints the full grid.
|
|
220
|
+
- **Speed.** A query takes 41–115 µs on average (p99 under 0.7 ms on long FineWeb documents) in pure Python on a
|
|
221
|
+
laptop CPU; the model loads in under 50 ms. Typeling-25M takes 23–25 ms on chat and 33 ms on long text (PyTorch,
|
|
222
|
+
4 CPU threads).
|
|
223
|
+
|
|
224
|
+
## Building the model
|
|
225
|
+
|
|
226
|
+
The build script is a [uv](https://docs.astral.sh/uv/) script; its dependencies (numpy, pyarrow, huggingface_hub)
|
|
227
|
+
are installed automatically into an isolated environment.
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
uv run training/build.py fetch # download and clean the corpora into data/corpus/
|
|
231
|
+
uv run training/build.py model # count, prune and export typeling/en.bin (about 30 s)
|
|
232
|
+
uv run training/build.py # both steps
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`fetch` skips sources that are already downloaded and accepts `--sources`. `model` accepts `--out PATH` (default
|
|
236
|
+
`typeling/en.bin`), `--budget BYTES` (default 5e6), `--min-count N` (drop n-grams seen fewer than N times,
|
|
237
|
+
default 2) and `--workers N` (default 8).
|
|
238
|
+
|
|
239
|
+
Each corpus is cleaned (emails, URLs and phone numbers are removed; chat sources keep only turns that look typed by a
|
|
240
|
+
person), and about 1% is held out as the dev split and 1% as the test split by content hash.
|
|
241
|
+
|
|
242
|
+
| Corpus | Dataset | License | Used for |
|
|
243
|
+
|---|---|---|---|
|
|
244
|
+
| FineWeb | [HuggingFaceFW/fineweb](https://huggingface.co/datasets/HuggingFaceFW/fineweb) | ODC-By 1.0 | writing |
|
|
245
|
+
| SODA | [allenai/soda](https://huggingface.co/datasets/allenai/soda) | CC BY 4.0 | everyday dialogue (generated by InstructGPT) |
|
|
246
|
+
| WildChat-1M | [allenai/WildChat-1M](https://huggingface.co/datasets/allenai/WildChat-1M) | ODC-By 1.0 | real user-typed turns (first 7.5M training words) |
|
|
247
|
+
| OpenAssistant oasst2 | [OpenAssistant/oasst2](https://huggingface.co/datasets/OpenAssistant/oasst2) | Apache-2.0 | real user-typed turns |
|
|
248
|
+
| Ubuntu IRC | [common-pile/ubuntu_irc_filtered](https://huggingface.co/datasets/common-pile/ubuntu_irc_filtered) | Public Domain | informal internet chat (messages that look like commands or code are dropped) |
|
|
249
|
+
|
|
250
|
+
The bundled model was built from 55M tokens: FineWeb 18.5M words, SODA 16.3M, WildChat 7.5M, Ubuntu IRC 4.4M and
|
|
251
|
+
oasst2 0.4M.
|
|
252
|
+
|
|
253
|
+
The [LDNOOBW](https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words) English word list
|
|
254
|
+
(CC BY 4.0) is used only to mark offensive words, and the American, British and Canadian word lists of the
|
|
255
|
+
[English Speller Database](https://github.com/en-wl/wordlist) (ESDB, formerly SCOWL; MIT-like license) only to
|
|
256
|
+
detect misspellings.
|
|
257
|
+
|
|
258
|
+
## Project layout
|
|
259
|
+
|
|
260
|
+
```text
|
|
261
|
+
typeling/ runtime package (standard library only, except lm.py)
|
|
262
|
+
predictor.py public API: Predictor
|
|
263
|
+
model.py binary model format and n-gram scoring
|
|
264
|
+
text.py tokenizer shared by training and runtime
|
|
265
|
+
user.py local user model
|
|
266
|
+
keyboard.py QWERTY typing-error model
|
|
267
|
+
lm.py language model decoder: LMPredictor (typeling[lm])
|
|
268
|
+
demo.py terminal demo (python -m typeling)
|
|
269
|
+
en.bin bundled model
|
|
270
|
+
training/build.py corpus download and n-gram model build
|
|
271
|
+
bench/eval.py typing-simulation benchmark
|
|
272
|
+
tests/ unit tests (python -m unittest discover tests)
|
|
273
|
+
lm/ Typeling-25M: data, training, typo experiments and benchmark (PyTorch, uv scripts)
|
|
274
|
+
docs/model-plan.md plan and results for Typeling-25M
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
The code is licensed under the [Apache License 2.0](LICENSE). The bundled model `typeling/en.bin` is licensed
|
|
280
|
+
under the [Open Data Commons Attribution License (ODC-By) 1.0](https://opendatacommons.org/licenses/by/1-0/), and
|
|
281
|
+
Typeling-25M under the Apache License 2.0; see [NOTICE](NOTICE) for the required attributions.
|