transcripts()->where('status', '!=', 'failed')->latest()->first(); if ($existing) { return $existing; } $transcript = Transcript::create([ 'owner_ref' => $session->owner_ref, 'session_id' => $session->id, 'recording_id' => $recording?->id, 'status' => 'processing', 'live_captions_enabled' => (bool) $session->room->setting('live_captions', false), ]); $this->populateFromChat($transcript, $session); GenerateAiSummary::dispatch($transcript->id); return $transcript->fresh(); } public function appendSegment(Transcript $transcript, string $speaker, string $text): Transcript { $segments = $transcript->segments ?? []; $segments[] = [ 'speaker' => $speaker, 'text' => trim($text), 'at' => now()->toIso8601String(), ]; $content = collect($segments)->map(fn ($s) => ($s['speaker'] ?? 'Speaker').': '.($s['text'] ?? ''))->implode("\n"); $transcript->update([ 'segments' => $segments, 'content' => $content, 'status' => 'ready', ]); return $transcript; } protected function populateFromChat(Transcript $transcript, Session $session): void { $messages = $session->messages()->orderBy('created_at')->get(); $segments = $messages->map(fn ($m) => [ 'speaker' => $m->sender_name, 'text' => $m->body, 'at' => $m->created_at->toIso8601String(), ])->all(); $content = $messages->map(fn ($m) => $m->sender_name.': '.$m->body)->implode("\n"); $transcript->update([ 'segments' => $segments, 'content' => $content ?: 'No transcript content available.', 'status' => 'ready', ]); } }