easyspeak-linux 0.2.0__tar.gz → 0.3.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.
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/.github/workflows/pipeline.yml +18 -1
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/.gitignore +4 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/PKG-INFO +37 -17
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/README.md +27 -16
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/easyspeak_linux.egg-info/PKG-INFO +37 -17
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/easyspeak_linux.egg-info/SOURCES.txt +8 -3
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/easyspeak_linux.egg-info/requires.txt +12 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/pyproject.toml +26 -3
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/core/config.py +3 -0
- easyspeak_linux-0.3.0/src/core/gnome_extension.py +335 -0
- easyspeak_linux-0.3.0/src/core/main.py +472 -0
- easyspeak_linux-0.3.0/src/core/mediakeys.py +52 -0
- easyspeak_linux-0.3.0/src/core/speech.py +240 -0
- easyspeak_linux-0.3.0/src/core/tray.py +194 -0
- easyspeak_linux-0.3.0/src/extension-helpers.js +60 -0
- easyspeak_linux-0.3.0/src/extension.js +680 -0
- easyspeak_linux-0.3.0/src/metadata.json +7 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/00_mousegrid.py +2 -136
- easyspeak_linux-0.3.0/src/plugins/apps.py +203 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/browser.py +26 -4
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/files.py +2 -1
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/media.py +16 -8
- easyspeak_linux-0.3.0/src/plugins/sleep.py +34 -0
- easyspeak_linux-0.3.0/src/plugins/system.py +161 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/zz_base.py +5 -5
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/uv.lock +283 -50
- easyspeak_linux-0.2.0/CONTRIBUTING.md +0 -89
- easyspeak_linux-0.2.0/flake.lock +0 -61
- easyspeak_linux-0.2.0/flake.nix +0 -236
- easyspeak_linux-0.2.0/src/core/main.py +0 -311
- easyspeak_linux-0.2.0/src/plugins/apps.py +0 -93
- easyspeak_linux-0.2.0/src/plugins/system.py +0 -122
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/.github/actions/benchmark/action.yml +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/.github/workflows/benchmark.yml +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/.github/workflows/publish.yml +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/.github/workflows/safety.yml +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/LICENSE +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/easyspeak_linux.egg-info/dependency_links.txt +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/easyspeak_linux.egg-info/entry_points.txt +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/easyspeak_linux.egg-info/top_level.txt +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/setup.cfg +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/core/__init__.py +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/core/__main__.py +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/00_eyetrack.py +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/__init__.py +0 -0
- {easyspeak_linux-0.2.0 → easyspeak_linux-0.3.0}/src/plugins/dictation.py +0 -0
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
- lint --
|
|
21
21
|
- types
|
|
22
22
|
- package
|
|
23
|
-
-
|
|
23
|
+
- gate
|
|
24
24
|
fail-fast: false
|
|
25
25
|
steps:
|
|
26
26
|
- uses: actions/checkout@v6
|
|
@@ -33,6 +33,23 @@ jobs:
|
|
|
33
33
|
sudo apt install -y portaudio19-dev
|
|
34
34
|
- run: just ${{ matrix.task }}
|
|
35
35
|
|
|
36
|
+
js:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
strategy:
|
|
39
|
+
matrix:
|
|
40
|
+
task:
|
|
41
|
+
- lint-js
|
|
42
|
+
- test-js
|
|
43
|
+
fail-fast: false
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v6
|
|
46
|
+
- uses: actions/setup-node@v5
|
|
47
|
+
with:
|
|
48
|
+
node-version: '22'
|
|
49
|
+
- uses: taiki-e/install-action@just
|
|
50
|
+
- run: npm install --global eslint@10
|
|
51
|
+
- run: just ${{ matrix.task }}
|
|
52
|
+
|
|
36
53
|
test:
|
|
37
54
|
runs-on: ubuntu-latest
|
|
38
55
|
strategy:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: easyspeak-linux
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Voice control for Linux desktops. Fully local, no cloud, Wayland-native.
|
|
5
5
|
Author-email: Matt Hartley <matt@matthartley.com>
|
|
6
6
|
Maintainer-email: Matt Hartley <matt@matthartley.com>
|
|
@@ -24,19 +24,28 @@ Requires-Python: <3.14,>=3.10
|
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
Requires-Dist: faster-whisper>=1.2.1
|
|
27
|
+
Requires-Dist: jeepney>=0.9
|
|
27
28
|
Requires-Dist: numpy>=2.2.6
|
|
28
29
|
Requires-Dist: onnxruntime>=1.23.2
|
|
29
30
|
Requires-Dist: onnxruntime<1.24; python_full_version < "3.11"
|
|
30
31
|
Requires-Dist: pyaudio>=0.2.14
|
|
32
|
+
Provides-Extra: acceptance
|
|
33
|
+
Requires-Dist: pytest>=8; extra == "acceptance"
|
|
34
|
+
Requires-Dist: pytest-bdd>=7; extra == "acceptance"
|
|
31
35
|
Provides-Extra: benchmark
|
|
32
36
|
Requires-Dist: pytest>=8; extra == "benchmark"
|
|
33
37
|
Requires-Dist: pytest-benchmark>=5; extra == "benchmark"
|
|
34
38
|
Provides-Extra: head-tracking
|
|
35
39
|
Requires-Dist: opencv-python>=4.13.0.90; extra == "head-tracking"
|
|
36
40
|
Requires-Dist: sixdrepnet>=0.1.6; extra == "head-tracking"
|
|
41
|
+
Provides-Extra: integration
|
|
42
|
+
Requires-Dist: pytest>=8; extra == "integration"
|
|
37
43
|
Provides-Extra: mypy
|
|
38
44
|
Requires-Dist: mypy>=1.19.1; extra == "mypy"
|
|
39
45
|
Requires-Dist: types-pyaudio>=0.2.16.20250801; extra == "mypy"
|
|
46
|
+
Provides-Extra: unittest
|
|
47
|
+
Requires-Dist: coverage[toml]>=7.14; extra == "unittest"
|
|
48
|
+
Requires-Dist: pytest>=8; extra == "unittest"
|
|
40
49
|
Dynamic: license-file
|
|
41
50
|
|
|
42
51
|
# EasySpeak [](https://pypi.org/project/easyspeak-linux/)
|
|
@@ -196,7 +205,10 @@ easyspeak # the project execution script
|
|
|
196
205
|
|
|
197
206
|
Activate the venv each time you open a new terminal.
|
|
198
207
|
|
|
199
|
-
Say "Hey Jarvis" followed by a command.
|
|
208
|
+
Say "Hey Jarvis" followed by a command. After a command that gives no spoken
|
|
209
|
+
reply (such as volume changes), EasySpeak keeps listening for a few seconds so
|
|
210
|
+
you can chain commands — say "louder", "louder", "louder" without repeating the
|
|
211
|
+
wake word each time.
|
|
200
212
|
|
|
201
213
|
## Commands
|
|
202
214
|
|
|
@@ -315,9 +327,10 @@ Built-in bookmarks: youtube, google, gmail, github, reddit, twitter, facebook, a
|
|
|
315
327
|
| close [app] | Close application |
|
|
316
328
|
|
|
317
329
|
Default apps in `plugins/apps.py` (edit to match your system):
|
|
318
|
-
- firefox, steam, spotify, calculator, settings, files, terminal, browser
|
|
330
|
+
- firefox, steam, spotify, calculator, settings, files, terminal, browser, music player
|
|
319
331
|
|
|
320
|
-
These are just examples. Edit `apps.py` to add your own apps.
|
|
332
|
+
These are just examples. Edit `apps.py` to add your own apps. Some accept
|
|
333
|
+
spoken aliases — e.g. "open music app" works the same as "open music player".
|
|
321
334
|
|
|
322
335
|
### Files
|
|
323
336
|
|
|
@@ -328,6 +341,7 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
328
341
|
| open pictures | Open Pictures folder |
|
|
329
342
|
| open music | Open Music folder |
|
|
330
343
|
| open videos | Open Videos folder |
|
|
344
|
+
| open projects | Open Projects folder |
|
|
331
345
|
| open home | Open home folder |
|
|
332
346
|
| open desktop | Open Desktop folder |
|
|
333
347
|
|
|
@@ -336,7 +350,7 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
336
350
|
| Command | Action |
|
|
337
351
|
|---------|--------|
|
|
338
352
|
| play | Resume playback |
|
|
339
|
-
| pause | Pause playback |
|
|
353
|
+
| pause / stop the music | Pause playback |
|
|
340
354
|
| next / skip | Next track |
|
|
341
355
|
| previous / back | Previous track |
|
|
342
356
|
|
|
@@ -344,30 +358,35 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
344
358
|
|
|
345
359
|
| Command | Action |
|
|
346
360
|
|---------|--------|
|
|
347
|
-
| volume up/down | Adjust volume |
|
|
361
|
+
| volume up/down (or louder / quieter) | Adjust volume one step (repeat to keep going) |
|
|
362
|
+
| very loud / very silent | Jump straight to near-max (85%) / low (15%, not muted) |
|
|
348
363
|
| mute | Toggle mute |
|
|
349
364
|
| brightness up/down | Adjust brightness |
|
|
350
365
|
| do not disturb on/off | Toggle notifications |
|
|
351
366
|
|
|
367
|
+
Volume changes are silent — GNOME's own on-screen display and chime acknowledge them.
|
|
368
|
+
|
|
352
369
|
### General
|
|
353
370
|
|
|
354
371
|
| Command | Action |
|
|
355
372
|
|---------|--------|
|
|
356
373
|
| help | List all commands |
|
|
357
|
-
|
|
|
374
|
+
| go to sleep / stop listening | Release the mic (reactivate from the tray icon) |
|
|
375
|
+
| quit / exit / goodbye | Exit EasySpeak |
|
|
358
376
|
|
|
359
377
|
## File Structure
|
|
360
378
|
|
|
361
379
|
```
|
|
362
380
|
easyspeak/
|
|
363
|
-
├── extension.js # GNOME Shell extension
|
|
364
|
-
├── metadata.json # Extension metadata
|
|
365
381
|
├── pyproject.toml
|
|
366
382
|
├── src
|
|
383
|
+
│ ├── extension.js # GNOME Shell extension (bundled as package data)
|
|
384
|
+
│ ├── metadata.json # Extension metadata
|
|
367
385
|
│ ├── core
|
|
368
386
|
│ │ ├── __init__.py
|
|
369
387
|
│ │ ├── __main__.py
|
|
370
388
|
│ │ ├── config.py # Tuning constants + Whisper model factory
|
|
389
|
+
│ │ ├── gnome_extension.py # Installs/refreshes/enables the extension
|
|
371
390
|
│ │ └── main.py # EasySpeak class + main loop
|
|
372
391
|
│ └── plugins
|
|
373
392
|
│ ├── __init__.py
|
|
@@ -386,9 +405,9 @@ easyspeak/
|
|
|
386
405
|
└── plugins # tests for src/plugins/
|
|
387
406
|
```
|
|
388
407
|
|
|
389
|
-
On first start,
|
|
390
|
-
|
|
391
|
-
|
|
408
|
+
On first start, core auto-installs the GNOME Shell extension to the
|
|
409
|
+
user-local extensions directory (unless GNOME already sees it via a
|
|
410
|
+
system-wide install). Files copied:
|
|
392
411
|
|
|
393
412
|
```
|
|
394
413
|
~/.local/share/gnome-shell/extensions/easyspeak-grid@local/
|
|
@@ -444,11 +463,12 @@ def handle(cmd, core):
|
|
|
444
463
|
|
|
445
464
|
**Mouse grid: "Failed to show grid — is extension enabled?"**
|
|
446
465
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
466
|
+
You don't install the extension yourself — EasySpeak does it automatically
|
|
467
|
+
on startup, copying it to
|
|
468
|
+
`~/.local/share/gnome-shell/extensions/easyspeak-grid@local/` and keeping it
|
|
469
|
+
up to date (look for an `easyspeak: installed ...` or `easyspeak: updated ...`
|
|
470
|
+
message). On Wayland, GNOME Shell only scans for new extensions at login, so
|
|
471
|
+
you typically have to **log out and back in** before it becomes loadable.
|
|
452
472
|
|
|
453
473
|
After re-login, enable it from the command line:
|
|
454
474
|
|
|
@@ -155,7 +155,10 @@ easyspeak # the project execution script
|
|
|
155
155
|
|
|
156
156
|
Activate the venv each time you open a new terminal.
|
|
157
157
|
|
|
158
|
-
Say "Hey Jarvis" followed by a command.
|
|
158
|
+
Say "Hey Jarvis" followed by a command. After a command that gives no spoken
|
|
159
|
+
reply (such as volume changes), EasySpeak keeps listening for a few seconds so
|
|
160
|
+
you can chain commands — say "louder", "louder", "louder" without repeating the
|
|
161
|
+
wake word each time.
|
|
159
162
|
|
|
160
163
|
## Commands
|
|
161
164
|
|
|
@@ -274,9 +277,10 @@ Built-in bookmarks: youtube, google, gmail, github, reddit, twitter, facebook, a
|
|
|
274
277
|
| close [app] | Close application |
|
|
275
278
|
|
|
276
279
|
Default apps in `plugins/apps.py` (edit to match your system):
|
|
277
|
-
- firefox, steam, spotify, calculator, settings, files, terminal, browser
|
|
280
|
+
- firefox, steam, spotify, calculator, settings, files, terminal, browser, music player
|
|
278
281
|
|
|
279
|
-
These are just examples. Edit `apps.py` to add your own apps.
|
|
282
|
+
These are just examples. Edit `apps.py` to add your own apps. Some accept
|
|
283
|
+
spoken aliases — e.g. "open music app" works the same as "open music player".
|
|
280
284
|
|
|
281
285
|
### Files
|
|
282
286
|
|
|
@@ -287,6 +291,7 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
287
291
|
| open pictures | Open Pictures folder |
|
|
288
292
|
| open music | Open Music folder |
|
|
289
293
|
| open videos | Open Videos folder |
|
|
294
|
+
| open projects | Open Projects folder |
|
|
290
295
|
| open home | Open home folder |
|
|
291
296
|
| open desktop | Open Desktop folder |
|
|
292
297
|
|
|
@@ -295,7 +300,7 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
295
300
|
| Command | Action |
|
|
296
301
|
|---------|--------|
|
|
297
302
|
| play | Resume playback |
|
|
298
|
-
| pause | Pause playback |
|
|
303
|
+
| pause / stop the music | Pause playback |
|
|
299
304
|
| next / skip | Next track |
|
|
300
305
|
| previous / back | Previous track |
|
|
301
306
|
|
|
@@ -303,30 +308,35 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
303
308
|
|
|
304
309
|
| Command | Action |
|
|
305
310
|
|---------|--------|
|
|
306
|
-
| volume up/down | Adjust volume |
|
|
311
|
+
| volume up/down (or louder / quieter) | Adjust volume one step (repeat to keep going) |
|
|
312
|
+
| very loud / very silent | Jump straight to near-max (85%) / low (15%, not muted) |
|
|
307
313
|
| mute | Toggle mute |
|
|
308
314
|
| brightness up/down | Adjust brightness |
|
|
309
315
|
| do not disturb on/off | Toggle notifications |
|
|
310
316
|
|
|
317
|
+
Volume changes are silent — GNOME's own on-screen display and chime acknowledge them.
|
|
318
|
+
|
|
311
319
|
### General
|
|
312
320
|
|
|
313
321
|
| Command | Action |
|
|
314
322
|
|---------|--------|
|
|
315
323
|
| help | List all commands |
|
|
316
|
-
|
|
|
324
|
+
| go to sleep / stop listening | Release the mic (reactivate from the tray icon) |
|
|
325
|
+
| quit / exit / goodbye | Exit EasySpeak |
|
|
317
326
|
|
|
318
327
|
## File Structure
|
|
319
328
|
|
|
320
329
|
```
|
|
321
330
|
easyspeak/
|
|
322
|
-
├── extension.js # GNOME Shell extension
|
|
323
|
-
├── metadata.json # Extension metadata
|
|
324
331
|
├── pyproject.toml
|
|
325
332
|
├── src
|
|
333
|
+
│ ├── extension.js # GNOME Shell extension (bundled as package data)
|
|
334
|
+
│ ├── metadata.json # Extension metadata
|
|
326
335
|
│ ├── core
|
|
327
336
|
│ │ ├── __init__.py
|
|
328
337
|
│ │ ├── __main__.py
|
|
329
338
|
│ │ ├── config.py # Tuning constants + Whisper model factory
|
|
339
|
+
│ │ ├── gnome_extension.py # Installs/refreshes/enables the extension
|
|
330
340
|
│ │ └── main.py # EasySpeak class + main loop
|
|
331
341
|
│ └── plugins
|
|
332
342
|
│ ├── __init__.py
|
|
@@ -345,9 +355,9 @@ easyspeak/
|
|
|
345
355
|
└── plugins # tests for src/plugins/
|
|
346
356
|
```
|
|
347
357
|
|
|
348
|
-
On first start,
|
|
349
|
-
|
|
350
|
-
|
|
358
|
+
On first start, core auto-installs the GNOME Shell extension to the
|
|
359
|
+
user-local extensions directory (unless GNOME already sees it via a
|
|
360
|
+
system-wide install). Files copied:
|
|
351
361
|
|
|
352
362
|
```
|
|
353
363
|
~/.local/share/gnome-shell/extensions/easyspeak-grid@local/
|
|
@@ -403,11 +413,12 @@ def handle(cmd, core):
|
|
|
403
413
|
|
|
404
414
|
**Mouse grid: "Failed to show grid — is extension enabled?"**
|
|
405
415
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
416
|
+
You don't install the extension yourself — EasySpeak does it automatically
|
|
417
|
+
on startup, copying it to
|
|
418
|
+
`~/.local/share/gnome-shell/extensions/easyspeak-grid@local/` and keeping it
|
|
419
|
+
up to date (look for an `easyspeak: installed ...` or `easyspeak: updated ...`
|
|
420
|
+
message). On Wayland, GNOME Shell only scans for new extensions at login, so
|
|
421
|
+
you typically have to **log out and back in** before it becomes loadable.
|
|
411
422
|
|
|
412
423
|
After re-login, enable it from the command line:
|
|
413
424
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: easyspeak-linux
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Voice control for Linux desktops. Fully local, no cloud, Wayland-native.
|
|
5
5
|
Author-email: Matt Hartley <matt@matthartley.com>
|
|
6
6
|
Maintainer-email: Matt Hartley <matt@matthartley.com>
|
|
@@ -24,19 +24,28 @@ Requires-Python: <3.14,>=3.10
|
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
Requires-Dist: faster-whisper>=1.2.1
|
|
27
|
+
Requires-Dist: jeepney>=0.9
|
|
27
28
|
Requires-Dist: numpy>=2.2.6
|
|
28
29
|
Requires-Dist: onnxruntime>=1.23.2
|
|
29
30
|
Requires-Dist: onnxruntime<1.24; python_full_version < "3.11"
|
|
30
31
|
Requires-Dist: pyaudio>=0.2.14
|
|
32
|
+
Provides-Extra: acceptance
|
|
33
|
+
Requires-Dist: pytest>=8; extra == "acceptance"
|
|
34
|
+
Requires-Dist: pytest-bdd>=7; extra == "acceptance"
|
|
31
35
|
Provides-Extra: benchmark
|
|
32
36
|
Requires-Dist: pytest>=8; extra == "benchmark"
|
|
33
37
|
Requires-Dist: pytest-benchmark>=5; extra == "benchmark"
|
|
34
38
|
Provides-Extra: head-tracking
|
|
35
39
|
Requires-Dist: opencv-python>=4.13.0.90; extra == "head-tracking"
|
|
36
40
|
Requires-Dist: sixdrepnet>=0.1.6; extra == "head-tracking"
|
|
41
|
+
Provides-Extra: integration
|
|
42
|
+
Requires-Dist: pytest>=8; extra == "integration"
|
|
37
43
|
Provides-Extra: mypy
|
|
38
44
|
Requires-Dist: mypy>=1.19.1; extra == "mypy"
|
|
39
45
|
Requires-Dist: types-pyaudio>=0.2.16.20250801; extra == "mypy"
|
|
46
|
+
Provides-Extra: unittest
|
|
47
|
+
Requires-Dist: coverage[toml]>=7.14; extra == "unittest"
|
|
48
|
+
Requires-Dist: pytest>=8; extra == "unittest"
|
|
40
49
|
Dynamic: license-file
|
|
41
50
|
|
|
42
51
|
# EasySpeak [](https://pypi.org/project/easyspeak-linux/)
|
|
@@ -196,7 +205,10 @@ easyspeak # the project execution script
|
|
|
196
205
|
|
|
197
206
|
Activate the venv each time you open a new terminal.
|
|
198
207
|
|
|
199
|
-
Say "Hey Jarvis" followed by a command.
|
|
208
|
+
Say "Hey Jarvis" followed by a command. After a command that gives no spoken
|
|
209
|
+
reply (such as volume changes), EasySpeak keeps listening for a few seconds so
|
|
210
|
+
you can chain commands — say "louder", "louder", "louder" without repeating the
|
|
211
|
+
wake word each time.
|
|
200
212
|
|
|
201
213
|
## Commands
|
|
202
214
|
|
|
@@ -315,9 +327,10 @@ Built-in bookmarks: youtube, google, gmail, github, reddit, twitter, facebook, a
|
|
|
315
327
|
| close [app] | Close application |
|
|
316
328
|
|
|
317
329
|
Default apps in `plugins/apps.py` (edit to match your system):
|
|
318
|
-
- firefox, steam, spotify, calculator, settings, files, terminal, browser
|
|
330
|
+
- firefox, steam, spotify, calculator, settings, files, terminal, browser, music player
|
|
319
331
|
|
|
320
|
-
These are just examples. Edit `apps.py` to add your own apps.
|
|
332
|
+
These are just examples. Edit `apps.py` to add your own apps. Some accept
|
|
333
|
+
spoken aliases — e.g. "open music app" works the same as "open music player".
|
|
321
334
|
|
|
322
335
|
### Files
|
|
323
336
|
|
|
@@ -328,6 +341,7 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
328
341
|
| open pictures | Open Pictures folder |
|
|
329
342
|
| open music | Open Music folder |
|
|
330
343
|
| open videos | Open Videos folder |
|
|
344
|
+
| open projects | Open Projects folder |
|
|
331
345
|
| open home | Open home folder |
|
|
332
346
|
| open desktop | Open Desktop folder |
|
|
333
347
|
|
|
@@ -336,7 +350,7 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
336
350
|
| Command | Action |
|
|
337
351
|
|---------|--------|
|
|
338
352
|
| play | Resume playback |
|
|
339
|
-
| pause | Pause playback |
|
|
353
|
+
| pause / stop the music | Pause playback |
|
|
340
354
|
| next / skip | Next track |
|
|
341
355
|
| previous / back | Previous track |
|
|
342
356
|
|
|
@@ -344,30 +358,35 @@ These are just examples. Edit `apps.py` to add your own apps.
|
|
|
344
358
|
|
|
345
359
|
| Command | Action |
|
|
346
360
|
|---------|--------|
|
|
347
|
-
| volume up/down | Adjust volume |
|
|
361
|
+
| volume up/down (or louder / quieter) | Adjust volume one step (repeat to keep going) |
|
|
362
|
+
| very loud / very silent | Jump straight to near-max (85%) / low (15%, not muted) |
|
|
348
363
|
| mute | Toggle mute |
|
|
349
364
|
| brightness up/down | Adjust brightness |
|
|
350
365
|
| do not disturb on/off | Toggle notifications |
|
|
351
366
|
|
|
367
|
+
Volume changes are silent — GNOME's own on-screen display and chime acknowledge them.
|
|
368
|
+
|
|
352
369
|
### General
|
|
353
370
|
|
|
354
371
|
| Command | Action |
|
|
355
372
|
|---------|--------|
|
|
356
373
|
| help | List all commands |
|
|
357
|
-
|
|
|
374
|
+
| go to sleep / stop listening | Release the mic (reactivate from the tray icon) |
|
|
375
|
+
| quit / exit / goodbye | Exit EasySpeak |
|
|
358
376
|
|
|
359
377
|
## File Structure
|
|
360
378
|
|
|
361
379
|
```
|
|
362
380
|
easyspeak/
|
|
363
|
-
├── extension.js # GNOME Shell extension
|
|
364
|
-
├── metadata.json # Extension metadata
|
|
365
381
|
├── pyproject.toml
|
|
366
382
|
├── src
|
|
383
|
+
│ ├── extension.js # GNOME Shell extension (bundled as package data)
|
|
384
|
+
│ ├── metadata.json # Extension metadata
|
|
367
385
|
│ ├── core
|
|
368
386
|
│ │ ├── __init__.py
|
|
369
387
|
│ │ ├── __main__.py
|
|
370
388
|
│ │ ├── config.py # Tuning constants + Whisper model factory
|
|
389
|
+
│ │ ├── gnome_extension.py # Installs/refreshes/enables the extension
|
|
371
390
|
│ │ └── main.py # EasySpeak class + main loop
|
|
372
391
|
│ └── plugins
|
|
373
392
|
│ ├── __init__.py
|
|
@@ -386,9 +405,9 @@ easyspeak/
|
|
|
386
405
|
└── plugins # tests for src/plugins/
|
|
387
406
|
```
|
|
388
407
|
|
|
389
|
-
On first start,
|
|
390
|
-
|
|
391
|
-
|
|
408
|
+
On first start, core auto-installs the GNOME Shell extension to the
|
|
409
|
+
user-local extensions directory (unless GNOME already sees it via a
|
|
410
|
+
system-wide install). Files copied:
|
|
392
411
|
|
|
393
412
|
```
|
|
394
413
|
~/.local/share/gnome-shell/extensions/easyspeak-grid@local/
|
|
@@ -444,11 +463,12 @@ def handle(cmd, core):
|
|
|
444
463
|
|
|
445
464
|
**Mouse grid: "Failed to show grid — is extension enabled?"**
|
|
446
465
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
466
|
+
You don't install the extension yourself — EasySpeak does it automatically
|
|
467
|
+
on startup, copying it to
|
|
468
|
+
`~/.local/share/gnome-shell/extensions/easyspeak-grid@local/` and keeping it
|
|
469
|
+
up to date (look for an `easyspeak: installed ...` or `easyspeak: updated ...`
|
|
470
|
+
message). On Wayland, GNOME Shell only scans for new extensions at login, so
|
|
471
|
+
you typically have to **log out and back in** before it becomes loadable.
|
|
452
472
|
|
|
453
473
|
After re-login, enable it from the command line:
|
|
454
474
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
.gitignore
|
|
2
|
-
CONTRIBUTING.md
|
|
3
2
|
LICENSE
|
|
4
3
|
README.md
|
|
5
|
-
flake.lock
|
|
6
|
-
flake.nix
|
|
7
4
|
pyproject.toml
|
|
8
5
|
uv.lock
|
|
9
6
|
.github/actions/benchmark/action.yml
|
|
@@ -17,10 +14,17 @@ easyspeak_linux.egg-info/dependency_links.txt
|
|
|
17
14
|
easyspeak_linux.egg-info/entry_points.txt
|
|
18
15
|
easyspeak_linux.egg-info/requires.txt
|
|
19
16
|
easyspeak_linux.egg-info/top_level.txt
|
|
17
|
+
src/extension-helpers.js
|
|
18
|
+
src/extension.js
|
|
19
|
+
src/metadata.json
|
|
20
20
|
src/core/__init__.py
|
|
21
21
|
src/core/__main__.py
|
|
22
22
|
src/core/config.py
|
|
23
|
+
src/core/gnome_extension.py
|
|
23
24
|
src/core/main.py
|
|
25
|
+
src/core/mediakeys.py
|
|
26
|
+
src/core/speech.py
|
|
27
|
+
src/core/tray.py
|
|
24
28
|
src/plugins/00_eyetrack.py
|
|
25
29
|
src/plugins/00_mousegrid.py
|
|
26
30
|
src/plugins/__init__.py
|
|
@@ -29,5 +33,6 @@ src/plugins/browser.py
|
|
|
29
33
|
src/plugins/dictation.py
|
|
30
34
|
src/plugins/files.py
|
|
31
35
|
src/plugins/media.py
|
|
36
|
+
src/plugins/sleep.py
|
|
32
37
|
src/plugins/system.py
|
|
33
38
|
src/plugins/zz_base.py
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
faster-whisper>=1.2.1
|
|
2
|
+
jeepney>=0.9
|
|
2
3
|
numpy>=2.2.6
|
|
3
4
|
onnxruntime>=1.23.2
|
|
4
5
|
pyaudio>=0.2.14
|
|
@@ -6,6 +7,10 @@ pyaudio>=0.2.14
|
|
|
6
7
|
[:python_full_version < "3.11"]
|
|
7
8
|
onnxruntime<1.24
|
|
8
9
|
|
|
10
|
+
[acceptance]
|
|
11
|
+
pytest>=8
|
|
12
|
+
pytest-bdd>=7
|
|
13
|
+
|
|
9
14
|
[benchmark]
|
|
10
15
|
pytest>=8
|
|
11
16
|
pytest-benchmark>=5
|
|
@@ -14,6 +19,13 @@ pytest-benchmark>=5
|
|
|
14
19
|
opencv-python>=4.13.0.90
|
|
15
20
|
sixdrepnet>=0.1.6
|
|
16
21
|
|
|
22
|
+
[integration]
|
|
23
|
+
pytest>=8
|
|
24
|
+
|
|
17
25
|
[mypy]
|
|
18
26
|
mypy>=1.19.1
|
|
19
27
|
types-pyaudio>=0.2.16.20250801
|
|
28
|
+
|
|
29
|
+
[unittest]
|
|
30
|
+
coverage[toml]>=7.14
|
|
31
|
+
pytest>=8
|
|
@@ -43,6 +43,7 @@ readme = "README.md"
|
|
|
43
43
|
requires-python = ">=3.10, <3.14"
|
|
44
44
|
dependencies = [
|
|
45
45
|
"faster-whisper>=1.2.1",
|
|
46
|
+
"jeepney>=0.9",
|
|
46
47
|
"numpy>=2.2.6",
|
|
47
48
|
# "openwakeword", # requires Python <3.13 for speexdsp-ns (missing wheels)
|
|
48
49
|
"onnxruntime>=1.23.2",
|
|
@@ -51,6 +52,10 @@ dependencies = [
|
|
|
51
52
|
]
|
|
52
53
|
|
|
53
54
|
[project.optional-dependencies]
|
|
55
|
+
acceptance = [
|
|
56
|
+
"pytest>=8",
|
|
57
|
+
"pytest-bdd>=7",
|
|
58
|
+
]
|
|
54
59
|
benchmark = [
|
|
55
60
|
"pytest>=8",
|
|
56
61
|
"pytest-benchmark>=5",
|
|
@@ -59,10 +64,17 @@ head-tracking = [
|
|
|
59
64
|
"opencv-python>=4.13.0.90",
|
|
60
65
|
"sixdrepnet>=0.1.6",
|
|
61
66
|
]
|
|
67
|
+
integration = [
|
|
68
|
+
"pytest>=8",
|
|
69
|
+
]
|
|
62
70
|
mypy = [
|
|
63
71
|
"mypy>=1.19.1",
|
|
64
72
|
"types-pyaudio>=0.2.16.20250801",
|
|
65
73
|
]
|
|
74
|
+
unittest = [
|
|
75
|
+
"coverage[toml]>=7.14",
|
|
76
|
+
"pytest>=8",
|
|
77
|
+
]
|
|
66
78
|
|
|
67
79
|
[project.scripts]
|
|
68
80
|
easyspeak = "easyspeak.core.main:run"
|
|
@@ -72,6 +84,7 @@ easyspeak = "easyspeak.core.main:run"
|
|
|
72
84
|
|
|
73
85
|
[tool.coverage.report]
|
|
74
86
|
exclude_also = ["if __name__ == .__main__.:"]
|
|
87
|
+
fail_under = 99
|
|
75
88
|
show_missing = true
|
|
76
89
|
|
|
77
90
|
[tool.coverage.run]
|
|
@@ -84,9 +97,13 @@ warn_unreachable = true
|
|
|
84
97
|
warn_unused_ignores = true
|
|
85
98
|
|
|
86
99
|
[tool.pytest.ini_options]
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
|
|
100
|
+
# Folders excluded from default discovery are opt-in: they need preparation
|
|
101
|
+
# the plain unit run doesn't (large model downloads, real external binaries,
|
|
102
|
+
# an audio server). Each has its own `just` target.
|
|
103
|
+
# tests/acceptance -> `just acceptance` (Gherkin scenarios; needs pytest-bdd)
|
|
104
|
+
# tests/benchmarks -> `just benchmark` (downloads large Whisper models)
|
|
105
|
+
# tests/integration -> `just integration` (runs real piper/audio-player binaries)
|
|
106
|
+
addopts = "--ignore=tests/acceptance --ignore=tests/benchmarks --ignore=tests/integration"
|
|
90
107
|
|
|
91
108
|
[tool.ruff.lint]
|
|
92
109
|
extend-select = ["I"] # "ALL" one day
|
|
@@ -95,6 +112,12 @@ extend-ignore = ["D", "E722"]
|
|
|
95
112
|
[tool.setuptools.package-dir]
|
|
96
113
|
easyspeak = "src"
|
|
97
114
|
|
|
115
|
+
# The bundled GNOME Shell extension is package data: core.gnome_extension
|
|
116
|
+
# copies it into the user's extensions directory at startup, so it must ship
|
|
117
|
+
# inside the wheel (alongside the easyspeak package), not just the sdist.
|
|
118
|
+
[tool.setuptools.package-data]
|
|
119
|
+
easyspeak = ["extension.js", "extension-helpers.js", "metadata.json"]
|
|
120
|
+
|
|
98
121
|
[tool.setuptools_scm]
|
|
99
122
|
local_scheme = "no-local-version"
|
|
100
123
|
|
|
@@ -18,6 +18,9 @@ WAKE_COOLDOWN = 3.0 # Seconds to ignore wake word after trigger
|
|
|
18
18
|
SILENCE_THRESHOLD = 300
|
|
19
19
|
SILENCE_DURATION = 0.3
|
|
20
20
|
|
|
21
|
+
MISUNDERSTAND_GRACE = 4.0 # Seconds to ignore repeat misses after feedback
|
|
22
|
+
FOLLOWUP_IDLE_ROUNDS = 2 # Quiet listens tolerated before a command session ends
|
|
23
|
+
|
|
21
24
|
# --- Models ---
|
|
22
25
|
PIPER_MODEL = os.environ.get(
|
|
23
26
|
"EASYSPEAK_PIPER_MODEL",
|