Stream Whisper verbose metadata live without overflowing Reverb.
Persist accumulated verbose_json on the recording and broadcast only transcript/whisper deltas so the show page can render language, segments, word timestamps, and confidence while a run is in progress.
This commit is contained in:
@@ -125,12 +125,37 @@ class IndexTest extends TestCase
|
||||
|
||||
Livewire::test(Index::class)
|
||||
->assertSee('wire:poll', false)
|
||||
->assertDontSee('echo-private', false)
|
||||
->assertSee('Transcribing')
|
||||
->assertSee('40%')
|
||||
->assertDontSee('Transcribing locally…')
|
||||
->assertSeeHtml('bg-amber-400');
|
||||
}
|
||||
|
||||
public function test_processing_recordings_do_not_show_zero_percent(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
Recording::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'title' => 'Just started',
|
||||
'original_filename' => 'fresh.mp3',
|
||||
'file_path' => 'recordings/fresh.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'processing',
|
||||
'transcription_progress' => 'Transcribing locally…',
|
||||
'transcription_percent' => 0,
|
||||
'transcription_driver' => 'local',
|
||||
'transcription_started_at' => now(),
|
||||
]);
|
||||
|
||||
Livewire::test(Index::class)
|
||||
->assertSee('Just started')
|
||||
->assertSee('Transcribing')
|
||||
->assertDontSee('0%');
|
||||
}
|
||||
|
||||
public function test_queued_recordings_do_not_show_fake_percent(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
@@ -60,7 +60,7 @@ class ShowTest extends TestCase
|
||||
$this->assertDatabaseMissing('recordings', ['id' => $recording->id]);
|
||||
}
|
||||
|
||||
public function test_show_polls_while_transcription_is_active(): void
|
||||
public function test_show_polls_while_transcription_is_queued(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
@@ -71,7 +71,7 @@ class ShowTest extends TestCase
|
||||
'original_filename' => 'active.mp3',
|
||||
'file_path' => 'recordings/active.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'processing',
|
||||
'transcription_status' => 'pending',
|
||||
'transcription_progress' => 'Queued — waiting to start…',
|
||||
'transcription_percent' => null,
|
||||
'transcription_driver' => 'local',
|
||||
@@ -80,9 +80,33 @@ class ShowTest extends TestCase
|
||||
|
||||
Livewire::test(Show::class, ['recording' => $recording])
|
||||
->assertSee('wire:poll', false)
|
||||
->assertDontSee('echo-private', false)
|
||||
->assertSee('Queued — waiting to start…');
|
||||
}
|
||||
|
||||
public function test_show_does_not_poll_while_transcription_is_processing(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$recording = Recording::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'title' => 'Live stream',
|
||||
'original_filename' => 'active.mp3',
|
||||
'file_path' => 'recordings/active.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'processing',
|
||||
'transcription_progress' => 'Transcribing locally…',
|
||||
'transcription_percent' => 20,
|
||||
'transcription_driver' => 'local',
|
||||
'transcription_started_at' => now(),
|
||||
]);
|
||||
|
||||
Livewire::test(Show::class, ['recording' => $recording])
|
||||
->assertDontSee('wire:poll', false)
|
||||
->assertSee('userId', false);
|
||||
}
|
||||
|
||||
public function test_show_page_includes_partial_transcript_while_processing(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
@@ -107,6 +131,44 @@ class ShowTest extends TestCase
|
||||
->assertSee('status.transcript', false);
|
||||
}
|
||||
|
||||
public function test_show_page_includes_live_whisper_segment_bindings(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$recording = Recording::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'title' => 'Verbose live',
|
||||
'original_filename' => 'active.mp3',
|
||||
'file_path' => 'recordings/active.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'processing',
|
||||
'transcription_driver' => 'local',
|
||||
'transcription_started_at' => now(),
|
||||
'transcript' => 'Hello',
|
||||
'transcription_verbose' => [
|
||||
'language' => 'en',
|
||||
'duration' => 4.0,
|
||||
'segments' => [
|
||||
[
|
||||
'text' => 'Hello',
|
||||
'start' => 0.0,
|
||||
'end' => 1.0,
|
||||
'avg_logprob' => -0.1,
|
||||
'words' => [
|
||||
['word' => 'Hello', 'start' => 0.0, 'end' => 1.0, 'probability' => 0.9],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
Livewire::test(Show::class, ['recording' => $recording])
|
||||
->assertSee('whisper.segments', false)
|
||||
->assertSee('whisper.language', false)
|
||||
->assertSee('Hello');
|
||||
}
|
||||
|
||||
public function test_show_does_not_poll_when_transcription_is_idle(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
@@ -126,7 +188,7 @@ class ShowTest extends TestCase
|
||||
->assertDontSee('wire:poll', false);
|
||||
}
|
||||
|
||||
public function test_show_refreshes_recording_on_transcription_broadcast(): void
|
||||
public function test_show_poll_refresh_picks_up_processing_status(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
@@ -152,12 +214,68 @@ class ShowTest extends TestCase
|
||||
]);
|
||||
|
||||
$component
|
||||
->call('onTranscriptionUpdated', [
|
||||
'id' => $recording->id,
|
||||
'status' => 'processing',
|
||||
])
|
||||
->call('$refresh')
|
||||
->assertSet('recording.transcription_status', 'processing')
|
||||
->assertSet('recording.transcription_percent', 40)
|
||||
->assertSee('Transcribing locally…');
|
||||
}
|
||||
|
||||
public function test_show_poll_refresh_picks_up_completed_transcript(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$recording = Recording::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'title' => 'Almost done',
|
||||
'original_filename' => 'live.mp3',
|
||||
'file_path' => 'recordings/live.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'processing',
|
||||
'transcription_progress' => 'Transcribing locally…',
|
||||
'transcription_percent' => 90,
|
||||
'transcription_driver' => 'local',
|
||||
'transcription_started_at' => now(),
|
||||
'transcript' => 'Partial',
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Show::class, ['recording' => $recording]);
|
||||
|
||||
$recording->update([
|
||||
'transcription_status' => 'done',
|
||||
'transcription_percent' => 100,
|
||||
'transcript' => 'Finished live transcript',
|
||||
'transcribed_at' => now(),
|
||||
]);
|
||||
|
||||
$component
|
||||
->call('$refresh')
|
||||
->assertSet('recording.transcription_status', 'done')
|
||||
->assertSet('recording.transcription_percent', 100)
|
||||
->assertSee('Finished live transcript');
|
||||
}
|
||||
|
||||
public function test_show_alpine_root_key_does_not_include_percent(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$recording = Recording::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'title' => 'Stable key',
|
||||
'original_filename' => 'live.mp3',
|
||||
'file_path' => 'recordings/live.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'processing',
|
||||
'transcription_progress' => 'Transcribing locally…',
|
||||
'transcription_percent' => 62,
|
||||
'transcription_driver' => 'local',
|
||||
'transcription_started_at' => now(),
|
||||
]);
|
||||
|
||||
Livewire::test(Show::class, ['recording' => $recording])
|
||||
->assertSee('wire:ignore.self', false)
|
||||
->assertSee('transcription-ui-'.$recording->id.'-processing-', false)
|
||||
->assertDontSee('transcription-ui-'.$recording->id.'-processing-62', false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user