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
+40 -17
View File
@@ -95,6 +95,17 @@ class WhisperTranscriptionStream
];
}
if ($this->isLiveSegmentEvent($type, $data)) {
return [
'append' => $data['text'],
'replace' => null,
'end' => $end,
'done' => false,
'legacy' => true,
'whisper' => $whisper,
];
}
if (isset($data['segments']) && is_array($data['segments'])) {
$text = $data['text'] ?? '';
@@ -112,22 +123,6 @@ class WhisperTranscriptionStream
];
}
if (
($type === null || $type === 'segment')
&& isset($data['text'])
&& is_string($data['text'])
&& $data['text'] !== ''
) {
return [
'append' => $data['text'],
'replace' => null,
'end' => $end,
'done' => false,
'legacy' => true,
'whisper' => $whisper,
];
}
if ($whisper !== []) {
return [
'append' => null,
@@ -217,7 +212,7 @@ class WhisperTranscriptionStream
}
}
if ($segments !== []) {
if ($segments !== [] && ! isset($meta['segment'])) {
$meta['segments'] = $segments;
}
}
@@ -274,6 +269,34 @@ class WhisperTranscriptionStream
return array_filter($segment, fn (mixed $value): bool => $value !== null && $value !== []);
}
/**
* One streamed Whisper chunk (not a finished verbose_json document).
*
* @param array<string, mixed> $data
*/
private function isLiveSegmentEvent(mixed $type, array $data): bool
{
$text = $data['text'] ?? null;
if (! is_string($text) || $text === '') {
return false;
}
if ($type === 'segment') {
return true;
}
if ($type !== null && $type !== '') {
return false;
}
if (isset($data['start']) || isset($data['end'])) {
return true;
}
return ! (isset($data['segments']) && is_array($data['segments']));
}
/**
* @return list<string>
*/