Consume faster-whisper SSE instead of blocking on one JSON response, persist growing text and progress over Reverb, and drop the fake percent heartbeat.
92 lines
3.1 KiB
PHP
92 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Services\WhisperTranscriptionStream;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class WhisperTranscriptionStreamTest extends TestCase
|
|
{
|
|
private WhisperTranscriptionStream $stream;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->stream = new WhisperTranscriptionStream;
|
|
}
|
|
|
|
public function test_extracts_sse_data_payloads_from_buffer(): void
|
|
{
|
|
$buffer = "data: {\"type\":\"transcript.text.delta\",\"delta\":\"Hello\"}\n\npartial";
|
|
|
|
$payloads = $this->stream->extractPayloads($buffer);
|
|
|
|
$this->assertSame(['{"type":"transcript.text.delta","delta":"Hello"}'], $payloads);
|
|
$this->assertSame('partial', $buffer);
|
|
}
|
|
|
|
public function test_parses_openai_delta_and_done_events(): void
|
|
{
|
|
$delta = $this->stream->parseEvent('{"type":"transcript.text.delta","delta":"Hello "}');
|
|
$done = $this->stream->parseEvent('{"type":"transcript.text.done","text":"Hello world"}');
|
|
|
|
$this->assertSame('Hello ', $delta['append']);
|
|
$this->assertFalse($delta['done']);
|
|
$this->assertSame('Hello world', $done['replace']);
|
|
$this->assertTrue($done['done']);
|
|
}
|
|
|
|
public function test_parses_legacy_segment_events(): void
|
|
{
|
|
$event = $this->stream->parseEvent('{"text":"First segment","start":0,"end":12.5}');
|
|
|
|
$this->assertTrue($event['legacy']);
|
|
$this->assertSame('First segment', $event['append']);
|
|
$this->assertSame(12.5, $event['end']);
|
|
}
|
|
|
|
public function test_applies_delta_then_done_replace(): void
|
|
{
|
|
$delta = $this->stream->parseEvent('{"type":"transcript.text.delta","delta":"Hel"}');
|
|
$text = $this->stream->applyEvent('', $delta);
|
|
$delta2 = $this->stream->parseEvent('{"type":"transcript.text.delta","delta":"lo"}');
|
|
$text = $this->stream->applyEvent($text, $delta2);
|
|
$done = $this->stream->parseEvent('{"type":"transcript.text.done","text":"Hello world"}');
|
|
$text = $this->stream->applyEvent($text, $done);
|
|
|
|
$this->assertSame('Hello world', $text);
|
|
}
|
|
|
|
public function test_joins_legacy_segments_with_spaces(): void
|
|
{
|
|
$first = $this->stream->parseEvent('{"text":"Hello from","end":10}');
|
|
$second = $this->stream->parseEvent('{"text":"whisper.","end":20}');
|
|
|
|
$text = $this->stream->applyEvent('', $first);
|
|
$text = $this->stream->applyEvent($text, $second);
|
|
|
|
$this->assertSame('Hello from whisper.', $text);
|
|
}
|
|
|
|
public function test_ignores_done_sentinel_and_non_json(): void
|
|
{
|
|
$buffer = "data: [DONE]\n\ndata: not-json\n\n";
|
|
|
|
$payloads = $this->stream->extractPayloads($buffer);
|
|
|
|
$this->assertSame(['not-json'], $payloads);
|
|
$this->assertNull($this->stream->parseEvent('not-json'));
|
|
}
|
|
|
|
public function test_flush_buffer_emits_trailing_frame(): void
|
|
{
|
|
$buffer = 'data: {"text":"Last"}';
|
|
|
|
$payloads = $this->stream->flushBuffer($buffer);
|
|
|
|
$this->assertSame(['{"text":"Last"}'], $payloads);
|
|
$this->assertSame('', $buffer);
|
|
}
|
|
}
|