110 lines
3.2 KiB
PHP
110 lines
3.2 KiB
PHP
<?php
|
|
/**
|
|
* CustomOpenAI - Direct client for OpenAI API to support multimodal features (Vision).
|
|
*/
|
|
class CustomOpenAI {
|
|
private string $apiKey;
|
|
private string $baseUrl = 'https://api.openai.com/v1/chat/completions';
|
|
|
|
public function __construct(string $apiKey) {
|
|
$this->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);
|
|
}
|
|
}
|