Initial commit: Runware-powered content generator foundation
Laravel app with a cost-tracked Runware.ai integration (image, video, text generation), a hard monthly EUR budget cap with live USD/EUR FX conversion, and a locally-maintained model/pricing table since Runware's model-search API doesn't expose pricing.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Runware;
|
||||
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Thin wrapper around Runware's HTTP API. Image and video generation use the
|
||||
* batched task-array endpoint (POST /v1, body is a JSON array of tasks);
|
||||
* text/LLM generation uses Runware's separate OpenAI-compatible endpoint
|
||||
* (POST /v1/chat/completions). See https://runware.ai/docs/platform/introduction
|
||||
* and https://runware.ai/docs/platform/openai.
|
||||
*/
|
||||
class RunwareClient
|
||||
{
|
||||
public function __construct(
|
||||
protected string $apiKey,
|
||||
protected string $baseUrl,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $tasks
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function runTasks(array $tasks): array
|
||||
{
|
||||
$response = Http::withToken($this->apiKey)
|
||||
->timeout(120)
|
||||
->post($this->baseUrl, $tasks);
|
||||
|
||||
if ($response->failed()) {
|
||||
throw new RuntimeException('Runware API request failed: '.$response->body());
|
||||
}
|
||||
|
||||
$data = $response->json('data');
|
||||
|
||||
if (! is_array($data)) {
|
||||
throw new RuntimeException('Unexpected Runware response shape: '.$response->body());
|
||||
}
|
||||
|
||||
foreach ($data as $result) {
|
||||
if (isset($result['error']) || ($result['status'] ?? null) === 'error') {
|
||||
throw new RuntimeException('Runware task failed: '.json_encode($result));
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function pollTask(string $taskUUID): array
|
||||
{
|
||||
$results = $this->runTasks([[
|
||||
'taskType' => 'getResponse',
|
||||
'taskUUID' => $taskUUID,
|
||||
]]);
|
||||
|
||||
return $results[0] ?? throw new RuntimeException("No poll result for task {$taskUUID}");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function chatCompletion(array $payload): array
|
||||
{
|
||||
$response = Http::withToken($this->apiKey)
|
||||
->timeout(120)
|
||||
->post(rtrim($this->baseUrl, '/').'/chat/completions', $payload);
|
||||
|
||||
if ($response->failed()) {
|
||||
throw new RuntimeException('Runware chat completion failed: '.$response->body());
|
||||
}
|
||||
|
||||
return $response->json();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user