232 lines
8.3 KiB
PHP
232 lines
8.3 KiB
PHP
<?php
|
|
|
|
namespace App\Api\Plugins;
|
|
|
|
use App\Models\ApiProvider;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Str;
|
|
|
|
class RunwareAi implements ApiPluginInterface
|
|
{
|
|
use LoggablePlugin;
|
|
|
|
protected $apiProvider;
|
|
|
|
public function __construct(ApiProvider $apiProvider)
|
|
{
|
|
$this->apiProvider = $apiProvider;
|
|
$this->logInfo('RunwareAi plugin initialized.', ['provider_name' => $apiProvider->name]);
|
|
}
|
|
|
|
public function getIdentifier(): string
|
|
{
|
|
return 'runwareai';
|
|
}
|
|
|
|
public function getName(): string
|
|
{
|
|
return 'RunwareAI';
|
|
}
|
|
|
|
public function isEnabled(): bool
|
|
{
|
|
return $this->apiProvider->enabled;
|
|
}
|
|
|
|
public function enable(): bool
|
|
{
|
|
$this->apiProvider->enabled = true;
|
|
$result = $this->apiProvider->save();
|
|
if ($result) {
|
|
$this->logInfo('RunwareAi plugin enabled.', ['provider_name' => $this->apiProvider->name]);
|
|
} else {
|
|
$this->logError('Failed to enable RunwareAi plugin.', ['provider_name' => $this->apiProvider->name]);
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
public function disable(): bool
|
|
{
|
|
$this->apiProvider->enabled = false;
|
|
$result = $this->apiProvider->save();
|
|
if ($result) {
|
|
$this->logInfo('RunwareAi plugin disabled.', ['provider_name' => $this->apiProvider->name]);
|
|
} else {
|
|
$this->logError('Failed to disable RunwareAi plugin.', ['provider_name' => $this->apiProvider->name]);
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
public function getStatus(string $imageUUID): array
|
|
{
|
|
$this->logDebug('Getting status for image.', ['image_uuid' => $imageUUID]);
|
|
// Implement RunwareAI specific status check
|
|
return ['status' => 'unknown'];
|
|
}
|
|
|
|
public function getProgress(string $imageUUID): array
|
|
{
|
|
$this->logDebug('Getting progress for image.', ['image_uuid' => $imageUUID]);
|
|
// Implement RunwareAI specific progress check
|
|
return ['progress' => 0];
|
|
}
|
|
|
|
public function processImageStyleChange(\App\Models\Image $image, \App\Models\Style $style): array
|
|
{
|
|
// Step 1: Upload the original image
|
|
$uploadResult = $this->upload(public_path('storage/' . $image->path));
|
|
|
|
if (!isset($uploadResult['data'][0]['imageUUID'])) {
|
|
throw new \Exception('Image upload to AI service failed or returned no UUID.');
|
|
}
|
|
$seedImageUUID = $uploadResult['data'][0]['imageUUID'];
|
|
|
|
// Step 2: Request style change using the uploaded image's UUID
|
|
$result = $this->styleChangeRequest($style, $seedImageUUID);
|
|
|
|
if (!isset($result['base64Data'])) {
|
|
throw new \Exception('AI service did not return base64 image data.');
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function testConnection(array $data): bool
|
|
{
|
|
$apiUrl = rtrim($data['api_url'], '/');
|
|
$token = $data['token'] ?? null;
|
|
|
|
if (!$apiUrl || !$token) {
|
|
$this->logError('RunwareAI connection test failed: API URL or Token missing.');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$response = Http::withHeaders([
|
|
'Content-Type' => 'application/json',
|
|
'Accept' => 'application/json',
|
|
])->timeout(5)->post($apiUrl, [
|
|
[
|
|
'taskType' => 'authentication',
|
|
'apiKey' => $token,
|
|
]
|
|
]);
|
|
|
|
$responseData = $response->json();
|
|
|
|
if ($response->successful() && isset($responseData['data']) && !isset($responseData['error'])) {
|
|
$this->logInfo('RunwareAI connection test successful: Authentication successful.', [
|
|
'status' => $response->status(),
|
|
'response' => $responseData,
|
|
]);
|
|
return true;
|
|
} else {
|
|
$errorMessage = $responseData['error'] ?? 'Unknown error';
|
|
$this->logError('RunwareAI connection test failed: Authentication failed.', [
|
|
'status' => $response->status(),
|
|
'response' => $responseData,
|
|
'error_message' => $errorMessage,
|
|
]);
|
|
return false;
|
|
}
|
|
} catch (\Exception $e) {
|
|
$this->logError('RunwareAI connection test failed: Exception caught.', ['error' => $e->getMessage()]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private function upload(string $imagePath): array
|
|
{
|
|
$this->logInfo('Attempting to upload image to RunwareAI.', ['image_path' => $imagePath]);
|
|
if (!$this->apiProvider->api_url || !$this->apiProvider->token) {
|
|
$this->logError('RunwareAI API URL or Token not configured for upload.', ['provider_name' => $this->apiProvider->name]);
|
|
throw new \Exception('RunwareAI API URL or Token not configured.');
|
|
}
|
|
|
|
$apiUrl = rtrim($this->apiProvider->api_url, '/');
|
|
$token = $this->apiProvider->token;
|
|
$taskUUID = (string) Str::uuid();
|
|
|
|
$imageData = 'data:image/png;base64,' . base64_encode(file_get_contents($imagePath));
|
|
|
|
try {
|
|
$response = Http::withHeaders([
|
|
'Authorization' => 'Bearer ' . $token,
|
|
'Accept' => 'application/json',
|
|
'Content-Type' => 'application/json',
|
|
])->post($apiUrl, [
|
|
[
|
|
'taskType' => 'imageUpload',
|
|
'taskUUID' => $taskUUID,
|
|
'image' => $imageData,
|
|
]
|
|
]);
|
|
|
|
$response->throw();
|
|
$this->logInfo('Image uploaded successfully to RunwareAI.', ['task_uuid' => $taskUUID, 'response' => $response->json()]);
|
|
return $response->json();
|
|
} catch (\Exception $e) {
|
|
$this->logError('Image upload to RunwareAI failed.', ['error' => $e->getMessage(), 'image_path' => $imagePath]);
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
private function styleChangeRequest(\App\Models\Style $style, string $seedImageUUID): array
|
|
{
|
|
$this->logInfo('Attempting style change request to RunwareAI.', ['style_id' => $style->id, 'seed_image_uuid' => $seedImageUUID]);
|
|
if (!$this->apiProvider->api_url || !$this->apiProvider->token) {
|
|
$this->logError('RunwareAI API URL or Token not configured for style change.', ['provider_name' => $this->apiProvider->name]);
|
|
throw new \Exception('RunwareAI API URL or Token not configured.');
|
|
}
|
|
|
|
$apiUrl = rtrim($this->apiProvider->api_url, '/');
|
|
$token = $this->apiProvider->token;
|
|
$taskUUID = (string) Str::uuid();
|
|
|
|
$modelParams = $style->aiModel->parameters ?? [];
|
|
$styleParams = $style->parameters ?? [];
|
|
$mergedParams = array_replace_recursive($modelParams, $styleParams);
|
|
|
|
$data = [
|
|
'taskType' => 'imageInference',
|
|
'taskUUID' => $taskUUID,
|
|
'positivePrompt' => $style->prompt,
|
|
'seedImage' => $seedImageUUID,
|
|
'outputType' => 'base64Data',
|
|
'model' => $style->aiModel->model_id,
|
|
];
|
|
|
|
foreach ($mergedParams as $key => $value) {
|
|
$data[$key] = $value;
|
|
}
|
|
|
|
try {
|
|
$response = Http::withHeaders([
|
|
'Authorization' => 'Bearer ' . $token,
|
|
'Accept' => 'application/json',
|
|
])->post($apiUrl, [
|
|
$data
|
|
]);
|
|
|
|
$response->throw();
|
|
$responseData = $response->json();
|
|
|
|
if (!isset($responseData['data'][0]['imageBase64Data'])) {
|
|
throw new \Exception('AI service did not return base64 image data.');
|
|
}
|
|
|
|
$base64Image = $responseData['data'][0]['imageBase64Data'];
|
|
|
|
$this->logInfo('Style change request successful to RunwareAI.', ['task_uuid' => $taskUUID, 'response' => $responseData]);
|
|
return ['base64Data' => $base64Image];
|
|
} catch (\Exception $e) {
|
|
$errorData = [];
|
|
/*if ($e instanceof \Illuminate\Http\Client\RequestException && $e->response) {
|
|
$errorData['response_body'] = $e->response->body();
|
|
$errorData['response_status'] = $e->response->status();
|
|
}*/
|
|
$this->logError('Style change request to RunwareAI failed.', ['error' => $e->getMessage(), 'task_uuid' => $taskUUID] + $errorData);
|
|
throw $e;
|
|
}
|
|
}
|
|
} |