15f0c5114SCharles Chan<?php 25f0c5114SCharles Chanclass OpenAIHttpClient { 35f0c5114SCharles Chan private $apiKey; 45f0c5114SCharles Chan private $baseUrl = ''; 55f0c5114SCharles Chan 65f0c5114SCharles Chan public function __construct($serverUrl, $apiKey) { 75f0c5114SCharles Chan $this->baseUrl = rtrim($serverUrl, '/'); 85f0c5114SCharles Chan $this->apiKey = $apiKey; 95f0c5114SCharles Chan } 105f0c5114SCharles Chan 115f0c5114SCharles Chan /** 125f0c5114SCharles Chan * 发送聊天请求 135f0c5114SCharles Chan */ 145f0c5114SCharles Chan public function chatCompletion($params) { 15*abb7d3a8SCharles Chan return $this->request('/v1/chat/completions', $params); 165f0c5114SCharles Chan } 175f0c5114SCharles Chan 185f0c5114SCharles Chan /** 195f0c5114SCharles Chan * 发送补全请求 205f0c5114SCharles Chan */ 215f0c5114SCharles Chan public function completion($params) { 22*abb7d3a8SCharles Chan return $this->request('/v1/completions', $params); 235f0c5114SCharles Chan } 245f0c5114SCharles Chan 255f0c5114SCharles Chan /** 265f0c5114SCharles Chan * 通用 HTTP 请求方法 275f0c5114SCharles Chan */ 285f0c5114SCharles Chan private function request($endpoint, $data) { 295f0c5114SCharles Chan $url = $this->baseUrl . $endpoint; 305f0c5114SCharles Chan 315f0c5114SCharles Chan $headers = [ 325f0c5114SCharles Chan 'Content-Type: application/json', 335f0c5114SCharles Chan 'Authorization: Bearer ' . $this->apiKey 345f0c5114SCharles Chan ]; 355f0c5114SCharles Chan 365f0c5114SCharles Chan $ch = curl_init($url); 375f0c5114SCharles Chan 385f0c5114SCharles Chan curl_setopt_array($ch, [ 395f0c5114SCharles Chan CURLOPT_RETURNTRANSFER => true, 405f0c5114SCharles Chan CURLOPT_POST => true, 415f0c5114SCharles Chan CURLOPT_HTTPHEADER => $headers, 425f0c5114SCharles Chan CURLOPT_POSTFIELDS => json_encode($data), 435f0c5114SCharles Chan CURLOPT_TIMEOUT => 300, 445f0c5114SCharles Chan CURLOPT_SSL_VERIFYPEER => true, 455f0c5114SCharles Chan CURLOPT_FAILONERROR => false 465f0c5114SCharles Chan ]); 475f0c5114SCharles Chan 485f0c5114SCharles Chan $response = curl_exec($ch); 495f0c5114SCharles Chan $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 505f0c5114SCharles Chan $error = curl_error($ch); 515f0c5114SCharles Chan curl_close($ch); 525f0c5114SCharles Chan 535f0c5114SCharles Chan if ($error) { 545f0c5114SCharles Chan throw new Exception("cURL Error: " . $error); 555f0c5114SCharles Chan } 565f0c5114SCharles Chan 575f0c5114SCharles Chan $decoded = json_decode($response, true); 585f0c5114SCharles Chan 595f0c5114SCharles Chan if ($httpCode !== 200) { 605f0c5114SCharles Chan $errorMsg = $decoded['error']['message'] ?? "HTTP {$httpCode}"; 615f0c5114SCharles Chan throw new Exception("API Error: " . $errorMsg); 625f0c5114SCharles Chan } 635f0c5114SCharles Chan 645f0c5114SCharles Chan return $decoded; 655f0c5114SCharles Chan } 665f0c5114SCharles Chan 675f0c5114SCharles Chan /** 685f0c5114SCharles Chan * 流式响应(适合长文本) 695f0c5114SCharles Chan */ 705f0c5114SCharles Chan public function streamChatCompletion($params, $callback) { 715f0c5114SCharles Chan $params['stream'] = true; 72*abb7d3a8SCharles Chan $url = $this->baseUrl . '/v1/chat/completions'; 735f0c5114SCharles Chan 745f0c5114SCharles Chan $headers = [ 755f0c5114SCharles Chan 'Content-Type: application/json', 765f0c5114SCharles Chan 'Authorization: Bearer ' . $this->apiKey, 775f0c5114SCharles Chan 'Accept: text/event-stream', 785f0c5114SCharles Chan 'Cache-Control: no-cache' 795f0c5114SCharles Chan ]; 805f0c5114SCharles Chan 815f0c5114SCharles Chan $ch = curl_init($url); 825f0c5114SCharles Chan 835f0c5114SCharles Chan curl_setopt_array($ch, [ 845f0c5114SCharles Chan CURLOPT_RETURNTRANSFER => true, 855f0c5114SCharles Chan CURLOPT_POST => true, 865f0c5114SCharles Chan CURLOPT_HTTPHEADER => $headers, 875f0c5114SCharles Chan CURLOPT_POSTFIELDS => json_encode($params), 885f0c5114SCharles Chan CURLOPT_WRITEFUNCTION => function($ch, $data) use ($callback) { 895f0c5114SCharles Chan $callback($data); 905f0c5114SCharles Chan return strlen($data); 915f0c5114SCharles Chan }, 925f0c5114SCharles Chan CURLOPT_TIMEOUT => 120 935f0c5114SCharles Chan ]); 945f0c5114SCharles Chan 955f0c5114SCharles Chan curl_exec($ch); 965f0c5114SCharles Chan curl_close($ch); 975f0c5114SCharles Chan } 985f0c5114SCharles Chan 995f0c5114SCharles Chan /** 1005f0c5114SCharles Chan * 获取可用模型列表 1015f0c5114SCharles Chan */ 1025f0c5114SCharles Chan public function listModels() { 103*abb7d3a8SCharles Chan $url = $this->baseUrl . '/v1/models'; 1045f0c5114SCharles Chan 1055f0c5114SCharles Chan $headers = [ 1065f0c5114SCharles Chan 'Authorization: Bearer ' . $this->apiKey 1075f0c5114SCharles Chan ]; 1085f0c5114SCharles Chan 1095f0c5114SCharles Chan $ch = curl_init($url); 1105f0c5114SCharles Chan curl_setopt_array($ch, [ 1115f0c5114SCharles Chan CURLOPT_RETURNTRANSFER => true, 1125f0c5114SCharles Chan CURLOPT_HTTPHEADER => $headers, 1135f0c5114SCharles Chan CURLOPT_TIMEOUT => 10 1145f0c5114SCharles Chan ]); 1155f0c5114SCharles Chan 1165f0c5114SCharles Chan $response = curl_exec($ch); 1175f0c5114SCharles Chan curl_close($ch); 1185f0c5114SCharles Chan 1195f0c5114SCharles Chan return json_decode($response, true); 1205f0c5114SCharles Chan } 1215f0c5114SCharles Chan} 122