buildExtractionPrompt(); $payload = [ "contents" => [ [ "parts" => [ ["text" => $prompt . " If the image is not an invoice, is blank, or is completely unreadable, return ONLY: {\"error\": \"invalid_invoice\"}. DO NOT guess or invent data."], [ "inline_data" => [ "mime_type" => $mimeType, "data" => $base64Data ] ] ] ] ], "generationConfig" => [ "response_mime_type" => "application/json" ] ]; $ch = curl_init(self::$baseUrl . "?key=" . $apiKey); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode !== 200) { error_log("AI Error: Gemini API returned code $httpCode. Response: " . $response); return null; } $result = json_decode($response, true); $textResponse = $result['candidates'][0]['content']['parts'][0]['text'] ?? null; if (!$textResponse) return null; $data = json_decode($textResponse, true); if (isset($data['error']) && $data['error'] === 'invalid_invoice') { return null; } return $data; } }