python-voiceio 0.3.10__tar.gz → 0.3.11__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.
- {python_voiceio-0.3.10/python_voiceio.egg-info → python_voiceio-0.3.11}/PKG-INFO +16 -10
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/README.md +14 -2
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/pyproject.toml +3 -6
- {python_voiceio-0.3.10 → python_voiceio-0.3.11/python_voiceio.egg-info}/PKG-INFO +16 -10
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/python_voiceio.egg-info/requires.txt +0 -10
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_commands.py +21 -9
- python_voiceio-0.3.11/voiceio/__init__.py +1 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/app.py +19 -1
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/commands.py +5 -2
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/config.py +1 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/platform.py +4 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/clipboard.py +1 -1
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/wizard.py +15 -12
- python_voiceio-0.3.10/voiceio/__init__.py +0 -1
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/LICENSE +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/python_voiceio.egg-info/SOURCES.txt +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/python_voiceio.egg-info/dependency_links.txt +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/python_voiceio.egg-info/entry_points.txt +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/python_voiceio.egg-info/top_level.txt +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/setup.cfg +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_app_wiring.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_autocorrect.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_backend_probes.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_clipboard_read.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_config.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_corrections.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_fallback.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_health.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_hints.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_history.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_ibus_typer.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_llm.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_llm_api.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_numbers.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_platform.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_postprocess.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_prebuffer.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_prompt.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_recorder_integration.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_robustness.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_streaming.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_transcriber.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_tts.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_vad.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_vocabulary.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/tests/test_wordfreq.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/__main__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/autocorrect.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/backends.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/cli.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/clipboard_read.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/corrections.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/demo.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/feedback.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/health.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/hints.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/history.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/hotkeys/__init__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/hotkeys/base.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/hotkeys/chain.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/hotkeys/evdev.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/hotkeys/pynput_backend.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/hotkeys/socket_backend.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/ibus/__init__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/ibus/engine.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/llm.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/llm_api.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/models/__init__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/models/silero_vad.onnx +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/numbers.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/pidlock.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/postprocess.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/prompt.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/recorder.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/service.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/sounds/__init__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/sounds/commit.wav +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/sounds/start.wav +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/sounds/stop.wav +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/streaming.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/transcriber.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tray/__init__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tray/_icons.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tray/_indicator.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tray/_pystray.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tts/__init__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tts/base.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tts/chain.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tts/edge_engine.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tts/espeak.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tts/piper_engine.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/tts/player.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/__init__.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/base.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/chain.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/ibus.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/pynput_type.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/wtype.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/xdotool.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/typers/ydotool.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/vad.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/vocabulary.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/wordfreq.py +0 -0
- {python_voiceio-0.3.10 → python_voiceio-0.3.11}/voiceio/worker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-voiceio
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: Speak → text, locally, instantly.
|
|
5
5
|
Author: Hugo Montenegro
|
|
6
6
|
License-Expression: MIT
|
|
@@ -26,16 +26,10 @@ Requires-Dist: numpy>=1.24.0
|
|
|
26
26
|
Requires-Dist: onnxruntime>=1.16.0
|
|
27
27
|
Requires-Dist: wordfreq>=3.0
|
|
28
28
|
Requires-Dist: evdev>=1.6.0; sys_platform == "linux"
|
|
29
|
-
Requires-Dist: pynput>=1.7.6
|
|
30
|
-
Requires-Dist: pynput>=1.7.6; sys_platform == "darwin"
|
|
29
|
+
Requires-Dist: pynput>=1.7.6
|
|
31
30
|
Requires-Dist: pyperclip>=1.8.0; sys_platform == "win32"
|
|
32
31
|
Requires-Dist: win11toast>=0.36; sys_platform == "win32"
|
|
33
|
-
Provides-Extra: x11
|
|
34
|
-
Requires-Dist: pynput>=1.7.6; extra == "x11"
|
|
35
|
-
Provides-Extra: mac
|
|
36
|
-
Requires-Dist: pynput>=1.7.6; extra == "mac"
|
|
37
32
|
Provides-Extra: win
|
|
38
|
-
Requires-Dist: pynput>=1.7.6; extra == "win"
|
|
39
33
|
Requires-Dist: pyperclip>=1.8.0; extra == "win"
|
|
40
34
|
Requires-Dist: win11toast>=0.36; extra == "win"
|
|
41
35
|
Provides-Extra: tray
|
|
@@ -52,6 +46,15 @@ Dynamic: license-file
|
|
|
52
46
|
|
|
53
47
|
# voiceio
|
|
54
48
|
|
|
49
|
+
```
|
|
50
|
+
██╗ ██╗ ██████╗ ██╗ ██████╗███████╗██╗ ██████╗
|
|
51
|
+
██║ ██║██╔═══██╗██║██╔════╝██╔════╝██║██╔═══██╗
|
|
52
|
+
██║ ██║██║ ██║██║██║ █████╗ ██║██║ ██║
|
|
53
|
+
╚██╗ ██╔╝██║ ██║██║██║ ██╔══╝ ██║██║ ██║
|
|
54
|
+
╚████╔╝ ╚██████╔╝██║╚██████╗███████╗██║╚██████╔╝
|
|
55
|
+
╚═══╝ ╚═════╝ ╚═╝ ╚═════╝╚══════╝╚═╝ ╚═════╝
|
|
56
|
+
```
|
|
57
|
+
|
|
55
58
|
[](https://github.com/Hugo0/voiceio/actions/workflows/ci.yml)
|
|
56
59
|
[](https://pypi.org/project/python-voiceio/)
|
|
57
60
|
[](https://pypi.org/project/python-voiceio/)
|
|
@@ -60,11 +63,13 @@ Dynamic: license-file
|
|
|
60
63
|
|
|
61
64
|
Speak → text, locally, instantly.
|
|
62
65
|
|
|
66
|
+
https://github.com/user-attachments/assets/9cf5d1ac-b4bb-4cf8-b775-7a66dc16b376
|
|
67
|
+
|
|
63
68
|
## Quick start
|
|
64
69
|
|
|
65
70
|
```bash
|
|
66
71
|
# 1. Install system dependencies (Ubuntu/Debian)
|
|
67
|
-
sudo apt install pipx ibus gir1.2-ibus-1.0 python3-gi portaudio19-dev
|
|
72
|
+
sudo apt install pipx ibus gir1.2-ibus-1.0 python3-gi python3-dev portaudio19-dev
|
|
68
73
|
|
|
69
74
|
# 2. Install voiceio
|
|
70
75
|
pipx install python-voiceio
|
|
@@ -79,7 +84,7 @@ That's it. Press **Ctrl+Alt+V** (or your chosen hotkey) to start dictating.
|
|
|
79
84
|
<summary><strong>Fedora</strong></summary>
|
|
80
85
|
|
|
81
86
|
```bash
|
|
82
|
-
sudo dnf install pipx ibus python3-gobject portaudio-devel
|
|
87
|
+
sudo dnf install pipx ibus python3-gobject python3-devel portaudio-devel
|
|
83
88
|
pipx install python-voiceio
|
|
84
89
|
voiceio setup
|
|
85
90
|
```
|
|
@@ -90,6 +95,7 @@ voiceio setup
|
|
|
90
95
|
|
|
91
96
|
```bash
|
|
92
97
|
sudo pacman -S python-pipx ibus python-gobject portaudio
|
|
98
|
+
# Note: Arch includes Python headers by default with the python package
|
|
93
99
|
pipx install python-voiceio
|
|
94
100
|
voiceio setup
|
|
95
101
|
```
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# voiceio
|
|
2
2
|
|
|
3
|
+
```
|
|
4
|
+
██╗ ██╗ ██████╗ ██╗ ██████╗███████╗██╗ ██████╗
|
|
5
|
+
██║ ██║██╔═══██╗██║██╔════╝██╔════╝██║██╔═══██╗
|
|
6
|
+
██║ ██║██║ ██║██║██║ █████╗ ██║██║ ██║
|
|
7
|
+
╚██╗ ██╔╝██║ ██║██║██║ ██╔══╝ ██║██║ ██║
|
|
8
|
+
╚████╔╝ ╚██████╔╝██║╚██████╗███████╗██║╚██████╔╝
|
|
9
|
+
╚═══╝ ╚═════╝ ╚═╝ ╚═════╝╚══════╝╚═╝ ╚═════╝
|
|
10
|
+
```
|
|
11
|
+
|
|
3
12
|
[](https://github.com/Hugo0/voiceio/actions/workflows/ci.yml)
|
|
4
13
|
[](https://pypi.org/project/python-voiceio/)
|
|
5
14
|
[](https://pypi.org/project/python-voiceio/)
|
|
@@ -8,11 +17,13 @@
|
|
|
8
17
|
|
|
9
18
|
Speak → text, locally, instantly.
|
|
10
19
|
|
|
20
|
+
https://github.com/user-attachments/assets/9cf5d1ac-b4bb-4cf8-b775-7a66dc16b376
|
|
21
|
+
|
|
11
22
|
## Quick start
|
|
12
23
|
|
|
13
24
|
```bash
|
|
14
25
|
# 1. Install system dependencies (Ubuntu/Debian)
|
|
15
|
-
sudo apt install pipx ibus gir1.2-ibus-1.0 python3-gi portaudio19-dev
|
|
26
|
+
sudo apt install pipx ibus gir1.2-ibus-1.0 python3-gi python3-dev portaudio19-dev
|
|
16
27
|
|
|
17
28
|
# 2. Install voiceio
|
|
18
29
|
pipx install python-voiceio
|
|
@@ -27,7 +38,7 @@ That's it. Press **Ctrl+Alt+V** (or your chosen hotkey) to start dictating.
|
|
|
27
38
|
<summary><strong>Fedora</strong></summary>
|
|
28
39
|
|
|
29
40
|
```bash
|
|
30
|
-
sudo dnf install pipx ibus python3-gobject portaudio-devel
|
|
41
|
+
sudo dnf install pipx ibus python3-gobject python3-devel portaudio-devel
|
|
31
42
|
pipx install python-voiceio
|
|
32
43
|
voiceio setup
|
|
33
44
|
```
|
|
@@ -38,6 +49,7 @@ voiceio setup
|
|
|
38
49
|
|
|
39
50
|
```bash
|
|
40
51
|
sudo pacman -S python-pipx ibus python-gobject portaudio
|
|
52
|
+
# Note: Arch includes Python headers by default with the python package
|
|
41
53
|
pipx install python-voiceio
|
|
42
54
|
voiceio setup
|
|
43
55
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-voiceio"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.11"
|
|
8
8
|
description = "Speak → text, locally, instantly."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -28,16 +28,13 @@ dependencies = [
|
|
|
28
28
|
"onnxruntime>=1.16.0",
|
|
29
29
|
"wordfreq>=3.0",
|
|
30
30
|
"evdev>=1.6.0; sys_platform == 'linux'",
|
|
31
|
-
"pynput>=1.7.6
|
|
32
|
-
"pynput>=1.7.6; sys_platform == 'darwin'",
|
|
31
|
+
"pynput>=1.7.6",
|
|
33
32
|
"pyperclip>=1.8.0; sys_platform == 'win32'",
|
|
34
33
|
"win11toast>=0.36; sys_platform == 'win32'",
|
|
35
34
|
]
|
|
36
35
|
|
|
37
36
|
[project.optional-dependencies]
|
|
38
|
-
|
|
39
|
-
mac = ["pynput>=1.7.6"]
|
|
40
|
-
win = ["pynput>=1.7.6", "pyperclip>=1.8.0", "win11toast>=0.36"]
|
|
37
|
+
win = ["pyperclip>=1.8.0", "win11toast>=0.36"]
|
|
41
38
|
tray = ["pystray>=0.19", "Pillow>=10.0"]
|
|
42
39
|
tts = ["piper-tts>=1.2.0"]
|
|
43
40
|
tts-cloud = ["edge-tts>=6.1.0"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-voiceio
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: Speak → text, locally, instantly.
|
|
5
5
|
Author: Hugo Montenegro
|
|
6
6
|
License-Expression: MIT
|
|
@@ -26,16 +26,10 @@ Requires-Dist: numpy>=1.24.0
|
|
|
26
26
|
Requires-Dist: onnxruntime>=1.16.0
|
|
27
27
|
Requires-Dist: wordfreq>=3.0
|
|
28
28
|
Requires-Dist: evdev>=1.6.0; sys_platform == "linux"
|
|
29
|
-
Requires-Dist: pynput>=1.7.6
|
|
30
|
-
Requires-Dist: pynput>=1.7.6; sys_platform == "darwin"
|
|
29
|
+
Requires-Dist: pynput>=1.7.6
|
|
31
30
|
Requires-Dist: pyperclip>=1.8.0; sys_platform == "win32"
|
|
32
31
|
Requires-Dist: win11toast>=0.36; sys_platform == "win32"
|
|
33
|
-
Provides-Extra: x11
|
|
34
|
-
Requires-Dist: pynput>=1.7.6; extra == "x11"
|
|
35
|
-
Provides-Extra: mac
|
|
36
|
-
Requires-Dist: pynput>=1.7.6; extra == "mac"
|
|
37
32
|
Provides-Extra: win
|
|
38
|
-
Requires-Dist: pynput>=1.7.6; extra == "win"
|
|
39
33
|
Requires-Dist: pyperclip>=1.8.0; extra == "win"
|
|
40
34
|
Requires-Dist: win11toast>=0.36; extra == "win"
|
|
41
35
|
Provides-Extra: tray
|
|
@@ -52,6 +46,15 @@ Dynamic: license-file
|
|
|
52
46
|
|
|
53
47
|
# voiceio
|
|
54
48
|
|
|
49
|
+
```
|
|
50
|
+
██╗ ██╗ ██████╗ ██╗ ██████╗███████╗██╗ ██████╗
|
|
51
|
+
██║ ██║██╔═══██╗██║██╔════╝██╔════╝██║██╔═══██╗
|
|
52
|
+
██║ ██║██║ ██║██║██║ █████╗ ██║██║ ██║
|
|
53
|
+
╚██╗ ██╔╝██║ ██║██║██║ ██╔══╝ ██║██║ ██║
|
|
54
|
+
╚████╔╝ ╚██████╔╝██║╚██████╗███████╗██║╚██████╔╝
|
|
55
|
+
╚═══╝ ╚═════╝ ╚═╝ ╚═════╝╚══════╝╚═╝ ╚═════╝
|
|
56
|
+
```
|
|
57
|
+
|
|
55
58
|
[](https://github.com/Hugo0/voiceio/actions/workflows/ci.yml)
|
|
56
59
|
[](https://pypi.org/project/python-voiceio/)
|
|
57
60
|
[](https://pypi.org/project/python-voiceio/)
|
|
@@ -60,11 +63,13 @@ Dynamic: license-file
|
|
|
60
63
|
|
|
61
64
|
Speak → text, locally, instantly.
|
|
62
65
|
|
|
66
|
+
https://github.com/user-attachments/assets/9cf5d1ac-b4bb-4cf8-b775-7a66dc16b376
|
|
67
|
+
|
|
63
68
|
## Quick start
|
|
64
69
|
|
|
65
70
|
```bash
|
|
66
71
|
# 1. Install system dependencies (Ubuntu/Debian)
|
|
67
|
-
sudo apt install pipx ibus gir1.2-ibus-1.0 python3-gi portaudio19-dev
|
|
72
|
+
sudo apt install pipx ibus gir1.2-ibus-1.0 python3-gi python3-dev portaudio19-dev
|
|
68
73
|
|
|
69
74
|
# 2. Install voiceio
|
|
70
75
|
pipx install python-voiceio
|
|
@@ -79,7 +84,7 @@ That's it. Press **Ctrl+Alt+V** (or your chosen hotkey) to start dictating.
|
|
|
79
84
|
<summary><strong>Fedora</strong></summary>
|
|
80
85
|
|
|
81
86
|
```bash
|
|
82
|
-
sudo dnf install pipx ibus python3-gobject portaudio-devel
|
|
87
|
+
sudo dnf install pipx ibus python3-gobject python3-devel portaudio-devel
|
|
83
88
|
pipx install python-voiceio
|
|
84
89
|
voiceio setup
|
|
85
90
|
```
|
|
@@ -90,6 +95,7 @@ voiceio setup
|
|
|
90
95
|
|
|
91
96
|
```bash
|
|
92
97
|
sudo pacman -S python-pipx ibus python-gobject portaudio
|
|
98
|
+
# Note: Arch includes Python headers by default with the python package
|
|
93
99
|
pipx install python-voiceio
|
|
94
100
|
voiceio setup
|
|
95
101
|
```
|
|
@@ -3,15 +3,12 @@ sounddevice>=0.4.6
|
|
|
3
3
|
numpy>=1.24.0
|
|
4
4
|
onnxruntime>=1.16.0
|
|
5
5
|
wordfreq>=3.0
|
|
6
|
-
|
|
7
|
-
[:sys_platform == "darwin"]
|
|
8
6
|
pynput>=1.7.6
|
|
9
7
|
|
|
10
8
|
[:sys_platform == "linux"]
|
|
11
9
|
evdev>=1.6.0
|
|
12
10
|
|
|
13
11
|
[:sys_platform == "win32"]
|
|
14
|
-
pynput>=1.7.6
|
|
15
12
|
pyperclip>=1.8.0
|
|
16
13
|
win11toast>=0.36
|
|
17
14
|
|
|
@@ -19,9 +16,6 @@ win11toast>=0.36
|
|
|
19
16
|
pytest>=7.0
|
|
20
17
|
pytest-mock
|
|
21
18
|
|
|
22
|
-
[mac]
|
|
23
|
-
pynput>=1.7.6
|
|
24
|
-
|
|
25
19
|
[tray]
|
|
26
20
|
pystray>=0.19
|
|
27
21
|
Pillow>=10.0
|
|
@@ -33,9 +27,5 @@ piper-tts>=1.2.0
|
|
|
33
27
|
edge-tts>=6.1.0
|
|
34
28
|
|
|
35
29
|
[win]
|
|
36
|
-
pynput>=1.7.6
|
|
37
30
|
pyperclip>=1.8.0
|
|
38
31
|
win11toast>=0.36
|
|
39
|
-
|
|
40
|
-
[x11]
|
|
41
|
-
pynput>=1.7.6
|
|
@@ -59,30 +59,36 @@ class TestFormatting:
|
|
|
59
59
|
|
|
60
60
|
class TestUndo:
|
|
61
61
|
def test_scratch_that(self):
|
|
62
|
-
cp = CommandProcessor()
|
|
62
|
+
cp = CommandProcessor(editing=True)
|
|
63
63
|
result = cp.process("hello world scratch that")
|
|
64
64
|
assert result == "hello world"
|
|
65
65
|
assert cp.undo_requested is True
|
|
66
66
|
|
|
67
67
|
def test_undo_that(self):
|
|
68
|
-
cp = CommandProcessor()
|
|
68
|
+
cp = CommandProcessor(editing=True)
|
|
69
69
|
result = cp.process("hello world undo that")
|
|
70
70
|
assert result == "hello world"
|
|
71
71
|
assert cp.undo_requested is True
|
|
72
72
|
|
|
73
73
|
def test_scratch_that_only(self):
|
|
74
|
-
cp = CommandProcessor()
|
|
74
|
+
cp = CommandProcessor(editing=True)
|
|
75
75
|
result = cp.process("scratch that")
|
|
76
76
|
assert result == ""
|
|
77
77
|
assert cp.undo_requested is True
|
|
78
78
|
|
|
79
79
|
def test_undo_resets_between_calls(self):
|
|
80
|
-
cp = CommandProcessor()
|
|
80
|
+
cp = CommandProcessor(editing=True)
|
|
81
81
|
cp.process("scratch that")
|
|
82
82
|
assert cp.undo_requested is True
|
|
83
83
|
cp.process("hello world")
|
|
84
84
|
assert cp.undo_requested is False
|
|
85
85
|
|
|
86
|
+
def test_editing_off_ignores_scratch(self):
|
|
87
|
+
cp = CommandProcessor(editing=False)
|
|
88
|
+
result = cp.process("hello world scratch that")
|
|
89
|
+
assert result == "hello world scratch that"
|
|
90
|
+
assert cp.undo_requested is False
|
|
91
|
+
|
|
86
92
|
|
|
87
93
|
class TestEdgeCases:
|
|
88
94
|
def test_no_commands(self):
|
|
@@ -127,27 +133,27 @@ class TestEdgeCases:
|
|
|
127
133
|
|
|
128
134
|
class TestCorrectThat:
|
|
129
135
|
def test_correct_that_sets_flag(self):
|
|
130
|
-
cp = CommandProcessor()
|
|
136
|
+
cp = CommandProcessor(editing=True)
|
|
131
137
|
result = cp.process("hello world correct that")
|
|
132
138
|
assert cp.flag_requested is True
|
|
133
139
|
assert cp.flagged_word == "world"
|
|
134
140
|
assert result == "hello"
|
|
135
141
|
|
|
136
142
|
def test_correct_that_no_preceding_word(self):
|
|
137
|
-
cp = CommandProcessor()
|
|
143
|
+
cp = CommandProcessor(editing=True)
|
|
138
144
|
result = cp.process("correct that")
|
|
139
145
|
assert cp.flag_requested is True
|
|
140
146
|
assert cp.flagged_word == ""
|
|
141
147
|
assert result == ""
|
|
142
148
|
|
|
143
149
|
def test_correct_that_returns_text_before(self):
|
|
144
|
-
cp = CommandProcessor()
|
|
150
|
+
cp = CommandProcessor(editing=True)
|
|
145
151
|
result = cp.process("one two three correct that")
|
|
146
152
|
assert result == "one two"
|
|
147
153
|
assert cp.flagged_word == "three"
|
|
148
154
|
|
|
149
155
|
def test_flag_resets_between_calls(self):
|
|
150
|
-
cp = CommandProcessor()
|
|
156
|
+
cp = CommandProcessor(editing=True)
|
|
151
157
|
cp.process("hello correct that")
|
|
152
158
|
assert cp.flag_requested is True
|
|
153
159
|
cp.process("hello world")
|
|
@@ -155,11 +161,17 @@ class TestCorrectThat:
|
|
|
155
161
|
assert cp.flagged_word == ""
|
|
156
162
|
|
|
157
163
|
def test_undo_not_set_on_flag(self):
|
|
158
|
-
cp = CommandProcessor()
|
|
164
|
+
cp = CommandProcessor(editing=True)
|
|
159
165
|
cp.process("hello correct that")
|
|
160
166
|
assert cp.flag_requested is True
|
|
161
167
|
assert cp.undo_requested is False
|
|
162
168
|
|
|
169
|
+
def test_editing_off_ignores_correct(self):
|
|
170
|
+
cp = CommandProcessor(editing=False)
|
|
171
|
+
result = cp.process("hello world correct that")
|
|
172
|
+
assert result == "hello world correct that"
|
|
173
|
+
assert cp.flag_requested is False
|
|
174
|
+
|
|
163
175
|
|
|
164
176
|
class TestSpacing:
|
|
165
177
|
def test_no_double_spaces(self):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.11"
|
|
@@ -126,6 +126,24 @@ class VoiceIO:
|
|
|
126
126
|
self._socket: SocketHotkey | None = None
|
|
127
127
|
if self._hotkey.name != "socket":
|
|
128
128
|
self._socket = SocketHotkey()
|
|
129
|
+
elif self.platform.desktop not in ("GNOME", "KDE"):
|
|
130
|
+
# Socket backend has no physical hotkey listener — user must bind
|
|
131
|
+
# `voiceio toggle` to a key in their WM config.
|
|
132
|
+
log.warning(
|
|
133
|
+
"Hotkey backend is 'socket' on desktop '%s'. "
|
|
134
|
+
"Physical hotkey capture is not available. "
|
|
135
|
+
"Bind 'voiceio toggle' to a key in your window manager config "
|
|
136
|
+
"(e.g. i3: bindsym Ctrl+Alt+v exec voiceio toggle). "
|
|
137
|
+
"Or: sudo usermod -aG input $USER && log out/in to enable evdev.",
|
|
138
|
+
self.platform.desktop,
|
|
139
|
+
)
|
|
140
|
+
print(
|
|
141
|
+
f"\n NOTE: No physical hotkey listener available on '{self.platform.desktop}'.\n"
|
|
142
|
+
f" Bind 'voiceio toggle' to a key in your WM config, e.g.:\n"
|
|
143
|
+
f" i3/sway: bindsym Ctrl+Alt+v exec voiceio toggle\n"
|
|
144
|
+
f" hyprland: bind = CTRL ALT, V, exec, voiceio toggle\n"
|
|
145
|
+
f" Or fix evdev: sudo usermod -aG input $USER (then log out/in)\n",
|
|
146
|
+
)
|
|
129
147
|
|
|
130
148
|
print(f"Loading model '{cfg.model.name}'...", end="", flush=True)
|
|
131
149
|
t0 = time.monotonic()
|
|
@@ -146,7 +164,7 @@ class VoiceIO:
|
|
|
146
164
|
if vocab:
|
|
147
165
|
self.transcriber.set_initial_prompt(vocab)
|
|
148
166
|
|
|
149
|
-
self._command_processor = CommandProcessor(enabled=cfg.commands.enabled)
|
|
167
|
+
self._command_processor = CommandProcessor(enabled=cfg.commands.enabled, editing=cfg.commands.editing)
|
|
150
168
|
self._cleanup = cfg.output.punctuation_cleanup
|
|
151
169
|
self._number_conversion = cfg.output.number_conversion
|
|
152
170
|
self._streaming = cfg.output.streaming
|
|
@@ -83,9 +83,12 @@ def _normalize_spacing(text: str) -> str:
|
|
|
83
83
|
class CommandProcessor:
|
|
84
84
|
"""Detects and replaces voice commands in transcribed text."""
|
|
85
85
|
|
|
86
|
-
def __init__(self, enabled: bool = True):
|
|
86
|
+
def __init__(self, enabled: bool = True, editing: bool = False):
|
|
87
87
|
self._enabled = enabled
|
|
88
|
-
self._commands =
|
|
88
|
+
self._commands = {
|
|
89
|
+
k: v for k, v in DEFAULT_COMMANDS.items()
|
|
90
|
+
if editing or v not in (_UNDO_SENTINEL, _FLAG_SENTINEL)
|
|
91
|
+
}
|
|
89
92
|
self._max_words = max(len(k) for k in self._commands) if self._commands else 1
|
|
90
93
|
self.undo_requested = False
|
|
91
94
|
self.flag_requested = False
|
|
@@ -234,6 +234,10 @@ def open_in_terminal(cmd: list[str]) -> bool:
|
|
|
234
234
|
_TERMINALS = [
|
|
235
235
|
(["gnome-terminal", "--"], "gnome-terminal"),
|
|
236
236
|
(["konsole", "-e"], "konsole"),
|
|
237
|
+
(["alacritty", "-e"], "alacritty"),
|
|
238
|
+
(["kitty", "--"], "kitty"),
|
|
239
|
+
(["foot", "--"], "foot"),
|
|
240
|
+
(["wezterm", "start", "--"], "wezterm"),
|
|
237
241
|
(["xfce4-terminal", "-e"], "xfce4-terminal"),
|
|
238
242
|
(["xterm", "-e"], "xterm"),
|
|
239
243
|
]
|
|
@@ -80,7 +80,7 @@ class ClipboardTyper:
|
|
|
80
80
|
return ProbeResult(
|
|
81
81
|
ok=False,
|
|
82
82
|
reason="No clipboard tool found",
|
|
83
|
-
fix_hint="Install xclip (X11), wl-copy (Wayland), or pbcopy (macOS).",
|
|
83
|
+
fix_hint="Install xclip + xdotool (X11), wl-copy + ydotool/wtype (Wayland), or pbcopy (macOS).",
|
|
84
84
|
)
|
|
85
85
|
if sys.platform == "win32":
|
|
86
86
|
try:
|
|
@@ -945,10 +945,11 @@ def run_wizard() -> None:
|
|
|
945
945
|
"will use GPU" if checks["cuda"] else "will use CPU (still fast)",
|
|
946
946
|
optional=True)
|
|
947
947
|
|
|
948
|
-
if checks["
|
|
948
|
+
if checks["is_linux"]:
|
|
949
949
|
_print_check("Input group (evdev)", checks["input_group"],
|
|
950
|
-
"" if checks["input_group"]
|
|
951
|
-
|
|
950
|
+
"evdev hotkeys available" if checks["input_group"]
|
|
951
|
+
else "sudo usermod -aG input $USER (then log out/in)",
|
|
952
|
+
optional=checks["input_group"])
|
|
952
953
|
|
|
953
954
|
# Tray icon
|
|
954
955
|
from voiceio.tray import probe_availability
|
|
@@ -1067,13 +1068,12 @@ def run_wizard() -> None:
|
|
|
1067
1068
|
else:
|
|
1068
1069
|
print(f" {YELLOW}⚠{RESET} {DIM}Could not install IBus component, will use fallback{RESET}")
|
|
1069
1070
|
|
|
1070
|
-
if checks["
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
backend = "socket"
|
|
1071
|
+
if checks["input_group"]:
|
|
1072
|
+
backend = "evdev"
|
|
1073
|
+
elif checks["pynput"] and checks["display"] != "wayland":
|
|
1074
|
+
backend = "auto" # pynput works on X11
|
|
1075
1075
|
else:
|
|
1076
|
-
backend = "
|
|
1076
|
+
backend = "socket"
|
|
1077
1077
|
|
|
1078
1078
|
# ── Defaults for optional settings ──────────────────────────────────
|
|
1079
1079
|
sound_enabled = True
|
|
@@ -1286,9 +1286,12 @@ def run_wizard() -> None:
|
|
|
1286
1286
|
print(f" {YELLOW}⚠{RESET} Auto-setup failed. Add manually in Settings → Keyboard → Shortcuts:")
|
|
1287
1287
|
print(" Command: voiceio-toggle")
|
|
1288
1288
|
elif backend == "socket":
|
|
1289
|
-
print(f"\n {YELLOW}ℹ{RESET} Add a keyboard shortcut
|
|
1290
|
-
print(f"
|
|
1291
|
-
print(f"
|
|
1289
|
+
print(f"\n {YELLOW}ℹ{RESET} Add a keyboard shortcut in your window manager config:")
|
|
1290
|
+
print(f" {DIM}i3/sway:{RESET} bindsym Ctrl+Alt+v exec voiceio toggle")
|
|
1291
|
+
print(f" {DIM}hyprland:{RESET} bind = CTRL ALT, V, exec, voiceio toggle")
|
|
1292
|
+
print(f" {DIM}other:{RESET} bind {BOLD}{hotkey}{RESET} → {BOLD}voiceio toggle{RESET}")
|
|
1293
|
+
print(f"\n {DIM}Or enable evdev (no WM config needed):{RESET}")
|
|
1294
|
+
print(f" sudo usermod -aG input $USER {DIM}(then log out and back in){RESET}")
|
|
1292
1295
|
|
|
1293
1296
|
# Autostart
|
|
1294
1297
|
from voiceio.service import install_service
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.3.10"
|
|
File without changes
|
|
File without changes
|
{python_voiceio-0.3.10 → python_voiceio-0.3.11}/python_voiceio.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|