stt2desktop 0.0.1__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.
- stt2desktop-0.0.1/.editorconfig +20 -0
- stt2desktop-0.0.1/.github/workflows/tests.yml +81 -0
- stt2desktop-0.0.1/.gitignore +15 -0
- stt2desktop-0.0.1/.idea/.gitignore +3 -0
- stt2desktop-0.0.1/.pre-commit-config.yaml +7 -0
- stt2desktop-0.0.1/.pre-commit-hooks.yaml +13 -0
- stt2desktop-0.0.1/.run/Template Python tests.run.xml +21 -0
- stt2desktop-0.0.1/.run/Unittests __all__.run.xml +21 -0
- stt2desktop-0.0.1/.venv-app/.gitignore +1 -0
- stt2desktop-0.0.1/.venv-app/lib/python3.14/site-packages/cli_base/tests/shell_complete_snapshots/.gitignore +1 -0
- stt2desktop-0.0.1/PKG-INFO +171 -0
- stt2desktop-0.0.1/README.md +153 -0
- stt2desktop-0.0.1/cli.py +71 -0
- stt2desktop-0.0.1/dev-cli.py +73 -0
- stt2desktop-0.0.1/dist/.gitignore +1 -0
- stt2desktop-0.0.1/noxfile.py +27 -0
- stt2desktop-0.0.1/pyproject.toml +161 -0
- stt2desktop-0.0.1/stt2desktop/__init__.py +8 -0
- stt2desktop-0.0.1/stt2desktop/__main__.py +10 -0
- stt2desktop-0.0.1/stt2desktop/cli_app/__init__.py +41 -0
- stt2desktop-0.0.1/stt2desktop/cli_app/listen.py +85 -0
- stt2desktop-0.0.1/stt2desktop/cli_dev/__init__.py +70 -0
- stt2desktop-0.0.1/stt2desktop/cli_dev/__main__.py +10 -0
- stt2desktop-0.0.1/stt2desktop/cli_dev/code_style.py +12 -0
- stt2desktop-0.0.1/stt2desktop/cli_dev/packaging.py +62 -0
- stt2desktop-0.0.1/stt2desktop/cli_dev/testing.py +52 -0
- stt2desktop-0.0.1/stt2desktop/cli_dev/update_readme_history.py +33 -0
- stt2desktop-0.0.1/stt2desktop/constants.py +28 -0
- stt2desktop-0.0.1/stt2desktop/get_bin.py +29 -0
- stt2desktop-0.0.1/stt2desktop/stt.py +107 -0
- stt2desktop-0.0.1/stt2desktop/tests/__init__.py +36 -0
- stt2desktop-0.0.1/stt2desktop/tests/test_doctests.py +10 -0
- stt2desktop-0.0.1/stt2desktop/tests/test_project_setup.py +49 -0
- stt2desktop-0.0.1/stt2desktop/tests/test_readme.py +83 -0
- stt2desktop-0.0.1/stt2desktop/tests/test_readme_history.py +9 -0
- stt2desktop-0.0.1/uv.lock +2152 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# see https://editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
indent_style = space
|
|
6
|
+
indent_size = 4
|
|
7
|
+
end_of_line = lf
|
|
8
|
+
charset = utf-8
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
insert_final_newline = true
|
|
11
|
+
|
|
12
|
+
[*.py]
|
|
13
|
+
max_line_length = 119
|
|
14
|
+
|
|
15
|
+
[{Makefile,**.mk}]
|
|
16
|
+
indent_style = tab
|
|
17
|
+
insert_final_newline = false
|
|
18
|
+
|
|
19
|
+
[{*.yaml,*.yml}]
|
|
20
|
+
indent_size = 2
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
|
|
2
|
+
name: tests
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
pull_request:
|
|
11
|
+
schedule:
|
|
12
|
+
- cron: '0 8 * * *'
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test:
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.14", "3.13", "3.12"]
|
|
20
|
+
os: [ubuntu-latest, macos-latest] # TODO: windows-latest
|
|
21
|
+
runs-on: ${{ matrix.os }}
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout
|
|
24
|
+
run: |
|
|
25
|
+
echo $GITHUB_REF $GITHUB_SHA
|
|
26
|
+
git clone https://github.com/$GITHUB_REPOSITORY.git .
|
|
27
|
+
git fetch origin $GITHUB_SHA:temporary-ci-branch
|
|
28
|
+
git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA)
|
|
29
|
+
|
|
30
|
+
- name: 'Set up Python ${{ matrix.python-version }}'
|
|
31
|
+
uses: actions/setup-python@main
|
|
32
|
+
# https://github.com/marketplace/actions/setup-python
|
|
33
|
+
with:
|
|
34
|
+
python-version: '${{ matrix.python-version }}'
|
|
35
|
+
cache: 'pip' # caching pip dependencies
|
|
36
|
+
cache-dependency-path: '**/requirements.*.txt'
|
|
37
|
+
|
|
38
|
+
- name: Install uv and set the Python version
|
|
39
|
+
# https://docs.astral.sh/uv/guides/integration/github/#multiple-python-versions
|
|
40
|
+
uses: astral-sh/setup-uv@main
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
|
|
44
|
+
- name: 'Bootstrap app venv'
|
|
45
|
+
# The first CLI call will create the .venv
|
|
46
|
+
run: |
|
|
47
|
+
./cli.py version
|
|
48
|
+
|
|
49
|
+
- name: 'app CLI help'
|
|
50
|
+
run: |
|
|
51
|
+
./cli.py --help
|
|
52
|
+
|
|
53
|
+
- name: 'Bootstrap dev venv'
|
|
54
|
+
# The first CLI call will create the .venv
|
|
55
|
+
run: |
|
|
56
|
+
./dev-cli.py version
|
|
57
|
+
|
|
58
|
+
- name: 'dev CLI help'
|
|
59
|
+
run: |
|
|
60
|
+
./dev-cli.py --help
|
|
61
|
+
|
|
62
|
+
- name: 'Run pip-audit'
|
|
63
|
+
run: |
|
|
64
|
+
./dev-cli.py pip-audit
|
|
65
|
+
|
|
66
|
+
- name: 'Run tests with Python v${{ matrix.python-version }}'
|
|
67
|
+
env:
|
|
68
|
+
PYTHONUNBUFFERED: 1
|
|
69
|
+
PYTHONWARNINGS: always
|
|
70
|
+
run: |
|
|
71
|
+
./dev-cli.py coverage
|
|
72
|
+
|
|
73
|
+
- name: 'Upload coverage report'
|
|
74
|
+
uses: codecov/codecov-action@main
|
|
75
|
+
# https://github.com/marketplace/actions/codecov
|
|
76
|
+
with:
|
|
77
|
+
# https://docs.codecov.com/docs/codecov-tokens#example-github-actions--official-codecov-action
|
|
78
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
79
|
+
fail_ci_if_error: false
|
|
80
|
+
verbose: true
|
|
81
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# https://pre-commit.com/#creating-new-hooks
|
|
2
|
+
- id: update-readme-history
|
|
3
|
+
name: cli-base-utilities
|
|
4
|
+
description: >-
|
|
5
|
+
Update history in README.md from git log.
|
|
6
|
+
entry: "python -m cli_base update-readme-history -v"
|
|
7
|
+
language: python
|
|
8
|
+
language_version: python3
|
|
9
|
+
require_serial: true
|
|
10
|
+
pass_filenames: false
|
|
11
|
+
always_run: true
|
|
12
|
+
verbose: true
|
|
13
|
+
stages: [pre-commit, post-rewrite, pre-push]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<component name="ProjectRunConfigurationManager">
|
|
2
|
+
<configuration default="true" type="tests" factoryName="Unittests">
|
|
3
|
+
<module name="stt2desktop" />
|
|
4
|
+
<option name="ENV_FILES" value="" />
|
|
5
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
6
|
+
<option name="PARENT_ENVS" value="true" />
|
|
7
|
+
<option name="SDK_HOME" value="$PROJECT_DIR$/.venv/bin/python3" />
|
|
8
|
+
<option name="SDK_NAME" value="Python 3.14 (stt2desktop)" />
|
|
9
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
10
|
+
<option name="IS_MODULE_SDK" value="false" />
|
|
11
|
+
<option name="ADD_CONTENT_ROOTS" value="false" />
|
|
12
|
+
<option name="ADD_SOURCE_ROOTS" value="false" />
|
|
13
|
+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
|
14
|
+
<option name="RUN_TOOL" value="" />
|
|
15
|
+
<option name="_new_pattern" value="""" />
|
|
16
|
+
<option name="_new_additionalArguments" value="""" />
|
|
17
|
+
<option name="_new_target" value="""" />
|
|
18
|
+
<option name="_new_targetType" value=""CUSTOM"" />
|
|
19
|
+
<method v="2" />
|
|
20
|
+
</configuration>
|
|
21
|
+
</component>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<component name="ProjectRunConfigurationManager">
|
|
2
|
+
<configuration default="false" name="Unittests **all**" type="tests" factoryName="Unittests">
|
|
3
|
+
<module name="stt2desktop" />
|
|
4
|
+
<option name="ENV_FILES" value="" />
|
|
5
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
6
|
+
<option name="PARENT_ENVS" value="true" />
|
|
7
|
+
<option name="SDK_HOME" value="$PROJECT_DIR$/.venv/bin/python3" />
|
|
8
|
+
<option name="SDK_NAME" value="Python 3.14 (stt2desktop)" />
|
|
9
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
10
|
+
<option name="IS_MODULE_SDK" value="false" />
|
|
11
|
+
<option name="ADD_CONTENT_ROOTS" value="false" />
|
|
12
|
+
<option name="ADD_SOURCE_ROOTS" value="false" />
|
|
13
|
+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
|
14
|
+
<option name="RUN_TOOL" value="" />
|
|
15
|
+
<option name="_new_pattern" value="""" />
|
|
16
|
+
<option name="_new_additionalArguments" value="""" />
|
|
17
|
+
<option name="_new_target" value="""" />
|
|
18
|
+
<option name="_new_targetType" value=""CUSTOM"" />
|
|
19
|
+
<method v="2" />
|
|
20
|
+
</configuration>
|
|
21
|
+
</component>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!.*
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stt2desktop
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Local speech-to-text for desktop using faster-whisper
|
|
5
|
+
Project-URL: Documentation, https://github.com/jedie/stt2desktop
|
|
6
|
+
Project-URL: Source, https://github.com/jedie/stt2desktop
|
|
7
|
+
Author-email: Jens Diemer <stt2desktop@jensdiemer.de>
|
|
8
|
+
License: GPL-3.0-or-later
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Requires-Dist: bx-py-utils
|
|
11
|
+
Requires-Dist: cli-base-utilities>=0.27.1
|
|
12
|
+
Requires-Dist: faster-whisper
|
|
13
|
+
Requires-Dist: pynput
|
|
14
|
+
Requires-Dist: rich
|
|
15
|
+
Requires-Dist: sounddevice
|
|
16
|
+
Requires-Dist: tyro
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# stt2desktop
|
|
20
|
+
|
|
21
|
+
[](https://github.com/jedie/stt2desktop/actions/workflows/tests.yml)
|
|
22
|
+
[](https://app.codecov.io/github/jedie/stt2desktop)
|
|
23
|
+
[](https://pypi.org/project/stt2desktop/)
|
|
24
|
+
[](https://github.com/jedie/stt2desktop/blob/main/pyproject.toml)
|
|
25
|
+
[](https://github.com/jedie/stt2desktop/blob/main/LICENSE)
|
|
26
|
+
|
|
27
|
+
Local speech-to-text for desktop using [faster-whisper](https://github.com/SYSTRAN/faster-whisper).
|
|
28
|
+
|
|
29
|
+
Let's you dictate text into any application without sending audio to any cloud services.
|
|
30
|
+
Everything runs locally on your machine — no internet connection required after the initial model was download.
|
|
31
|
+
|
|
32
|
+
## How it works
|
|
33
|
+
|
|
34
|
+
1. Run `./cli.py listen` — the Whisper model is loaded into memory (downloaded on first run).
|
|
35
|
+
2. Hold **Scroll Lock** to record from your microphone.
|
|
36
|
+
3. Release **Scroll Lock** — the audio is transcribed locally by faster-whisper (CPU, `int8`).
|
|
37
|
+
4. The text is typed into the focused window via `wtype` (Wayland) or `xdotool` (X11).
|
|
38
|
+
|
|
39
|
+
## Setup
|
|
40
|
+
|
|
41
|
+
Requirements: Python 3.12+, [`uv`](https://github.com/astral-sh/uv), a working microphone, and either `wtype` (Wayland) or `xdotool` (X11):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
sudo apt install wtype # Wayland
|
|
45
|
+
sudo apt install xdotool # X11
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then run:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
./cli.py listen
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
[comment]: <> (✂✂✂ auto generated listen help start ✂✂✂)
|
|
55
|
+
```
|
|
56
|
+
usage: ./cli.py listen [-h] [LISTEN OPTIONS]
|
|
57
|
+
|
|
58
|
+
Start the STT listener. Hold the hotkey to record, release to transcribe and insert.
|
|
59
|
+
|
|
60
|
+
╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
61
|
+
│ -h, --help show this help message and exit │
|
|
62
|
+
│ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
|
|
63
|
+
│ --model {tiny_en,tiny,base_en,base,small_en,small,medium_en,medium,large_v1,large_v2,large_v3,large,distil_large_v2, │
|
|
64
|
+
│ distil_medium_en,distil_small_en,distil_large_v3,distil_large_v3_5,large_v3_turbo,turbo} │
|
|
65
|
+
│ Whisper model to use for transcription. (default: small) │
|
|
66
|
+
│ --hotkey {alt,alt_l,alt_r,alt_gr,backspace,caps_lock,cmd,cmd_l,cmd_r,ctrl,ctrl_l,ctrl_r,delete,down,end,enter,esc, │
|
|
67
|
+
│ f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,f18,f19,f20,home,left,page_down,page_up,right,shift, │
|
|
68
|
+
│ shift_l,shift_r,space,tab,up,media_play_pause,media_volume_mute,media_volume_down,media_volume_up,media_previous, │
|
|
69
|
+
│ media_next,insert,menu,num_lock,pause,print_screen,scroll_lock} │
|
|
70
|
+
│ Key to hold for recording. Release to transcribe and insert text. (default: scroll_lock) │
|
|
71
|
+
│ --sample-rate INT Audio sample rate in Hz. Whisper expects 16000. (default: 16000) │
|
|
72
|
+
│ --device STR Device to run inference on, e.g. cpu or cuda. (default: auto) │
|
|
73
|
+
│ --compute-type STR Quantization type, e.g. int8, float16, float32. (default: int8) │
|
|
74
|
+
│ --num-workers INT Number of parallel transcription workers. Defaults to CPU count. (default:XY) │
|
|
75
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
76
|
+
```
|
|
77
|
+
[comment]: <> (✂✂✂ auto generated listen help end ✂✂✂)
|
|
78
|
+
|
|
79
|
+
### Available models
|
|
80
|
+
|
|
81
|
+
| Model | Size | Speed | Accuracy |
|
|
82
|
+
|-------|------|-------|----------|
|
|
83
|
+
| `tiny` | ~75 MB | fastest | lowest |
|
|
84
|
+
| `base` | ~145 MB | fast | good (default) |
|
|
85
|
+
| `small` | ~460 MB | slower | better |
|
|
86
|
+
| `medium` | ~1.5 GB | slow | high |
|
|
87
|
+
|
|
88
|
+
Larger models produce more accurate transcriptions but take longer to process. For most use cases `base` or `small` is a good starting point.
|
|
89
|
+
|
|
90
|
+
## CLI
|
|
91
|
+
|
|
92
|
+
[comment]: <> (✂✂✂ auto generated main help start ✂✂✂)
|
|
93
|
+
```
|
|
94
|
+
usage: ./cli.py [-h] {listen,version}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
╭─ options ─────────────────────────────────────────────────────────────────────────────────────────╮
|
|
99
|
+
│ -h, --help show this help message and exit │
|
|
100
|
+
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
101
|
+
╭─ subcommands ─────────────────────────────────────────────────────────────────────────────────────╮
|
|
102
|
+
│ (required) │
|
|
103
|
+
│ • listen Start the STT listener. Hold the hotkey to record, release to transcribe and insert. │
|
|
104
|
+
│ • version Print version and exit │
|
|
105
|
+
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
106
|
+
```
|
|
107
|
+
[comment]: <> (✂✂✂ auto generated main help end ✂✂✂)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
## start development
|
|
111
|
+
|
|
112
|
+
At least `uv` is needed. Install e.g.: via pipx:
|
|
113
|
+
```bash
|
|
114
|
+
apt-get install pipx
|
|
115
|
+
pipx install uv
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Clone the project and just start the CLI help commands.
|
|
119
|
+
A virtual environment will be created/updated automatically.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
~$ git clone https://github.com/jedie/stt2desktop.git
|
|
123
|
+
~$ cd stt2desktop
|
|
124
|
+
~/stt2desktop$ ./cli.py --help
|
|
125
|
+
~/stt2desktop$ ./dev-cli.py --help
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
[comment]: <> (✂✂✂ auto generated dev help start ✂✂✂)
|
|
129
|
+
```
|
|
130
|
+
usage: ./dev-cli.py [-h] {coverage,install,lint,mypy,nox,pip-audit,publish,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
135
|
+
│ -h, --help show this help message and exit │
|
|
136
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
137
|
+
╭─ subcommands ────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
138
|
+
│ (required) │
|
|
139
|
+
│ • coverage Run tests and show coverage report. │
|
|
140
|
+
│ • install Install requirements and 'stt2desktop' via pip as editable. │
|
|
141
|
+
│ • lint Check/fix code style by run: "ruff check --fix" │
|
|
142
|
+
│ • mypy Run Mypy (configured in pyproject.toml) │
|
|
143
|
+
│ • nox Run nox │
|
|
144
|
+
│ • pip-audit │
|
|
145
|
+
│ Run pip-audit check against current requirements files │
|
|
146
|
+
│ • publish Build and upload this project to PyPi │
|
|
147
|
+
│ • test Run unittests │
|
|
148
|
+
│ • update Update dependencies (uv.lock) and git pre-commit hooks │
|
|
149
|
+
│ • update-readme-history │
|
|
150
|
+
│ Update project history base on git commits/tags in README.md Will be exited with 1 if the README.md │
|
|
151
|
+
│ was updated otherwise with 0. │
|
|
152
|
+
│ │
|
|
153
|
+
│ Also, callable via e.g.: │
|
|
154
|
+
│ python -m cli_base update-readme-history -v │
|
|
155
|
+
│ • update-test-snapshot-files │
|
|
156
|
+
│ Update all test snapshot files (by remove and recreate all snapshot files) │
|
|
157
|
+
│ • version Print version and exit │
|
|
158
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
159
|
+
```
|
|
160
|
+
[comment]: <> (✂✂✂ auto generated dev help end ✂✂✂)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
## History
|
|
164
|
+
|
|
165
|
+
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
166
|
+
|
|
167
|
+
* [**dev**](https://github.com/jedie/stt2desktop/compare/b407f8f...main)
|
|
168
|
+
* 2026-03-26 - Add POC
|
|
169
|
+
* 2026-03-26 - init
|
|
170
|
+
|
|
171
|
+
[comment]: <> (✂✂✂ auto generated history end ✂✂✂)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# stt2desktop
|
|
2
|
+
|
|
3
|
+
[](https://github.com/jedie/stt2desktop/actions/workflows/tests.yml)
|
|
4
|
+
[](https://app.codecov.io/github/jedie/stt2desktop)
|
|
5
|
+
[](https://pypi.org/project/stt2desktop/)
|
|
6
|
+
[](https://github.com/jedie/stt2desktop/blob/main/pyproject.toml)
|
|
7
|
+
[](https://github.com/jedie/stt2desktop/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
Local speech-to-text for desktop using [faster-whisper](https://github.com/SYSTRAN/faster-whisper).
|
|
10
|
+
|
|
11
|
+
Let's you dictate text into any application without sending audio to any cloud services.
|
|
12
|
+
Everything runs locally on your machine — no internet connection required after the initial model was download.
|
|
13
|
+
|
|
14
|
+
## How it works
|
|
15
|
+
|
|
16
|
+
1. Run `./cli.py listen` — the Whisper model is loaded into memory (downloaded on first run).
|
|
17
|
+
2. Hold **Scroll Lock** to record from your microphone.
|
|
18
|
+
3. Release **Scroll Lock** — the audio is transcribed locally by faster-whisper (CPU, `int8`).
|
|
19
|
+
4. The text is typed into the focused window via `wtype` (Wayland) or `xdotool` (X11).
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
Requirements: Python 3.12+, [`uv`](https://github.com/astral-sh/uv), a working microphone, and either `wtype` (Wayland) or `xdotool` (X11):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
sudo apt install wtype # Wayland
|
|
27
|
+
sudo apt install xdotool # X11
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then run:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
./cli.py listen
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
[comment]: <> (✂✂✂ auto generated listen help start ✂✂✂)
|
|
37
|
+
```
|
|
38
|
+
usage: ./cli.py listen [-h] [LISTEN OPTIONS]
|
|
39
|
+
|
|
40
|
+
Start the STT listener. Hold the hotkey to record, release to transcribe and insert.
|
|
41
|
+
|
|
42
|
+
╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
43
|
+
│ -h, --help show this help message and exit │
|
|
44
|
+
│ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
|
|
45
|
+
│ --model {tiny_en,tiny,base_en,base,small_en,small,medium_en,medium,large_v1,large_v2,large_v3,large,distil_large_v2, │
|
|
46
|
+
│ distil_medium_en,distil_small_en,distil_large_v3,distil_large_v3_5,large_v3_turbo,turbo} │
|
|
47
|
+
│ Whisper model to use for transcription. (default: small) │
|
|
48
|
+
│ --hotkey {alt,alt_l,alt_r,alt_gr,backspace,caps_lock,cmd,cmd_l,cmd_r,ctrl,ctrl_l,ctrl_r,delete,down,end,enter,esc, │
|
|
49
|
+
│ f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,f18,f19,f20,home,left,page_down,page_up,right,shift, │
|
|
50
|
+
│ shift_l,shift_r,space,tab,up,media_play_pause,media_volume_mute,media_volume_down,media_volume_up,media_previous, │
|
|
51
|
+
│ media_next,insert,menu,num_lock,pause,print_screen,scroll_lock} │
|
|
52
|
+
│ Key to hold for recording. Release to transcribe and insert text. (default: scroll_lock) │
|
|
53
|
+
│ --sample-rate INT Audio sample rate in Hz. Whisper expects 16000. (default: 16000) │
|
|
54
|
+
│ --device STR Device to run inference on, e.g. cpu or cuda. (default: auto) │
|
|
55
|
+
│ --compute-type STR Quantization type, e.g. int8, float16, float32. (default: int8) │
|
|
56
|
+
│ --num-workers INT Number of parallel transcription workers. Defaults to CPU count. (default:XY) │
|
|
57
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
58
|
+
```
|
|
59
|
+
[comment]: <> (✂✂✂ auto generated listen help end ✂✂✂)
|
|
60
|
+
|
|
61
|
+
### Available models
|
|
62
|
+
|
|
63
|
+
| Model | Size | Speed | Accuracy |
|
|
64
|
+
|-------|------|-------|----------|
|
|
65
|
+
| `tiny` | ~75 MB | fastest | lowest |
|
|
66
|
+
| `base` | ~145 MB | fast | good (default) |
|
|
67
|
+
| `small` | ~460 MB | slower | better |
|
|
68
|
+
| `medium` | ~1.5 GB | slow | high |
|
|
69
|
+
|
|
70
|
+
Larger models produce more accurate transcriptions but take longer to process. For most use cases `base` or `small` is a good starting point.
|
|
71
|
+
|
|
72
|
+
## CLI
|
|
73
|
+
|
|
74
|
+
[comment]: <> (✂✂✂ auto generated main help start ✂✂✂)
|
|
75
|
+
```
|
|
76
|
+
usage: ./cli.py [-h] {listen,version}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
╭─ options ─────────────────────────────────────────────────────────────────────────────────────────╮
|
|
81
|
+
│ -h, --help show this help message and exit │
|
|
82
|
+
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
83
|
+
╭─ subcommands ─────────────────────────────────────────────────────────────────────────────────────╮
|
|
84
|
+
│ (required) │
|
|
85
|
+
│ • listen Start the STT listener. Hold the hotkey to record, release to transcribe and insert. │
|
|
86
|
+
│ • version Print version and exit │
|
|
87
|
+
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
88
|
+
```
|
|
89
|
+
[comment]: <> (✂✂✂ auto generated main help end ✂✂✂)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
## start development
|
|
93
|
+
|
|
94
|
+
At least `uv` is needed. Install e.g.: via pipx:
|
|
95
|
+
```bash
|
|
96
|
+
apt-get install pipx
|
|
97
|
+
pipx install uv
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Clone the project and just start the CLI help commands.
|
|
101
|
+
A virtual environment will be created/updated automatically.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
~$ git clone https://github.com/jedie/stt2desktop.git
|
|
105
|
+
~$ cd stt2desktop
|
|
106
|
+
~/stt2desktop$ ./cli.py --help
|
|
107
|
+
~/stt2desktop$ ./dev-cli.py --help
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
[comment]: <> (✂✂✂ auto generated dev help start ✂✂✂)
|
|
111
|
+
```
|
|
112
|
+
usage: ./dev-cli.py [-h] {coverage,install,lint,mypy,nox,pip-audit,publish,test,update,update-readme-history,update-test-snapshot-files,version}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
117
|
+
│ -h, --help show this help message and exit │
|
|
118
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
119
|
+
╭─ subcommands ────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
120
|
+
│ (required) │
|
|
121
|
+
│ • coverage Run tests and show coverage report. │
|
|
122
|
+
│ • install Install requirements and 'stt2desktop' via pip as editable. │
|
|
123
|
+
│ • lint Check/fix code style by run: "ruff check --fix" │
|
|
124
|
+
│ • mypy Run Mypy (configured in pyproject.toml) │
|
|
125
|
+
│ • nox Run nox │
|
|
126
|
+
│ • pip-audit │
|
|
127
|
+
│ Run pip-audit check against current requirements files │
|
|
128
|
+
│ • publish Build and upload this project to PyPi │
|
|
129
|
+
│ • test Run unittests │
|
|
130
|
+
│ • update Update dependencies (uv.lock) and git pre-commit hooks │
|
|
131
|
+
│ • update-readme-history │
|
|
132
|
+
│ Update project history base on git commits/tags in README.md Will be exited with 1 if the README.md │
|
|
133
|
+
│ was updated otherwise with 0. │
|
|
134
|
+
│ │
|
|
135
|
+
│ Also, callable via e.g.: │
|
|
136
|
+
│ python -m cli_base update-readme-history -v │
|
|
137
|
+
│ • update-test-snapshot-files │
|
|
138
|
+
│ Update all test snapshot files (by remove and recreate all snapshot files) │
|
|
139
|
+
│ • version Print version and exit │
|
|
140
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
141
|
+
```
|
|
142
|
+
[comment]: <> (✂✂✂ auto generated dev help end ✂✂✂)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
## History
|
|
146
|
+
|
|
147
|
+
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
|
148
|
+
|
|
149
|
+
* [**dev**](https://github.com/jedie/stt2desktop/compare/b407f8f...main)
|
|
150
|
+
* 2026-03-26 - Add POC
|
|
151
|
+
* 2026-03-26 - init
|
|
152
|
+
|
|
153
|
+
[comment]: <> (✂✂✂ auto generated history end ✂✂✂)
|
stt2desktop-0.0.1/cli.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
`./cli.py` is for normal usage.
|
|
5
|
+
Just call this file, and the magic happens ;)
|
|
6
|
+
|
|
7
|
+
The `uv` tool is required to run the development CLI.
|
|
8
|
+
|
|
9
|
+
e.g.: Install `uv` via `pipx`
|
|
10
|
+
apt-get install pipx
|
|
11
|
+
pipx install uv
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import shlex
|
|
16
|
+
import shutil
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
assert sys.version_info >= (3, 12), f'Python version {sys.version_info} is too old!'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Create and use "/.venv-app/" for virtualenv:
|
|
26
|
+
VIRTUAL_ENV = '.venv-app'
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def print_uv_error_and_exit():
|
|
30
|
+
print('\nError: "uv" command not found in PATH. Please install "uv" first!\n')
|
|
31
|
+
print('Hint:')
|
|
32
|
+
print('\tapt-get install pipx\n')
|
|
33
|
+
print('\tpipx install uv\n')
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def verbose_check_call(*popen_args, **extra_env):
|
|
38
|
+
print(f'\n+ {shlex.join(str(arg) for arg in popen_args)}\n')
|
|
39
|
+
env = {
|
|
40
|
+
'VIRTUAL_ENV': VIRTUAL_ENV,
|
|
41
|
+
'UV_VENV': VIRTUAL_ENV,
|
|
42
|
+
**os.environ,
|
|
43
|
+
**extra_env,
|
|
44
|
+
}
|
|
45
|
+
return subprocess.check_call(
|
|
46
|
+
popen_args,
|
|
47
|
+
env=env,
|
|
48
|
+
cwd=Path(__file__).parent, # Needed if called from other working directory
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def main(argv):
|
|
53
|
+
uv_bin = shutil.which('uv') # Ensure 'uv' is available in PATH
|
|
54
|
+
if not uv_bin:
|
|
55
|
+
print_uv_error_and_exit()
|
|
56
|
+
|
|
57
|
+
if not Path(VIRTUAL_ENV).is_dir():
|
|
58
|
+
verbose_check_call(uv_bin, 'venv', VIRTUAL_ENV)
|
|
59
|
+
|
|
60
|
+
# Call our entry point CLI:
|
|
61
|
+
try:
|
|
62
|
+
verbose_check_call(uv_bin, 'run', '--active', '-m', 'stt2desktop', *argv[1:])
|
|
63
|
+
except subprocess.CalledProcessError as err:
|
|
64
|
+
sys.exit(err.returncode)
|
|
65
|
+
except KeyboardInterrupt:
|
|
66
|
+
print('Bye!')
|
|
67
|
+
sys.exit(130)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if __name__ == '__main__':
|
|
71
|
+
main(sys.argv)
|