1*5f0c5114SCharles Chan<?php 2*5f0c5114SCharles Chanclass OpenAIHttpClient { 3*5f0c5114SCharles Chan private $apiKey; 4*5f0c5114SCharles Chan private $baseUrl = ''; 5*5f0c5114SCharles Chan 6*5f0c5114SCharles Chan public function __construct($serverUrl, $apiKey) { 7*5f0c5114SCharles Chan $this->baseUrl = rtrim($serverUrl, '/'); 8*5f0c5114SCharles Chan $this->apiKey = $apiKey; 9*5f0c5114SCharles Chan } 10*5f0c5114SCharles Chan 11*5f0c5114SCharles Chan /** 12*5f0c5114SCharles Chan * 发送聊天请求 13*5f0c5114SCharles Chan */ 14*5f0c5114SCharles Chan public function chatCompletion($params) { 15*5f0c5114SCharles Chan return $this->request('/chat/completions', $params); 16*5f0c5114SCharles Chan } 17*5f0c5114SCharles Chan 18*5f0c5114SCharles Chan /** 19*5f0c5114SCharles Chan * 发送补全请求 20*5f0c5114SCharles Chan */ 21*5f0c5114SCharles Chan public function completion($params) { 22*5f0c5114SCharles Chan return $this->request('/completions', $params); 23*5f0c5114SCharles Chan } 24*5f0c5114SCharles Chan 25*5f0c5114SCharles Chan /** 26*5f0c5114SCharles Chan * 通用 HTTP 请求方法 27*5f0c5114SCharles Chan */ 28*5f0c5114SCharles Chan private function request($endpoint, $data) { 29*5f0c5114SCharles Chan $url = $this->baseUrl . $endpoint; 30*5f0c5114SCharles Chan 31*5f0c5114SCharles Chan $headers = [ 32*5f0c5114SCharles Chan 'Content-Type: application/json', 33*5f0c5114SCharles Chan 'Authorization: Bearer ' . $this->apiKey 34*5f0c5114SCharles Chan ]; 35*5f0c5114SCharles Chan 36*5f0c5114SCharles Chan $ch = curl_init($url); 37*5f0c5114SCharles Chan 38*5f0c5114SCharles Chan curl_setopt_array($ch, [ 39*5f0c5114SCharles Chan CURLOPT_RETURNTRANSFER => true, 40*5f0c5114SCharles Chan CURLOPT_POST => true, 41*5f0c5114SCharles Chan CURLOPT_HTTPHEADER => $headers, 42*5f0c5114SCharles Chan CURLOPT_POSTFIELDS => json_encode($data), 43*5f0c5114SCharles Chan CURLOPT_TIMEOUT => 300, 44*5f0c5114SCharles Chan CURLOPT_SSL_VERIFYPEER => true, 45*5f0c5114SCharles Chan CURLOPT_FAILONERROR => false 46*5f0c5114SCharles Chan ]); 47*5f0c5114SCharles Chan 48*5f0c5114SCharles Chan $response = curl_exec($ch); 49*5f0c5114SCharles Chan $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 50*5f0c5114SCharles Chan $error = curl_error($ch); 51*5f0c5114SCharles Chan curl_close($ch); 52*5f0c5114SCharles Chan 53*5f0c5114SCharles Chan if ($error) { 54*5f0c5114SCharles Chan throw new Exception("cURL Error: " . $error); 55*5f0c5114SCharles Chan } 56*5f0c5114SCharles Chan 57*5f0c5114SCharles Chan $decoded = json_decode($response, true); 58*5f0c5114SCharles Chan 59*5f0c5114SCharles Chan if ($httpCode !== 200) { 60*5f0c5114SCharles Chan $errorMsg = $decoded['error']['message'] ?? "HTTP {$httpCode}"; 61*5f0c5114SCharles Chan throw new Exception("API Error: " . $errorMsg); 62*5f0c5114SCharles Chan } 63*5f0c5114SCharles Chan 64*5f0c5114SCharles Chan return $decoded; 65*5f0c5114SCharles Chan } 66*5f0c5114SCharles Chan 67*5f0c5114SCharles Chan /** 68*5f0c5114SCharles Chan * 流式响应(适合长文本) 69*5f0c5114SCharles Chan */ 70*5f0c5114SCharles Chan public function streamChatCompletion($params, $callback) { 71*5f0c5114SCharles Chan $params['stream'] = true; 72*5f0c5114SCharles Chan $url = $this->baseUrl . '/chat/completions'; 73*5f0c5114SCharles Chan 74*5f0c5114SCharles Chan $headers = [ 75*5f0c5114SCharles Chan 'Content-Type: application/json', 76*5f0c5114SCharles Chan 'Authorization: Bearer ' . $this->apiKey, 77*5f0c5114SCharles Chan 'Accept: text/event-stream', 78*5f0c5114SCharles Chan 'Cache-Control: no-cache' 79*5f0c5114SCharles Chan ]; 80*5f0c5114SCharles Chan 81*5f0c5114SCharles Chan $ch = curl_init($url); 82*5f0c5114SCharles Chan 83*5f0c5114SCharles Chan curl_setopt_array($ch, [ 84*5f0c5114SCharles Chan CURLOPT_RETURNTRANSFER => true, 85*5f0c5114SCharles Chan CURLOPT_POST => true, 86*5f0c5114SCharles Chan CURLOPT_HTTPHEADER => $headers, 87*5f0c5114SCharles Chan CURLOPT_POSTFIELDS => json_encode($params), 88*5f0c5114SCharles Chan CURLOPT_WRITEFUNCTION => function($ch, $data) use ($callback) { 89*5f0c5114SCharles Chan $callback($data); 90*5f0c5114SCharles Chan return strlen($data); 91*5f0c5114SCharles Chan }, 92*5f0c5114SCharles Chan CURLOPT_TIMEOUT => 120 93*5f0c5114SCharles Chan ]); 94*5f0c5114SCharles Chan 95*5f0c5114SCharles Chan curl_exec($ch); 96*5f0c5114SCharles Chan curl_close($ch); 97*5f0c5114SCharles Chan } 98*5f0c5114SCharles Chan 99*5f0c5114SCharles Chan /** 100*5f0c5114SCharles Chan * 获取可用模型列表 101*5f0c5114SCharles Chan */ 102*5f0c5114SCharles Chan public function listModels() { 103*5f0c5114SCharles Chan $url = $this->baseUrl . '/models'; 104*5f0c5114SCharles Chan 105*5f0c5114SCharles Chan $headers = [ 106*5f0c5114SCharles Chan 'Authorization: Bearer ' . $this->apiKey 107*5f0c5114SCharles Chan ]; 108*5f0c5114SCharles Chan 109*5f0c5114SCharles Chan $ch = curl_init($url); 110*5f0c5114SCharles Chan curl_setopt_array($ch, [ 111*5f0c5114SCharles Chan CURLOPT_RETURNTRANSFER => true, 112*5f0c5114SCharles Chan CURLOPT_HTTPHEADER => $headers, 113*5f0c5114SCharles Chan CURLOPT_TIMEOUT => 10 114*5f0c5114SCharles Chan ]); 115*5f0c5114SCharles Chan 116*5f0c5114SCharles Chan $response = curl_exec($ch); 117*5f0c5114SCharles Chan curl_close($ch); 118*5f0c5114SCharles Chan 119*5f0c5114SCharles Chan return json_decode($response, true); 120*5f0c5114SCharles Chan } 121*5f0c5114SCharles Chan} 122