sizeFromAspect($aspect); $endpoint = $baseUrl.'/'.ltrim($model, '/'); $urls = []; for ($i = 0; $i < $count; $i++) { $seed = random_int(1, 999999999); $payload = [ 'inputs' => $cleanPrompt, 'parameters' => [ 'width' => $width, 'height' => $height, 'num_inference_steps' => 28, 'guidance_scale' => 7.5, 'seed' => $seed, ], 'options' => [ 'wait_for_model' => true, 'use_cache' => false, ], ]; $response = Http::timeout($timeout) ->withHeaders([ 'Authorization' => 'Bearer '.$token, 'Accept' => 'image/png', 'Content-Type' => 'application/json', ]) ->withBody((string) json_encode($payload, JSON_UNESCAPED_SLASHES), 'application/json') ->send('POST', $endpoint); if (! $response->successful()) { $message = trim((string) data_get($response->json(), 'error', data_get($response->json(), 'message', $response->body()))); throw new RuntimeException('Hugging Face image request gagal: '.$response->status().' - '.Str::limit($message, 240)); } $contentType = strtolower((string) $response->header('Content-Type', '')); if (! Str::contains($contentType, 'image/')) { $jsonError = trim((string) data_get($response->json(), 'error', data_get($response->json(), 'message', 'Output model bukan image.'))); throw new RuntimeException('Hugging Face tidak mengembalikan image: '.Str::limit($jsonError, 240)); } $binary = $response->body(); if ($binary === '') { throw new RuntimeException('Output image Hugging Face kosong.'); } $extension = $this->extensionFromMime($contentType); $filename = 'hf_'.now()->format('Ymd_His').'_'.Str::lower(Str::random(8)).'.'.$extension; $relativePath = 'images/'.$filename; Storage::disk('public')->put($relativePath, $binary); $urls[] = $this->offloadPublicPath($relativePath); } if ($urls === []) { throw new RuntimeException('Hugging Face tidak mengembalikan URL image.'); } return $urls; } private function sizeFromAspect(string $aspect): array { return match ($aspect) { 'portrait' => [768, 1344], 'square' => [1024, 1024], default => [1344, 768], }; } private function extensionFromMime(string $mime): string { return match (Str::before($mime, ';')) { 'image/jpeg' => 'jpg', 'image/webp' => 'webp', 'image/png' => 'png', default => 'png', }; } private function offloadPublicPath(string $relativePath): string { try { return $this->hfMedia()->offloadPublicRelativePath($relativePath); } catch (\Throwable) { return Storage::url($relativePath); } } private function hfMedia(): HuggingFaceMediaStorageService { if ($this->hfMediaStorage instanceof HuggingFaceMediaStorageService) { return $this->hfMediaStorage; } $service = app(HuggingFaceMediaStorageService::class); if (! $service instanceof HuggingFaceMediaStorageService) { throw new RuntimeException('Service HuggingFaceMediaStorageService tidak tersedia.'); } $this->hfMediaStorage = $service; return $this->hfMediaStorage; } }