false, 'error' => 'input_missing', 'message' => 'Parameter "input" is required.']; } if (!isset($payload['model']) || $payload['model'] === '') { $payload['model'] = $cfg['default_model']; } $initial = self::request($options['path'] ?? null, $payload, $options); if (empty($initial['success'])) return $initial; $data = $initial['data'] ?? null; if (is_array($data) && isset($data['ai_request_id'])) { return self::awaitResponse($data['ai_request_id'], $options); } return $initial; } private static function directRequest(array $params, string $apiKey): array { $url = 'https://api.openai.com/v1/chat/completions'; // Map input to messages $messages = []; foreach ($params['input'] as $msg) { $messages[] = ['role' => $msg['role'] ?? 'user', 'content' => $msg['content'] ?? '']; } $payload = [ 'model' => $params['model'] ?? 'gpt-4o', 'messages' => $messages ]; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Authorization: Bearer ' . $apiKey ]); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); $result = curl_exec($ch); $err = curl_error($ch); curl_close($ch); if ($err) return ['success' => false, 'error' => $err]; $data = json_decode($result, true); // Wrap to match existing structure return [ 'success' => true, 'data' => [ 'choices' => $data['choices'] ?? [] ] ]; } public static function create_response(array $params, array $options = []): array { return self::createResponse($params, $options); } public static function request(?string $path = null, array $payload = [], array $options = []): array { $cfg = self::config(); $projectUuid = $cfg['project_uuid']; $defaultPath = $cfg['responses_path'] ?? null; $resolvedPath = $path ?? ($options['path'] ?? $defaultPath); $url = self::buildUrl($resolvedPath, $cfg['base_url']); $timeout = isset($options['timeout']) ? (int) $options['timeout'] : 30; $headers = ['Content-Type: application/json', 'Accept: application/json', ($cfg['project_header'] ?? 'Project-UUID') . ': ' . $projectUuid]; $payload['project_uuid'] = $projectUuid; return self::sendCurl($url, 'POST', json_encode($payload), $headers, $timeout, true); } public static function awaitResponse($aiRequestId, array $options = []): array { $deadline = time() + 300; while (time() < $deadline) { $statusResp = self::fetchStatus($aiRequestId); if (!empty($statusResp['success'])) { $data = $statusResp['data']; if (($data['status'] ?? '') === 'success') return ['success' => true, 'data' => $data['response'] ?? $data]; if (($data['status'] ?? '') === 'failed') return ['success' => false, 'error' => 'AI request failed']; } sleep(5); } return ['success' => false, 'error' => 'timeout']; } public static function fetchStatus($aiRequestId): array { $cfg = self::config(); $url = self::buildUrl('/ai-request/' . rawurlencode((string)$aiRequestId) . '/status', $cfg['base_url']); $headers = [($cfg['project_header'] ?? 'Project-UUID') . ': ' . $cfg['project_uuid']]; return self::sendCurl($url, 'GET', null, $headers, 30, true); } public static function extractText(array $response): string { $payload = $response['data'] ?? $response; if (!empty($payload['choices'][0]['message']['content'])) return (string) $payload['choices'][0]['message']['content']; return ''; } private static function config(): array { if (self::$configCache === null) self::$configCache = require __DIR__ . '/config.php'; return self::$configCache; } private static function buildUrl(string $path, string $baseUrl): string { return str_starts_with($path, 'http') ? $path : $baseUrl . '/' . ltrim($path, '/'); } private static function sendCurl(string $url, string $method, ?string $body, array $headers, int $timeout, bool $verifyTls): array { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_SSL_VERIFYPEER => $verifyTls, ]); if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $body); } $resp = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return ['success' => ($status >= 200 && $status < 300), 'data' => json_decode($resp, true)]; } }