Skip to main content

Local meeting recorder with transcription and speaker diarization for Obsidian

Project description

tapeback

Local meeting recorder for Linux. Records system audio + microphone via PipeWire/PulseAudio, transcribes with Whisper, identifies speakers, saves Markdown to your Obsidian vault. Everything runs on your machine, no cloud services or API calls needed for transcription.

Works with any video call platform: Google Meet, Zoom, Teams, Telegram, Discord, Slack huddles.

Features

  • Platform-agnostic: captures OS-level audio, works with any app
  • Local transcription: faster-whisper on CPU or CUDA GPU
  • Speaker diarization: pyannote identifies who said what
  • Stereo channel separation: your mic (left) vs. others (right) for accurate "You" attribution
  • Obsidian-native output: Markdown with YAML frontmatter, wikilinks to audio files
  • LLM summarization: optional, via Anthropic, OpenAI, Groq, Gemini, DeepSeek, OpenRouter, Qwen (with automatic provider fallback)
  • CLI-first: tapeback start, Ctrl+C to stop, done

Requirements

  • Linux (PipeWire or PulseAudio)
  • Python 3.13+
  • ffmpeg
  • parecord (usually comes with pulseaudio-utils or pipewire-pulse)
  • NVIDIA GPU (optional, for faster transcription and diarization)

Installation

1. System dependencies

# Arch / Manjaro
sudo pacman -S python uv ffmpeg pipewire-pulse

# Ubuntu / Debian
sudo apt install python3 pipx ffmpeg pulseaudio-utils
pipx ensurepath  # adds ~/.local/bin to PATH

# Fedora
sudo dnf install python3 pipx ffmpeg pipewire-pulseaudio
pipx ensurepath

2. Install tapeback

The base package records audio and transcribes locally. Optional extras add speaker diarization and LLM summaries:

Extra What it adds Size
(none) Recording + transcription ~150 MB
[llm] LLM summarization (Anthropic, OpenAI, Gemini, etc.) +50 MB
[diarize] Speaker diarization (pyannote + PyTorch) +2 GB
[llm,diarize] Everything +2 GB

With uv (recommended)

uv tool install tapeback                  # basic
uv tool install "tapeback[llm]"           # + summaries
uv tool install "tapeback[diarize]"       # + speaker diarization
uv tool install "tapeback[llm,diarize]"   # everything

With pipx

pipx install tapeback                     # basic
pipx install "tapeback[llm]"              # + summaries
pipx install "tapeback[diarize]"          # + speaker diarization
pipx install "tapeback[llm,diarize]"      # everything

Arch Linux (AUR)

yay -S tapeback                  # basic
yay -S tapeback-llm              # + summaries
yay -S tapeback-diarize          # + speaker diarization (~2 GB PyTorch)

Nix

nix run github:yastcher/tapeback              # basic
nix run github:yastcher/tapeback#llm          # + summaries
nix run github:yastcher/tapeback#diarize      # + speaker diarization
nix run github:yastcher/tapeback#full         # everything

From source (development)

git clone https://github.com/yastcher/tapeback
cd tapeback
uv sync --group dev    # all dependencies + dev tools

3. Uninstall

# Remove tapeback
uv tool uninstall tapeback    # if installed with uv
pipx uninstall tapeback       # if installed with pipx

# Remove cached ML models (~2-5 GB)
# ⚠ Skip if you have other HuggingFace projects
rm -rf ~/.cache/huggingface/

# Arch Linux
yay -R tapeback tapeback-diarize tapeback-llm

Quick start

1. Configure

# Required: set your Obsidian vault path
export TAPEBACK_VAULT_PATH=~/Documents/obsidian/vault

# Or create a .env file in the project root:
echo 'TAPEBACK_VAULT_PATH=~/Documents/obsidian/vault' > .env

2. Record a meeting

# Start recording (blocks, Ctrl+C to stop and transcribe)
tapeback start

# Optionally give the session a name
tapeback start "weekly-standup"

3. Check your vault

The recording is saved as a Markdown note with audio attachment:

vault/
  meetings/2026-03-23_14-30-00.md
  attachments/audio/2026-03-23_14-30-00.wav

Process an existing recording

# Transcribe any audio file (mp3, m4a, ogg, wav)
tapeback process meeting.mp3

# With options
tapeback process call.wav --name "client-call" --no-diarize

Add summary to existing transcript

tapeback summarize vault/meetings/2026-03-23.md
tapeback summarize transcript.md --provider gemini

Configuration

All settings via environment variables (prefix TAPEBACK_) or .env file. Copy .env.example to .env and adjust:

cp .env.example .env

Core

Variable Default Description
TAPEBACK_VAULT_PATH (required) Path to Obsidian vault
TAPEBACK_MEETINGS_DIR meetings Subdirectory for meeting notes
TAPEBACK_ATTACHMENTS_DIR attachments/audio Subdirectory for audio files

Transcription

Variable Default Description
TAPEBACK_WHISPER_MODEL large-v3-turbo Whisper model (tiny, base, small, medium, large-v3-turbo)
TAPEBACK_LANGUAGE en Transcription language code
TAPEBACK_DEVICE cuda cuda or cpu
TAPEBACK_COMPUTE_TYPE float16 float16, int8, or float32
TAPEBACK_BEAM_SIZE 5 Whisper beam search width
TAPEBACK_PAUSE_THRESHOLD 1.0 Seconds; split segments on silence gaps >= this

Audio

Variable Default Description
TAPEBACK_MONITOR_SOURCE auto PulseAudio monitor source name
TAPEBACK_MIC_SOURCE auto PulseAudio mic source name
TAPEBACK_SAMPLE_RATE 48000 Recording sample rate

Speaker diarization

Variable Default Description
TAPEBACK_DIARIZE true Enable speaker diarization (requires tapeback[diarize])
TAPEBACK_HF_TOKEN (empty) HuggingFace token for pyannote models
TAPEBACK_MAX_SPEAKERS (auto) Maximum number of speakers

Speaker diarization requires the diarize extra (uv tool install "tapeback[diarize]") and a HuggingFace token with access to pyannote models:

  1. Create account at huggingface.co
  2. Accept license at pyannote/speaker-diarization-3.1
  3. Accept license at pyannote/segmentation-3.0
  4. Accept license at pyannote/speaker-diarization-community-1
  5. Create token at huggingface.co/settings/tokens
  6. Set TAPEBACK_HF_TOKEN=hf_your_token_here

Without a token, tapeback still works but skips diarization.

LLM summarization

Requires the llm extra: uv tool install "tapeback[llm]"

Variable Default Description
TAPEBACK_SUMMARIZE true Enable LLM summarization
TAPEBACK_LLM_PROVIDER anthropic Primary LLM provider
TAPEBACK_LLM_API_KEY (empty) API key (or use provider-specific env var)
TAPEBACK_LLM_MODEL (provider default) Override model name

Supported providers and their env vars:

Provider Env var Default model
anthropic ANTHROPIC_API_KEY claude-sonnet-4-20250514
openai OPENAI_API_KEY gpt-4o
groq GROQ_API_KEY llama-3.3-70b-versatile
gemini GEMINI_API_KEY gemini-2.5-flash
openrouter OPENROUTER_API_KEY google/gemini-2.5-flash:free
deepseek DEEPSEEK_API_KEY deepseek-chat
qwen DASHSCOPE_API_KEY qwen-turbo

If the primary provider fails, tapeback automatically tries the next available provider (any provider with an API key set).

CLI reference

tapeback --help                    Show help and quick start guide
tapeback start [NAME]              Start recording (Ctrl+C to stop)
tapeback stop                      Stop recording from another terminal
tapeback process <FILE> [--name N] Transcribe an existing audio file
tapeback summarize <FILE>          Add LLM summary to transcript
tapeback status                    Show recording status and settings

Common options

tapeback start --no-diarize        # Skip speaker identification
tapeback start --no-summarize      # Skip LLM summary
tapeback process file.mp3 --name "weekly-standup"
tapeback summarize file.md --provider gemini --model gemini-2.5-pro

Output format

---
date: 2026-03-23
time: "14:30"
duration: "01:23:45"
language: en
tags:
  - meeting
  - transcript
---

## Summary

Brief overview of the meeting.

### Action Items

- [ ] **You:** Send the report by Friday
- [ ] **Speaker 1:** Review the PR

### Key Decisions

- Use PostgreSQL instead of MongoDB

---

# Meeting 2026-03-23 14:30

![[attachments/audio/2026-03-23_14-30-00.wav]]

[00:00:01] **You:** Hello, let's start with the backend changes.

[00:01:23] **Speaker 1:** Sure, I have the slides ready.

[00:02:45] **Speaker 2:** Can we start with the backend changes?

Architecture

src/tapeback/
  cli.py          Click CLI (start, stop, process, summarize, status)
  recorder.py     PulseAudio recording via parecord
  audio.py        ffmpeg audio processing (split channels, normalize, convert)
  transcriber.py  faster-whisper transcription
  diarizer.py     pyannote speaker diarization + spectral speaker merging
  formatter.py    Markdown generation (pure formatting, no I/O)
  vault.py        Obsidian vault file I/O
  summarizer.py   LLM summarization with multi-provider fallback
  models.py       Domain objects (Segment, Word, DiarizationSegment, Summary)
  settings.py     pydantic-settings configuration

Development

git clone https://github.com/yastcher/tapeback
cd tapeback
uv sync --group dev

uv run ruff check       # lint
uv run ruff format      # format
uv run ty check         # type check
uv run pytest           # test (coverage >= 85%)

Releasing

scripts/release.sh 0.9.0          # bump version in pyproject.toml + PKGBUILDs
# commit, tag, push → CI publishes to PyPI
scripts/aur-publish.sh 0.9.0      # update all 3 AUR packages

Roadmap

  • Custom diarization model: train a speaker embedding model on meeting audio to replace the generic pyannote pipeline
  • Windows client: WASAPI loopback capture
  • Real-time transcription: live streaming with partial results
  • Web dashboard: browser UI for reviewing and searching meeting history
  • Speaker profiles: learn and remember recurring speakers across meetings
  • Multi-language meetings: detect and handle language switches mid-meeting

License

Apache-2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tapeback-0.8.2.tar.gz (62.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tapeback-0.8.2-py3-none-any.whl (35.3 kB view details)

Uploaded Python 3

File details

Details for the file tapeback-0.8.2.tar.gz.

File metadata

  • Download URL: tapeback-0.8.2.tar.gz
  • Upload date:
  • Size: 62.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for tapeback-0.8.2.tar.gz
Algorithm Hash digest
SHA256 536223958b2debf3b3298a11b57a4111759d65d84eba6751ba6009a972261d98
MD5 f7abb6d36bf9c783e3bb4d3005bafd24
BLAKE2b-256 b20a04a05deac454d79d626345a71e7ffd4b49ffd66bb2e77ddd4518132a5e00

See more details on using hashes here.

Provenance

The following attestation bundles were made for tapeback-0.8.2.tar.gz:

Publisher: publish.yml on yastcher/tapeback

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tapeback-0.8.2-py3-none-any.whl.

File metadata

  • Download URL: tapeback-0.8.2-py3-none-any.whl
  • Upload date:
  • Size: 35.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for tapeback-0.8.2-py3-none-any.whl
Algorithm Hash digest
SHA256 377bc313b44d70c4caabf3f3b92a5ec3f7a6b6aa2292887ac7a62498db63946d
MD5 40ab8b8da3819c5ede42acc50d5b9918
BLAKE2b-256 dfcf2481d380f98ec19054469f973468189e24d640000d9fe00341bf841a1c9c

See more details on using hashes here.

Provenance

The following attestation bundles were made for tapeback-0.8.2-py3-none-any.whl:

Publisher: publish.yml on yastcher/tapeback

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page