-
Notifications
You must be signed in to change notification settings - Fork 2
Developer Guide
π Language: English | FranΓ§ais
Everything you need to build, test, and contribute to dictee. The project combines Rust (ASR engine via ONNX Runtime), Python / PyQt6 (setup wizard + tray), QML (KDE plasmoid), and Bash (main orchestration script).
Build artifacts are packaged as .deb, .rpm, Arch PKGBUILD, and a portable tarball. This guide covers repo layout, Cargo features, build scripts, testing harnesses, i18n, and the contribution workflow.
- Repo layout
- Source of truth vs packaged files
- Building from source
- Package builds
- Audio pipeline internals
- Runtime state & IPC
- Testing
- Internationalization
- Contributing
dictee/ # git repo root
βββ Cargo.toml # Rust workspace
βββ src/ # Rust β moteur ASR (bibliothΓ¨que + binaires)
β βββ lib.rs # Public API
β βββ audio.rs # WAV, STFT, mel-spectrograms
β βββ parakeet_tdt.rs # TDT model (25 languages)
β βββ canary.rs # Canary AED model
β βββ nemotron.rs # Nemotron streaming (EN only)
β βββ sortformer.rs # Diarization, streaming (4 speakers)
β βββ diar/ # Multi-speaker diarization engine (no cap, v1.4)
β βββ model*.rs, decoder*.rs # ONNX wrappers
β βββ timestamps.rs # Tokenβwordβsentence alignment
β βββ bin/ # Executables
β βββ transcribe.rs # CLI batch
β βββ transcribe_daemon.rs # Unix socket server
β βββ transcribe_client.rs # Daemon client + mic recording
β βββ transcribe_diarize.rs # TDT + Sortformer
β βββ transcribe_stream_diarize.rs # Nemotron + Sortformer
β βββ transcribe_diarize_batch.rs # Chunked pipeline (v1.3 final)
βββ dictee # Main shell script (source of truth)
βββ dictee-setup.py # PyQt6 setup wizard
βββ dictee-tray.py # PyQt6 tray icon
βββ plasmoid/ # KDE Plasma 6 widget
β βββ package/
β βββ metadata.json
β βββ contents/
β βββ ui/ # QML (main.qml, CompactRepresentation, etc.)
β βββ assets/ # SVG animations (bars, wave, pulse, dots, waveform)
β βββ locale/{fr,de,es,it,uk,pt}/
βββ po/ # gettext translations (setup + tray)
β βββ dictee.pot # Template
β βββ {fr,de,es,it,uk,pt}.po
βββ pkg/ # dpkg-deb tree (artifact, NOT source of truth)
βββ tests/ # Test suites
β βββ test-postprocess.py # 682 unittest cases
β βββ test-pipeline.py # 148 pipeline cases
β βββ test-wer.py # WER benchmark harness
βββ build-deb.sh # .deb build (CPU + CUDA)
βββ build-rpm.sh # .rpm build (CPU + CUDA)
βββ PKGBUILD # Arch package
βββ install.sh / uninstall.sh
Files at the repo root (dictee, dictee-setup.py, dictee-tray.py) are the source of truth.
build-deb.sh copies them into pkg/ at build time. Never edit files in pkg/ directly β they will be overwritten on the next build.
git clone https://github.com/rcspam/dictee.git
cd dictee
# CPU-only (default)
cargo build --release
# CUDA + Sortformer diarization
cargo build --release --features "cuda,sortformer"Output binaries in target/release/:
-
libparakeet_rs.so(library, for future bindings) -
transcribe,transcribe-daemon,transcribe-client -
transcribe-diarize,transcribe-stream-diarize,transcribe-diarize-batch
Declared in Cargo.toml:
| Feature | Default | Purpose |
|---|---|---|
cpu |
β | CPU execution provider |
ort-defaults |
β | ONNX Runtime sensible defaults |
cuda |
β | CUDA 12 execution provider |
tensorrt |
β | TensorRT optimization (experimental) |
coreml |
β | Apple CoreML (macOS-only, unused in dictee) |
directml |
β | DirectX 12 (Windows-only, unused) |
openvino |
β | Intel OpenVINO |
webgpu |
β | WebGPU (browser use) |
nnapi |
β | Android NNAPI (unused) |
sortformer |
β | Speaker diarization via Sortformer |
Typical combos:
- Dev machine:
--features cuda,sortformer - CI CPU build: (default, no features)
- CI CUDA build:
--features cuda,sortformer
No build step β files at dictee-setup.py and dictee-tray.py are interpreted at runtime.
Dependencies (install for development):
pip install PyQt6 PyQt6-WebEngine text2num faster-whisper voskFor PyQt6 on Ubuntu 22.04 (which ships 5.15):
pip install --user 'PyQt6>=6.5' 'PyQt6-Qt6>=6.5'Dev install (doesn't require packaging):
kpackagetool6 -t Plasma/Applet -i plasmoid/packageReinstall after edits:
kpackagetool6 -t Plasma/Applet -u plasmoid/package
# Restart plasmashell if the widget is already on a panel:
killall -15 plasmashell && kstart plasmashell &./build-deb.shProduces:
dictee-cpu_1.3.1_amd64.debdictee-cuda_1.3.1_amd64.debdictee-plasmoid_1.3.1_all.deb-
dictee-1.3.1_amd64.tar.gz(portable tarball)
Key steps:
-
cargo build --release(for CPU variant) +cargo build --release --features cuda,sortformer(for CUDA) - Copy Rust binaries to
pkg/dictee/usr/bin/ - Copy shell scripts (
dictee,dictee-postprocess, etc.) topkg/dictee/usr/bin/ - Copy Python scripts (
dictee-setup.pyβ/usr/bin/dictee-setup) β note: renamed without.py - Copy plasmoid to
pkg/dictee-plasmoid/usr/share/dictee/dictee.plasmoid - Build CUDA variant: bundle CUDA libs via pip venv (since v1.3)
-
dpkg-deb --build pkg/dictee-cpuetc.
./build-rpm.shSame outputs but .rpm. Uses rpmbuild with a spec file.
makepkg -siUses PKGBUILD in the repo root. Builds from source, no prebuilt binaries.
See the memory note feedback-cuda-build-flags: certain cargo flags combinations have been problematic 5+ times. Always double-check:
-
LIBTORCHnot set globally -
ORT_STRATEGY=downloadfor CI -
ORT_DYLIB_PATHset at runtime in the systemd unit
Microphone (PipeWire)
β parecord --format=s16le --rate=48000 --channels=1
β
/dev/shm/.dictee_rec.wav (raw capture)
β sox resample to 16 kHz mono
β
/dev/shm/.dictee_rec_16k.wav
β transcribe-client sends via Unix socket
β
Unix socket: $XDG_RUNTIME_DIR/transcribe.sock
β
transcribe-daemon (Rust)
β
src/audio.rs: preemphasis(0.97) β STFT(n_fft=512, hop=160, win=400, Hann)
β
Mel filterbank (128 bins, Slaney, log guard 5.96e-8)
β
ONNX tensor (1 Γ 128 Γ T)
β
Encoder (FastConformer) β Decoder (TDT)
β
Text (with native punctuation)
β
Unix socket response
β
dictee shell script β dictee-postprocess β dotool type
Full source: src/audio.rs (Rust side), pkg/dictee/usr/bin/dictee-transcribe (Python wrapper).
See CLI-Reference#state-files for the full list. Multi-user safe via $UID suffix.
Daemon listens on $XDG_RUNTIME_DIR/transcribe.sock. Protocol is line-based:
Request:
TRANSCRIBE /path/to/audio.wav [lang=fr] [translate_to=en]
Response:
OK <json-payload>
Payload includes: transcription text, word-level timestamps, speaker labels (if diarization), language detected, confidence.
Implementation in src/bin/transcribe_daemon.rs.
cargo test
cargo test --features sortformer682 tests in tests/test-postprocess.py β 12 pipeline steps Γ 7 languages Γ edge cases:
cd tests
python -m unittest test-postprocess.py -v148 tests in tests/test-pipeline.py β full transcription pipeline with mocked ASR:
python -m unittest test-pipeline.py -vpython tests/test-wer.py --backend parakeet --lang fr --corpus commonvoice- docs/test-checklist-ui-pipeline.md β 39 UI checks
- docs/test-protocol-vocal.md β 38 vocal dictations to verify
GitHub Actions runs all automated tests on every push:
- Post-processing (isolated
XDG_CONFIG_HOME) - Pipeline
- Rust unit tests
-
msgfmt --checkon all.pofiles
dictee-setup.py and dictee-tray.py use gettext with domain dictee and catalogs in po/:
-
po/dictee.potβ template (regenerated from source strings viaxgettext) -
po/{fr,de,es,it,uk,pt}.poβ translations -
po/{lang}/LC_MESSAGES/dictee.moβ compiled (generated bymsgfmt)
Workflow:
# Extract new strings into the template
xgettext -L Python -o po/dictee.pot dictee-setup.py dictee-tray.py
# Update existing translations
msgmerge --update po/fr.po po/dictee.pot
# Compile to .mo
msgfmt po/fr.po -o po/fr/LC_MESSAGES/dictee.moSeparate domain plasma_applet_com.github.rcspam.dictee:
plasmoid/package/contents/locale/{fr,de,es,it,uk,pt}/LC_MESSAGES/plasma_applet_com.github.rcspam.dictee.mo
Built by the plasmoid packager.
Inline, e.g.:
Name=DictΓ©e
Name[fr]=DictΓ©e
Name[de]=Diktat
GenericName=Voice dictation
GenericName[fr]=DictΓ©e vocale
- Fork the repo at github.com/rcspam/dictee
- Create a feature branch:
git checkout -b feat/my-feature - Commit with conventional commits:
feat(scope): description/fix(scope): description - Push and open a PR against
master - CI must be green
- Code review by maintainer
Examples from git log:
feat(plasmoid): combo langue compact + popup wide + close on deactivatefix(setup): wizard trans sync + langues cibles complΓ¨tes + largeur combosdocs(wiki): scaffold 20 pages (stubs)chore(version): bump 1.3.0~beta5 β 1.3.0~rc1
- Create
src/<backend>.rswith the ONNX model wrapper - Add a binary in
src/bin/or extendtranscribe_daemonto support it - Create a systemd unit at
pkg/dictee/usr/lib/systemd/user/dictee-<backend>.service - Update
dictee-switch-backendto recognize the new backend name - Add UI support in
dictee-setup.py(ASR backend combo + model download logic) - Document in ASR-Backends and CLI-Reference
- Add regex rules in
pkg/dictee/usr/share/dictee/rules.conf.defaultwith[xx]prefix - Add continuation trigger word in
continuation.conf.default - Add
.potranslation for setup + tray:po/xx.po - Add plasmoid translation:
plasmoid/package/contents/locale/xx/ - Test manually against test-protocol-vocal.md
- CLI-Reference β all binaries documented
- ASR-Backends β backends overview
- Changelog β release notes and roadmap
- Troubleshooting β debug common issues
π¬π§ Home Β· π«π· Accueil
Getting started / Premiers pas
- Installation Β· π¬π§ Β· π«π·
- Setup-Wizard Β· π¬π§ Β· π«π·
- Configuration Β· π¬π§ Β· π«π·
- Plasmoid-Widget Β· π¬π§ Β· π«π·
- Tray-Icon Β· π¬π§ Β· π«π·
- Keyboard-Shortcuts Β· π¬π§ Β· π«π·
- Voice-Commands Β· π¬π§ Β· π«π·
- GPU-Setup Β· π¬π§ Β· π«π·
- Diarization Β· π¬π§ Β· π«π·
- LLM-Diarization Β· π¬π§ Β· π«π·
Speech recognition / ASR
- ASR-Backends Β· π¬π§ Β· π«π·
- Parakeet-TDT-Deep-Dive Β· π¬π§ Β· π«π·
- Canary-1B-Deep-Dive Β· π¬π§ Β· π«π·
Translation / Traduction
Post-processing / Post-traitement
- Overview Β· π¬π§ Β· π«π·
- Rules-and-Dictionary Β· π¬π§ Β· π«π·
- LLM-Correction Β· π¬π§ Β· π«π·
- Numbers-Dates-Continuation Β· π¬π§ Β· π«π·
CLI
Reference / RΓ©fΓ©rence
- Troubleshooting Β· π¬π§ Β· π«π·
- FAQ Β· π¬π§ Β· π«π·
- Developer-Guide Β· π¬π§ Β· π«π·
- Changelog Β· π¬π§ Β· π«π·
π Repo Β· π¦ Releases Β· π Issues