lh hai 1 mes
pai
achega
7532647733
Modificáronse 1 ficheiros con 53 adicións e 18 borrados
  1. 53 18
      app/Services/DeepSeek/DeepSeekService.php

+ 53 - 18
app/Services/DeepSeek/DeepSeekService.php

@@ -2768,9 +2768,11 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
      * GPT 中转站探活:GET /v1/models,5 秒短超时
      * GPT 中转站探活:GET /v1/models,5 秒短超时
      * 连接成功(含 401/403/404)视为可用;连接失败/超时/5xx/429 视为不可用
      * 连接成功(含 401/403/404)视为可用;连接失败/超时/5xx/429 视为不可用
      */
      */
-    private function checkGptServiceAvailable()
+    private function checkGptServiceAvailable($apiKey = null)
     {
     {
-        $apiKey = env('GPT_54_API_KEY');
+        if ($apiKey === null) {
+            $apiKey = env('GPT_54_API_KEY');
+        }
         if (empty($apiKey)) {
         if (empty($apiKey)) {
             return false;
             return false;
         }
         }
@@ -2794,13 +2796,13 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
      * 探活并重试:最多重试 gptRetryTimes() 次,间隔 gptRetryInterval() 秒
      * 探活并重试:最多重试 gptRetryTimes() 次,间隔 gptRetryInterval() 秒
      * 全部失败抛出友好错误
      * 全部失败抛出友好错误
      */
      */
-    private function ensureGptServiceAvailable()
+    private function ensureGptServiceAvailable($apiKey = null)
     {
     {
         $maxRetries = $this->gptRetryTimes();
         $maxRetries = $this->gptRetryTimes();
         $interval = $this->gptRetryInterval();
         $interval = $this->gptRetryInterval();
 
 
         for ($attempt = 0; $attempt <= $maxRetries; $attempt++) {
         for ($attempt = 0; $attempt <= $maxRetries; $attempt++) {
-            if ($this->checkGptServiceAvailable()) {
+            if ($this->checkGptServiceAvailable($apiKey)) {
                 return;
                 return;
             }
             }
 
 
@@ -2828,21 +2830,22 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
      * @return \Generator 返回生成器,用于流式输出
      * @return \Generator 返回生成器,用于流式输出
      */
      */
     private function gpt54StreamResponse($post_data) {
     private function gpt54StreamResponse($post_data) {
-        $apiKey = env('GPT_54_API_KEY');
+        // 按模型取 Key:gpt-5.6-luna 使用 GPT_56_LUNA_API_KEY,其余使用 GPT_54_API_KEY
+        $modelName = (string)getProp($post_data, 'model', 'gpt-5.4');
+        $lunaApiKey = env('GPT_56_LUNA_API_KEY');
+        $apiKey = $modelName === 'gpt-5.6-luna' ? $lunaApiKey : env('GPT_54_API_KEY');
+        $usedLunaFallback = false;
+        // 流式请求长时间无任何返回(TTFB)超过该秒数时切换备用 Key(env 可配置,默认 600 秒)
+        $ttfbTimeoutSeconds = (int)env('GPT_SWITCH_LUNA_AFTER_SECONDS', 600);
         
         
         if (empty($apiKey)) {
         if (empty($apiKey)) {
             Utils::throwError('20003:GPT API Key未配置');
             Utils::throwError('20003:GPT API Key未配置');
         }
         }
 
 
         // 先探活,服务不可用时自动重试
         // 先探活,服务不可用时自动重试
-        $this->ensureGptServiceAvailable();
+        $this->ensureGptServiceAvailable($apiKey);
 
 
-        $client = new Client(['timeout' => 1800, 'verify' => false]);
-        $headers = [
-            'Authorization' => 'Bearer ' . $apiKey,
-            'Content-Type'  => 'application/json',
-            'Accept'        => 'text/event-stream'
-        ];
+        $client = new Client(['timeout' => 1800, 'verify' => false, 'read_timeout' => $ttfbTimeoutSeconds]);
 
 
         // 移除 thinking 参数,GPT-5.4 不支持
         // 移除 thinking 参数,GPT-5.4 不支持
         if (isset($post_data['thinking'])) {
         if (isset($post_data['thinking'])) {
@@ -2869,6 +2872,13 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
             $buffer = '';
             $buffer = '';
             $suspectJsonWrap = false;
             $suspectJsonWrap = false;
             $pendingContent = '';
             $pendingContent = '';
+            $requestStartedAt = microtime(true);
+
+            $headers = [
+                'Authorization' => 'Bearer ' . $apiKey,
+                'Content-Type'  => 'application/json',
+                'Accept'        => 'text/event-stream'
+            ];
 
 
             try {
             try {
                 // 备用中转站地址1: https://token.ithinkai.cn/v1/chat/completions
                 // 备用中转站地址1: https://token.ithinkai.cn/v1/chat/completions
@@ -2885,6 +2895,10 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
 
 
                 // 逐行读取流式响应
                 // 逐行读取流式响应
                 while (!$body->eof()) {
                 while (!$body->eof()) {
+                    // 长时间没有任何内容返回时,切换备用 Key 重试
+                    if ($fullContent === '' && empty($usage) && (microtime(true) - $requestStartedAt) > $ttfbTimeoutSeconds) {
+                        throw new \RuntimeException('GPT 流式响应长时间无返回,等待切换备用 Key');
+                    }
                     $chunk = $body->read(1024); // 每次读取 1KB
                     $chunk = $body->read(1024); // 每次读取 1KB
                     $buffer .= $chunk;
                     $buffer .= $chunk;
                     
                     
@@ -3008,6 +3022,14 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
                 ];
                 ];
                 return;
                 return;
             } catch (\Exception $e) {
             } catch (\Exception $e) {
+                // 报错或长时间无返回时,切到 GPT_56_LUNA_API_KEY 重试一次(收费更高,慎用;仅原本未用 luna key 时触发)
+                if (!$usedLunaFallback && !empty($lunaApiKey) && $apiKey !== $lunaApiKey) {
+                    $usedLunaFallback = true;
+                    $apiKey = $lunaApiKey;
+                    dLog('deepseek')->warning('GPT 请求异常,切换 GPT_56_LUNA_API_KEY 重试', ['error' => $e->getMessage()]);
+                    continue;
+                }
+
                 // 已输出内容不重试(避免重复);非可重试异常不重试;重试次数用完则抛出
                 // 已输出内容不重试(避免重复);非可重试异常不重试;重试次数用完则抛出
                 if (!empty($fullContent) || !$this->isGptRetryableException($e) || $attempt >= $maxRetries) {
                 if (!empty($fullContent) || !$this->isGptRetryableException($e) || $attempt >= $maxRetries) {
                     dLog('deepseek')->error('GPT 流式请求失败: ' . $e->getMessage());
                     dLog('deepseek')->error('GPT 流式请求失败: ' . $e->getMessage());
@@ -14220,20 +14242,20 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
 
 
     // 仅调用 GPT-5.4 对话接口(非流式)
     // 仅调用 GPT-5.4 对话接口(非流式)
     private function gpt54ChatOnly($post_data) {
     private function gpt54ChatOnly($post_data) {
-        $apiKey = env('GPT_54_API_KEY');
+        // 按模型取 Key:gpt-5.6-luna 使用 GPT_56_LUNA_API_KEY,其余使用 GPT_54_API_KEY
+        $modelName = (string)getProp($post_data, 'model', 'gpt-5.4');
+        $lunaApiKey = env('GPT_56_LUNA_API_KEY');
+        $apiKey = $modelName === 'gpt-5.6-luna' ? $lunaApiKey : env('GPT_54_API_KEY');
+        $usedLunaFallback = false;
         
         
         if (empty($apiKey)) {
         if (empty($apiKey)) {
             Utils::throwError('20003:GPT-5.4 API Key未配置');
             Utils::throwError('20003:GPT-5.4 API Key未配置');
         }
         }
 
 
         // 先探活,服务不可用时自动重试
         // 先探活,服务不可用时自动重试
-        $this->ensureGptServiceAvailable();
+        $this->ensureGptServiceAvailable($apiKey);
 
 
         $client = new Client(['timeout' => 1800, 'verify' => false]);
         $client = new Client(['timeout' => 1800, 'verify' => false]);
-        $headers = [
-            'Authorization' => 'Bearer ' . $apiKey,
-            'Content-Type'  => 'application/json'
-        ];
 
 
         // 移除 thinking 参数,GPT-5.4 不支持
         // 移除 thinking 参数,GPT-5.4 不支持
         if (isset($post_data['thinking'])) {
         if (isset($post_data['thinking'])) {
@@ -14253,6 +14275,11 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
 
 
         while (true) {
         while (true) {
             try {
             try {
+                $headers = [
+                    'Authorization' => 'Bearer ' . $apiKey,
+                    'Content-Type'  => 'application/json'
+                ];
+
                 // 备用中转站地址: https://token.ithinkai.cn/v1/chat/completions
                 // 备用中转站地址: https://token.ithinkai.cn/v1/chat/completions
                 // 备用中转站地址2: https://api.nonelinear.com/v1/chat/completions
                 // 备用中转站地址2: https://api.nonelinear.com/v1/chat/completions
                 $result = $client->post('https://ai-api.kkidc.com/v1/chat/completions', [
                 $result = $client->post('https://ai-api.kkidc.com/v1/chat/completions', [
@@ -14277,6 +14304,14 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
                     'usage' => $usage
                     'usage' => $usage
                 ];
                 ];
             } catch (\Exception $e) {
             } catch (\Exception $e) {
+                // 报错或超时时,切到 GPT_56_LUNA_API_KEY 重试一次(收费更高,慎用;仅原本未用 luna key 时触发)
+                if (!$usedLunaFallback && !empty($lunaApiKey) && $apiKey !== $lunaApiKey) {
+                    $usedLunaFallback = true;
+                    $apiKey = $lunaApiKey;
+                    dLog('deepseek')->warning('GPT-5.4 请求异常,切换 GPT_56_LUNA_API_KEY 重试', ['error' => $e->getMessage()]);
+                    continue;
+                }
+
                 if (!$this->isGptRetryableException($e) || $attempt >= $maxRetries) {
                 if (!$this->isGptRetryableException($e) || $attempt >= $maxRetries) {
                     dLog('deepseek')->error('GPT-5.4 请求失败: ' . $e->getMessage());
                     dLog('deepseek')->error('GPT-5.4 请求失败: ' . $e->getMessage());
                     logDB('deepseek', 'error', 'GPT-5.4 请求失败', ['error' => $e->getMessage()]);
                     logDB('deepseek', 'error', 'GPT-5.4 请求失败', ['error' => $e->getMessage()]);