whereIn('list_type', ['residential', 'commercial']) ->inRandomOrder() ->first(); return Inertia::render('admin/background-gen', [ 'pendingMedia' => $pendingMedia, ]); } public function generate(Request $request) { $request->validate([ 'prompt' => 'required|string|max:1000', 'media_id' => 'required|exists:background_medias,id', ]); $prompt = $request->input('prompt'); // Call Replicate API $replicateResponse = $this->callReplicateAPI($prompt); if (! $replicateResponse || ! isset($replicateResponse['urls']['get'])) { return response()->json(['error' => 'Failed to start generation'], 500); } // Poll for result $result = $this->pollReplicateResult($replicateResponse['urls']['get']); if (! $result || ! isset($result['output'][0])) { return response()->json(['error' => 'Generation failed or timed out'], 500); } return response()->json([ 'success' => true, 'image_url' => $result['output'][0], ]); } public function delete($id) { try { $media = BackgroundMedia::where('id', $id) ->where('status', 'pending_media') ->first(); if (! $media) { return response()->json([ 'success' => false, 'error' => 'Pending media not found or already processed', ], 404); } $media->delete(); return response()->json([ 'success' => true, 'message' => 'Media deleted successfully', ]); } catch (\Exception $e) { \Log::error('Error deleting pending media: '.$e->getMessage()); return response()->json([ 'success' => false, 'error' => 'An error occurred while deleting the media', ], 500); } } public function save(Request $request) { $request->validate([ 'media_id' => 'required|exists:background_medias,id', 'image_url' => 'required|url', 'prompt' => 'required|string', ]); $backgroundMedia = BackgroundMedia::findOrFail($request->input('media_id')); // try { // Use MediaEngine to download and store the image $media = \App\Helpers\FirstParty\MediaEngine\MediaEngine::addMedia( 'system-i', 'image', 'system_uploaded', 'replicate', null, $request->input('image_url'), 'download' ); // Update the background media record $backgroundMedia->update([ 'status' => 'completed', 'media_uuid' => $media->uuid, 'media_url' => \App\Helpers\FirstParty\MediaEngine\MediaEngine::getMediaCloudUrl($media), 'prompt' => $request->input('prompt'), ]); return response()->json(['success' => true]); // } catch (\Exception $e) { // return response()->json(['error' => 'Failed to save media: ' . $e->getMessage()], 500); // } } private function callReplicateAPI($prompt) { $apiToken = config('services.replicate.api_token'); $data = [ 'input' => [ 'prompt' => $prompt, 'go_fast' => true, 'megapixels' => '1', 'num_outputs' => 1, 'aspect_ratio' => '1:1', 'output_format' => 'webp', 'output_quality' => 80, 'num_inference_steps' => 4, ], ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://api.replicate.com/v1/models/black-forest-labs/flux-schnell/predictions'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer '.$apiToken, 'Content-Type: application/json', 'Prefer: wait', ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode !== 201) { return false; } return json_decode($response, true); } private function pollReplicateResult($getUrl) { $maxAttempts = 30; // 5 minutes max (30 * 10 seconds) $attempt = 0; while ($attempt < $maxAttempts) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $getUrl); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer '.config('services.replicate.api_token'), ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode === 200) { $result = json_decode($response, true); if ($result['status'] === 'succeeded' && isset($result['output'][0])) { return $result; } elseif ($result['status'] === 'failed') { return false; } } $attempt++; sleep(3); // Wait 10 seconds before next poll } return false; // Timeout } }