Skip to content

fix(summary): await onSave to persist editor edits#416

Open
arvanus wants to merge 37 commits intoZackriya-Solutions:mainfrom
arvanus:fix/save-summary-await
Open

fix(summary): await onSave to persist editor edits#416
arvanus wants to merge 37 commits intoZackriya-Solutions:mainfrom
arvanus:fix/save-summary-await

Conversation

@arvanus
Copy link
Copy Markdown

@arvanus arvanus commented Mar 30, 2026

Summary

  • Adds missing await on onSave() call in BlockNoteSummaryView.handleSave
  • Without await, the save handler resolved instantly — dirty flag reset before Tauri command completed, errors were silently swallowed, and spinner/toast feedback was imperceptible
  • Now the save properly awaits the Tauri api_save_meeting_summary command before clearing dirty state

Fixes

Closes #394

Test plan

  • Edit a meeting summary in the BlockNote editor
  • Click Save — confirm spinner appears during save
  • Confirm success toast shows after save completes
  • Reopen the meeting and verify edits persisted

🤖 Generated with Claude Code

arvanus and others added 30 commits March 12, 2026 20:25
Adds a `get_build_info` Tauri command that exposes compile-time info
(GPU backend, build profile, OS/arch) and displays it in the About page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Emits `model-loading-status` events from Whisper and Parakeet validation
so the frontend can show a loading indicator while the transcription
model initializes. Displays an animated banner above recording controls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stereo recording (mic=L, system=R) with mono toggle for compatibility.
Addresses issue Zackriya-Solutions#241.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address AudioChunk channel awareness, checkpoint frame math,
RecordingMode plumbing path, serde defaults for backward compat,
file size notes, and expanded testing section.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Default changed to mono (stereo is opt-in advanced option)
- Pre-allocated interleave buffer to avoid per-window allocation
- debug_assert_eq! instead of assert_eq! in hot path
- AAC 256kbps for stereo mode
- Retranscribe edge case covered
- Future iterations section (downmix playback, export mono)
- Design decisions log with rationale

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10-task plan covering AudioChunk channels field, RecordingMode enum,
IncrementalAudioSaver multi-channel math, pipeline stereo interleave,
preference wiring, AAC bitrate, frontend toggle, and tests.

Fixes from plan review: load_preferences via recording_commands.rs
(has AppHandle), no broken commits, split metadata into own task,
stereo duration test, explicit RecordingSaver struct changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frame-based checkpoint math ensures stereo checkpoints trigger at
correct 30s intervals. Includes tests for stereo checkpoint timing
and duration calculation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
STEP 4 now produces interleaved stereo or mixed mono based on
RecordingMode. Uses pre-allocated buffer for zero-alloc hot path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Serde defaults ensure old metadata.json files without these fields
deserialize correctly as mono/1-channel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ng path

RecordingMode flows: preferences -> recording_commands -> recording_manager
-> pipeline + saver -> incremental_saver -> encoder. Replaces temporary
Mono default with actual user preference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Advanced option to record mic and system audio on separate stereo
channels. Default: OFF (mono).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vulkan was hardcoded in the Windows target dependencies, causing a
dual-backend crash (CUDA + Vulkan) on NVIDIA systems. The error was:
"pre-allocated tensor in a backend that cannot run the operation"
followed by STATUS_STACK_BUFFER_OVERRUN.

GPU backends are now opt-in on all platforms via Cargo features:
- pnpm run tauri:dev         (CPU, works everywhere)
- pnpm run tauri:dev:cuda    (NVIDIA GPUs)
- pnpm run tauri:dev:vulkan  (AMD/Intel GPUs)

macOS retains hardcoded Metal+CoreML as those are the only option.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- window_ms: 600 -> 50 (was a debug value left behind, caused massive
  latency before any audio reached VAD/Whisper)
- can_mix: || -> && (only mix when BOTH mic and system buffers have
  enough data, preventing silence-padded chunks that confused VAD)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Partial transcriptions during continuous speech for immediate feedback,
replaced by final transcription when speaker pauses. Same UX pattern
as YouTube Live Captions / Google Meet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When retranscribing a multitrack stereo recording (mic=L, system=R),
each channel is now extracted, VAD-processed, and transcribed separately.
Results are labeled with [Mic] or [System] prefix and merged by timestamp.

- Add extract_channel() and is_multitrack_stereo() to DecodedAudio
- Retranscription detects stereo and forks into per-channel processing
- Mono recordings continue to work as before (no label prefix)
- Progress reporting adapted for dual-channel processing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add optional `source` field ("mic", "system", or null) to
TranscriptSegment instead of prefixing text with [Mic]/[System].
This allows the frontend to format/filter by source without parsing.

- TranscriptSegment gains `source: Option<String>` with serde defaults
- Retranscription passes source per channel instead of prefixing text
- JSON (transcripts.json) includes source field
- DB schema unchanged (source stored in JSON only for now)
- Test for source field added

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When source field is present (multitrack stereo), the transcript text
sent to the LLM includes [Mic] or [System] prefix for speaker context:

  [00:15] [Mic] Testing 1, 2, 3
  [00:18] [System] Hello everyone

Mono recordings continue without prefix. Also adds source field to
Transcript TypeScript interface.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The write_transcripts_json function was building JSON manually and
missing the source field. Now includes "source": "mic"/"system"
when present (omitted for mono recordings).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
VAD now emits intermediate partial segments every ~1.5s during ongoing
speech, providing real-time visual feedback before the speaker pauses.
When the speaker pauses (400ms silence), a final segment replaces all
partials for that speech segment.

Backend:
- VAD emits partial segments (confidence=-1.0 marker) every 1.5s
- Pipeline passes is_partial flag on AudioChunk
- Worker uses chunk-level partial flag instead of Whisper's
- Recording saver skips partials (only finals are persisted)

Frontend:
- TranscriptContext replaces partials with finals by audio_start_time
- Partials displayed in gray italic, finals in normal black
- TranscriptSegmentData gains is_partial field

Same UX pattern as YouTube Live Captions / Google Meet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolved conflict in pipeline.rs: added is_partial field to
recording chunk (multitrack stereo STEP 4).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
arvanus and others added 7 commits March 20, 2026 22:19
Only one speech segment is active at a time, so simply remove all
existing partials when a new partial or final arrives. Fixes issue
where partials accumulated instead of being replaced due to float
precision in audio_start_time comparison.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the worker picks up a partial chunk, it now drains any newer
partials from the queue and only processes the latest one. This
prevents partial accumulation when the speaker talks faster than
Whisper can transcribe (~1s per chunk).

If a final chunk is found while draining, it processes the final
instead (finals are never skipped).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Partial transcription works at the backend level but the frontend
display needs a separate data path. Currently partials leak into
the transcript list and recording saver despite filters.

Next step: brainstorm clean separation of partial vs final data flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Partials now use 'transcript-partial' event (text only), finals
use 'transcript-update' (unchanged). This completely isolates
partial data from the recording saver and transcript list.

Backend:
- Worker emits transcript-partial for partials, transcript-update for finals
- recording_commands listener no longer needs is_partial filter

Frontend:
- transcriptService.onTranscriptPartial() listens for partial event
- TranscriptContext sets partialText on partial, clears on final
- TranscriptPanel shows partialText as live preview box

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The VAD now emits partial segments (confidence < 0) for live preview,
but get_speech_chunks_with_progress (used by retranscription and
import) should only return final segments. Partials were leaking
into retranscription results, causing duplicate/incremental text.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Partial text now renders inside VirtualizedTranscriptView, directly
above the "Listening..." indicator, instead of outside the component.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The save handler was calling onSave() without await, causing the dirty
flag to reset before the Tauri command completed. This made save errors
silent and gave no visual feedback to the user. Fixes Zackriya-Solutions#394.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Save button in summary editor does not persist edits (v0.3.0)

1 participant