Parcourir la source

新增非流式文生文通用接口

lh il y a 1 semaine
Parent
commit
90a8ae0499

+ 15 - 0
app/Http/Controllers/DeepSeek/DeepSeekController.php

@@ -521,6 +521,21 @@ class DeepSeekController extends BaseController
         return $this->success($result);
         return $this->success($result);
     }
     }
 
 
+    /**
+     * 通用文生文(非流式版本)
+     * @param Request $request
+     * @return mixed
+     */
+    public function newGenerateText(Request $request) {
+        // 忽略所有超时限制
+        set_time_limit(0);
+        ini_set('max_execution_time', '0');
+
+        $data = $request->all();
+        $result = $this->deepseekService->newGenerateText($data);
+        return $this->success($result);
+    }
+
     // 新建对话
     // 新建对话
     public function addChat(Request $request) {
     public function addChat(Request $request) {
         // 忽略所有超时限制
         // 忽略所有超时限制

+ 255 - 2
app/Services/DeepSeek/DeepSeekService.php

@@ -243,8 +243,6 @@ class DeepSeekService
             $post_data['response_format'] = $data['response_format'];
             $post_data['response_format'] = $data['response_format'];
         }
         }
         
         
-        dLog('deepseek')->info('通用文生文请求参数', ['model' => $model, 'thinking' => $thinkingMode, 'messages_count' => count($messages)]);
-        
         // 根据模型类型选择调用方法
         // 根据模型类型选择调用方法
         if (in_array($model, ['deepseek-reasoner', 'deepseek-chat', 'deepseek-v4-flash', 'deepseek-v4-pro'])) {
         if (in_array($model, ['deepseek-reasoner', 'deepseek-chat', 'deepseek-v4-flash', 'deepseek-v4-pro'])) {
             // DeepSeek 官方模型使用 DeepSeek API
             // DeepSeek 官方模型使用 DeepSeek API
@@ -261,6 +259,261 @@ class DeepSeekService
     }
     }
     
     
     /**
     /**
+     * 通用文生文方法(非流式版本)- 支持多模型、图片输入、JSON输出和模板提示词
+     * 
+     * @param array $data 请求参数
+     * @return array 返回结果数组
+     */
+    public function newGenerateText($data) {
+        // 获取请求参数
+        $model = getProp($data, 'model', 'deepseek-v4-pro'); // 默认使用deepseek-v4
+        $messages = getProp($data, 'messages', []);
+        $systemPrompt = getProp($data, 'system_prompt', '');
+        $prompt = getProp($data, 'prompt', '');
+        $images = getProp($data, 'images', []); // 支持多张图片
+        $imageUrls = getProp($data, 'image_urls', []); // 支持图片URL
+        $responseFormat = getProp($data, 'response_format', 'text'); // 新增: 响应格式,默认text,可选json
+        $templateId = getProp($data, 'template_id', 0); // 新增: 模板ID
+        
+        // 新增: 如果提供了template_id,从数据库获取template_prompt
+        if ($templateId > 0) {
+            $template = DB::table('mp_prompt_templates')
+                ->where('id', $templateId)
+                ->where('is_deleted', 0)
+                ->first();
+            
+            if (!$template) {
+                Utils::throwError('20003:模板不存在或已删除');
+            }
+            
+            $templatePrompt = $template->template_prompt ?? '';
+            
+            // 将模板提示词和用户输入的prompt组合
+            // 模板为准,用户输入作为补充要求
+            if (!empty($templatePrompt)) {
+                if (!empty($prompt)) {
+                    $prompt = $templatePrompt . "\n\n用户要求:\n" . $prompt;
+                } else {
+                    $prompt = $templatePrompt;
+                }
+            }
+        }
+        
+        // 如果没有提供messages,则根据system_prompt、prompt和images构建
+        if (empty($messages)) {
+            $messages = [];
+            
+            // 添加系统提示词
+            if (!empty($systemPrompt)) {
+                $messages[] = [
+                    'role' => 'system',
+                    'content' => $systemPrompt
+                ];
+            }
+            
+            // 构建用户消息内容(支持文本+图片)
+            if (!empty($prompt) || !empty($images) || !empty($imageUrls)) {
+                $userMessage = [
+                    'role' => 'user',
+                    'content' => []
+                ];
+                
+                // 添加文本内容
+                if (!empty($prompt)) {
+                    $userMessage['content'][] = [
+                        'type' => 'text',
+                        'text' => $prompt
+                    ];
+                }
+                
+                // 处理上传的图片文件
+                if (!empty($images)) {
+                    if (!is_array($images)) {
+                        $images = [$images];
+                    }
+                    
+                    foreach ($images as $image) {
+                        $imageBase64 = $this->processImageToBase64($image);
+                        if ($imageBase64) {
+                            $userMessage['content'][] = [
+                                'type' => 'image_url',
+                                'image_url' => [
+                                    'url' => "data:image/jpeg;base64,{$imageBase64}"
+                                ]
+                            ];
+                        }
+                    }
+                }
+                
+                // 处理图片URL
+                if (!empty($imageUrls)) {
+                    if (!is_array($imageUrls)) {
+                        $imageUrls = [$imageUrls];
+                    }
+                    
+                    foreach ($imageUrls as $url) {
+                        if (!empty($url)) {
+                            $userMessage['content'][] = [
+                                'type' => 'image_url',
+                                'image_url' => [
+                                    'url' => $url
+                                ]
+                            ];
+                        }
+                    }
+                }
+                
+                // 如果只有文本内容,简化为字符串格式
+                if (count($userMessage['content']) === 1 && $userMessage['content'][0]['type'] === 'text') {
+                    $userMessage['content'] = $userMessage['content'][0]['text'];
+                }
+                
+                $messages[] = $userMessage;
+            }
+        }
+        
+        // 验证messages不为空
+        if (empty($messages)) {
+            Utils::throwError('20003:请提供有效的对话内容');
+        }
+        
+        // 模型兼容性处理:deepseek-chat 和 deepseek-reasoner 映射到 deepseek-v4-flash
+        $thinkingMode = getProp($data, 'thinking', 'disabled'); // 默认非思考模式
+        $reasoningEffort = getProp($data, 'reasoning_effort', 'high'); // 默认思考强度
+        
+        if ($model === 'deepseek-chat') {
+            // deepseek-chat 映射到 deepseek-v4-flash,非思考模式
+            $model = 'deepseek-v4-flash';
+            $thinkingMode = 'disabled';
+        } elseif ($model === 'deepseek-reasoner') {
+            // deepseek-reasoner 映射到 deepseek-v4-flash,思考模式
+            $model = 'deepseek-v4-flash';
+            $thinkingMode = 'enabled';
+        }
+        
+        // 构建请求参数(非流式)
+        $post_data = [
+            'model' => $model,
+            'messages' => $messages,
+            'temperature' => getProp($data, 'temperature', 1),
+            'frequency_penalty' => getProp($data, 'frequency_penalty', 0),
+            'presence_penalty' => getProp($data, 'presence_penalty', 0),
+            'thinking' => ['type' => $thinkingMode],
+            'stream' => false  // 非流式输出
+        ];
+        if ($thinkingMode == 'enabled') $post_data['reasoning_effort'] = $reasoningEffort;
+        
+        // 添加可选参数
+        if (isset($data['top_p'])) {
+            $post_data['top_p'] = $data['top_p'];
+        }
+        
+        // 新增: 根据response_format设置响应格式
+        if ($responseFormat === 'json') {
+            // 检查提示词中是否包含"json"关键词,如果没有则自动添加
+            $hasJsonKeyword = false;
+            foreach ($post_data['messages'] as $message) {
+                if (isset($message['content'])) {
+                    $content = is_array($message['content']) ? json_encode($message['content']) : $message['content'];
+                    if (stripos($content, 'json') !== false) {
+                        $hasJsonKeyword = true;
+                        break;
+                    }
+                }
+            }
+            
+            // 如果提示词中没有"json"关键词,在最后一条用户消息中添加JSON格式说明
+            // 这对所有模型都适用,确保模型理解需要返回JSON格式
+            if (!$hasJsonKeyword) {
+                $lastMessageIndex = count($post_data['messages']) - 1;
+                if ($lastMessageIndex >= 0 && $post_data['messages'][$lastMessageIndex]['role'] === 'user') {
+                    $lastContent = $post_data['messages'][$lastMessageIndex]['content'];
+                    
+                    // 如果content是字符串,直接追加
+                    if (is_string($lastContent)) {
+                        $post_data['messages'][$lastMessageIndex]['content'] .= "\n\n请以JSON格式返回结果。";
+                    } 
+                    // 如果content是数组(包含文本和图片),在文本部分追加
+                    else if (is_array($lastContent)) {
+                        foreach ($post_data['messages'][$lastMessageIndex]['content'] as &$contentPart) {
+                            if ($contentPart['type'] === 'text') {
+                                $contentPart['text'] .= "\n\n请以JSON格式返回结果。";
+                                break;
+                            }
+                        }
+                    }
+                    
+                    dLog('deepseek')->info('自动添加JSON格式提示词', ['model' => $model]);
+                }
+            }
+            
+            // 设置response_format参数(所有支持的模型)
+            if (in_array($model, ['deepseek-reasoner', 'deepseek-chat', 'deepseek-v4-flash', 'deepseek-v4-pro'])) {
+                // DeepSeek模型
+                $post_data['response_format'] = ['type' => 'json_object'];
+            } else if ($model === 'gpt-5.4') {
+                // GPT-5.4模型
+                $post_data['response_format'] = ['type' => 'json_object'];
+            } else if (in_array($model, $this->valid_text_models)) {
+                // 火山引擎模型
+                $post_data['response_format'] = ['type' => 'json_object'];
+            }
+        }
+        
+        // 根据模型类型选择调用方法(复用现有的chatOnly方法)
+        if (in_array($model, ['deepseek-reasoner', 'deepseek-chat', 'deepseek-v4-flash', 'deepseek-v4-pro'])) {
+            // DeepSeek 官方模型使用现有的 chatOnly 方法
+            $result = $this->chatOnly($post_data);
+            
+            // 记录实际使用的模型
+            dLog('deepseek')->info('newGenerateText使用DeepSeek模型', ['requested_model' => $model, 'actual_model' => $model]);
+            
+            return [
+                'content' => $result['fullContent'],
+                'reasoning_content' => $result['fullReasoningContent'],
+                'usage' => $result['usage'],
+                'model' => $model,
+                'finish_reason' => 'stop'
+            ];
+        } else if ($model === 'gpt-5.4') {
+            // GPT-5.4 模型使用现有的 gpt54ChatOnly 方法
+            $result = $this->gpt54ChatOnly($post_data);
+            
+            dLog('deepseek')->info('newGenerateText使用GPT-5.4模型', ['requested_model' => $model]);
+            
+            return [
+                'content' => $result['fullContent'],
+                'reasoning_content' => '',
+                'usage' => $result['usage'],
+                'model' => $model,
+                'finish_reason' => 'stop'
+            ];
+        } else if (in_array($model, $this->valid_text_models)) {
+            // 火山引擎支持的模型使用火山引擎 API(非流式)
+            $post_data['stream'] = false;
+            $result = $this->volcEngineChatCompletion($post_data);
+            
+            dLog('deepseek')->info('newGenerateText使用火山引擎模型', [
+                'requested_model' => $model,
+                'result_keys' => array_keys($result),
+                'has_fullContent' => isset($result['fullContent']),
+                'has_content' => isset($result['content'])
+            ]);
+            
+            // 火山引擎返回的数据结构使用 fullContent 和 fullReasoningContent
+            return [
+                'content' => $result['fullContent'] ?? $result['content'] ?? '',
+                'reasoning_content' => $result['fullReasoningContent'] ?? $result['reasoning_content'] ?? '',
+                'usage' => $result['usage'] ?? [],
+                'model' => $model,
+                'finish_reason' => $result['finish_reason'] ?? 'stop'
+            ];
+        } else {
+            Utils::throwError('20003:不支持的模型: ' . $model);
+        }
+    }
+    
+    /**
      * 处理图片转换为base64
      * 处理图片转换为base64
      * 
      * 
      * @param mixed $image 图片文件对象或文件路径
      * @param mixed $image 图片文件对象或文件路径

+ 1 - 0
routes/api.php

@@ -206,6 +206,7 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
             
             
             Route::get('generateImg', [AnimeController::class, 'generateImg']);     // 文生图(通用)
             Route::get('generateImg', [AnimeController::class, 'generateImg']);     // 文生图(通用)
             Route::post('generateText', [DeepSeekController::class, 'generateText']);    // 文生文(通用)
             Route::post('generateText', [DeepSeekController::class, 'generateText']);    // 文生文(通用)
+            Route::post('newGenerateText', [DeepSeekController::class, 'newGenerateText']);    // 文生文(通用-非流式)
             
             
             // 监控分镜图片和音频生成任务进度(SSE)
             // 监控分镜图片和音频生成任务进度(SSE)
             Route::get('segmentPicsInfo', [AnimeController::class, 'monitorSegmentTasks']);
             Route::get('segmentPicsInfo', [AnimeController::class, 'monitorSegmentTasks']);