Loading repository data…
Loading repository data…
UbhiTS / repository
Tauri + React desktop app for recording meetings, transcribing with speaker diarization, and writing one markdown note per meeting into an Obsidian vault. Local-first with a Python sidecar.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Always-on, fully-local meeting transcription for Windows and macOS. Hands-free start/stop on sustained speech, live AI coaching while you talk, one markdown note per meeting in Obsidian. Audio, models, and summaries never leave your machine.
Tauri 2 desktop app + Python sidecar. ASR via faster-whisper. Diarization via pyannote.audio 3.1. LLM via any OpenAI-compatible endpoint — LM Studio by default, or OpenAI / Gemini / OpenRouter / Anthropic-compat for frontier models. The sidecar probes hardware at startup and picks Whisper defaults that fit; CPU-only machines work too.
Releases: https://github.com/UbhiTS/aurascribe/releases
| Installer | Pick if | Installer | On disk |
|---|---|---|---|
| AuraScribe-CUDA-setup.exe | NVIDIA GPU. Streams a ~6 GB CUDA bundle on first launch (~10–20 min on broadband). | ~140 MB | ~6 GB |
| AuraScribe-CPU-setup.exe | No GPU, or smaller install. ~5–10× slower transcription, still usable. | ~260 MB | ~700–900 MB |
Per-user install at %LOCALAPPDATA%\Programs\AuraScribe (no admin). Data lives at %APPDATA%\AuraScribe and survives uninstall.
The CUDA bundle is split + streamed (not shipped in the installer) because the full CUDA payload is ~6 GB — NSIS can't mmap that on the CI runner, and GitHub release assets cap at 2 GB. CI bin-packs heavy files into <version>.partN.zip files; the sidecar reads <version>.manifest.txt on first launch and reassembles the original layout.
cargo install tauri-cli --version "^2.0"
npm install
py -3.13 -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".\sidecar[all]"
# NVIDIA GPU? Swap in the CUDA torch wheel (pyannote needs it; ctranslate2 has its own CUDA path):
pip install --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cu128 torch torchaudio
npm run tauri:dev
First launch shows a welcome dialog with your detected hardware and the chosen Whisper defaults. Open Settings to configure the LLM endpoint, HuggingFace token, Obsidian vault, or override anything.
int8; no GPU → CPU.pyannote/speaker-diarization-3.1, pyannote/segmentation-3.0, and pyannote/wespeaker-voxceleb-resnet34-LM.http://127.0.0.1:1234/v1 is the default. Long-context models (100k+) make Daily Briefs richer.Adaptive hardware — sidecar probes ctranslate2 + torch.cuda at boot; picks large-v3-turbo + cuda + float16 on ≥8 GB VRAM, scales down to small + cpu + int8 if no GPU. Header chips show where each pipeline runs (Whisper, Diarize). Override any default in Settings.
Hands-free auto-capture — opens a lightweight VAD stream when idle; auto-starts a meeting on sustained speech (3s default gate), auto-stops after sustained silence. Once silence has lasted past a configurable gate (default 5s), the Stop button morphs into a live Stop in MM:SS countdown so you know exactly how long until auto-stop fires — click to stop now, or let it run out. Manual recordings ignore auto-stop. The toggle is usable mid-recording (off = "don't auto-start next time"; the active recording continues). Meetings with zero captured utterances are discarded on stop instead of polluting the library with empty rows.
Three audio sources — Microphone, System Audio (WASAPI loopback / BlackHole captures Zoom/Teams/Meet participants), or Mix with Speex-AEC cancelling the loopback echo out of the mic so speakers-in-room don't double up. Last-used source persists by device name. Pre-recording VU + waveform animate the selected source so you can verify before hitting Start. Mic-permission failures surface a one-click "Open mic settings" modal.
Live transcription — VAD-gated chunks through faster-whisper. A 1.5s speculative loop transcribes the audio tail so partial lines appear while you speak. UI re-adopts in-flight recordings across HMR / dev restarts. Live-tail scroll pinning: scrolled up reading? viewport stays put.
Speakers / Voices — pyannote 3.1 emits a 256-dim embedding per utterance. Tag-as-you-go (no upfront enrollment); the embedding folds into the Voice's pool, future chunks match via cosine distance. Unknowns are clustered live into Speaker 1/2/… rather than dumped into one bucket. Per-utterance re-assignment is fully lossless. Recompute re-runs diarization over a saved meeting against the current Voices DB. The Voices page lists every speaker with samples, snippets, merge / delete / rename / recolour, plus inline-editable email / org / role (surfaced in the People-note frontmatter, email also drives filename disambiguation when two voices share a display name).
Live AI coaching — debounced LLM call (~20s after last utterance, hard-cap 60s) extracts highlights + action items (yours and others'). A 2–5 bullet support-intelligence card suggests what to say next: tools to mention, counterarguments to pre-empt, clarifying questions. Live title refinement: same call returns an entity + topic so the meeting title sharpens as it progresses (freeze with the lock icon to stop overrides). A progress bar shows when the next refresh fires.
Obsidian vault — flat, generic layout. AuraScribe owns three folders; taxonomy beyond that is yours (add #customer/acme, folder conventions, MOCs — whatever fits your PKM):
<vault>/
Meetings/YYYY/YYYY-MM-DD/HH-MM - <title>.md
People/<Display Name>.md # voice_id in frontmatter is the real identity key
Daily/YYYY-MM/YYYY-MM-DD.md # generated daily briefs, grouped by month
People notes are keyed by voice_id in frontmatter, not filename — rename a note in Obsidian and AuraScribe still finds it on the next write. Two voices with the same display name get a disambiguation suffix on creation (John Smith (acme).md — from email domain → org → short voice_id hash). Attendee wikilinks in meeting notes use alias syntax when disambiguated: [[John Smith (acme)|John Smith]].
Daily Brief — end-of-day rollup of every meeting on a date: tl;dr, highlights, decisions, open threads, action items, per-person takeaways, themes, tomorrow's focus. Marked stale and rebuilt in the background when a meeting finishes (toggleable).
Meeting Library — day-scoped browser: prev/next + native date picker match Daily Brief. Each card carries inline Summarize / Recompute / Delete icons; select multiple (or Select-all) and the bulk bar sweeps newest→oldest with an amber ring tracking the current card. Summarize is strictly sequential to avoid parallel LLM calls; Recompute fans out (DB-only). Live Feed keeps the last stopped meeting on screen until the next recording starts, so you never lose context mid-thought.
Meeting editing — rename (Obsidian file moves to match), trim before/after a timestamp, split at a timestamp (both halves get their own files), bulk-delete by id list or "last N days", click-to-play any utterance into the Opus recording at that exact offset, summarize + suggest title in one LLM pass.
Editable prompts — live_intelligence.md, daily_brief.md, meeting_analysis.md live under APP_DATA/prompts/ (seeded from bundled defaults). One-click open from Settings; edits picked up on the next call.
Diagnostics — React error boundary catches blank-screen renders; sidecar sys.excepthook writes crash-YYYYMMDD-HHMMSS.log; Rust panic hook writes crash-<unix>-rust.log; rotating file log (5 × 5 MB). Heartbeat polls /api/status every 30s — header flips to Sidecar unreachable if the process dies. On launch the Rust shell sweeps the process table and kills any orphan sidecars from a prior crash so the fresh child always owns the canonical port.
Everything sits under one data directory (default %APPDATA%\AuraScribe). The folder holds the SQLite DB, per-meeting .opus files, Whisper model cache, logs, editable prompts, and config.json. Copy it to migrate.
| Key | Default | Purpose |
|---|---|---|
hf_token | — | HuggingFace token for pyannote |
llm_base_url | http://127.0.0.1:1234/v1 | OpenAI-compat root |
llm_api_key | lm-studio | Provider key (any non-empty for LM Studio) |
llm_model | local-model | Model id (gpt-4o, gemini-2.0-flash, etc.) |
llm_context_tokens | 4096 | Total context budget |
whisper_model / whisper_device / whisper_compute_type | auto | Override the hardware-aware defaults |
whisper_language | en | ISO code; empty for auto-detect |
my_speaker_label | Me | How your voice is labelled |
obsidian_vault | — | Vault root; empty disables Obsidian writes |
rt_highlights_debounce_sec / _max_interval_sec / _window_sec | 20 / 60 / 180 | Live-intel cadence + transcript window |
auto_capture_enabled | true | Master switch for hands-free start/stop |
auto_capture_start_speech_sec | 3.0 | Sustained speech before auto-start |
auto_capture_stop_silence_sec | 30 | Sustained silence before auto-stop |
auto_capture_countdown_after_silence_sec | 5 | Silence before the Stop button shows the countdown |
auto_capture_vad_threshold | 0.5 | Listening sensitivity (raise in noisy rooms) |
Advanced (Advanced Settings block — defaults match the old hard-coded values):
| Key | Default | Purpose |
|---|---|---|
chunk_duration / silence_duration / vad_threshold | 10.0 / 0.6 / 0.5 | Audio chunk + VAD gating |
aec_tail_ms | 200 | Echo-canceller tail in Mix mode |
voice_match_threshold_multi / _solo / voice_ratio_margin / min_voice_samples | 0.55 / 0.70 / 0.80 / 3 | Speaker-match tuning |
provisional_threshold | 0.50 | Live Speaker 1/2/… clustering gate |
speculative_interval_sec / _window_sec | 1.5 / 30.0 | Live-partial loop |
obsidian_write_interval_sec / _chunks | 15.0 / 5 | Throttle live vault writes (whichever fires first) |
daily_brief_auto_refresh | false | Auto-regen brief when a meeting finishes |
Settings UI shows the detected hardware (Detected: cuda · NVIDIA RTX 4090 · 24 GB VRAM) and tags each value custom / default. Most values need a sidecar restart; auto-capture knobs hot-reload. Sidecar bind: SIDECAR_HOST / SIDECAR_PORT env (default 127.0.0.1:8765).
DB policy — pre-GA. Schema changes drop and recreate (no migrations). db/database.py bumps a _CURRENT_SCHEMA_VERSION string; mismatch → fresh DB on next boot.
Tauri shell (Rust + WebView2 / WKWebView)
│
├── React 19 UI (Vite + Tailwind + lucide-react)
│ │
│ └── HTTP + WebSocket → Python sidecar (127.0.0.1:8765)
│ │
│ ├── faster-whisper (ASR; CUDA or CPU)
│ ├── pyannote.audio 3.1 (diarization + 256-dim embeddings)
│ ├── Silero VAD (auto-capture + chunking)
│ ├── sounddevice / soxr (mic capture, Speex-AEC)
│ ├── soundfile (Opus recorder)
│ ├── LLM client (OpenAI-compat)
│ ├── SQLite (aiosqlite) (meetings, voices, embeddings)
│ └── Obsidian writer (flat Meetings/People/Daily markdown)
│
├── spawns/kills sidecar subprocess
└── panics → APPDATA\AuraScribe\logs\crash-*-rust.log
Sidecar binds to `127.0.0.