markTestSkipped('curl extension required'); } Storage::fake('local'); Storage::disk('local')->put('recordings/large.mp3', str_repeat('A', 2_000_000)); $stub = base_path('tests/fixtures/whisper-sse-stub.php'); $host = '127.0.0.1'; $port = $this->reservePort($host); $docRoot = base_path('tests/fixtures'); $server = Process::timeout(30) ->path($docRoot) ->start([ PHP_BINARY, '-S', "{$host}:{$port}", 'whisper-sse-stub.php', ]); try { $this->waitForServer($host, $port); config([ 'ai.local_whisper_transport' => 'curl', 'ai.providers.local-whisper.url' => "http://{$host}:{$port}/v1", 'ai.providers.local-whisper.key' => 'test-key', ]); $user = User::factory()->create(); $recording = Recording::query()->create([ 'user_id' => $user->id, 'title' => 'Curl transport', 'original_filename' => 'large.mp3', 'file_path' => 'recordings/large.mp3', 'file_size_bytes' => 2_000_000, 'duration_seconds' => 40, 'transcription_status' => 'processing', 'transcription_driver' => 'local', ]); $partials = []; $text = app(TranscriptionService::class)->transcribe( $recording, function (string $message, int $percent, ?string $partial = null) use (&$partials): void { if ($partial !== null) { $partials[] = $partial; } }, ); $this->assertSame('Hello from whisper.', $text); $this->assertContains('Hello ', $partials); $this->assertContains('Hello from whisper.', $partials); } finally { $server->signal(SIGTERM); $server->wait(); } } private function reservePort(string $host): int { $socket = stream_socket_server("tcp://{$host}:0"); if ($socket === false) { $this->fail('Unable to reserve a local TCP port for the Whisper stub.'); } $name = stream_socket_get_name($socket, false); fclose($socket); if (! is_string($name) || ! str_contains($name, ':')) { $this->fail('Unable to determine reserved port.'); } return (int) substr($name, strrpos($name, ':') + 1); } private function waitForServer(string $host, int $port): void { $deadline = microtime(true) + 5; while (microtime(true) < $deadline) { $errno = 0; $errstr = ''; $fp = @fsockopen($host, $port, $errno, $errstr, 0.2); if (is_resource($fp)) { fclose($fp); return; } usleep(50_000); } $this->fail("Whisper stub server did not start on {$host}:{$port}"); } }