Local desktop speech-to-text app
  • TypeScript 96.8%
  • JavaScript 1.6%
  • CSS 1.4%
  • HTML 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-24 14:44:49 +02:00
scripts Repo hygiene: remove CI workflow, stray files, npm fallback; refresh docs 2026-07-20 02:25:36 +02:00
src/main Add optional streaming output 2026-08-23 18:21:51 +02:00
tests Add optional streaming output 2026-08-23 18:21:51 +02:00
ui Update dependencies 2026-08-24 13:34:26 +02:00
.gitattributes Enforce LF line endings via .gitattributes 2026-06-23 22:20:33 +02:00
.gitignore Upgrade root dependencies to latest 2026-07-20 02:35:34 +02:00
.oxfmtrc.json Add fast TypeScript quality tooling (#4) 2026-06-18 08:14:32 +02:00
AGENTS.md Overhaul desktop app: browser capture, redesign, i18n, audit fixes 2026-06-19 03:18:16 +02:00
bun.lock Update dependencies 2026-08-24 13:34:26 +02:00
DEVELOPMENT.md Upgrade UI dependencies: Vite 8, plugin-react 6, ESLint 10, Tailwind 4.3, Radix 2026-07-20 02:48:48 +02:00
electron-builder.yml Emit release checksums and document signing/update policy 2026-06-23 22:39:07 +02:00
icon.svg Add app icon, cancel hotkey, UI redesign, and transcription history 2026-02-05 13:39:15 +01:00
knip.json Repo hygiene: remove CI workflow, stray files, npm fallback; refresh docs 2026-07-20 02:25:36 +02:00
LICENSE Add MIT LICENSE file and license field 2026-06-23 22:34:48 +02:00
package.json Update dependencies 2026-08-24 13:34:26 +02:00
README.md Repo hygiene: remove CI workflow, stray files, npm fallback; refresh docs 2026-07-20 02:25:36 +02:00
SECURITY.md Overhaul desktop app: browser capture, redesign, i18n, audit fixes 2026-06-19 03:18:16 +02:00
THIRD_PARTY_NOTICES.md Overhaul desktop app: browser capture, redesign, i18n, audit fixes 2026-06-19 03:18:16 +02:00
tsconfig.json Add fast TypeScript quality tooling (#4) 2026-06-18 08:14:32 +02:00

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-node for Parakeet and @fugood/whisper.node for Whisper
  • Browser Web Audio APIs for recording, waveform display, resampling, and WAV encoding

Core workflow

  1. Press the record hotkey to start recording.
  2. Press it again to stop, or use the cancel hotkey to abort.
  3. Voice Typer captures 16 kHz mono PCM WAV audio in the renderer.
  4. The app transcribes the captured audio locally with the selected engine.
  5. 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 tiny through large-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, and native
  • 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.node
  • uiohook-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.

  1. 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.
  2. Configure the Parakeet language detector if Parakeet is selected.
    • Tiny is the default detector.
    • None disables language-ID downloads and Parakeet results remain unknown.
    • Base, Small, and Medium trade larger downloads for more language-ID capacity.
    • Parakeet readiness is complete only when both the ASR model and the selected detector are ready.
  3. Configure the record hotkey.
    • The default record hotkey is Right Alt.
    • The default cancel hotkey is Escape.
  4. 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 unknown language 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
  • None Parakeet detector skips detector download and leaves language metadata as unknown
  • 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.ts boots Electron, configures CSP, validates startup state, manages the tray, and handles app shutdown.
  • src/main/preload.ts exposes a narrow contextBridge API to the renderer.
  • src/main/ipc.ts owns the IPC command surface, recording session coordination, and model commands.
  • src/main/audio.ts manages recording-directory cleanup.
  • src/main/wav.ts validates submitted WAV files and computes audio stats.
  • ui/src/hooks/use-browser-recorder.ts owns microphone capture, waveform samples, recording control, and WAV submission.
  • ui/src/lib/audio-wav.ts owns browser audio decoding, resampling, WAV encoding, and microphone enumeration helpers.
  • src/main/parakeet.ts and src/main/parakeet-worker.ts manage Parakeet model download, extraction, loading, transcription, and optional language-ID.
  • src/main/whisper.ts and src/main/whisper-worker.ts manage Whisper model download, loading, backend detection, and transcription.
  • src/main/state.ts persists settings, history, and logs.
  • ui/src/App.tsx and ui/src/hooks/use-voice-typer.ts drive the renderer UI.

Security posture

Current Electron security controls in the app include:

  • contextIsolation: true
  • sandbox: true
  • nodeIntegration: 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