From cf919f149913502e673b53945631c589291ce7e4 Mon Sep 17 00:00:00 2001 From: iamdoubz <> Date: Wed, 15 Jul 2026 09:49:57 -0500 Subject: [PATCH 01/39] fix(notes): refresh notes pane after re-transcribe; add AI-enhance + slash/toolbar Re-sync the editor buffer after reprocess (was stale until restart). Adds a Granola-style AI-enhance button (grounded in transcript, one-step undo), H3/ numbered/quote/divider toolbar buttons, and slash commands. --- src/lib/views/TranscriptNotes.svelte | 160 ++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 1 deletion(-) diff --git a/src/lib/views/TranscriptNotes.svelte b/src/lib/views/TranscriptNotes.svelte index e34fa3d..6c8f4d9 100644 --- a/src/lib/views/TranscriptNotes.svelte +++ b/src/lib/views/TranscriptNotes.svelte @@ -6,7 +6,7 @@ import { meetings } from "../stores/meetings.svelte"; import { settings } from "../stores/settings.svelte"; import { player } from "../stores/player.svelte"; - import { api, type SpeakerInfo } from "../api"; + import { api, errorMessage, type SpeakerInfo } from "../api"; import { t } from "../i18n/index.svelte"; import { renderMarkdown } from "../markdown"; import { save, open } from "@tauri-apps/plugin-dialog"; @@ -17,8 +17,14 @@ Italic, Heading1, Heading2, + Heading3, List, + ListOrdered, ListChecks, + Quote, + Minus, + Sparkles, + Undo2, FileDown, FileText, FolderOutput, @@ -158,6 +164,70 @@ scheduleSave(); } + // Slash commands: typing "/todo" (etc.) at the start of a line and pressing + // Space/Enter swaps it for the matching Markdown prefix. Reuses the same + // line-prefix model as the toolbar buttons — no rich inline menu. + // ponytail: line-prefix slash only; add a picker popover if users ask. + const SLASH_COMMANDS: Record = { + h1: "# ", + h2: "## ", + h3: "### ", + todo: "- [ ] ", + bullet: "- ", + num: "1. ", + quote: "> ", + divider: "---\n", + }; + function handleNotesKeydown(e: KeyboardEvent) { + if (e.key !== "Enter" && e.key !== " ") return; + const el = editorEl; + if (!el) return; + const { selectionStart: s, value } = el; + const lineStart = value.lastIndexOf("\n", s - 1) + 1; + const match = /^\/(\w+)$/.exec(value.slice(lineStart, s)); + if (!match) return; + const prefix = SLASH_COMMANDS[match[1].toLowerCase()]; + if (prefix === undefined) return; + e.preventDefault(); + const head = value.slice(0, lineStart) + prefix; + notesText = head + value.slice(s); + queueMicrotask(() => { + el.focus(); + el.selectionStart = el.selectionEnd = head.length; + }); + scheduleSave(); + } + + // AI-enhance (Granola-style): expand the user's rough notes into structured + // Markdown grounded in the transcript, via the configured LlmProvider (local + // by default, no new egress). Keeps a one-step Undo so we never silently lose + // what the user typed. + let enhancing = $state(false); + let enhanceError = $state(null); + let notesBeforeEnhance = $state(null); + async function enhanceNotes() { + const m = meetings.selected; + if (!m || enhancing) return; + enhancing = true; + enhanceError = null; + try { + const enhanced = await api.enhanceNotes(m.id, notesText); + notesBeforeEnhance = notesText; + notesText = enhanced; + scheduleSave(); + } catch (e) { + enhanceError = errorMessage(e); + } finally { + enhancing = false; + } + } + function undoEnhance() { + if (notesBeforeEnhance === null) return; + notesText = notesBeforeEnhance; + notesBeforeEnhance = null; + scheduleSave(); + } + async function exportMd() { const m = meetings.selected; if (!m) return; @@ -247,6 +317,15 @@ reprocessing = true; try { await meetings.reprocess(m.id, reprocessModel, reprocessLanguage || undefined); + // Re-transcribe rebuilds notes.md server-side (merging saved manual notes), + // but the meeting stays selected (same id), so the buffer-sync $effect — + // which only fires on an id change — won't pick it up. Resync explicitly so + // the notes pane updates in place instead of only after a restart. + const updated = meetings.selected; + if (updated && updated.id === m.id) { + notesText = updated.notes_markdown; + loadedForId = updated.id; + } } finally { reprocessing = false; } @@ -423,6 +502,39 @@ >