xref: /plugin/ragasker/OpenAIHttpClient.php (revision 5f0c5114d87f8140fd00a9b6f05655e54e173dde)
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