lh 5 дней назад
Родитель
Сommit
1501c1c88b

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

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

+ 142 - 38
app/Services/DeepSeek/DeepSeekService.php

@@ -257,6 +257,50 @@ class DeepSeekService
             Utils::throwError('20003:不支持的模型: ' . $model);
         }
     }
+
+    public function createGenerateText($data) {
+        $file = getProp($data, 'file');
+        $uid = Site::getUid();
+        $cpid = Site::getCpid();
+        
+        if (!$file) {
+            Utils::throwError('20003:请上传文件');
+        }
+        
+        // 提取文件内容
+        $content = $this->extractFileContent($file);
+        if (!$content) {
+            Utils::throwError('20003:无法提取文件内容,请检查文件格式');
+        }
+        
+        // 获取原始文件名(不含扩展名)作为script_name
+        $originalName = $file->getClientOriginalName();
+        $script_name = pathinfo($originalName, PATHINFO_FILENAME);
+        
+        if (!$script_name) {
+            $script_name = '剧本_' . date('YmdHis');
+        }
+        
+        // 如果剧本名称已存在,添加时间戳后缀
+        if (DB::table('mp_scripts')->where('script_name', $script_name)->where('is_deleted', 0)->exists()) {
+            $script_name .= '_' . date('YmdHis');
+        }
+        
+        // 插入数据到mp_scripts表
+        $script_id = DB::table('mp_scripts')->insertGetId([
+            'script_name' => $script_name,
+            'user_id'     => $uid,
+            'cpid'        => $cpid,
+            'content'     => $content,
+            'created_at'  => date('Y-m-d H:i:s'),
+            'updated_at'  => date('Y-m-d H:i:s')
+        ]);
+        
+        return [
+            'script_id' => $script_id,
+            'script_name' => $script_name
+        ];
+    }
     
     /**
      * 通用文生文方法(非流式版本)- 支持多模型、图片输入、JSON输出和模板提示词
@@ -274,6 +318,36 @@ class DeepSeekService
         $imageUrls = getProp($data, 'image_urls', []); // 支持图片URL
         $responseFormat = getProp($data, 'response_format', 'text'); // 新增: 响应格式,默认text,可选json
         $templateId = getProp($data, 'template_id', 0); // 新增: 模板ID
+        $script_id = getProp($data, 'script_id', 0); // 新增: 剧本ID
+        $sequence = getProp($data, 'sequence', 0); // 新增: 剧集序号
+        
+        // 新增: 如果提供了script_id,从数据库获取剧本内容作为原文
+        $originalContent = '';
+        if ($script_id > 0) {
+            $script = DB::table('mp_scripts')
+                ->where('id', $script_id)
+                ->where('is_deleted', 0)
+                ->first();
+            
+            if (!$script) {
+                Utils::throwError('20003:剧本不存在或已删除');
+            }
+            
+            $originalContent = $script->content ?? '';
+            
+            if (empty($originalContent)) {
+                Utils::throwError('20003:剧本内容为空');
+            }
+            
+            // 将剧本内容添加到提示词前面
+            if (!empty($originalContent)) {
+                if (!empty($prompt)) {
+                    $prompt = "原文内容:\n" . $originalContent . "\n\n用户要求:\n" . $prompt;
+                } else {
+                    $prompt = "原文内容:\n" . $originalContent;
+                }
+            }
+        }
         
         // 新增: 如果提供了template_id,从数据库获取template_prompt
         if ($templateId > 0) {
@@ -292,7 +366,7 @@ class DeepSeekService
             // 模板为准,用户输入作为补充要求
             if (!empty($templatePrompt)) {
                 if (!empty($prompt)) {
-                    $prompt = $templatePrompt . "\n\n用户要求:\n" . $prompt;
+                    $prompt = $templatePrompt . "\n\n" . $prompt;
                 } else {
                     $prompt = $templatePrompt;
                 }
@@ -461,6 +535,7 @@ class DeepSeekService
         }
         
         // 根据模型类型选择调用方法(复用现有的chatOnly方法)
+        $aiResult = null;
         if (in_array($model, ['deepseek-reasoner', 'deepseek-chat', 'deepseek-v4-flash', 'deepseek-v4-pro'])) {
             // DeepSeek 官方模型使用现有的 chatOnly 方法
             $result = $this->chatOnly($post_data);
@@ -468,7 +543,7 @@ class DeepSeekService
             // 记录实际使用的模型
             dLog('deepseek')->info('newGenerateText使用DeepSeek模型', ['requested_model' => $model, 'actual_model' => $model]);
             
-            return [
+            $aiResult = [
                 'content' => $result['fullContent'],
                 'reasoning_content' => $result['fullReasoningContent'],
                 'usage' => $result['usage'],
@@ -481,7 +556,7 @@ class DeepSeekService
             
             dLog('deepseek')->info('newGenerateText使用GPT-5.4模型', ['requested_model' => $model]);
             
-            return [
+            $aiResult = [
                 'content' => $result['fullContent'],
                 'reasoning_content' => '',
                 'usage' => $result['usage'],
@@ -501,7 +576,7 @@ class DeepSeekService
             ]);
             
             // 火山引擎返回的数据结构使用 fullContent 和 fullReasoningContent
-            return [
+            $aiResult = [
                 'content' => $result['fullContent'] ?? $result['content'] ?? '',
                 'reasoning_content' => $result['fullReasoningContent'] ?? $result['reasoning_content'] ?? '',
                 'usage' => $result['usage'] ?? [],
@@ -511,14 +586,65 @@ class DeepSeekService
         } else {
             Utils::throwError('20003:不支持的模型: ' . $model);
         }
+        
+        // 新增: 如果提供了script_id,保存对话记录
+        if ($script_id > 0 && $aiResult) {
+            try {
+                $uid = Site::getUid();
+                $now = now();
+                
+                // 获取用户原始的prompt(不包含剧本内容)
+                $originalPrompt = getProp($data, 'prompt', '');
+                
+                $records = [
+                    [
+                        'uid' => $uid,
+                        'script_id' => $script_id,
+                        'sequence' => $sequence,
+                        'role' => 'user',
+                        'content' => $originalPrompt,
+                        'created_at' => $now,
+                        'updated_at' => $now,
+                    ],
+                    [
+                        'uid' => $uid,
+                        'script_id' => $script_id,
+                        'sequence' => $sequence,
+                        'role' => 'assistant',
+                        'content' => $aiResult['content'],
+                        'created_at' => $now,
+                        'updated_at' => $now,
+                    ]
+                ];
+                
+                DB::table('mp_script_records')->insert($records);
+                
+                dLog('deepseek')->info('保存剧本对话记录成功', ['script_id' => $script_id, 'sequence' => $sequence]);
+            } catch (\Exception $e) {
+                // 记录错误但不影响主流程
+                dLog('deepseek')->error('保存剧本对话记录失败: ' . $e->getMessage());
+            }
+        }
+        
+        return $aiResult;
     }
 
     public function saveScriptChatHistory($data) {
         $uid = Site::getUid();
+        $rid = getProp($data, 'rid');
         $script_id = getProp($data, 'script_id');
         $sequence = getProp($data, 'sequence', 0);
-        $messages = getProp($data, 'messages', []);
+        $products = getProp($data, 'products', []);
         
+        if (!$rid) {
+            Utils::throwError('20003:请选择对话记录ID');
+        }
+
+        $record = DB::table('mp_script_records')->where('id', $rid)->first();
+        if (!$record) {
+            Utils::throwError('20003:对话记录不存在');
+        }
+
         if (!$script_id) {
             Utils::throwError('20003:请选择剧本');
         }
@@ -529,48 +655,24 @@ class DeepSeekService
         }
 
         // 解析 messages(可能是 JSON 字符串或数组)
-        if (is_string($messages)) {
-            $messages = json_decode($messages, true);
+        if (is_string($products)) {
+            $products = json_decode($products, true);
             if (json_last_error() !== JSON_ERROR_NONE) {
                 Utils::throwError('20003:消息格式错误');
             }
         }
 
-        if (!is_array($messages) || empty($messages)) {
+        if (empty($products)) {
             Utils::throwError('20003:消息不能为空');
         }
 
-        // 提取 role 为 user 和 assistant 的消息并保存
-        $records = [];
-        $now = now();
-
-        foreach ($messages as $message) {
-            if (!isset($message['role']) || !isset($message['content'])) {
-                continue;
-            }
-
-            // 只处理 user 和 assistant 角色
-            if (!in_array($message['role'], ['user', 'assistant'])) {
-                continue;
-            }
-
-            $records[] = [
-                'uid' => $uid,
-                'script_id' => $script_id,
-                'sequence' => $sequence,
-                'role' => $message['role'],
-                'content' => is_array($message['content']) ? json_encode($message['content'], JSON_UNESCAPED_UNICODE) : $message['content'],
-                'created_at' => $now,
-                'updated_at' => $now,
-            ];
-        }
-
-        if (empty($records)) {
-            Utils::throwError('20003:没有有效的对话记录');
-        }
+        $json = json_decode($products, 256);
 
         // 批量插入数据
-        return DB::table('mp_script_records')->insert($records);
+        return DB::table('mp_script_records')->where('id', $rid)->update([
+            'products'      => $json,
+            'updated_at'    => date('Y-m-d H:i:s')
+        ]);
     }
 
     /**
@@ -609,16 +711,18 @@ class DeepSeekService
         }
 
         // 查询记录并按 id 正序排序
-        $records = $query->select('script_id', 'sequence', 'role', 'content', 'created_at')
+        $records = $query->select('id', 'script_id', 'sequence', 'role', 'content', 'products', 'created_at')
             ->orderBy('created_at', 'asc')
             ->orderBy('id', 'asc')
             ->get()
             ->map(function ($record) {
                 return [
+                    'rid' => $record->id,
                     'script_id' => $record->script_id,
                     'sequence' => $record->sequence,
                     'role' => $record->role,
                     'content' => $record->content,
+                    'products' => $record->products ? json_decode($record->products) : [],
                     'created_at' => $record->created_at,
                 ];
             })

+ 1 - 0
routes/api.php

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