bolotype 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.
- bolotype-0.1.0/LICENSE +21 -0
- bolotype-0.1.0/PKG-INFO +351 -0
- bolotype-0.1.0/README.md +297 -0
- bolotype-0.1.0/pyproject.toml +98 -0
- bolotype-0.1.0/setup.cfg +4 -0
- bolotype-0.1.0/src/bolotype/__init__.py +1 -0
- bolotype-0.1.0/src/bolotype/__main__.py +3 -0
- bolotype-0.1.0/src/bolotype/accessibility/__init__.py +0 -0
- bolotype-0.1.0/src/bolotype/accessibility/linux_atspi.py +597 -0
- bolotype-0.1.0/src/bolotype/asr/__init__.py +0 -0
- bolotype-0.1.0/src/bolotype/asr/base.py +18 -0
- bolotype-0.1.0/src/bolotype/asr/moonshine_asr.py +54 -0
- bolotype-0.1.0/src/bolotype/asr/nemotron_asr.py +328 -0
- bolotype-0.1.0/src/bolotype/cli.py +128 -0
- bolotype-0.1.0/src/bolotype/config.py +204 -0
- bolotype-0.1.0/src/bolotype/control.py +47 -0
- bolotype-0.1.0/src/bolotype/daemon.py +366 -0
- bolotype-0.1.0/src/bolotype/editor.py +121 -0
- bolotype-0.1.0/src/bolotype/input/__init__.py +0 -0
- bolotype-0.1.0/src/bolotype/input/linux.py +139 -0
- bolotype-0.1.0/src/bolotype/installer.py +137 -0
- bolotype-0.1.0/src/bolotype/llm.py +140 -0
- bolotype-0.1.0/src/bolotype/resources/default_settings.json +26 -0
- bolotype-0.1.0/src/bolotype/resources/default_system_prompt.txt +18 -0
- bolotype-0.1.0/src/bolotype.egg-info/PKG-INFO +351 -0
- bolotype-0.1.0/src/bolotype.egg-info/SOURCES.txt +28 -0
- bolotype-0.1.0/src/bolotype.egg-info/dependency_links.txt +1 -0
- bolotype-0.1.0/src/bolotype.egg-info/entry_points.txt +2 -0
- bolotype-0.1.0/src/bolotype.egg-info/requires.txt +34 -0
- bolotype-0.1.0/src/bolotype.egg-info/top_level.txt +1 -0
bolotype-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abdullah Baig
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
bolotype-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bolotype
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: System-wide local voice typing with AI-powered editing
|
|
5
|
+
Author: Muhammad Abdullah Baig
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/baig97/bolotype
|
|
8
|
+
Project-URL: Repository, https://github.com/baig97/bolotype
|
|
9
|
+
Project-URL: Issues, https://github.com/baig97/bolotype/issues
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: openai>=1.0
|
|
24
|
+
Requires-Dist: platformdirs>=4.0
|
|
25
|
+
Provides-Extra: moonshine
|
|
26
|
+
Requires-Dist: moonshine-voice; extra == "moonshine"
|
|
27
|
+
Provides-Extra: nemotron
|
|
28
|
+
Requires-Dist: transformers>=4.47; extra == "nemotron"
|
|
29
|
+
Requires-Dist: torch>=2.0; extra == "nemotron"
|
|
30
|
+
Requires-Dist: accelerate>=1.14; extra == "nemotron"
|
|
31
|
+
Requires-Dist: sounddevice>=0.4; extra == "nemotron"
|
|
32
|
+
Requires-Dist: librosa; extra == "nemotron"
|
|
33
|
+
Requires-Dist: Pillow>=9.1; extra == "nemotron"
|
|
34
|
+
Requires-Dist: numpy<2,>=1.26; extra == "nemotron"
|
|
35
|
+
Requires-Dist: scipy<1.16,>=1.11; extra == "nemotron"
|
|
36
|
+
Requires-Dist: scikit-learn>=1.4; extra == "nemotron"
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: moonshine-voice; extra == "all"
|
|
39
|
+
Requires-Dist: transformers>=4.47; extra == "all"
|
|
40
|
+
Requires-Dist: torch>=2.0; extra == "all"
|
|
41
|
+
Requires-Dist: accelerate>=1.14; extra == "all"
|
|
42
|
+
Requires-Dist: sounddevice>=0.4; extra == "all"
|
|
43
|
+
Requires-Dist: librosa; extra == "all"
|
|
44
|
+
Requires-Dist: Pillow>=9.1; extra == "all"
|
|
45
|
+
Requires-Dist: numpy<2,>=1.26; extra == "all"
|
|
46
|
+
Requires-Dist: scipy<1.16,>=1.11; extra == "all"
|
|
47
|
+
Requires-Dist: scikit-learn>=1.4; extra == "all"
|
|
48
|
+
Provides-Extra: dev
|
|
49
|
+
Requires-Dist: build; extra == "dev"
|
|
50
|
+
Requires-Dist: twine; extra == "dev"
|
|
51
|
+
Requires-Dist: pytest; extra == "dev"
|
|
52
|
+
Requires-Dist: ruff; extra == "dev"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# BoloType — Type at the speed of sound. Refine with LLMs of your choice.
|
|
56
|
+
|
|
57
|
+
> System-wide voice typing with instant dictation and AI-powered editing.
|
|
58
|
+
|
|
59
|
+
[](LICENSE)
|
|
60
|
+
|
|
61
|
+
> **Platform support:** Linux only. Windows and macOS support is coming soon.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
|
|
67
|
+
- **Instant dictation** — speech inserts at the cursor as soon as a phrase completes. No push-to-talk, no button to hold.
|
|
68
|
+
- **Bring your own LLM** — connect any OpenAI-compatible endpoint: llama.cpp, LMDeploy, vLLM, Ollama, OpenAI, Groq, and more. One setting to change.
|
|
69
|
+
- **Fully local by default** — audio never leaves your machine. LLM calls go only to the endpoint you configure. Nothing is sent anywhere unless you choose a cloud endpoint.
|
|
70
|
+
- **Private and safe** — no cloud account required, no telemetry, no data collection of any kind.
|
|
71
|
+
- **Voice polish commands** — say *"polish this paragraph"* and the LLM rewrites that span in place. Works on a line, paragraph, selection, or the entire field.
|
|
72
|
+
- **Precise undo** — *"undo that"* restores the exact pre-polish text, not a generic Ctrl+Z that may affect unrelated changes.
|
|
73
|
+
- **Two ASR engines** — [Moonshine](https://github.com/usefulsensors/moonshine) is fast, low-latency, and works on CPU. [Nemotron 3.5](https://huggingface.co/nvidia/nemotron-3.5-asr-streaming-0.6b) offers higher accuracy and requires a CUDA GPU.
|
|
74
|
+
- **System-wide** — works in any text field reachable via AT-SPI2: GTK apps, browsers, Electron apps, terminals, and more.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Quickstart
|
|
79
|
+
|
|
80
|
+
> Requires Ubuntu/Debian with a CUDA or CPU setup. Moonshine engine used below.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
git clone https://github.com/baig97/bolotype.git
|
|
84
|
+
cd bolotype
|
|
85
|
+
|
|
86
|
+
python3 -m venv --system-site-packages .venv
|
|
87
|
+
source .venv/bin/activate
|
|
88
|
+
|
|
89
|
+
pip install --upgrade pip setuptools wheel
|
|
90
|
+
pip install -e .
|
|
91
|
+
bolotype install moonshine
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Edit `~/.bolotype/settings.json` and set your LLM endpoint and model name (see [Configure](#configure)), then:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
bolotype run --start-active
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Say *"hello world"* — it appears at the cursor. Say *"polish this paragraph"* — the LLM rewrites it in place.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Install
|
|
105
|
+
|
|
106
|
+
> BoloType is not yet published on PyPI. Install from source.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/baig97/bolotype.git
|
|
110
|
+
cd bolotype
|
|
111
|
+
|
|
112
|
+
python3 -m venv --system-site-packages .venv
|
|
113
|
+
source .venv/bin/activate
|
|
114
|
+
|
|
115
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
116
|
+
pip install -e .
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
This installs only the lightweight core (CLI, LLM client, config). Then install your ASR engine:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
bolotype install moonshine # Moonshine — CPU-friendly, low latency (recommended)
|
|
123
|
+
bolotype install nemotron # Nemotron 3.5 — higher accuracy, requires CUDA GPU
|
|
124
|
+
bolotype install # both engines
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`bolotype install` also installs Linux system packages (`python3-pyatspi`, `xdotool`, `xclip`, etc.) via apt and creates `~/.bolotype/` with default config files.
|
|
128
|
+
|
|
129
|
+
> **Nemotron note:** Nemotron 3.5 has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use Moonshine.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Voice commands
|
|
134
|
+
|
|
135
|
+
| Command | What it polishes |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `polish this line` | The line the caret is on |
|
|
138
|
+
| `polish this paragraph` | The paragraph the caret is in (blank-line delimited) |
|
|
139
|
+
| `polish everything` | The entire field |
|
|
140
|
+
| `polish the selection` | The currently selected text |
|
|
141
|
+
| `polish this` | Alias for *polish everything* |
|
|
142
|
+
| `undo that` | Restore the last polished span |
|
|
143
|
+
|
|
144
|
+
Commands trigger when a completed phrase exactly matches one of the above after punctuation and whitespace normalization.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Configure
|
|
149
|
+
|
|
150
|
+
All settings live in `~/.bolotype/settings.json`. Only set the keys you want to override — everything else uses the defaults shown below.
|
|
151
|
+
|
|
152
|
+
### LLM
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"llm": {
|
|
157
|
+
"base_url": "http://127.0.0.1:8000/v1",
|
|
158
|
+
"model": "your-model-name",
|
|
159
|
+
"api_key": "",
|
|
160
|
+
"api_key_env": "OPENAI_API_KEY",
|
|
161
|
+
"timeout_seconds": 20,
|
|
162
|
+
"temperature": 0,
|
|
163
|
+
"max_output_tokens": 1000
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
| Key | Default | Description |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `base_url` | `""` | OpenAI-compatible API base URL. E.g. `http://127.0.0.1:8000/v1` for a local server or `https://api.openai.com/v1` for OpenAI. |
|
|
171
|
+
| `model` | `""` | **Required.** Model name exactly as your server expects it. |
|
|
172
|
+
| `api_key` | `""` | API key value. Leave empty if your local server doesn't require one. |
|
|
173
|
+
| `api_key_env` | `"OPENAI_API_KEY"` | Name of the environment variable to read the key from. Takes precedence over `api_key`. |
|
|
174
|
+
| `timeout_seconds` | `20` | Seconds to wait for the LLM response before raising an error. |
|
|
175
|
+
| `temperature` | `0` | Generation temperature. `0` is deterministic and gives the most consistent edits. |
|
|
176
|
+
| `max_output_tokens` | `1000` | Maximum tokens in the polished response. |
|
|
177
|
+
|
|
178
|
+
### ASR
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"asr": {
|
|
183
|
+
"engine": "moonshine",
|
|
184
|
+
"language": "en",
|
|
185
|
+
"nemotron_model_id": "nvidia/nemotron-3.5-asr-streaming-0.6b",
|
|
186
|
+
"nemotron_lookahead_tokens": 3,
|
|
187
|
+
"nemotron_vad_threshold": 0.01,
|
|
188
|
+
"nemotron_silence_duration_s": 1.25
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
| Key | Default | Description |
|
|
194
|
+
|---|---|---|
|
|
195
|
+
| `engine` | `"moonshine"` | ASR engine to use. `"moonshine"` or `"nemotron"`. Can also be set via `--asr-engine` flag or `BOLOTYPE_ASR_ENGINE` env var. |
|
|
196
|
+
| `language` | `"en"` | Language code. Moonshine accepts `"en"`. Nemotron accepts locale codes such as `"en-US"`, `"de-DE"`, or `"auto"`. |
|
|
197
|
+
| `nemotron_model_id` | `"nvidia/nemotron-3.5-asr-streaming-0.6b"` | HuggingFace model ID for Nemotron. Downloaded automatically on first run. |
|
|
198
|
+
| `nemotron_lookahead_tokens` | `3` | Controls the streaming chunk size and right-context window. Supported values: `0` (80 ms), `1` (160 ms), `3` (320 ms), `6` (560 ms), `13` (1120 ms). Lower values reduce latency; higher values give the model more context. |
|
|
199
|
+
| `nemotron_vad_threshold` | `0.01` | RMS energy level that triggers speech onset detection. Increase if background noise causes false triggers; decrease if the first syllable is being clipped. |
|
|
200
|
+
| `nemotron_silence_duration_s` | `1.25` | Seconds of silence after speech ends before the utterance is submitted for transcription. Increase for slower or more deliberate speech. |
|
|
201
|
+
|
|
202
|
+
### Input
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"input": {
|
|
207
|
+
"backend": "auto",
|
|
208
|
+
"append_space": true
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
| Key | Default | Description |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| `backend` | `"auto"` | Keyboard injection backend. `"auto"` picks `xdotool` on X11 and `ydotool`/`wtype` on Wayland. Set explicitly if auto-detection is wrong. |
|
|
216
|
+
| `append_space` | `true` | Append a space after each inserted phrase so the next phrase starts cleanly. |
|
|
217
|
+
|
|
218
|
+
### Accessibility
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"accessibility": {
|
|
223
|
+
"max_text_characters": 12000
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
| Key | Default | Description |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| `max_text_characters` | `12000` | Safety limit. Polish is refused for text spans larger than this. Prevents accidentally sending a very large document to the LLM. |
|
|
231
|
+
|
|
232
|
+
### Environment variables
|
|
233
|
+
|
|
234
|
+
All settings can also be set via environment variables, which take precedence over `settings.json`.
|
|
235
|
+
|
|
236
|
+
| Variable | Maps to |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `BOLOTYPE_ASR_ENGINE` | `asr.engine` |
|
|
239
|
+
| `OPENAI_BASE_URL` | `llm.base_url` |
|
|
240
|
+
| `OPENAI_API_KEY` | `llm.api_key` |
|
|
241
|
+
| `VOICE_LLM_MODEL` | `llm.model` |
|
|
242
|
+
| `VOICE_LLM_TIMEOUT` | `llm.timeout_seconds` |
|
|
243
|
+
| `VOICE_LLM_TEMPERATURE` | `llm.temperature` |
|
|
244
|
+
| `VOICE_LLM_MAX_TOKENS` | `llm.max_output_tokens` |
|
|
245
|
+
| `BOLOTYPE_CONFIG_DIR` | Config directory (default: `~/.bolotype`) |
|
|
246
|
+
|
|
247
|
+
### Prompt customization
|
|
248
|
+
|
|
249
|
+
The LLM polish prompt lives at `~/.bolotype/system_prompt.txt` and is created by `bolotype install`. Edit it freely:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
bolotype prompt-path # prints the path
|
|
253
|
+
nano ~/.bolotype/system_prompt.txt
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Run
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
bolotype run --start-active
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
All subcommands:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
bolotype install moonshine # install Moonshine ASR + system deps + create config
|
|
268
|
+
bolotype install nemotron # install Nemotron ASR + system deps + create config
|
|
269
|
+
bolotype install # install both ASR engines + system deps + create config
|
|
270
|
+
bolotype run # start the daemon
|
|
271
|
+
bolotype toggle # start/stop listening
|
|
272
|
+
bolotype polish # polish entire focused field
|
|
273
|
+
bolotype polish-line # polish current line
|
|
274
|
+
bolotype polish-paragraph # polish current paragraph
|
|
275
|
+
bolotype polish-selection # polish selected text
|
|
276
|
+
bolotype undo # undo last polish
|
|
277
|
+
bolotype status # show daemon status
|
|
278
|
+
bolotype shutdown # stop the daemon
|
|
279
|
+
bolotype config-path # print ~/.bolotype
|
|
280
|
+
bolotype prompt-path # print ~/.bolotype/system_prompt.txt
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
For GNOME keyboard shortcuts, use the absolute path to the venv binary so the shortcut works outside a terminal session:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
/path/to/bolotype/.venv/bin/bolotype toggle
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Replacement strategy
|
|
292
|
+
|
|
293
|
+
**Native GTK fields** (gedit, GNOME Text Editor, LibreOffice, terminals): AT-SPI `EditableText` writes the span directly.
|
|
294
|
+
|
|
295
|
+
**Browser/Electron fields** (Chrome, Electron apps): AT-SPI `Text.setSelection` selects the span, the polished text is placed on the clipboard via `xclip`/`wl-copy`, and `Ctrl+V` pastes it.
|
|
296
|
+
|
|
297
|
+
Fields exposing neither interface (password fields, some embedded widgets) are unsupported.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Development
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
pip install -e ".[dev]"
|
|
305
|
+
python -m build
|
|
306
|
+
twine check dist/*
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Known issues
|
|
312
|
+
|
|
313
|
+
### Virtual environment
|
|
314
|
+
|
|
315
|
+
Ubuntu's `pyatspi` and `gi` packages are installed via the system package manager and are not available on PyPI. A normal isolated venv will not see them.
|
|
316
|
+
|
|
317
|
+
**Required:**
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
python3 -m venv --system-site-packages .venv
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Conda
|
|
324
|
+
|
|
325
|
+
Conda environments may be incompatible with Ubuntu's compiled `gi` bindings due to ABI differences. Recommended pattern: run BoloType in a system-Python venv; run external model servers (LMDeploy, vLLM) in their own conda environment and communicate over HTTP.
|
|
326
|
+
|
|
327
|
+
### Nemotron: GPU required
|
|
328
|
+
|
|
329
|
+
Nemotron 3.5 is loaded with `device_map="auto"` and has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use the Moonshine engine instead.
|
|
330
|
+
|
|
331
|
+
### Nemotron: latency
|
|
332
|
+
|
|
333
|
+
Nemotron processes audio in streaming chunks but submits complete utterances for transcription. End-to-end latency depends on GPU speed and utterance length. Detailed benchmarking has not been done. Moonshine is lower latency on both CPU and GPU. You are encouraged to tune `nemotron_lookahead_tokens` and `nemotron_silence_duration_s` to match your hardware and speaking style.
|
|
334
|
+
|
|
335
|
+
### Browser and Electron accessibility
|
|
336
|
+
|
|
337
|
+
Chromium-based rich text editors may expose only an object-replacement placeholder (`U+FFFC`) via AT-SPI. BoloType searches the AT-SPI subtree for the real text node. If none is found, polish is unsupported for that field.
|
|
338
|
+
|
|
339
|
+
### Wayland
|
|
340
|
+
|
|
341
|
+
Input injection differs between compositors. X11 via `xdotool` is more reliable. Wayland requires `ydotool` or `wtype`.
|
|
342
|
+
|
|
343
|
+
### Rich text
|
|
344
|
+
|
|
345
|
+
Targeted replacement through accessibility APIs may flatten formatting or operate only on the exposed accessible node.
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## License
|
|
350
|
+
|
|
351
|
+
MIT © 2026 Muhammad Abdullah Baig
|
bolotype-0.1.0/README.md
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# BoloType — Type at the speed of sound. Refine with LLMs of your choice.
|
|
2
|
+
|
|
3
|
+
> System-wide voice typing with instant dictation and AI-powered editing.
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
> **Platform support:** Linux only. Windows and macOS support is coming soon.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Instant dictation** — speech inserts at the cursor as soon as a phrase completes. No push-to-talk, no button to hold.
|
|
14
|
+
- **Bring your own LLM** — connect any OpenAI-compatible endpoint: llama.cpp, LMDeploy, vLLM, Ollama, OpenAI, Groq, and more. One setting to change.
|
|
15
|
+
- **Fully local by default** — audio never leaves your machine. LLM calls go only to the endpoint you configure. Nothing is sent anywhere unless you choose a cloud endpoint.
|
|
16
|
+
- **Private and safe** — no cloud account required, no telemetry, no data collection of any kind.
|
|
17
|
+
- **Voice polish commands** — say *"polish this paragraph"* and the LLM rewrites that span in place. Works on a line, paragraph, selection, or the entire field.
|
|
18
|
+
- **Precise undo** — *"undo that"* restores the exact pre-polish text, not a generic Ctrl+Z that may affect unrelated changes.
|
|
19
|
+
- **Two ASR engines** — [Moonshine](https://github.com/usefulsensors/moonshine) is fast, low-latency, and works on CPU. [Nemotron 3.5](https://huggingface.co/nvidia/nemotron-3.5-asr-streaming-0.6b) offers higher accuracy and requires a CUDA GPU.
|
|
20
|
+
- **System-wide** — works in any text field reachable via AT-SPI2: GTK apps, browsers, Electron apps, terminals, and more.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quickstart
|
|
25
|
+
|
|
26
|
+
> Requires Ubuntu/Debian with a CUDA or CPU setup. Moonshine engine used below.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/baig97/bolotype.git
|
|
30
|
+
cd bolotype
|
|
31
|
+
|
|
32
|
+
python3 -m venv --system-site-packages .venv
|
|
33
|
+
source .venv/bin/activate
|
|
34
|
+
|
|
35
|
+
pip install --upgrade pip setuptools wheel
|
|
36
|
+
pip install -e .
|
|
37
|
+
bolotype install moonshine
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Edit `~/.bolotype/settings.json` and set your LLM endpoint and model name (see [Configure](#configure)), then:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bolotype run --start-active
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Say *"hello world"* — it appears at the cursor. Say *"polish this paragraph"* — the LLM rewrites it in place.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
> BoloType is not yet published on PyPI. Install from source.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git clone https://github.com/baig97/bolotype.git
|
|
56
|
+
cd bolotype
|
|
57
|
+
|
|
58
|
+
python3 -m venv --system-site-packages .venv
|
|
59
|
+
source .venv/bin/activate
|
|
60
|
+
|
|
61
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
62
|
+
pip install -e .
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This installs only the lightweight core (CLI, LLM client, config). Then install your ASR engine:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
bolotype install moonshine # Moonshine — CPU-friendly, low latency (recommended)
|
|
69
|
+
bolotype install nemotron # Nemotron 3.5 — higher accuracy, requires CUDA GPU
|
|
70
|
+
bolotype install # both engines
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`bolotype install` also installs Linux system packages (`python3-pyatspi`, `xdotool`, `xclip`, etc.) via apt and creates `~/.bolotype/` with default config files.
|
|
74
|
+
|
|
75
|
+
> **Nemotron note:** Nemotron 3.5 has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use Moonshine.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Voice commands
|
|
80
|
+
|
|
81
|
+
| Command | What it polishes |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `polish this line` | The line the caret is on |
|
|
84
|
+
| `polish this paragraph` | The paragraph the caret is in (blank-line delimited) |
|
|
85
|
+
| `polish everything` | The entire field |
|
|
86
|
+
| `polish the selection` | The currently selected text |
|
|
87
|
+
| `polish this` | Alias for *polish everything* |
|
|
88
|
+
| `undo that` | Restore the last polished span |
|
|
89
|
+
|
|
90
|
+
Commands trigger when a completed phrase exactly matches one of the above after punctuation and whitespace normalization.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Configure
|
|
95
|
+
|
|
96
|
+
All settings live in `~/.bolotype/settings.json`. Only set the keys you want to override — everything else uses the defaults shown below.
|
|
97
|
+
|
|
98
|
+
### LLM
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"llm": {
|
|
103
|
+
"base_url": "http://127.0.0.1:8000/v1",
|
|
104
|
+
"model": "your-model-name",
|
|
105
|
+
"api_key": "",
|
|
106
|
+
"api_key_env": "OPENAI_API_KEY",
|
|
107
|
+
"timeout_seconds": 20,
|
|
108
|
+
"temperature": 0,
|
|
109
|
+
"max_output_tokens": 1000
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
| Key | Default | Description |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| `base_url` | `""` | OpenAI-compatible API base URL. E.g. `http://127.0.0.1:8000/v1` for a local server or `https://api.openai.com/v1` for OpenAI. |
|
|
117
|
+
| `model` | `""` | **Required.** Model name exactly as your server expects it. |
|
|
118
|
+
| `api_key` | `""` | API key value. Leave empty if your local server doesn't require one. |
|
|
119
|
+
| `api_key_env` | `"OPENAI_API_KEY"` | Name of the environment variable to read the key from. Takes precedence over `api_key`. |
|
|
120
|
+
| `timeout_seconds` | `20` | Seconds to wait for the LLM response before raising an error. |
|
|
121
|
+
| `temperature` | `0` | Generation temperature. `0` is deterministic and gives the most consistent edits. |
|
|
122
|
+
| `max_output_tokens` | `1000` | Maximum tokens in the polished response. |
|
|
123
|
+
|
|
124
|
+
### ASR
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"asr": {
|
|
129
|
+
"engine": "moonshine",
|
|
130
|
+
"language": "en",
|
|
131
|
+
"nemotron_model_id": "nvidia/nemotron-3.5-asr-streaming-0.6b",
|
|
132
|
+
"nemotron_lookahead_tokens": 3,
|
|
133
|
+
"nemotron_vad_threshold": 0.01,
|
|
134
|
+
"nemotron_silence_duration_s": 1.25
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
| Key | Default | Description |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| `engine` | `"moonshine"` | ASR engine to use. `"moonshine"` or `"nemotron"`. Can also be set via `--asr-engine` flag or `BOLOTYPE_ASR_ENGINE` env var. |
|
|
142
|
+
| `language` | `"en"` | Language code. Moonshine accepts `"en"`. Nemotron accepts locale codes such as `"en-US"`, `"de-DE"`, or `"auto"`. |
|
|
143
|
+
| `nemotron_model_id` | `"nvidia/nemotron-3.5-asr-streaming-0.6b"` | HuggingFace model ID for Nemotron. Downloaded automatically on first run. |
|
|
144
|
+
| `nemotron_lookahead_tokens` | `3` | Controls the streaming chunk size and right-context window. Supported values: `0` (80 ms), `1` (160 ms), `3` (320 ms), `6` (560 ms), `13` (1120 ms). Lower values reduce latency; higher values give the model more context. |
|
|
145
|
+
| `nemotron_vad_threshold` | `0.01` | RMS energy level that triggers speech onset detection. Increase if background noise causes false triggers; decrease if the first syllable is being clipped. |
|
|
146
|
+
| `nemotron_silence_duration_s` | `1.25` | Seconds of silence after speech ends before the utterance is submitted for transcription. Increase for slower or more deliberate speech. |
|
|
147
|
+
|
|
148
|
+
### Input
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"input": {
|
|
153
|
+
"backend": "auto",
|
|
154
|
+
"append_space": true
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
| Key | Default | Description |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| `backend` | `"auto"` | Keyboard injection backend. `"auto"` picks `xdotool` on X11 and `ydotool`/`wtype` on Wayland. Set explicitly if auto-detection is wrong. |
|
|
162
|
+
| `append_space` | `true` | Append a space after each inserted phrase so the next phrase starts cleanly. |
|
|
163
|
+
|
|
164
|
+
### Accessibility
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"accessibility": {
|
|
169
|
+
"max_text_characters": 12000
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
| Key | Default | Description |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| `max_text_characters` | `12000` | Safety limit. Polish is refused for text spans larger than this. Prevents accidentally sending a very large document to the LLM. |
|
|
177
|
+
|
|
178
|
+
### Environment variables
|
|
179
|
+
|
|
180
|
+
All settings can also be set via environment variables, which take precedence over `settings.json`.
|
|
181
|
+
|
|
182
|
+
| Variable | Maps to |
|
|
183
|
+
|---|---|
|
|
184
|
+
| `BOLOTYPE_ASR_ENGINE` | `asr.engine` |
|
|
185
|
+
| `OPENAI_BASE_URL` | `llm.base_url` |
|
|
186
|
+
| `OPENAI_API_KEY` | `llm.api_key` |
|
|
187
|
+
| `VOICE_LLM_MODEL` | `llm.model` |
|
|
188
|
+
| `VOICE_LLM_TIMEOUT` | `llm.timeout_seconds` |
|
|
189
|
+
| `VOICE_LLM_TEMPERATURE` | `llm.temperature` |
|
|
190
|
+
| `VOICE_LLM_MAX_TOKENS` | `llm.max_output_tokens` |
|
|
191
|
+
| `BOLOTYPE_CONFIG_DIR` | Config directory (default: `~/.bolotype`) |
|
|
192
|
+
|
|
193
|
+
### Prompt customization
|
|
194
|
+
|
|
195
|
+
The LLM polish prompt lives at `~/.bolotype/system_prompt.txt` and is created by `bolotype install`. Edit it freely:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
bolotype prompt-path # prints the path
|
|
199
|
+
nano ~/.bolotype/system_prompt.txt
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Run
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
bolotype run --start-active
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
All subcommands:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
bolotype install moonshine # install Moonshine ASR + system deps + create config
|
|
214
|
+
bolotype install nemotron # install Nemotron ASR + system deps + create config
|
|
215
|
+
bolotype install # install both ASR engines + system deps + create config
|
|
216
|
+
bolotype run # start the daemon
|
|
217
|
+
bolotype toggle # start/stop listening
|
|
218
|
+
bolotype polish # polish entire focused field
|
|
219
|
+
bolotype polish-line # polish current line
|
|
220
|
+
bolotype polish-paragraph # polish current paragraph
|
|
221
|
+
bolotype polish-selection # polish selected text
|
|
222
|
+
bolotype undo # undo last polish
|
|
223
|
+
bolotype status # show daemon status
|
|
224
|
+
bolotype shutdown # stop the daemon
|
|
225
|
+
bolotype config-path # print ~/.bolotype
|
|
226
|
+
bolotype prompt-path # print ~/.bolotype/system_prompt.txt
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
For GNOME keyboard shortcuts, use the absolute path to the venv binary so the shortcut works outside a terminal session:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
/path/to/bolotype/.venv/bin/bolotype toggle
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Replacement strategy
|
|
238
|
+
|
|
239
|
+
**Native GTK fields** (gedit, GNOME Text Editor, LibreOffice, terminals): AT-SPI `EditableText` writes the span directly.
|
|
240
|
+
|
|
241
|
+
**Browser/Electron fields** (Chrome, Electron apps): AT-SPI `Text.setSelection` selects the span, the polished text is placed on the clipboard via `xclip`/`wl-copy`, and `Ctrl+V` pastes it.
|
|
242
|
+
|
|
243
|
+
Fields exposing neither interface (password fields, some embedded widgets) are unsupported.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Development
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
pip install -e ".[dev]"
|
|
251
|
+
python -m build
|
|
252
|
+
twine check dist/*
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Known issues
|
|
258
|
+
|
|
259
|
+
### Virtual environment
|
|
260
|
+
|
|
261
|
+
Ubuntu's `pyatspi` and `gi` packages are installed via the system package manager and are not available on PyPI. A normal isolated venv will not see them.
|
|
262
|
+
|
|
263
|
+
**Required:**
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
python3 -m venv --system-site-packages .venv
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Conda
|
|
270
|
+
|
|
271
|
+
Conda environments may be incompatible with Ubuntu's compiled `gi` bindings due to ABI differences. Recommended pattern: run BoloType in a system-Python venv; run external model servers (LMDeploy, vLLM) in their own conda environment and communicate over HTTP.
|
|
272
|
+
|
|
273
|
+
### Nemotron: GPU required
|
|
274
|
+
|
|
275
|
+
Nemotron 3.5 is loaded with `device_map="auto"` and has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use the Moonshine engine instead.
|
|
276
|
+
|
|
277
|
+
### Nemotron: latency
|
|
278
|
+
|
|
279
|
+
Nemotron processes audio in streaming chunks but submits complete utterances for transcription. End-to-end latency depends on GPU speed and utterance length. Detailed benchmarking has not been done. Moonshine is lower latency on both CPU and GPU. You are encouraged to tune `nemotron_lookahead_tokens` and `nemotron_silence_duration_s` to match your hardware and speaking style.
|
|
280
|
+
|
|
281
|
+
### Browser and Electron accessibility
|
|
282
|
+
|
|
283
|
+
Chromium-based rich text editors may expose only an object-replacement placeholder (`U+FFFC`) via AT-SPI. BoloType searches the AT-SPI subtree for the real text node. If none is found, polish is unsupported for that field.
|
|
284
|
+
|
|
285
|
+
### Wayland
|
|
286
|
+
|
|
287
|
+
Input injection differs between compositors. X11 via `xdotool` is more reliable. Wayland requires `ydotool` or `wtype`.
|
|
288
|
+
|
|
289
|
+
### Rich text
|
|
290
|
+
|
|
291
|
+
Targeted replacement through accessibility APIs may flatten formatting or operate only on the exposed accessible node.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## License
|
|
296
|
+
|
|
297
|
+
MIT © 2026 Muhammad Abdullah Baig
|