From bb55ea8e083dbd5dc8ac7d6f050523c5c918f4de Mon Sep 17 00:00:00 2001 From: pro Date: Wed, 28 Jan 2026 08:45:43 +0900 Subject: [PATCH] =?UTF-8?q?fix:Vertex=20AI=20API=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EC=8B=9C=20role=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Vertex AI는 contents에 role: 'user' 필수 - Google AI Studio와 Vertex AI 분기 처리 Co-Authored-By: Claude Opus 4.5 --- app/Services/BusinessCardOcrService.php | 41 ++++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/app/Services/BusinessCardOcrService.php b/app/Services/BusinessCardOcrService.php index d3ff331b..15bf9034 100644 --- a/app/Services/BusinessCardOcrService.php +++ b/app/Services/BusinessCardOcrService.php @@ -53,7 +53,7 @@ private function callVertexAiApi(AiConfig $config, string $base64Image): array return $this->callGeminiApi($url, $base64Image, [ 'Authorization' => 'Bearer ' . $accessToken, 'Content-Type' => 'application/json', - ]); + ], true); // Vertex AI } /** @@ -69,13 +69,13 @@ private function callGoogleAiStudioApi(AiConfig $config, string $base64Image): a return $this->callGeminiApi($url, $base64Image, [ 'Content-Type' => 'application/json', - ]); + ], false); // Google AI Studio } /** * Gemini API 공통 호출 로직 */ - private function callGeminiApi(string $url, string $base64Image, array $headers): array + private function callGeminiApi(string $url, string $base64Image, array $headers, bool $isVertexAi = false): array { // Base64 데이터에서 prefix 제거 $imageData = $base64Image; @@ -88,25 +88,30 @@ private function callGeminiApi(string $url, string $base64Image, array $headers) $prompt = $this->buildPrompt(); + // Vertex AI는 role 필드 필요 + $content = [ + 'parts' => [ + [ + 'inlineData' => [ + 'mimeType' => $mimeType, + 'data' => $imageData, + ], + ], + [ + 'text' => $prompt, + ], + ], + ]; + + if ($isVertexAi) { + $content['role'] = 'user'; + } + try { $response = Http::timeout(30) ->withHeaders($headers) ->post($url, [ - 'contents' => [ - [ - 'parts' => [ - [ - 'inlineData' => [ - 'mimeType' => $mimeType, - 'data' => $imageData, - ], - ], - [ - 'text' => $prompt, - ], - ], - ], - ], + 'contents' => [$content], 'generationConfig' => [ 'temperature' => 0.1, 'topK' => 40,