Skip to content

Latest commit

 

History

History
312 lines (244 loc) · 16.7 KB

File metadata and controls

312 lines (244 loc) · 16.7 KB

whispernotes — command line reference

Everything the UI does, headlessly. Useful for batch-transcribing recordings and for running a capture session from a terminal without the window in the way.

All commands write into the same organised notes tree the UI reads, so a session transcribed from a recording shows up in the UI alongside live ones.

whispernotes devices

Lists the audio endpoints you can capture, with the ids to pass to --channel.

$ whispernotes devices

LOOPBACK (system audio — capture what you HEAR, e.g. Teams)
  * speakers-realtek-hd    Speakers (Realtek High Definition Audio)   48000 Hz / 2ch   [default]
    vb-cable-in            CABLE Input (VB-Audio Virtual Cable)       48000 Hz / 2ch

MICROPHONE (capture what you SAY)
  * headset-mic            Headset Microphone (Jabra Evolve 65)       16000 Hz / 1ch   [default]

APPLICATIONS (capture ONE app's audio — nothing else on the machine)
  ! Per-application capture needs Windows build 20348 or later (Windows 11 / Server 2022). This machine reports build 19045, so application inputs record system audio instead.
    brave       brave                               44100 Hz / 2ch
    discord     Discord                             44100 Hz / 2ch
    outlook     Inbox - you@example.com - Outlook   44100 Hz / 2ch
    ms-teams    ms-teams                            44100 Hz / 2ch
    spotify     Spotify Premium                     44100 Hz / 2ch

  * = system default for that role

To transcribe a Teams call you want a LOOPBACK entry — the render endpoint Teams is playing through. See "Isolating Teams audio" in the README.

The short id in the first column is derived from the endpoint's friendly name, because the raw WASAPI endpoint id looks like {0.0.0.00000000}.{ab116aac-...} and nobody is retyping that. --channel accepts either form, plus the exact friendly name; ids are matched case-insensitively. The short id stays stable when you change your default device, and a numeric suffix (-2, -3) disambiguates endpoints whose names collide.

APPLICATIONS lists running processes instead of device endpoints, so you can capture, say, Outlook's audio without also picking up Spotify. Its slug is derived from the executable stem (outlook, not the window title), and the raw id is app:outlook.exe — keyed on the executable name rather than the process id, so it keeps working after the app (or WhisperNotes) restarts. --channel accepts any of the slug, the raw id, or the bare executable name (outlook.exe). Applications are never chosen implicitly: listen with no --channel always falls back to device loopback, never to an app, since guessing which running process to isolate would silently narrow a recording to whatever happened to have focus.

Per-application capture is built on WASAPI process loopback, which Windows only exposes from build 20348 onward — in practice that means Windows 11 or Windows Server 2022; Microsoft's own docs call the floor "Windows 10 Build 20348", which is misleading, since 20348 is the Server 2022 RTM build and retail Windows 10 tops out at 19045. Below that build, an application input does not fail — it falls back to recording the whole machine's audio, same as a LOOPBACK entry, and every surface (the ! line above, listen's channel line, the Inputs page, and the capture bar) says so rather than quietly scoping the note to more than it claims.

Add --verbose to also print each endpoint's raw id; for an application this line also carries its live process id, since that's the one place a pid is shown — it isn't part of the id itself because pids get recycled between runs.

whispernotes listen

Live capture and dictation. Runs until Ctrl+C, then finalizes the session and writes notes.md.

Option Default Meaning
-c, --channel <id> last used, else default render loopback Endpoint or application from whispernotes devices.
-t, --title <text> local timestamp Session title; also the folder name.
-p, --project <name> from settings Groups the session into a project folder.
-m, --model <size> base tiny|base|small|medium|large-v3|large-v3-turbo
-l, --language <code> auto ISO code, or auto to detect.
--tag <tag> none Repeatable.
--prompt <text> from settings Vocabulary hint — client names, acronyms.
--keep-audio off Also save the captured WAV next to the notes.
--threads <n> CPU count, capped Decoder threads.
--diarize from settings (on) Label each line with the speaker who said it.
--no-diarize Skip speaker attribution, even if settings enable it.
--max-speakers <n> 8 Ceiling on how many voices may be reported.
--quiet off Suppress the live transcript echo; only print the final path.
$ whispernotes listen --channel speakers-realtek-hd --project "Acme Corp" --title "Sprint review" --model small

  model    small (already downloaded)
  channel  Speakers (Realtek High Definition Audio) [loopback]
  session  ~/Documents/WhisperNotes/Acme Corp/2026/2026-07-25/143022-sprint-review
  Ctrl+C to stop.

[00:00:04] Right, let's get started. Dan, where are we on the firewall change?
[00:00:11] Still blocked. I've chased the network team twice this week.
^C
  finalized  1 min 12 sec, 18 entries
  notes      ~/Documents/WhisperNotes/Acme Corp/2026/2026-07-25/143022-sprint-review/notes.md

Ctrl+C is the normal way to end a session, not an abort: the first press stops the capture, lets the decoder flush the audio still buffered, appends those last segments, finalizes and renders notes.md, then exits 130. A second Ctrl+C terminates immediately, in case a decode wedges.

The endpoint actually used is written back to LastChannelId, which is what "last used" in the table above reads on the next run. Nothing else about the invocation is persisted — a one-off --notes-root or --models-root never ends up in the settings file.

--channel targeting an application prints an [application] kind on the channel line instead of [loopback] or [microphone] — or [application → system audio fallback] on a Windows build below 20348, where the session is honestly labelled as system audio rather than pretending it isolated the app. Since applications are excluded from the "last used, else default" fallback in the table above, an application --channel always has to be named explicitly.

With --keep-audio the captured WAV is written to <session>/audio/session.wav as 16 kHz mono 16-bit PCM, which is the format transcribe can re-read directly.

Speakers. Diarization works out who spoke when. It runs offline, from a small voice-embedding model that turns each stretch of speech into a vector and groups the stretches that sound like the same person. New voices come out as Speaker 1, Speaker 2 and so on. Names are supplied by a human in the desktop app, then retained in the local speaker-profile catalog so CLI and desktop recordings can recognize them later. Several separate voice profiles may share one name, which repairs false splits without discarding either voiceprint. --max-speakers caps how many clusters may be reported, and a recording with only one unknown voice is left unlabelled. Tune within-session clustering with Diarization.MergeThreshold and cross-session matching with Diarization.ProfileMatchThreshold.

whispernotes transcribe

This is the --video flag. Converts a video (or any media file) to a 16 kHz mono audio channel with ffmpeg, then runs the same local Whisper over it.

Option Default Meaning
-v, --video <path> required Input media. Any container ffmpeg reads. --input/-i are accepted aliases.
--stream <n> first audio stream Which audio stream to take, from --list-streams.
--list-streams off Print the file's audio streams and exit without transcribing.
-t, --title <text> input filename Session title.
-p, --project <name> from settings Project folder.
-m, --model <size> base As above.
-l, --language <code> auto As above.
--tag <tag> none Repeatable.
--prompt <text> from settings Vocabulary hint.
--keep-audio off Keep the extracted WAV instead of deleting it.
--threads <n> CPU count, capped Decoder threads.
--diarize from settings (on) As above.
--no-diarize As above.
--max-speakers <n> 8 As above.
-o, --output <dir> notes root Override where this session is written.
$ whispernotes transcribe --video "Sprint review-20260725.mp4" --list-streams

  #1 aac 2ch 48000Hz [eng] "Mixed audio"
  #2 aac 1ch 48000Hz [und] "Dan Whitfield"

$ whispernotes transcribe --video "Sprint review-20260725.mp4" --stream 2 --project "Acme Corp" --model small

  model         small (already downloaded)
  session       ~/Documents/WhisperNotes/Acme Corp/2026/2026-07-25/143022-sprint-review-20260725
  extracting    ██████████████████████ 100%   (ffmpeg, stream #2 -> 16 kHz mono)
  transcribing  ████████████░░░░░░░░░░  58%   00:12:31 / 00:21:40
  notes         ~/Documents/WhisperNotes/Acme Corp/2026/2026-07-25/143022-sprint-review-20260725/notes.md

--stream takes the ffmpeg stream index printed by --list-streams, which counts every stream in the container — in a video file the first audio stream is usually #1, not #0.

Teams meeting recordings download as .mp4, so this is the recovery path for the case that prompted this tool: Teams' own transcription didn't run, but you have the recording.

The extracted WAV goes to a temp file and is deleted when the run finishes; --keep-audio writes it to <session>/audio/session.wav instead and leaves it there. -o/--output redirects just this session's tree, overriding the global --notes-root.

Chunks that hold nothing but digital silence are not sent to the decoder. Whisper reliably invents captions for silence, and an invented line in a billable record is worse than a missing one.

whispernotes sessions

Lists past sessions from the notes tree.

Option Meaning
-p, --project <name> Filter to one project.
--since <date> / --until <date> Date range, yyyy-MM-dd or relative like 7d.
-s, --search <text> Match against title and transcript text.
--json Machine-readable output.

Relative bounds take a h (hours), d (days) or w (weeks) suffix and count back from now. --until on a plain yyyy-MM-dd includes that whole day.

Each session prints one summary line — start, project, title, duration, entry count — followed by the path to its notes.md. --json emits the same records with the session id, tags, model, source description and the transcript path as well.

whispernotes export

Exports authored notes from the Notes page. Markdown, HTML, and PDF export one note selected by its id or exact title. Obsidian exports the whole authored-note library as a ZIP of UTF-8 Markdown files grouped by project.

# One note. The extension and a safe filename are chosen automatically.
whispernotes export markdown --document "Sprint review"
whispernotes export html --document "Sprint review" --output .\exports
whispernotes export pdf --document "Sprint review" --output .\exports\sprint-review.pdf

# Every authored note, ready to extract and open/copy into an Obsidian vault.
whispernotes export obsidian --output .\exports\whispernotes-obsidian.zip
Argument / option Meaning
format markdown, html, pdf, or obsidian.
-d, --document <id-or-title> Required for the single-note formats; exact titles are case-insensitive.
-o, --output <path> Destination file or an existing directory; defaults to the current directory.
--overwrite Explicitly replace an existing destination. Without it, export refuses to clobber a file.

If more than one note has the requested title, the command prints the ids to choose from. An Obsidian export ignores the current UI search and always includes every authored note. Extract the ZIP, then open that folder as a vault or move its project folders into an existing vault.

whispernotes models

Subcommand Meaning
models list Show each model, its size on disk, and whether it's downloaded.
models download <size> Pre-fetch weights with a progress bar.
models path Print the models directory.

Pre-downloading matters: the first listen on an un-fetched medium would otherwise stall for a 1.5 GB download at the exact moment your meeting starts.

whispernotes doctor

Answers "is this actually using my graphics card?". Whisper.net picks a native runtime when the first model loads and falls back to the CPU without saying so, and a CPU fallback looks exactly like a GPU run except roughly 40x slower. doctor loads a model and reports what came back.

$ whispernotes doctor

  model       large-v3-turbo
  requested   gpu, device 0
  backend     vulkan — gpu accelerated
  devices     0 = NVIDIA GeForce RTX 3080 (NVIDIA) | uma: 0 | fp16: 1 | bf16: 1 | ...
              1 = Intel(R) UHD Graphics 770 (Intel Corporation) | uma: 1 | fp16: 1 | ...

  More than one adapter is visible and device 0 is in use. Try the others with --gpu-device <n>,
  and make the winner stick by setting Gpu.Device in the settings file.
  load        1.7 s

It needs at least one model on disk — it has to load something to find out what that load resolves to. Any downloaded model will do; if the configured one is missing it uses whichever is present, and tells you to models download tiny if none are.

backend: cpu when you did ask for the GPU is the failure case, and doctor says so and why. The Vulkan runtime needs vulkan-1.dll, which current NVIDIA, AMD and Intel drivers all install, so updating the graphics driver is the usual fix. --verbose prints every path the loader tried.

whispernotes config

Subcommand Meaning
config show Print effective settings and the settings file path.
config set <key> <value> Set one value, e.g. config set NotesRoot "D:\Notes".
config path Print the settings file path.

Keys, matched case-insensitively: NotesRoot, ModelsRoot, Model, Language, Threads, Gpu.Enabled, Gpu.Device, LastChannelId, DefaultProject, InitialPrompt, KeepSessionAudio, FfmpegPath, Chunking.MinChunkSeconds, Chunking.MaxChunkSeconds, Chunking.SilenceMilliseconds, Chunking.SilenceThreshold, Diarization.Enabled, Diarization.MaxSpeakers, Diarization.MergeThreshold, Diarization.ProfileMatchThreshold, Diarization.MinObservationSeconds, Diarization.MaxObservationSeconds. Passing an empty value clears an optional setting back to its default.

config show prints the effective settings — the file merged with this invocation's global options. config set always writes the file itself, never the merged view.

Global options

Option Meaning
--notes-root <dir> Override the notes root for this invocation.
--models-root <dir> Override the models directory.
--ffmpeg <path> Explicit ffmpeg location if it isn't on PATH.
--verbose Diagnostic logging, including resolved binary paths.
--no-gpu Decode on the CPU. Roughly 40x slower — for working around a bad driver.
--gpu-device <n> Which adapter to decode on, indexed as whispernotes doctor lists them.

--no-gpu and --gpu-device are per-invocation, like every other global: they never touch the settings file. Make a choice permanent with config set Gpu.Enabled / config set Gpu.Device. They apply to doctor too, which is the point — try an adapter, see what it resolved to, keep the one that won.

Exit codes

Code Meaning
0 Success.
1 Bad usage / invalid argument. Includes an unparseable command line, an unknown --model, a --stream the file doesn't have, and a --video path that does not exist.
2 Requested audio device not found — or the device the session was capturing died mid-run, in which case the notes are still finalized first.
3 ffmpeg or ffprobe missing, or the probe/conversion failed (including a file ffmpeg cannot read).
4 Model missing and could not be downloaded.
130 Interrupted with Ctrl+C. For listen this is the NORMAL exit and notes are still finalized.

Every command reports failures as one sentence on stderr and one of these codes. Nothing prints a stack trace; --verbose adds the full exception underneath if you need it.

Progress bars redraw in place on a real console and degrade to periodic complete lines when stdout is redirected to a file or a pipe, so piping a run into a log never produces a wall of overwritten bars.