Keep live Whisper segments on screen without a page refresh.

Treat streamed chunks as appends, stop Livewire from remorphing the Alpine tree, and hydrate from HTTP while a run is active so segment cards appear as they arrive.
This commit is contained in:
ben
2026-08-13 16:35:33 +02:00
parent 187b6b5d12
commit 3a9cf50529
7 changed files with 265 additions and 65 deletions
@@ -1,21 +1,20 @@
{{--
Full wire:ignore: Livewire must not remorph this tree while Echo/Alpine own the live UI.
Status + whisper segments hydrate over HTTP while active (no wire:poll here).
--}}
<div
@if ($recording->transcription_status === 'pending')
wire:poll.2s.visible
@endif
wire:ignore
wire:key="transcription-ui-{{ $recording->id }}-{{ $recording->transcription_status }}-{{ $recording->transcribed_at?->timestamp }}"
x-data="transcriptionMonitor(@js([
'statusUrl' => route('recordings.transcription-status', $recording),
'userId' => (int) $recording->user_id,
'initial' => $recording->transcriptionStatusPayload(),
]))"
x-init="
start();
return () => destroy();
"
>
<div
wire:ignore.self
wire:key="transcription-ui-{{ $recording->id }}-{{ $recording->transcription_status }}-{{ $recording->transcribed_at?->timestamp }}"
x-data="transcriptionMonitor(@js([
'statusUrl' => route('recordings.transcription-status', $recording),
'userId' => (int) $recording->user_id,
'initial' => $recording->transcriptionStatusPayload(),
]))"
x-init="
start();
return () => destroy();
"
>
<div class="mb-6 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div>
<flux:link href="{{ route('recordings.index') }}" wire:navigate class="text-sm"> Recordings</flux:link>
@@ -181,7 +180,6 @@
</div>
<div
wire:ignore
class="mt-4 whitespace-pre-wrap text-sm leading-relaxed text-zinc-800 dark:text-zinc-100"
x-show="status.transcript && !whisper.segments.length"
x-text="status.transcript"
@@ -245,7 +243,6 @@
</div>
<div
wire:ignore
class="mt-4 space-y-4"
x-show="whisper.language || whisper.segments.length || whisper.logprobs.length"
>
@@ -263,7 +260,7 @@
</span>
</div>
<template x-for="(segment, index) in whisper.segments" :key="segment.id ?? (segment.start + '-' + index)">
<template x-for="(segment, index) in whisper.segments" :key="segmentDomKey(segment, index)">
<div class="rounded-lg border border-zinc-200 p-3 dark:border-zinc-700">
<div class="flex flex-wrap items-baseline justify-between gap-2 text-xs text-zinc-500 dark:text-zinc-400">
<span class="tabular-nums">
@@ -329,5 +326,4 @@
No transcript yet. Transcription starts automatically after upload, or use the button above.
</flux:text>
</flux:card>
</div>
</div>