- final_transcribe gains optional speaker labeling and library upload: diarize_url runs a second tinydiarize pass and merges the turn times onto the quality transcript as 'Sprecher 1/2:' labels (diarize_merge, port of the Android Diarization object; failures keep the transcript unlabeled); library_url uploads the WAV + txt/srt/json bundle with the agenda — the server then generates summary + agenda coverage - WhisperServerEngine supports diarize mode (tinydiarize form field + speaker_turn_next parsing); multipart builder handles multiple files - CLI: --agenda-file, --diarize-url, --library-url (env vars MEETREC_DIARIZE_URL / MEETREC_LIBRARY_URL) - GUI: Library URL + Diarize URL fields and an agenda editor; upload progress lands in the status bar - validated end-to-end against the live servers: recording -> large-v3 transcription -> txt/srt/json -> library upload (all four files, device=desktop) -> server summary/agenda pipeline ran (honest error for a noise-only test recording)
MeetRec
Record an in-person meeting and transcribe it with Whisper.
Meetrec captures audio from any input (microphone, USB conference mic, USB audio interface, or a Pulse/PipeWire sink monitor) and produces transcripts in txt, srt, and json. It runs fully locally — no audio ever leaves your machine.
Two desktop interfaces plus an Android app:
meetrec.py— CLI: record, optionally show a live rolling transcript, and onCtrl+Crun a final higher-quality pass.meetrec_gui.py— Qt (PySide6) GUI: device/model/language selection, level meter, live transcript, and one-click Stop & transcribe.android/— native Kotlin app with the same on-device functionality, built on whisper.cpp via JNI (seeandroid/README.md).
Output files
With output stem -o meeting:
| File | Contents |
|---|---|
meeting.wav |
raw recording (mono WAV at the input's native rate) |
meeting.live.srt |
live rolling transcript (only with --live > 0) |
meeting.txt |
final transcript |
meeting.srt |
final transcript with timestamps |
meeting.json |
final transcript, structured (language, segments) |
Recording always uses the input device's native sample rate; audio is resampled to Whisper's 16 kHz automatically (both for the live window and the final pass).
Requirements
- Linux with an audio backend: PipeWire (or PulseAudio/ALSA). On Arch:
sudo pacman -S pipewire pipewire-pulse - Python 3.10+
- Python packages (installed for you by the install script):
numpy,sounddevice,faster-whisper,pyside6(GUI only) - A GPU (CUDA) is optional — transcription falls back to CPU.
Installation
Quick install
./install.sh
This:
- copies the app to
~/.local/share/meetrec, - creates a venv and installs all dependencies,
- installs the
meetrec(GUI) andmeetrec-clilaunchers into~/.local/bin, - installs the XDG desktop entry and icon (app menu shows MeetRec with its own red mic icon),
- pre-downloads the
smallWhisper model (first run is otherwise slow).
Options:
./install.sh --model base # pre-download a different model (tiny/base/small/medium/large-v3)
./install.sh --whisper-cpp # also build whisper.cpp with its Vulkan GPU backend
./install.sh --no-model # skip the model pre-download
./install.sh --uninstall # remove everything the installer created
PREFIX=/opt/meetrec ./install.sh # install into a different prefix
On an AMD GPU (e.g. Ryzen AI 300 laptops with a Radeon iGPU), use --whisper-cpp and select the whisper-cpp engine — see Engines below. The build needs git, cmake, g++, and Vulkan headers (sudo pacman -S vulkan-headers on Arch).
Manual install (venv)
sudo pacman -S python pipewire pipewire-pulse
python3 -m venv .venv && source .venv/bin/activate
pip install numpy sounddevice faster-whisper pyside6
Usage
GUI
meetrec # after ./install.sh
# or from a checkout:
python meetrec_gui.py
Pick a microphone (or type a name substring), model, language, and compute device/precision (switching model, device, or precision between recordings reloads the model automatically), press Record, watch the live transcript, then press Stop & transcribe.
CLI
meetrec-cli --list-sources # find your input devices
meetrec-cli -s "Conference Mic" --model small --live 8 -o meeting
meetrec-cli -s monitor --model base --language en # record system audio
meetrec-cli --engine whisper-cpp -o meeting # transcribe on the GPU (Vulkan)
MEETREC_SERVER_URL=http://100.103.83.12:8085 \
meetrec-cli --engine whisper-server -o meeting # transcribe on a remote server
python meetrec.py --help # all options
Key options:
| Option | Meaning |
|---|---|
--engine |
transcription backend: faster-whisper (default), whisper-cpp, or whisper-server |
--server-url |
whisper-server base URL, e.g. http://100.103.83.12:8085 (or MEETREC_SERVER_URL) |
-s, --source |
default or a substring of a device name (--list-sources) |
-m, --model |
tiny / base / small / medium / large-v3 (default small) |
-o, --output |
output file stem (default meeting) |
--live SEC |
live-transcription interval in seconds; 0 disables (default 8) |
--language |
force a language code, e.g. en, de (default: autodetect) |
--device |
auto / cpu / cuda (default auto); faster-whisper only |
--compute-type |
int8 / int8_float16 / float16 / float32 (default int8); faster-whisper only |
--agenda-file |
text file with agenda items, one per line — uploaded for the coverage check |
--diarize-url |
tinydiarize server URL → transcript gets Sprecher 1/2: labels (or MEETREC_DIARIZE_URL) |
--library-url |
meetrec-server URL → uploads the recording and triggers summary + agenda check (or MEETREC_LIBRARY_URL) |
Ctrl+C stops recording and runs the final transcription.
Tips
- Record system audio: sink monitors appear as
<sink name>.monitor; use-s monitor(or a matching substring). - Model size vs. speed/accuracy:
tiny/baseare fast and rough,smallis a good default,medium/large-v3are most accurate but much slower on CPU. - Models are cached in
~/.cache/huggingface(faster-whisper) and~/.cache/meetrec/whisper-cpp(whisper.cpp) and shared between the CLI and the GUI.
Engines
Meetrec supports two interchangeable transcription backends — --engine on the CLI, the Engine dropdown in the GUI:
| Engine | Backend | GPU support |
|---|---|---|
faster-whisper (default) |
CTranslate2 | NVIDIA CUDA (--device cuda); otherwise CPU |
whisper-cpp |
whisper.cpp | AMD / Intel / NVIDIA via Vulkan; falls back to CPU |
whisper-server |
remote whisper.cpp HTTP server | whatever the server has — see server/whisper-server/ (Docker Compose, Vulkan GPU, Tailscale) |
On AMD hardware (e.g. the Radeon iGPU in Ryzen AI 300 laptops) the faster-whisper path is CPU-only — use the whisper-cpp engine there, which runs on the GPU when whisper.cpp is built with -DWHISPER_VULKAN=ON (./install.sh --whisper-cpp does this for you). The whisper-server engine moves the work to a server entirely (ideal for slow clients such as phones) and can run large-v3 on a GPU.
Notes on whisper-cpp:
- The
whisper-clibinary is looked up inWHISPER_CPP_BIN, thenPATH, then~/.local/share/meetrec/whisper-cpp/bin/whisper-cli(whereinstall.sh --whisper-cppputs it). - GGML models (
ggml-*.bin) download automatically to~/.cache/meetrec/whisper-cppon first use. - VAD works like on faster-whisper: whisper.cpp's Silero VAD model (~1 MB) downloads automatically and is used for both live and final passes.
- Live mode spawns
whisper-clifor every rolling-window pass, so the GGML model is reloaded on each live tick — slightly heavier than faster-whisper, which loads once per recording.
Notes on whisper-server:
- The model lives on the server —
--model,--device,--compute-typedo not apply; beam size is a server-start setting in whisper.cpp v1.9.3 (no per-request override). - Run your own with the Docker Compose stack in
server/whisper-server/— Vulkan GPU (AMD/NVIDIA/Intel), model auto-download, Tailscale-only binding. - The server has no authentication: keep it on Tailscale or behind a VPN/firewall.
verbose_jsonreports language names ("german") rather than ISO codes.
Meeting protocol (library, summary, agenda, speakers)
The desktop app has feature parity with the Android app's M3 set:
MEETREC_SERVER_URL=http://100.103.83.12:8085 \
MEETREC_LIBRARY_URL=http://100.103.83.12:8090 \
MEETREC_DIARIZE_URL=http://100.103.83.12:8086 \
meetrec-cli --engine whisper-server --agenda-file agenda.txt -o meeting
--library-urluploads the WAV + transcripts after the final pass; the server then generates the German summary (Ollama, gemma4:12b) and checks which agenda items were discussed (browse everything in the Android app's Library tab).--agenda-filesupplies the agenda items (one per line).--diarize-urladds a second tinydiarize pass whose speaker-turn times are merged onto the transcript asSprecher 1:/Sprecher 2:labels (2 speakers, best-effort on non-English audio; failures keep the transcript unlabeled).- The GUI has the same options as fields (Library URL, Diarize URL, agenda editor).
--device/--compute-typedo not apply (GPU vs. CPU is decided by the whisper.cpp build).
Project layout
meetrec.py CLI: recording + live & final transcription
meetrec_gui.py PySide6 GUI (reuses meetrec.py's logic)
requirements.txt Python dependencies
install.sh install / uninstall into a local prefix
bin/meetrec GUI launcher (installed into ~/.local/bin)
bin/meetrec-cli CLI launcher (installed into ~/.local/bin)
share/applications/meetrec.desktop XDG desktop entry
share/icons/hicolor/ app icon (SVG + PNG fallbacks)
android/ native Android app (Kotlin + whisper.cpp JNI)
Privacy
Everything runs locally. The only network access is the one-time Whisper model download from Hugging Face.