apiKey = $apiKey; } /** * Analyze an image (base64 or URL) with a prompt. */ public function analyze(array $params): array { $model = $params['model'] ?? 'gpt-4o'; $prompt = $params['prompt'] ?? 'Analyze this image'; $content = [['type' => 'text', 'text' => $prompt]]; if (!empty($params['image_base64'])) { $type = $params['image_type'] ?? 'image/jpeg'; $content[] = [ 'type' => 'image_url', 'image_url' => [ 'url' => "data:$type;base64," . $params['image_base64'] ] ]; } elseif (!empty($params['image_url'])) { $content[] = [ 'type' => 'image_url', 'image_url' => [ 'url' => $params['image_url'] ] ]; } $payload = [ 'model' => $model, 'messages' => [ [ 'role' => 'user', 'content' => $content ] ], 'max_tokens' => 2000 ]; return $this->request($payload); } private function request(array $payload): array { $ch = curl_init($this->baseUrl); $jsonPayload = json_encode($payload); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $jsonPayload, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . $this->apiKey ], CURLOPT_TIMEOUT => 60 ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($response === false) { return [ 'success' => false, 'error' => 'cURL Error: ' . $curlError ]; } $decoded = json_decode($response, true); if ($httpCode !== 200) { return [ 'success' => false, 'error' => $decoded['error']['message'] ?? 'OpenAI API Error (Status: ' . $httpCode . ')', 'raw' => $decoded ]; } return [ 'success' => true, 'data' => $decoded ]; } public static function extractText(array $response): string { return $response['data']['choices'][0]['message']['content'] ?? ''; } public static function decodeJson(array $response): ?array { $text = self::extractText($response); if (empty($text)) return null; $decoded = json_decode($text, true); if (is_array($decoded)) return $decoded; // Try stripping markdown fences $stripped = preg_replace('/^```json|```$/m', '', trim($text)); return json_decode($stripped, true); } }