# MeetRec Record an in-person meeting and transcribe it with [Whisper](https://github.com/SYSTRAN/faster-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 on `Ctrl+C` run 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 (see `android/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 ```sh ./install.sh ``` This: 1. copies the app to `~/.local/share/meetrec`, 2. creates a venv and installs all dependencies, 3. installs the `meetrec` (GUI) and `meetrec-cli` launchers into `~/.local/bin`, 4. installs the XDG desktop entry and icon (app menu shows **MeetRec** with its own red mic icon), 5. pre-downloads the `small` Whisper model (first run is otherwise slow). Options: ```sh ./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](#engines) below. The build needs `git`, `cmake`, `g++`, and Vulkan headers (`sudo pacman -S vulkan-headers` on Arch). ### Manual install (venv) ```sh sudo pacman -S python pipewire pipewire-pulse python3 -m venv .venv && source .venv/bin/activate pip install numpy sounddevice faster-whisper pyside6 ``` ## Usage ### GUI ```sh 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 ```sh 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 `.monitor`; use `-s monitor` (or a matching substring). - **Model size vs. speed/accuracy**: `tiny`/`base` are fast and rough, `small` is a good default, `medium`/`large-v3` are 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](https://github.com/ggml-org/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/](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-cli` binary is looked up in `WHISPER_CPP_BIN`, then `PATH`, then `~/.local/share/meetrec/whisper-cpp/bin/whisper-cli` (where `install.sh --whisper-cpp` puts it). - GGML models (`ggml-*.bin`) download automatically to `~/.cache/meetrec/whisper-cpp` on 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-cli` for 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-type` do 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_json` reports 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: ```sh 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-url` uploads 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-file` supplies the agenda items (one per line). - `--diarize-url` adds a second tinydiarize pass whose speaker-turn times are merged onto the transcript as `Sprecher 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). ## Library tab (GUI) The desktop GUI has **Record** and **Library** tabs like the mobile app. The Library tab browses the server's recordings with summary, agenda coverage and the full transcript, and **auto-refreshes every 10 s** — record on the phone, and the meeting appears on the desktop while the tab is open: ```sh MEETREC_LIBRARY_URL=http://100.103.83.12:8090 python meetrec_gui.py ``` (The URL can also be typed into the tab's Library URL field.) - `--device` / `--compute-type` do 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 (PNGs; source: icon/make_icon_v3.py) 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.