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