Skip to content

Releases: ReidenXerx/whiz

v0.9.0 — auto-enable screenshots+speakers for video

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 13:38

For video inputs, --screenshots and --speakers (auto-detect) are now on by defaultwhiz transcribe recording.mov produces a labeled transcript plus per-segment frames for AI analysis / HTML output without extra flags.

What's new

  • Auto-enabled for video inputs: --screenshots and --speakers (auto-detect) turn on automatically for video files. Audio inputs are unaffected.
  • Opt-out flags: --no-screenshots and --no-speakers (added to both transcribe and merge) disable the auto-enabled defaults.
  • Graceful diarization fallback: when diarization is only auto-enabled (not explicitly requested) but sherpa-onnx or its models aren't installed, whiz prints a one-line hint and skips speaker labels (VAD stays on, screenshots still run) instead of crashing.
  • JSON forced when screenshots on: needed to drive the per-segment frame path even without diarization.
  • Privacy: replaced real names in README/source/tests with generic placeholders (Alice/Bob/Carol/Dave).

Upgrade

pipx install --force git+https://github.com/ReidenXerx/whiz.git

Co-Authored-By: Oz oz-agent@warp.dev

v0.8.1 — Test suite + resumability

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

New

  • --resume flag on whiz transcribe — skips whisper-cli when its JSON output already exists and goes straight to diarization + merge. An ergonomic alias for whiz merge triggered from whiz transcribe, so you don't have to switch subcommands to re-tune --speakers against an existing transcription.

Tests

  • pytest suite (67 tests, <0.1s, no external deps) covering the pure-Python modules:
    • test_merge.py — overlap assignment, speaker ordering by talk time, relabel, representative quotes, SRT/TXT formatting, JSON parsing (-oj + verbose_json words), HTML escaping
    • test_models.py — alias derivation, discovery, resolve (exact/short/path/unknown), pick_best preference, VAD discovery (isolated from host models via monkeypatch)
    • test_screenshots.py — frame naming, string-append path helpers for dotted stems, manifest round-trip + malformed-row handling
    • test_ai.py — prompt resolution, transcript rendering, even-spread subsampling, base64, mocked HTTP (API-key header, vision image content, HTTPError/URLError/no-choices)
    • test_diarize_cache.py — diar cache round-trip + param-mismatch + threshold epsilon; profiles cosine similarity + one-to-one matching + save/load/forget

Install

pipx install --force --editable '.[test]'
pytest tests/

Full changelog: v0.8.0...v0.8.1

v0.8.0 — Speaker voice profiles

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

✨ Speaker voice profiles (cross-recording recognition)

When you name a speaker (with --name-speakers or --speakers-names), whiz now saves a voice profile: a 512-dim embedding vector for that speaker's audio, computed with the same sherpa-onnx embedding extractor used for diarization. On later recordings, each detected cluster's embedding is compared (cosine similarity) to the stored profiles and a name is auto-assigned when the best match exceeds speaker_match_threshold (default 0.8).

So the first time you transcribe a meeting with --speakers-names Enric,Vadim,Thomas,Dziyana, those voice profiles are stored. The next recording with the same people is labeled automatically, no flags needed.

New

  • whiz/profiles.pycompute_speaker_embeddings() (audio chunked into 30s streaming windows, utterances <0.3s skipped), cosine_similarity(), match_speakers() with one-to-one assignment (a name never goes to two clusters), auto_assign_names(), JSON profile store at ~/.config/whiz/speakers/<Name>.json
  • whiz speakers subcommands: list, forget <name>, match <file> (dry-run showing every cluster-vs-profile cosine score)
  • Config: speaker_match_threshold (default 0.8), save_voice_profiles (default true)
  • --no-voice-profiles flag on transcribe + merge to skip auto-matching and profile saving

Usage

# First recording: name speakers — profiles saved automatically
whiz transcribe --speakers 4 --speakers-names Enric,Vadim,Thomas,Dziyana meeting1.mov

# Later recording: speakers auto-matched, no flags needed
whiz transcribe --speakers 4 meeting2.mov

# Inspect / tune / remove
whiz speakers list
whiz speakers match meeting2.mov --speakers 4
whiz speakers forget Dziyana

Naming precedence: voice-profile auto-match → --speakers-names--name-speakers (interactive, with auto-matched names shown as defaults).

Full changelog: v0.7.0...v0.8.0

v0.7.0 — HTML transcript + word timestamps

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

✨ Self-contained HTML transcript

Add html to --outputs to write a portable <stem>.speakers.html alongside the input. Each segment is a color-coded cue with a timestamp link, the speaker label, and (when --screenshots was set) the on-screen frame inlined as a base64 data: URI — so the single file is fully portable (email, wiki, offline) with no external image dependencies.

New

  • --outputs html on whiz transcribe and whiz merge
  • merge.format_speakers_html() — inline CSS, deterministic per-speaker colors (hash-based palette), HTML-escaped text, base64 frame inlining from <stem>.frames/
  • WhisperSeg.words field + parse_whisper_json() reads verbose_json words arrays (groundwork for karaoke-style word highlighting)

Usage

# Transcribe + diarize + capture frames + write HTML transcript
whiz transcribe --speakers 4 --screenshots --outputs srt,html recording.mov

# Add HTML to an existing run via merge (reuses diarization cache)
whiz merge --speakers 4 --screenshots --outputs html recording.mov

The HTML file can be large (one base64 JPEG per segment), but opens in any browser with no server and no missing images.

Full changelog: v0.6.0...v0.7.0

v0.6.0 — AI analysis via Ollama

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

✨ AI analysis (summary, action items, vision)

whiz analyze sends a prior transcript (and optionally on-screen frames) to a chat model via an OpenAI-compatible API (Ollama by default). Produces a markdown .analysis.md alongside the input and prints the response to stdout.

New

  • whiz/ai.py — urllib OpenAI-compatible client (chat_text / chat_vision), base64 frames at send time, ai_max_frames cap (spread evenly), clear error hints (text-only model rejecting images → vision hint; server unreachable → "is ollama running?")
  • whiz analyze subcommand: --summary, --actions, --prompt (freeform with {transcript} placeholder), --vision (send on-screen frames)
  • Config: ai_base_url (default http://localhost:11434/v1), ai_model, ai_api_key, ai_max_frames (default 50)

Usage

# Setup
whiz config set ai_model=gpt-4o-mini        # or any Ollama model

# Summary + action items (default)
whiz analyze recording.mov

# Vision analysis (requires a prior --screenshots run + vision model)
whiz analyze recording.mov --vision --summary

Works with Ollama, LM Studio, vLLM, and any OpenAI-compatible server. No new dependencies — uses urllib.request.

Full changelog: v0.5.0...v0.6.0

v0.5.0 — Diarization cache, naming, screenshots

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

✨ Quality-of-life + video screenshots

Three cheap wins that ship immediate value, plus the centerpiece video-screenshot pipeline that later phases build on.

New

Phase 1 — cheap wins

  • Diarization cache (<wav>.diar.json) — the expensive embedding pass runs once; later whiz merge runs with the same --speakers/--cluster-threshold reuse the cache and skip the ~3 min embedding pass. Re-tuning names/thresholds is now instant.
  • --speakers-names non-interactive flag — assign names by total talk time (most talkative first) without an interactive prompt.
  • Whisper-cli progress passthrough — run via subprocess.Popen, stream output line-by-line to stderr with an elapsed-time prefix. --print-progress on by default when stderr is a TTY.

Phase 2 — video screenshots

  • whiz/screenshots.py — extract one JPEG per transcribed segment at its start timestamp via ffmpeg seek-before-input (seg0001.jpg ↔ cue 1).
  • --screenshots flag on transcribe + merge; --screenshot-width (default 1280).
  • <stem>.frames.json manifest — paths only (no bytes), small and re-runnable. The join key for AI analysis (whiz analyze --vision) and the self-contained HTML transcript (which inlines frames as base64).

Full changelog: v0.4.0...v0.5.0

v0.4.0 — Interactive speaker naming + whiz merge

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

New

  • --name-speakers — after transcription + diarization, whiz shows one representative quote per detected speaker (the longest utterance — most identifying) and interactively prompts for a real name. Blank input keeps the default Speaker A label.
  • whiz merge subcommand — re-run only diarization + merge against an existing whisper JSON, so you can tune speaker count / threshold / names without redoing the expensive transcription.
  • Default cluster_threshold raised to 0.9 per sherpa-onnx guidance.

Full changelog: v0.3.1...v0.4.0

v0.3.1 — whisper JSON path fix + cluster_threshold 0.9

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

Fixes

  • Resolve whisper-cli JSON output at <wav>.json (whisper-cli names outputs after the full input path, so foo.wav.json — the .wav is part of the stem). Preserves dots in stems like ...16.03.40.
  • Raise default cluster_threshold to 0.9 (fewer, more accurate speakers).

Full changelog: v0.3.0...v0.3.1

v0.3.0 — Multi-speaker diarization

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:52

✨ Speaker diarization via sherpa-onnx

whiz transcribe --speakers runs true diarization (pyannote segmentation + 3D-Speaker embedding clustering) and emits labeled Speaker A: / Speaker B: output.

  • --speakers [N] — optional integer = known speaker count (more accurate); omit = auto-detect
  • --cluster-threshold — clustering threshold when auto-detecting (larger = fewer speakers)
  • Downloads diarization models (~90 MB) via whiz models download-diarization
  • Produces *.speakers.srt + *.speakers.txt alongside the input

Full changelog: v0.2.1...v0.3.0

v0.2.1 — VAD download 404 fix

Choose a tag to compare

@ReidenXerx ReidenXerx released this 17 Aug 11:53

Fixes

  • The Silero VAD model moved from ggerganov/whisper.cpp to a separate repo ggml-org/whisper-vad with versioned filenames. whiz now downloads from the new repo, fixing the 404.
  • whiz models download-vad [version] accepts v5.1.2, v6.2.0, or full filenames.

Full changelog: v0.2.0...v0.2.1