Source path: app/Services/Ai/Video/ReplicateVideo.php
Extracted from supplied specification. Review before copying into application.

<?php
namespace App\Services\Ai\Video;

use App\Services\Ai\VideoProvider;
use Illuminate\Support\Facades\Http;

class ReplicateVideo implements VideoProvider
{
    public function configured(array $c): bool { return !empty($c['api_key']) && !empty($c['model']); }

    public function submit(string $prompt, array $opts, array $c): array
    {
        $res = Http::withToken($c['api_key'])
            ->post("https://api.replicate.com/v1/models/{$c['model']}/predictions", [
                'input' => ['prompt' => $prompt, 'aspect_ratio' => $opts['aspect'] ?? '9:16'],
            ])->throw();
        return ['id' => $res->json('id')];
    }

    public function poll(array $meta, array $c): array
    {
        $r = Http::withToken($c['api_key'])->get("https://api.replicate.com/v1/predictions/{$meta['id']}")->throw();
        $s = $r->json('status');

        if (in_array($s, ['starting', 'processing'])) return ['status' => 'processing'];
        if ($s !== 'succeeded') return ['status' => 'failed', 'error' => $r->json('error') ?? $s];

        $o = $r->json('output');
        return ['status' => 'succeeded', 'url' => is_array($o) ? $o[0] : $o];
    }
}

Input field names (aspect_ratio, etc.) differ per video model, so check the model’s schema and adjust submit().

Text (captions), one driver for all OpenAI-compatible APIs
