Quellcode durchsuchen

1.优化画布模式默认提示词2.优化excel导入剧本资产接口统一用sse格式返回数据

lh vor 5 Tagen
Ursprung
Commit
0daca91604
1 geänderte Dateien mit 115 neuen und 25 gelöschten Zeilen
  1. 115 25
      app/Services/Anime/AnimeService.php

+ 115 - 25
app/Services/Anime/AnimeService.php

@@ -6161,7 +6161,7 @@ class AnimeService
     public static function appendInnerPrompt($prompt, $innerPromptType = 0)
     {
         $innerPromptMap = [
-            1 => '基于参考图生成主体的标准正面、侧面、后面三视图,主体完整。在最左侧添加主体正视图的特写,主体清晰完整。背景修改成纯白色,整体保持与参考图一致的美术风格和色彩搭配。画面无说明文字',
+            1 => '基于参考图生成主体的标准正面、侧面、后面三视图,主体完整。在最左侧添加主体正视图的特写,特写大小为标准一寸照,人物不要带表情。右侧是全身的三视图,其中正面、侧面的三视图给人脸打白色码、不显示五官。主体清晰完整。背景修改成纯白色,整体保持与参考图一致的美术风格和色彩搭配。画面无说明文字',
             2 => '基于参考图及提示词内容,生成9张连贯的系列图片:9张图片围绕同一主体展开,保持角色形象、美术风格和色彩搭配完全一致,画面内容依次衔接、情节连贯,整体构成一组完整的系列图。每张图片主体完整清晰,构图合理,画面干净,无文字、无水印、无字幕。',
         ];
 
@@ -7928,7 +7928,7 @@ class AnimeService
         ->where('type', 1)->first();
         if (!$product) Utils::throwError('20003:资产不存在');
         
-        $prompt = trim(getProp($data, 'prompt', '基于参考图生成主体的标准正面、侧面、后面三视图,主体完整。在最左侧添加主体正视图的特写,主体清晰完整。背景修改成纯白色,整体保持与参考图一致的美术风格和色彩搭配。画面无说明文字'));
+        $prompt = trim(getProp($data, 'prompt', '基于参考图生成主体的标准正面、侧面、后面三视图,主体完整。在最左侧添加主体正视图的特写,特写大小为标准一寸照,人物不要带表情。右侧是全身的三视图,其中正面、侧面的三视图给人脸打白色码、不显示五官。主体清晰完整。背景修改成纯白色,整体保持与参考图一致的美术风格和色彩搭配。画面无说明文字'));
         $ref_img_url = trim(getProp($data, 'ref_img_url'));
         if (!$ref_img_url) {
             // 如果没有传入参考图,使用角色表中的图片
@@ -8778,7 +8778,7 @@ class AnimeService
                 'task_center_id'      => $taskCenterId,
             ];
 
-            // 有需要轮询的任务(已有任务或本次补建):走 SSE 返回结果
+            // 有需要轮询的任务(已有任务或本次补建):走 SSE 轮询
             if (!empty($productTaskMap)) {
                 return $this->pollProductImageTasks(
                     $script_id,
@@ -8786,20 +8786,13 @@ class AnimeService
                     $productTaskMap,
                     $typeFolderIds,
                     $taskCenterId,
+                    ['import_result' => $resultData],
                     ['import_result' => $resultData]
                 );
             }
 
-            // 资产图片已全部生成完成或无法生成:直接返回结果
-            if ($taskCenterId) {
-                $this->taskCenterService->updateTask($taskCenterId, [
-                    'status'        => MpTaskCenter::STATUS_SUCCESS,
-                    'result'        => json_encode($resultData, JSON_UNESCAPED_UNICODE),
-                    'error_message' => null,
-                ]);
-            }
-
-            return $resultData;
+            // 没有需要轮询的任务:直接通过 complete 事件返回导入结果
+            return $this->streamImportComplete($script_id, $script_name, $resultData, $typeFolderIds, $taskCenterId);
         }
 
         // 事务内创建资产、类型文件夹与剧本映射
@@ -8940,7 +8933,7 @@ class AnimeService
             'task_center_id'      => $taskCenterId,
         ];
 
-        // 有待生成的图片任务:返回 SSE 轮询结果(导入统计在 init 事件中)
+        // 有待生成的图片任务:返回 SSE 轮询结果(导入统计在 init 与 complete 事件中)
         if (!empty($productTaskMap)) {
             return $this->pollProductImageTasks(
                 $script_id,
@@ -8948,20 +8941,13 @@ class AnimeService
                 $productTaskMap,
                 $typeFolderIds,
                 $taskCenterId,
+                ['import_result' => $resultData],
                 ['import_result' => $resultData]
             );
         }
 
-        // 所有资产都已有图片或未开启生成:直接返回结果
-        if ($taskCenterId) {
-            $this->taskCenterService->updateTask($taskCenterId, [
-                'status'        => MpTaskCenter::STATUS_SUCCESS,
-                'result'        => json_encode($resultData, JSON_UNESCAPED_UNICODE),
-                'error_message' => null,
-            ]);
-        }
-
-        return $resultData;
+        // 没有需要轮询的任务:直接通过 complete 事件返回导入结果
+        return $this->streamImportComplete($script_id, $script_name, $resultData, $typeFolderIds, $taskCenterId);
     }
 
     /**
@@ -10213,6 +10199,105 @@ class AnimeService
     }
     
     /**
+     * 无需轮询时的 SSE 返回:直接通过 complete 事件返回导入结果
+     *
+     * @param int $script_id
+     * @param string $script_name
+     * @param array $resultData 导入结果(原普通 JSON 的 data 内容)
+     * @param array $type_folder_ids
+     * @param int|null $taskCenterId
+     * @return \Generator
+     */
+    private function streamImportComplete($script_id, $script_name, array $resultData, $type_folder_ids, $taskCenterId = null) {
+        if ($taskCenterId) {
+            $initResponse = [
+                'type'           => 'init',
+                'script_id'      => $script_id,
+                'script_name'    => $script_name,
+                'timestamp'      => date('Y-m-d H:i:s'),
+                'task_center_id' => (int)$taskCenterId,
+                'import_result'  => $resultData,
+            ];
+
+            yield "data: " . json_encode($initResponse, JSON_UNESCAPED_UNICODE) . "\n\n";
+        }
+
+        $stats = $this->collectScriptProductStats($script_id);
+
+        $response = [
+            'type'          => 'complete',
+            'script_id'     => $script_id,
+            'script_name'   => $script_name,
+            'stats'         => $stats,
+            'timestamp'     => date('Y-m-d H:i:s'),
+            'import_result' => $resultData,
+        ];
+        if ($taskCenterId) {
+            $response['task_center_id'] = (int)$taskCenterId;
+        }
+
+        yield "data: " . json_encode($response, JSON_UNESCAPED_UNICODE) . "\n\n";
+
+        // 更新任务中心状态和结果
+        $this->finishScriptProductTask($taskCenterId, $response);
+    }
+
+    /**
+     * 统计剧本资产的图片生成状态(仅按 mp_products 当前状态统计,不驱动任务)
+     *
+     * @param int $script_id
+     * @return array
+     */
+    private function collectScriptProductStats($script_id) {
+        $stats = [
+            'character' => ['total' => 0, 'success' => 0, 'completed' => 0],
+            'scene'     => ['total' => 0, 'success' => 0, 'completed' => 0],
+            'prop'      => ['total' => 0, 'success' => 0, 'completed' => 0],
+        ];
+        $typeNames = [1 => 'roles', 2 => 'scenes', 3 => 'props'];
+
+        $productIds = DB::table('mp_script_product_mappings')
+            ->where('script_id', $script_id)
+            ->pluck('product_id')
+            ->unique()
+            ->toArray();
+
+        if (empty($productIds)) {
+            return [];
+        }
+
+        $products = DB::table('mp_products')
+            ->whereIn('id', $productIds)
+            ->where('is_deleted', 0)
+            ->get();
+
+        foreach ($products as $product) {
+            $typeName = $typeNames[$product->product] ?? 'unknown';
+
+            if (!isset($stats[$typeName])) {
+                $stats[$typeName] = ['total' => 0, 'success' => 0, 'completed' => 0];
+            }
+
+            $stats[$typeName]['total']++;
+
+            if ($product->pic_task_status === '生成成功') {
+                $stats[$typeName]['success']++;
+                $stats[$typeName]['completed']++;
+            } elseif ($product->pic_task_status === '生成失败') {
+                $stats[$typeName]['completed']++;
+            }
+        }
+
+        foreach ($stats as $typeName => $stat) {
+            if ($stat['total'] === 0) {
+                unset($stats[$typeName]);
+            }
+        }
+
+        return $stats;
+    }
+
+    /**
      * 轮询资产图片生成任务状态(SSE流式返回)
      * 只通过查询数据库获取任务状态,不主动调用API
      * 
@@ -10222,9 +10307,10 @@ class AnimeService
      * @param array $type_folder_ids 类型文件夹ID映射
      * @param int|null $taskCenterId 任务中心ID
      * @param array $initExtra 追加到 init 事件中的额外数据
+     * @param array $completeExtra 追加到 complete、timeout 事件中的额外数据
      * @return \Generator
      */
-    private function pollProductImageTasks($script_id, $script_name, $productTaskMap, $type_folder_ids, $taskCenterId = null, array $initExtra = []) {
+    private function pollProductImageTasks($script_id, $script_name, $productTaskMap, $type_folder_ids, $taskCenterId = null, array $initExtra = [], array $completeExtra = []) {
         $startTime = time();
         $timeout = 1800; // 30分钟超时
         $pollInterval = 10; // 10秒轮询一次
@@ -10409,6 +10495,9 @@ class AnimeService
                 if ($taskCenterId) {
                     $response['task_center_id'] = $taskCenterId;
                 }
+                if ($eventType === 'complete') {
+                    $response = array_merge($response, $completeExtra);
+                }
                 
                 yield "data: " . json_encode($response, JSON_UNESCAPED_UNICODE) . "\n\n";
                 
@@ -10446,6 +10535,7 @@ class AnimeService
             if ($taskCenterId) {
                 $response['task_center_id'] = $taskCenterId;
             }
+            $response = array_merge($response, $completeExtra);
             
             yield "data: " . json_encode($response, JSON_UNESCAPED_UNICODE) . "\n\n";