Files
muninn/app/Jobs/RunWorkflowStepJob.php
m105andClaude Sonnet 5 55fa2ebfda Add script/TTS step handlers, dashboard, and pipeline UI (#35, #36, #43, #44)
StepHandler abstraction (app/Support/VideoWorkflow/StepHandlers/) plugs
into WorkflowEngine without coupling it to how any given step type is
actually executed:
- ScriptGenerationHandler: builds a prompt from the project's title/
  description (or an explicit outline/tone/keywords/target length in
  step input), generates via an active OpenAI AiProvider, stores the
  result as a 'script' asset.
- TtsVoiceoverHandler: voices step.input.text, or falls back to the
  project's latest script asset, via an active ElevenLabs AiProvider;
  voice_id/model_id are configurable per step. No direct "speed"
  control — ElevenLabs' base TTS endpoint doesn't expose one.

RunWorkflowStepJob resolves a step's handler by type and runs it on
the queue, matching the existing PublishPostJob pattern (including a
stale-dispatch guard: no-op if the step isn't 'in_progress' anymore).

UI, under its own /video-projects routes and nav entry — separate
from /projects per the earlier decision:
- VideoProjects/Index (#43): list projects with status and step
  progress, create new ones.
- VideoProjects/Show (#44): start a project from a WorkflowTemplate or
  a hardcoded default 8-step pipeline; per-step Run/Approve/Reject/
  Retry/Skip actions; auto-queues the next step after any transition
  when a handler exists for its type (steps with no handler yet just
  sit in_progress rather than auto-failing); lists project assets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 20:56:01 +03:00

55 lines
1.6 KiB
PHP

<?php
namespace App\Jobs;
use App\Models\WorkflowStep;
use App\Support\VideoWorkflow\StepHandlers\StepHandlerManager;
use App\Support\VideoWorkflow\WorkflowEngine;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Throwable;
class RunWorkflowStepJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $timeout = 180;
public function __construct(public readonly int $stepId) {}
public function handle(StepHandlerManager $handlers, WorkflowEngine $engine): void
{
$step = WorkflowStep::find($this->stepId);
// Stale/duplicate dispatch — the step moved on (or was retried and
// re-dispatched) before this run got picked up.
if (! $step || $step->status !== 'in_progress') {
return;
}
$handler = $handlers->resolve($step->type);
if (! $handler) {
$engine->failStep($step, "No handler registered for step type '{$step->type}'.");
return;
}
try {
$handler->handle($step, $engine);
} catch (Throwable $e) {
Log::error('workflow step handler threw', ['step_id' => $step->id, 'error' => $e->getMessage()]);
$fresh = $step->fresh();
if ($fresh && $fresh->status === 'in_progress') {
$engine->failStep($fresh, $e->getMessage());
}
}
}
}