A local-first audio transcription and analysis pipeline. All processing happens on your machine — no cloud APIs, no data leaving your system.
This is a Rust workspace that bundles a desktop GUI and a CLI tool for transcribing audio and video. It uses whisper.cpp for speech recognition, pyannote for speaker diarization, yt-dlp for downloading from URLs, and Ollama for AI-powered summarization — all running locally.
apps/cli/ — Command-line interface (transcribe, diarize, verify)
apps/desktop/ — Tauri desktop app (GUI)
crates/transcription-core/ — Shared pipeline logic
scripts/ — Build helpers for whisper.cpp
Transcription
- Local speech-to-text via whisper.cpp (GPU-accelerated with ROCm/HIP or CUDA)
- Supports audio files (MP3, MP4, WAV, M4A, OGG, FLAC, WebM) and YouTube/web URLs via yt-dlp
- Configurable audio quality and language
- Inline transcript editing in the desktop app
Speaker diarization
- Identifies who spoke when using pyannote speaker diarization
- Configurable speaker count
- Speaker name assignment in the desktop UI
AI Summarization
- Generates summaries from transcripts using a locally running Ollama model
- Custom prompts and output language selection
- Combine multiple transcripts into one summary
- Streaming output in the desktop app
Desktop app
- Drag-and-drop audio files or paste a URL
- Audio playback with volume control
- Tag-based organization
- Copy transcript to clipboard
- Per-job summaries with delete confirmation
Install these before anything else. Each link points to the official documentation, which is the authoritative source for installation steps — they change between releases and differ by platform.
| Tool | Purpose | Link |
|---|---|---|
| Rust (stable, ≥ 1.85) | Build everything | https://rustup.rs |
| Node.js + pnpm | Desktop app frontend | https://nodejs.org / https://pnpm.io |
| FFmpeg | Audio normalization | https://ffmpeg.org/download.html |
| yt-dlp | YouTube/URL download | https://github.com/yt-dlp/yt-dlp#installation |
| Python 3 + venv | Diarization sidecar | https://www.python.org |
| whisper.cpp | Speech-to-text engine | https://github.com/ggerganov/whisper.cpp |
| Ollama | Local LLM for summaries | https://ollama.com/download |
These sections describe the general approach, not step-by-step instructions. GPU drivers, ROCm, CUDA, and WSL2 compatibility change frequently. Always refer to the official documentation for your specific OS version, GPU model, and driver version.
The smoothest path. Install system dependencies via your package manager, build whisper.cpp with the GPU backend that matches your hardware (see GPU section below), and run directly.
The simplest route is the installer built from WSL — see Windows installer. It ships a Vulkan build of whisper.cpp, which uses AMD, NVIDIA and Intel GPUs through the regular graphics driver. To build whisper.cpp natively instead (CUDA, ROCm-for-Windows), check the whisper.cpp build documentation — it changes as the project evolves.
For Ollama on Windows, download the installer from https://ollama.com/download. AMD GPU support on Windows goes through ROCm; NVIDIA goes through CUDA. If Ollama falls back to CPU, it may need environment variables set before the process starts — refer to the Ollama FAQ and GPU documentation for the current guidance.
Warning: GPU passthrough in WSL2 has significant limitations that are architecture- and driver-dependent. What works today may not reflect the current state of the project.
NVIDIA: CUDA passthrough via dxgkrnl is well-supported. Refer to the CUDA on WSL2 guide for setup.
AMD: ROCm GPU compute on WSL2 is more complex. AMD GPUs appear through the dxgkrnl paravirtualization driver but not through the standard KFD interface that ROCm expects. Support depends heavily on your GPU architecture, driver version, and ROCm version. Check the AMD ROCm documentation and WSL2 compatibility notes before investing time here.
Alternative for AMD on WSL2: Run Ollama natively on Windows (with full DirectML/ROCm GPU support) and access it from WSL2 over the virtual network interface. The Windows host is reachable from WSL2 at the default gateway IP, which you can find with:
ip route | grep default | awk '{print $3}'Then set OLLAMA_BASE_URL=http://<that-ip>:11434 in your .env.
Warning: GPU architecture support in whisper.cpp and Ollama changes with every release. The information here reflects the state when this was written. Always check the upstream documentation for your GPU model before troubleshooting.
Both whisper.cpp and Ollama have mature CUDA support. Build whisper.cpp with -DGGML_CUDA=ON. Ollama detects CUDA automatically if the driver and CUDA toolkit are installed.
ROCm support varies significantly by GPU architecture. Newer architectures (RDNA 3, RDNA 4) may not be in the pre-built kernels of a given whisper.cpp or Ollama release, requiring an architecture override (HSA_OVERRIDE_GFX_VERSION) to use a compatible fallback. This has performance and correctness implications.
For Ollama on Windows with AMD, Vulkan is an alternative backend that does not depend on ROCm and supports a broader range of GPU architectures. Set OLLAMA_VULKAN=1 before starting Ollama and check the Ollama GPU documentation for current status.
Copy .env.example to .env and fill in the values. The file is gitignored.
# Path to ffmpeg (defaults to "ffmpeg" on PATH)
FFMPEG_PATH=ffmpeg
# whisper.cpp binary — build it for your GPU, see the section below
WHISPER_CLI=whisper.cpp-vulkan/build-linux-hip-clang/bin/whisper-cli
WHISPER_MODEL=models/whisper/ggml-large-v3-turbo.bin
# Output directory for all jobs
TRANSCRIPTION_OUTPUT_DIR=data/runs
# Whisper threads (tune to your CPU core count)
WHISPER_THREADS=8
# Hugging Face token (required for pyannote diarization)
HF_TOKEN=hf_...
# Optional — defaults to "yt-dlp" on PATH
# YTDLP_PATH=/path/to/yt-dlp
# Optional — defaults to http://localhost:11434
# OLLAMA_BASE_URL=http://localhost:11434The
.envfile is never read by the shell. It is parsed by the Rust pipeline at startup. Do not use shell variable syntax like$(...)inside it.
Fetch the source (clones the upstream whisper.cpp repo into whisper.cpp-vulkan/, which is gitignored):
bash scripts/bootstrap_whisper_cpp.shBuild for ROCm/HIP (AMD):
bash scripts/build_whisper_hip.shFor other backends (CUDA, CPU, Vulkan), refer to the whisper.cpp build documentation and build manually. Point WHISPER_CLI in .env to the resulting binary.
You will also need a model file. The recommended starting point is ggml-large-v3-turbo. Download from Hugging Face and place it under models/whisper/.
Install the Python dependencies into a virtualenv:
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-diarization.txtDiarization uses pyannote, which requires accepting model terms on Hugging Face and a Hugging Face access token. See the pyannote access instructions.
In the desktop app, paste the token under Settings → Models → Hugging Face token. It is stored in the OS credential store (Windows Credential Manager, the macOS Keychain, or the Secret Service keyring on Linux), is never written to disk by the app, and cannot be read back into the UI — only replaced or removed. HF_TOKEN in .env or the environment still works as a fallback, and is what the CLI uses. WSL usually runs no Secret Service, so there the app reports that no credential store is available and .env remains the way to set it.
Install Ollama from https://ollama.com/download and pull a model:
ollama pull qwen2.5:7bThe qwen2.5:7b model is a reasonable default (~4 GB). Larger models produce better summaries but require more VRAM. Any model available on ollama.com/library will work.
Set OLLAMA_BASE_URL in .env to wherever Ollama is listening.
On Linux, install the Tauri system dependencies first:
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-devThen:
cd apps/desktop
pnpm install
pnpm tauri devFor a production build:
pnpm tauri buildBuilds a normal Windows setup .exe from WSL, so Windows needs no Rust, Node or project checkout. The installer bundles the app with:
whisper-cli.execross-compiled with the Vulkan backend (GPU through the regular driver; the build reads headers andvulkan-1.libfrom the Windows Vulkan SDK under/mnt/c/VulkanSDK, override withWINDOWS_VULKAN_SDK)ffmpeg.exe(gyan.dev essentials build) andyt-dlp.exe, at versions pinned and checksum-verified inscripts/build_windows_installer.sh- the Whisper model at
models/whisper/ggml-large-v3-turbo.bin(override withWHISPER_MODEL_FILE)
Not bundled: Ollama — install it on Windows; the app talks to http://localhost:11434. Speaker diarization (Python + pyannote) — the toggle is disabled in the installed app.
One-time setup in WSL (plus cmake, ninja, glslc and pnpm, which the Linux build already uses). The MSVC C++ headers that cargo xwin downloads require Clang 19 or newer, and Ubuntu 24.04's default clang is 18, so install the versioned LLVM 20 packages (clang-cl lives in clang-tools-20):
sudo apt install -y nsis clang-20 clang-tools-20 lld-20 llvm-20
cargo install --locked cargo-xwinBuild:
bash scripts/build_windows_installer.shThe setup file lands in target/x86_64-pc-windows-msvc/release/bundle/nsis/. It installs per user (no admin rights) into %LOCALAPPDATA%\Local Transcription; transcripts are stored in %APPDATA%\com.miguel.transcription-desktop\runs. That data folder and the saved Hugging Face token are keyed on the app identifier, so they survive a reinstall — keep identifier in tauri.conf.json unchanged. When uninstalling, leave "Delete the application data" unchecked unless you want the transcripts gone. The installer is unsigned, so Windows SmartScreen warns on first run (More info → Run anyway).
Notes:
cargo xwindownloads the MSVC CRT and Windows SDK, which come under Microsoft's license terms.- An NSIS installer cannot exceed 2 GiB, so one large model is the most it can carry. Compression is off: the model barely compresses and LZMA over ~1.8 GB takes a long time.
- The installed app reads a
.envfrom its install folder when one is present (for exampleWHISPER_THREADS=16). - The app icon is generated from
apps/desktop/app-icon.svg: edit it, runpnpm tauri icon app-icon.svginapps/desktop, then delete theandroid/,ios/and64x64.pngoutputs that desktop builds do not use. - The bundled yt-dlp ages as sites change; bump the pinned version and rebuild when URL downloads start failing.
- The essentials ffmpeg build is GPL-licensed. That is fine for personal use; publishing the installer brings GPL obligations for ffmpeg.
Verify environment. This checks required transcription tools, optional URL/diarization tools, detected hardware, and local Whisper models:
cargo run -p transcription-cli -- verifyTranscribe a file:
cargo run -p transcription-cli -- transcribe path/to/audio.mp3Transcribe with diarization:
cargo run -p transcription-cli -- transcribe path/to/audio.mp3 --diarize --num-speakers 2Transcribe a stereo call where each channel is one speaker (skips diarization):
cargo run -p transcription-cli -- transcribe path/to/call.mp4 --two-channelRun diarization on an existing normalized WAV:
cargo run -p transcription-cli -- diarize data/runs/<job-id>/work/audio.wav --num-speakers 2Output is written to data/runs/<job-id>/:
job.json
work/audio.wav
output/transcript.txt
output/transcript.srt
output/transcript.json
output/speakers.txt
output/speaker-transcript.txt
This project is local-first and supports local/private model endpoints only. See SECURITY.md before changing endpoint validation, subprocess execution, file serving, export, or deletion behavior.
cargo fmt --all -- --check
cargo clippy --workspace -- -D warnings
cargo test --workspace- This project is a personal tool, not a polished product. Breaking changes can happen at any time.
- GPU acceleration setup is environment-specific. What works on one machine may not work on another.
.envis local-only and gitignored. Never commit it — it contains API tokens and local paths.- Do not commit audio files, transcripts, model binaries, or Hugging Face tokens.
- pyannote requires accepting license terms on Hugging Face before use.
MIT — see LICENSE.
