30) { return true; } // If we're within cooldown period and have made too many requests, deny if (self::$requestCounter >= 5 && $timeSinceLastRequest < 60) { return false; } return true; } /** * Make a request to the OpenAI API */ public static function makeRequest($messages, $model = 'gpt-4', $temperature = 0.7) { // Check rate limiting if (!self::canMakeRequest()) { return [ 'success' => false, 'error' => 'Rate limit exceeded. Please wait before making another request.', 'response' => null ]; } // Get API key from config $apiKey = defined('OPENAI_API_KEY') ? OPENAI_API_KEY : null; if (empty($apiKey)) { return [ 'success' => false, 'error' => 'OpenAI API key not configured', 'response' => null ]; } // Prepare the request data $requestData = [ 'model' => $model, 'messages' => $messages, 'temperature' => $temperature, 'max_tokens' => defined('GPT_MAX_TOKENS') ? GPT_MAX_TOKENS : 500 ]; // Initialize cURL $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'https://api.openai.com/v1/chat/completions', CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($requestData), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . $apiKey ], CURLOPT_TIMEOUT => 30, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_USERAGENT => 'Syndia/1.0' ]); // Execute the request $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); // Update rate limiting counters self::$lastRequestTime = time(); self::$requestCounter++; // Handle cURL errors if ($error) { return [ 'success' => false, 'error' => 'cURL error: ' . $error, 'response' => null ]; } // Parse the response $responseData = json_decode($response, true); if ($httpCode !== 200) { $errorMessage = 'HTTP ' . $httpCode; if (isset($responseData['error']['message'])) { $errorMessage .= ': ' . $responseData['error']['message']; } // Handle rate limiting from OpenAI if ($httpCode === 429) { $errorMessage = 'OpenAI rate limit exceeded. Please wait and try again.'; } return [ 'success' => false, 'error' => $errorMessage, 'response' => null, 'http_code' => $httpCode, 'raw_response' => $response ]; } // Extract the message content if (isset($responseData['choices'][0]['message']['content'])) { return [ 'success' => true, 'error' => null, 'response' => trim($responseData['choices'][0]['message']['content']), 'usage' => $responseData['usage'] ?? null, 'model' => $responseData['model'] ?? $model ]; } else { return [ 'success' => false, 'error' => 'Invalid response format from OpenAI API', 'response' => null, 'raw_response' => $response ]; } } /** * Simple wrapper for text completion requests */ public static function complete($prompt, $model = 'gpt-4', $temperature = 0.7) { $messages = [ [ 'role' => 'user', 'content' => $prompt ] ]; return self::makeRequest($messages, $model, $temperature); } /** * Analyze demographic attribute combination */ public static function analyzeCombination($attr1Name, $choice1, $attr2Name, $choice2) { $prompt = "Analyze this demographic combination for real-world possibility: Attribute 1: {$attr1Name} Choice 1: {$choice1} Attribute 2: {$attr2Name} Choice 2: {$choice2} Question: Is it realistically possible for a person to have both '{$choice1}' for {$attr1Name} AND '{$choice2}' for {$attr2Name} simultaneously in the real world? Consider factors like: - Biological/physical constraints (age, gender, physical abilities) - Legal/social constraints (marriage laws, education requirements) - Logical impossibilities (contradictory states) - Age-related restrictions (employment, marriage, education) - Geographic/cultural factors Respond with: 1. POSSIBLE or IMPOSSIBLE 2. Brief reasoning (1-2 sentences explaining why) Format your response as: VERDICT: [POSSIBLE/IMPOSSIBLE] REASON: [Your reasoning]"; $messages = [ [ "role" => "system", "content" => "You are a demographic analysis expert. Analyze attribute combinations for real-world possibility with practical reasoning. Be conservative - only mark as IMPOSSIBLE if truly incompatible in real world." ], [ "role" => "user", "content" => $prompt ] ]; $response = self::makeRequest($messages, 'gpt-4', 0.3); if (!$response['success']) { return [ 'is_impossible' => false, 'reasoning' => 'GPT analysis failed: ' . $response['error'], 'raw_response' => $response['error'] ]; } $content = $response['response']; // Parse response $isImpossible = false; $reasoning = "Unable to parse GPT response"; if (preg_match('/VERDICT:\s*(POSSIBLE|IMPOSSIBLE)/i', $content, $matches)) { $verdict = strtoupper($matches[1]); $isImpossible = ($verdict === 'IMPOSSIBLE'); } if (preg_match('/REASON:\s*(.+?)(?=\n\n|\n*$)/s', $content, $matches)) { $reasoning = trim($matches[1]); } return [ 'is_impossible' => $isImpossible, 'reasoning' => $reasoning, 'raw_response' => $content ]; } /** * Get current rate limit status */ public static function getRateLimitStatus() { $currentTime = time(); $timeSinceLastRequest = $currentTime - self::$lastRequestTime; return [ 'can_make_request' => self::canMakeRequest(), 'requests_made' => self::$requestCounter, 'time_since_last_request' => $timeSinceLastRequest, 'cooldown_remaining' => max(0, 60 - $timeSinceLastRequest) ]; } } ?>