timeout = max(60, (int) config('ai.transcription_timeout', 600)); $this->runStartedAt = $recording->transcription_started_at?->toIso8601String(); } /** * Execute the job. */ public function handle(TranscriptionService $transcription): void { $recording = Recording::query()->find($this->recording->id); if ($recording === null) { return; } $this->recording = $recording; if ($this->runStartedAt !== null && ! $this->recording->ownsTranscriptionRun($this->runStartedAt)) { return; } if ($this->runStartedAt === null && ! $this->recording->isTranscribing()) { return; } $this->recording->forceFill([ 'transcription_status' => 'processing', 'transcription_started_at' => $this->recording->transcription_started_at ?? now(), 'transcription_error' => null, ])->save(); $this->runStartedAt ??= $this->recording->transcription_started_at?->toIso8601String(); $this->reportIfOwned('Preparing audio file…', 15); try { $text = $transcription->transcribe( $this->recording, function (string $message, int $percent): void { $this->reportIfOwned($message, $percent); }, ); if (! $this->recording->ownsTranscriptionRun($this->runStartedAt)) { return; } $this->reportIfOwned('Saving transcript…', 90); if (! $this->recording->ownsTranscriptionRun($this->runStartedAt)) { return; } $this->recording->forceFill([ 'transcript' => $text, 'transcription_status' => 'done', 'transcription_progress' => 'Transcription complete', 'transcription_percent' => 100, 'transcription_error' => null, 'transcribed_at' => now(), ])->save(); } catch (Throwable $e) { if (! $this->recording->ownsTranscriptionRun($this->runStartedAt)) { return; } Log::error('Transcription failed', [ 'recording_id' => $this->recording->id, 'driver' => $this->recording->transcription_driver, 'message' => $e->getMessage(), ]); $this->recording->markTranscriptionFailed($e->getMessage()); throw $e; } } /** * Handle a job failure (timeouts, worker kill, etc.). */ public function failed(?Throwable $e): void { $recording = Recording::query()->find($this->recording->id); if ($recording === null || ! $recording->ownsTranscriptionRun($this->runStartedAt)) { return; } $recording->markTranscriptionFailed( $e?->getMessage() ?: 'Transcription stopped unexpectedly.', ); } private function reportIfOwned(string $message, int $percent): void { if (! $this->recording->ownsTranscriptionRun($this->runStartedAt)) { return; } $this->recording->reportProgress($message, $percent); } }