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.
Whisper.cpp GPU acceleration on native Windows requires either CUDA (NVIDIA) or a ROCm-for-Windows build (AMD). Check the whisper.cpp build documentation for current Windows GPU build instructions — they change 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 providing an HF_TOKEN in .env. See the pyannote access instructions.
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 buildVerify environment (checks ffmpeg, whisper-cli, model, and HF_TOKEN; rocminfo shows "missing" on non-AMD machines — that is expected):
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
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.
