Skip to content

Repository files navigation

Local Transcription

License: MIT

App screenshot

A local-first audio transcription and analysis pipeline. All processing happens on your machine — no cloud APIs, no data leaving your system.

What this project is

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.

Workspace layout

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

Features

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

Prerequisites

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

Platform notes

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.

Linux (native)

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.

Windows (native)

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.

WSL2 (Windows Subsystem for Linux)

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.


GPU notes

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.

NVIDIA

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.

AMD

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.


Configuration

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:11434

The .env file is never read by the shell. It is parsed by the Rust pipeline at startup. Do not use shell variable syntax like $(...) inside it.


Building whisper.cpp

Fetch the source (clones the upstream whisper.cpp repo into whisper.cpp-vulkan/, which is gitignored):

bash scripts/bootstrap_whisper_cpp.sh

Build for ROCm/HIP (AMD):

bash scripts/build_whisper_hip.sh

For 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/.


Diarization setup

Install the Python dependencies into a virtualenv:

python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-diarization.txt

Diarization uses pyannote, which requires accepting model terms on Hugging Face and providing an HF_TOKEN in .env. See the pyannote access instructions.


Ollama setup

Install Ollama from https://ollama.com/download and pull a model:

ollama pull qwen2.5:7b

The 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.


Running the desktop app

On Linux, install the Tauri system dependencies first:

sudo apt-get install -y \
  libwebkit2gtk-4.1-dev \
  libgtk-3-dev \
  libayatana-appindicator3-dev \
  librsvg2-dev

Then:

cd apps/desktop
pnpm install
pnpm tauri dev

For a production build:

pnpm tauri build

Running the CLI

Verify environment (checks ffmpeg, whisper-cli, model, and HF_TOKEN; rocminfo shows "missing" on non-AMD machines — that is expected):

cargo run -p transcription-cli -- verify

Transcribe a file:

cargo run -p transcription-cli -- transcribe path/to/audio.mp3

Transcribe with diarization:

cargo run -p transcription-cli -- transcribe path/to/audio.mp3 --diarize --num-speakers 2

Transcribe a stereo call where each channel is one speaker (skips diarization):

cargo run -p transcription-cli -- transcribe path/to/call.mp4 --two-channel

Run diarization on an existing normalized WAV:

cargo run -p transcription-cli -- diarize data/runs/<job-id>/work/audio.wav --num-speakers 2

Output 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

Development

cargo fmt --all -- --check
cargo clippy --workspace -- -D warnings
cargo test --workspace

Disclaimers

  • 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.
  • .env is 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.

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages