Secrets: - Warm the secret-storage probe before loadSettings so a fresh install actually defaults to Obsidian secret storage instead of caching an unconfigured passphrase envelope first. - setEncryptionMode no longer early-returns on same-mode: an unconfigured passphrase store now always builds its kdf/verifier, so creating a passphrase (incl. on Linux without a keyring) writes secrets.json.nosync instead of silently no-opping. Modal: - The Record tab closes the modal on Stop and runs the pipeline detached with Notice progress (per-stage setMessage) and Notice errors, mirroring the reprocess-audio flow. The persisted recording is the recovery path, so no inline Retry. Paste / From note keep the in-modal Retry flow. Docs: - Replace FEATURES.md with ROADMAP.md: Planned / Unreleased / Released lifecycle, wired into the RELEASING.md release steps. - Update SECRETS.md, CLAUDE.md, and the Commands-and-Menus wiki page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2.8 KiB
Speaker diarization
Extracted from CLAUDE.md. Subject to the same maintenance rule: when you change diarization behavior, update this file in the same change, and keep the one-line summary in CLAUDE.md accurate.
Opt-in per-profile flag TranscriptionConfig.diarize?: boolean (src/types.ts). When on, the capable adapter embeds Speaker X: labels into the returned transcript string (the v1 shape from the diarization item in the ROADMAP.md archive; the transcribe(): Promise<string> interface is unchanged, and cleanup/insert treat the labels as ordinary text). Capability is centralized in transcriptionProviderSupportsDiarization(id) (src/transcription/index.ts), true only for assemblyai / deepgram / revai. The settings tab (src/settings/tab.ts) shows an "Identify speakers" toggle in the per-profile transcription block gated on that helper; the setup card is intentionally left without it (not a "fill in the basics" field).
Per-template override
A template can force diarization on for its own runs via NoteTemplate.diarize?: boolean (frontmatter diarize: true), independent of the profile toggle. src/pipeline.ts collectTranscript merges { ...profile.transcriptionConfig, diarize: true } for the transcribe call ONLY when template.diarize is set AND transcriptionProviderSupportsDiarization(profile.transcriptionProvider) is true; on a non-capable provider it leaves the config untouched (the flag is a documented no-op, not an error). The profile config is never mutated. The Meeting transcript default ships with this set. The override raises the effective setting only (a template never turns OFF a profile's diarization).
Per-adapter behavior
src/transcription/assemblyai.ts sets speaker_labels: true and formats the returned utterances[] (Speaker A: ..., native letter labels); src/transcription/deepgram.ts adds diarize=true and groups per-word speaker indices via formatDiarizedWords (0-based bumped to Speaker 1); src/transcription/revai.ts fetches the JSON transcript (Accept: application/vnd.rev.transcript.v1.0+json) instead of text/plain and rebuilds labels from monologues[] via formatMonologues (0-based bumped to Speaker 1). Each adapter falls back to its flat-text path when the labeled payload is missing, so toggling off is a clean no-op. Label survival through cleanup is handled by a clause in DEFAULT_SHARED_CORE (src/shared-core.ts) telling the LLM to preserve Speaker X: prefixes; the Podcast default template already tolerates labeled and unlabeled input.