diff --git a/src/lib/components/ProgressOverlay.svelte b/src/lib/components/ProgressOverlay.svelte index 5adcc55..f55c488 100644 --- a/src/lib/components/ProgressOverlay.svelte +++ b/src/lib/components/ProgressOverlay.svelte @@ -4,9 +4,25 @@ percent?: number; stage?: string; message?: string; + onCancel?: () => void; } - let { visible = false, percent = 0, stage = '', message = '' }: Props = $props(); + let { visible = false, percent = 0, stage = '', message = '', onCancel }: Props = $props(); + + let showConfirm = $state(false); + + function handleCancelClick() { + showConfirm = true; + } + + function confirmCancel() { + showConfirm = false; + onCancel?.(); + } + + function dismissCancel() { + showConfirm = false; + } // Pipeline steps in order const pipelineSteps = [ @@ -89,6 +105,20 @@

{message || 'Please wait...'}

This may take several minutes for large files

+ + {#if onCancel && !showConfirm} + + {/if} + + {#if showConfirm} +
+

Processing is incomplete. If you cancel now, the transcription will need to be started over.

+
+ + +
+
+ {/if} {/if} @@ -174,4 +204,62 @@ font-size: 0.75rem; color: #555; } + .cancel-btn { + margin-top: 1.25rem; + width: 100%; + padding: 0.5rem; + background: none; + border: 1px solid #4a5568; + color: #999; + border-radius: 6px; + cursor: pointer; + font-size: 0.85rem; + } + .cancel-btn:hover { + color: #e0e0e0; + border-color: #e94560; + } + .confirm-box { + margin-top: 1.25rem; + padding: 0.75rem; + background: rgba(233, 69, 96, 0.08); + border: 1px solid #e94560; + border-radius: 6px; + } + .confirm-text { + margin: 0 0 0.75rem; + font-size: 0.8rem; + color: #e0e0e0; + line-height: 1.4; + } + .confirm-actions { + display: flex; + gap: 0.5rem; + } + .confirm-keep { + flex: 1; + padding: 0.4rem; + background: #0f3460; + border: 1px solid #4a5568; + color: #e0e0e0; + border-radius: 4px; + cursor: pointer; + font-size: 0.8rem; + } + .confirm-keep:hover { + background: #1a4a7a; + } + .confirm-cancel { + flex: 1; + padding: 0.4rem; + background: #e94560; + border: none; + color: white; + border-radius: 4px; + cursor: pointer; + font-size: 0.8rem; + } + .confirm-cancel:hover { + background: #d63851; + } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 67d16eb..8c5887a 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -119,11 +119,23 @@ }; }); let isTranscribing = $state(false); + let transcriptionCancelled = $state(false); let transcriptionProgress = $state(0); let transcriptionStage = $state(''); let transcriptionMessage = $state(''); let extractingAudio = $state(false); + function handleCancelProcessing() { + transcriptionCancelled = true; + isTranscribing = false; + transcriptionProgress = 0; + transcriptionStage = ''; + transcriptionMessage = ''; + // Clear any partial results + segments.set([]); + speakers.set([]); + } + // Speaker color palette for auto-assignment const speakerColors = ['#e94560', '#4ecdc4', '#ffe66d', '#a8e6cf', '#ff8b94', '#c7ceea', '#ffd93d', '#6bcb77']; @@ -310,6 +322,7 @@ // Start pipeline (transcription + diarization) isTranscribing = true; + transcriptionCancelled = false; transcriptionProgress = 0; transcriptionStage = 'Starting...'; transcriptionMessage = 'Initializing pipeline...'; @@ -420,6 +433,9 @@ numSpeakers: $settings.num_speakers && $settings.num_speakers > 0 ? $settings.num_speakers : undefined, }); + // If cancelled while processing, discard results + if (transcriptionCancelled) return; + // Create speaker entries from pipeline result const newSpeakers: Speaker[] = (result.speakers || []).map((label, idx) => ({ id: `speaker-${idx}`, @@ -607,6 +623,7 @@ percent={transcriptionProgress} stage={transcriptionStage} message={transcriptionMessage} + onCancel={handleCancelProcessing} /> {#if extractingAudio}