withoutMiddleware(EnsurePlatformSession::class); $this->user = User::create([ 'public_id' => 'test-user-transcript', 'name' => 'Test User', 'email' => 'transcript@example.com', ]); $this->organization = Organization::create([ 'owner_ref' => $this->user->public_id, 'name' => 'Test Org', 'slug' => 'test-org-transcript', 'timezone' => 'UTC', 'settings' => ['onboarded' => true], ]); Member::create([ 'owner_ref' => $this->user->public_id, 'organization_id' => $this->organization->id, 'user_ref' => $this->user->public_id, 'role' => 'owner', ]); } public function test_finalize_and_summarize_merges_chat_and_captions_before_dispatching_summary(): void { Queue::fake(); [$session] = $this->liveSession(); Message::create([ 'owner_ref' => $this->user->public_id, 'session_id' => $session->id, 'sender_ref' => $this->user->public_id, 'sender_name' => 'Host', 'body' => 'Let us review the launch timeline.', 'type' => 'public', ]); $service = app(TranscriptService::class); $transcript = $service->getOrCreateForSession($session); $service->appendSegment($transcript, 'Host', 'We should ship the dashboard next week.'); $recording = Recording::create([ 'owner_ref' => $this->user->public_id, 'session_id' => $session->id, 'status' => 'ready', 'layout' => 'gallery', 'started_by_ref' => $this->user->public_id, 'started_at' => now()->subMinutes(30), 'ended_at' => now(), ]); $service->finalizeAndSummarize($session, $recording); $transcript->refresh(); $this->assertSame($recording->id, $transcript->recording_id); $this->assertStringContainsString('Let us review the launch timeline.', $transcript->content); $this->assertStringContainsString('We should ship the dashboard next week.', $transcript->content); Queue::assertPushed(GenerateAiSummary::class, function (GenerateAiSummary $job) use ($transcript) { return $job->transcriptId === $transcript->id; }); } public function test_caption_append_does_not_queue_summary_job(): void { Queue::fake(); [$session] = $this->liveSession(); $service = app(TranscriptService::class); $transcript = $service->getOrCreateForSession($session); $service->appendSegment($transcript, 'Host', 'Opening remarks.'); Queue::assertNothingPushed(); } public function test_caption_segments_collapse_progressive_duplicates(): void { Queue::fake(); [$session] = $this->liveSession(); $service = app(TranscriptService::class); $transcript = $service->getOrCreateForSession($session); $service->appendSegment($transcript, 'Trypose', 'Yeah'); $service->appendSegment($transcript, 'Trypose', 'Yeah I want to ask'); $service->appendSegment($transcript, 'Trypose', 'Yeah I want to ask question please'); $service->appendSegment($transcript, 'Trypose', 'Okay'); $service->appendSegment($transcript, 'Trypose', 'Okay'); $transcript->refresh(); $this->assertSame([ 'Trypose: Yeah I want to ask question please', 'Trypose: Okay', ], explode("\n", $transcript->content)); } /** @return array{0: Session, 1: Participant} */ protected function liveSession(): array { $room = Room::create([ 'organization_id' => $this->organization->id, 'owner_ref' => $this->user->public_id, 'host_user_ref' => $this->user->public_id, 'title' => 'Transcript meeting', 'type' => 'instant', 'status' => 'live', 'timezone' => 'UTC', 'settings' => ['live_captions' => true], ]); $session = Session::create([ 'room_id' => $room->id, 'owner_ref' => $this->user->public_id, 'media_room_name' => 'room-'.$room->uuid, 'status' => 'ended', 'started_at' => now()->subMinutes(30), 'ended_at' => now(), ]); $participant = Participant::create([ 'owner_ref' => $this->user->public_id, 'session_id' => $session->id, 'user_ref' => $this->user->public_id, 'role' => 'host', 'display_name' => 'Host', 'status' => 'joined', 'joined_at' => now()->subMinutes(30), ]); return [$session, $participant]; } }