- TypeScript 96.8%
- JavaScript 1.6%
- CSS 1.4%
- HTML 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| scripts | ||
| src/main | ||
| tests | ||
| ui | ||
| .gitattributes | ||
| .gitignore | ||
| .oxfmtrc.json | ||
| AGENTS.md | ||
| bun.lock | ||
| DEVELOPMENT.md | ||
| electron-builder.yml | ||
| icon.svg | ||
| knip.json | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
| SECURITY.md | ||
| THIRD_PARTY_NOTICES.md | ||
| tsconfig.json | ||
Voice Typer
Voice Typer is a local-first Electron desktop app that records microphone audio, transcribes it on-device with Parakeet or Whisper, and inserts the result into the currently focused app.
The repository combines:
- An Electron main process for windowing, hotkeys, typing, persistence, transcription orchestration, and native integrations
- A React 19 renderer for setup, settings, history, logs, runtime status, browser-native microphone capture, and audio-file normalization
- Worker-thread ASR runtimes backed by
sherpa-onnx-nodefor Parakeet and@fugood/whisper.nodefor Whisper - Browser Web Audio APIs for recording, waveform display, resampling, and WAV encoding
Core workflow
- Press the record hotkey to start recording.
- Press it again to stop, or use the cancel hotkey to abort.
- Voice Typer captures 16 kHz mono PCM WAV audio in the renderer.
- The app transcribes the captured audio locally with the selected engine.
- The app stores the transcription in history and optionally types it into the active window.
No cloud speech API is required for the main transcription flow.
Features
- Local Parakeet transcription with a CPU-friendly int8 model
- Optional Parakeet language identification using local Sherpa Whisper detector models
- Local Whisper transcription with downloadable multilingual models from
tinythroughlarge-v3-turbo - Browser-native microphone recording with live waveform display
- Browser-supported audio file import and normalization to 16 kHz mono WAV
- Configurable hotkeys for recording, cancellation, and per-language switching
- Multiple typing modes:
clipboard,direct, andnative - Audio device selection using browser microphone devices
- Whisper backend preference selection:
auto,cuda,vulkan,cpu - Transcription history and runtime logs
- Tray/minimize behavior controls
- Setup wizard for first-run configuration
Stack
- Electron
- TypeScript
- React 19
- Vite
- Tailwind CSS 4
sherpa-onnx-node@fugood/whisper.nodeuiohook-napi
Prerequisites
- Bun
- Git
- OS microphone access for the app
- Internet access for the first download of selected local models
FFmpeg is not required. Recording and file import now use Chromium/Web Audio APIs in the renderer. File import supports formats Chromium can decode, such as WAV, MP3, M4A, OGG, WebM, AAC, and FLAC when supported by the bundled Chromium build.
Whisper CUDA requires compatible NVIDIA drivers plus CUDA Toolkit 12.x on the target machine. Parakeet uses the Sherpa ONNX CPU path in the current app.
Setup
git clone https://git.kleb.sh/kleb/VoiceTyper.git
cd VoiceTyper
bun install
cd ui && bun install && cd ..
Start the app in development:
bun run dev
This runs:
- Vite for the renderer on
http://localhost:5173 - TypeScript watch for the Electron main process
- Electron with
electronmon
First-Time Setup
The first launch opens a setup wizard with Model and Hotkey screens.
- Choose and download a transcription engine.
- Parakeet is the default engine. It downloads the Parakeet ASR bundle and, unless disabled, a separate language-ID detector.
- Whisper is available as an alternate engine. It downloads the selected Whisper model only.
- Status and logs show model download, extraction percentage, and loading phases.
- Configure the Parakeet language detector if Parakeet is selected.
Tinyis the default detector.Nonedisables language-ID downloads and Parakeet results remainunknown.Base,Small, andMediumtrade larger downloads for more language-ID capacity.- Parakeet readiness is complete only when both the ASR model and the selected detector are ready.
- Configure the record hotkey.
- The default record hotkey is
Right Alt. - The default cancel hotkey is
Escape.
- The default record hotkey is
- Finish setup and make a short test recording.
- Start and stop recording from the hotkey or the UI.
- If the waveform does not move, check OS microphone privacy settings and the selected microphone in Settings.
- For Parakeet, short clips can still show
unknownlanguage when the detector cannot produce a reliable code.
After setup, Settings lets you change the engine, model, Parakeet detector, microphone device, language mode, Whisper backend, typing mode, auto-type behavior, hotkeys, and tray behavior.
Validation
bun run typecheck
bun run lint
bun run test
bun run build
cd ui && bun run lint
Recommended manual smoke tests after changes:
- Fresh launch starts at model setup and does not ask for FFmpeg
- Parakeet setup downloads the ASR bundle and selected language detector with download, extraction percentage, and loading progress
NoneParakeet detector skips detector download and leaves language metadata asunknown- Whisper setup downloads and loads a selected Whisper model
- Record and stop with the configured hotkey
- Cancel a recording or transcription
- Confirm the waveform animates while recording
- Change audio device selection and confirm the selected microphone persists after restart
- Import a Chromium-decodable audio file and confirm it transcribes
- Import an unsupported file and confirm the app shows a clear unsupported-format error
- Verify auto-type in the selected typing mode
- Restart the app and confirm settings persistence
- Confirm logs auto-scroll while setup and transcription logs are added
- Confirm logs contain no FFmpeg startup, install, conversion, or dependency messages
Packaging
bun run package:win
bun run package:mac
bun run package:linux
Windows CUDA note: package:win no longer downloads unrelated CUDA DLLs. The CUDA backend uses @fugood/whisper.node native packages and requires compatible NVIDIA drivers plus CUDA Toolkit 12.x on the target machine.
bun run setup:cuda is retained as a no-op compatibility message for older workflows.
Runtime architecture
src/main/index.tsboots Electron, configures CSP, validates startup state, manages the tray, and handles app shutdown.src/main/preload.tsexposes a narrowcontextBridgeAPI to the renderer.src/main/ipc.tsowns the IPC command surface, recording session coordination, and model commands.src/main/audio.tsmanages recording-directory cleanup.src/main/wav.tsvalidates submitted WAV files and computes audio stats.ui/src/hooks/use-browser-recorder.tsowns microphone capture, waveform samples, recording control, and WAV submission.ui/src/lib/audio-wav.tsowns browser audio decoding, resampling, WAV encoding, and microphone enumeration helpers.src/main/parakeet.tsandsrc/main/parakeet-worker.tsmanage Parakeet model download, extraction, loading, transcription, and optional language-ID.src/main/whisper.tsandsrc/main/whisper-worker.tsmanage Whisper model download, loading, backend detection, and transcription.src/main/state.tspersists settings, history, and logs.ui/src/App.tsxandui/src/hooks/use-voice-typer.tsdrive the renderer UI.
Security posture
Current Electron security controls in the app include:
contextIsolation: truesandbox: truenodeIntegration: false- A preload-only API surface
- Content Security Policy headers applied from the main process
- Renderer communication through IPC instead of direct Node access
See SECURITY.md for the repo-specific checklist and contributor guidance.
Models
Parakeet and Whisper models are downloaded on demand and remain local. New installs default to Parakeet with the Tiny Parakeet language detector. Whisper remains available for users who prefer Whisper language metadata, CUDA/Vulkan backend selection, or different quality, latency, disk, and memory tradeoffs.
Parakeet
| Model | Approx. size | Speed | Accuracy | Suggested use |
|---|---|---|---|---|
| parakeet-tdt-0.6b-v3-int8 | 650 MB | Fastest | Best | Default local dictation for supported languages |
Parakeet Language ID
Parakeet does not natively return a language code. Voice Typer can run a separate local Sherpa Whisper language-ID model after Parakeet transcription.
| Detector | Approx. size | Suggested use |
|---|---|---|
| none | 0 MB | Skip language detection; show unknown |
| tiny | 111 MB | Default lightweight detector |
| base | 198 MB | More language-ID capacity than Tiny |
| small | 610 MB | Higher-capacity detector with a larger download |
| medium | 1.8 GB | Largest detector option |
Whisper
| Model | Approx. size | Speed | Accuracy | Suggested use |
|---|---|---|---|---|
| tiny | 75 MB | Fastest | Basic | Fastest multilingual option for tests |
| base | 142 MB | Fast | Good | Default lightweight Whisper model |
| small | 466 MB | Medium | Better | Better quality when memory allows |
| medium | 1.5 GB | Slow | Great | Higher quality for longer dictation |
| large-v2 | 3.1 GB | Slowest | Excellent | Previous-generation full-precision model |
| large-v3 | 3.0 GB | Slowest | Best | Best local Whisper accuracy |
| large-v3-turbo | 1.6 GB | Medium-fast | Very good | Practical high-quality multilingual model |
| large-v3-turbo-q8_0 | 874 MB | Medium-fast | Very good | Higher-precision quantized Turbo |
The old Q5_0 and Q5_1 Whisper model entries are no longer part of the selectable catalog.
Language detection
The default language setting is auto.
Whisper uses language metadata returned by the Whisper runtime. If the runtime returns no language metadata, Voice Typer keeps the language as unknown.
Parakeet does not expose a native language code. When a Parakeet language detector is enabled, Voice Typer runs the selected local Sherpa Whisper language-ID model on the same audio and records returned language codes as language-id. Sherpa language-ID does not expose confidence, so Voice Typer does not display a fabricated percentage for this path. If the detector is disabled, returns nothing, or fails, the language stays unknown.
Voice Typer no longer infers language from transcript text. Forced language selection and language hotkeys still bypass auto-detection.
Data and logs
The app persists settings, history, and logs under the app data directory configured by the runtime environment. At startup the main process logs the effective data directory and log file location.
Downloaded models are stored under the app models directory. Deleting local Parakeet models removes both the Parakeet ASR cache and all Parakeet language-ID detector caches.
License
MIT