Browse Source

新建或编辑剧本分集里的主体或场景时同步保存到对应剧本资产中

lh 12 hours ago
parent
commit
7d52bf5743
3 changed files with 373 additions and 23 deletions
  1. 278 2
      app/Services/Anime/AnimeService.php
  2. 90 16
      app/Services/DeepSeek/DeepSeekService.php
  3. 5 5
      routes/api.php

+ 278 - 2
app/Services/Anime/AnimeService.php

@@ -1049,6 +1049,15 @@ class AnimeService
         if (!$episode) Utils::throwError('20003:该剧集不存在');
         $roles = json_decode(getProp($episode, 'roles'), true);
 
+        // 获取anime信息,检查是否有关联的script_id
+        $anime = DB::table('mp_animes')->where('id', $anime_id)->first();
+        if (!$anime) Utils::throwError('20003:动漫不存在');
+        
+        $script_id = getProp($anime, 'script_id');
+        $episode_number = getProp($episode, 'episode_number', 1);
+        $uid = Site::getUid();
+        $cpid = Site::getCpid();
+
         try {
             $target_role_name = getProp($target_roles, 'role');
             
@@ -1074,6 +1083,7 @@ class AnimeService
             } else {
                 // 新增或更新操作
                 $role_found = false;
+                $is_new_role = false;
                 
                 // 查找并更新已存在的角色
                 foreach($roles as &$role) {
@@ -1087,6 +1097,7 @@ class AnimeService
                 // 如果角色不存在,则新增
                 if (!$role_found) {
                     $roles[] = $target_roles;
+                    $is_new_role = true;
                 }
 
                 // 更新角色列表
@@ -1117,6 +1128,124 @@ class AnimeService
                         'voice_audio_url' => $voice_audio_url,
                         'updated_at' => date('Y-m-d H:i:s')
                     ]);
+
+                // 如果有关联的script_id,则同步到mp_products表
+                if ($script_id) {
+                    // 查询剧本信息
+                    $script = DB::table('mp_scripts')
+                        ->where('id', $script_id)
+                        ->where('is_deleted', 0)
+                        ->first();
+                    
+                    if ($script) {
+                        $script_name = $script->script_name ?? 'script_' . $script_id;
+                        $product_name = getProp($target_roles, 'role');
+                        $pic_prompt = getProp($target_roles, 'pic_prompt', '');
+                        $url = getProp($target_roles, 'url', '');
+                        $product_type = 1; // 1=角色
+                        
+                        // 查找或创建以script_name命名的文件夹
+                        $folder = DB::table('mp_products')
+                            ->where('cpid', $cpid)
+                            ->where('type', 2) // 文件夹类型
+                            ->where('product', $product_type) // 角色类型
+                            ->where('product_name', $script_name)
+                            ->where('parent_id', 0)
+                            ->where('is_deleted', 0)
+                            ->first();
+                        
+                        if (!$folder) {
+                            // 创建文件夹
+                            $folder_id = DB::table('mp_products')->insertGetId([
+                                'user_id' => $uid,
+                                'cpid' => $cpid,
+                                'type' => 2, // 文件夹
+                                'product' => $product_type, // 角色类型
+                                'parent_id' => 0,
+                                'level' => 1,
+                                'product_name' => $script_name,
+                                'sort_order' => time(),
+                                'is_deleted' => 0,
+                                'created_at' => date('Y-m-d H:i:s'),
+                                'updated_at' => date('Y-m-d H:i:s')
+                            ]);
+                        } else {
+                            $folder_id = $folder->id;
+                        }
+                        
+                        // 查找该文件夹下是否已存在同名资产
+                        $existing_product = DB::table('mp_products')
+                            ->where('cpid', $cpid)
+                            ->where('type', 1) // 资产类型
+                            ->where('product', $product_type)
+                            ->where('parent_id', $folder_id)
+                            ->where('product_name', $product_name)
+                            ->where('is_deleted', 0)
+                            ->first();
+                        
+                        if ($existing_product) {
+                            // 更新已存在的资产
+                            $updateData = [
+                                'pic_task_status'   => '生成成功',
+                            ];
+                            if ($pic_prompt) $updateData['pic_prompt'] = $pic_prompt;
+                            if ($url) $updateData['url'] = $url;
+                            
+                            // 处理versions字段
+                            $versions = getProp($target_roles, 'versions', []);
+                            if ($versions && is_array($versions)) {
+                                $updateData['versions'] = json_encode($versions, 256);
+                            }
+                            
+                            $updateData['updated_at'] = date('Y-m-d H:i:s');
+                            
+                            DB::table('mp_products')
+                                ->where('id', $existing_product->id)
+                                ->update($updateData);
+                            
+                            $product_id = $existing_product->id;
+                        } else {
+                            // 创建新资产
+                            $versions = getProp($target_roles, 'versions', []);
+                            
+                            $product_id = DB::table('mp_products')->insertGetId([
+                                'user_id' => $uid,
+                                'cpid' => $cpid,
+                                'type' => 1, // 资产
+                                'product' => $product_type, // 角色
+                                'parent_id' => $folder_id,
+                                'level' => 2,
+                                'product_name' => $product_name,
+                                'url' => $url,
+                                'pic_prompt' => $pic_prompt,
+                                'versions' => is_array($versions) ? json_encode($versions, 256) : '[]',
+                                'sort_order' => time(),
+                                'is_deleted' => 0,
+                                'pic_task_status' => '生成成功',
+                                'created_at' => date('Y-m-d H:i:s'),
+                                'updated_at' => date('Y-m-d H:i:s')
+                            ]);
+                        }
+                        
+                        // 建立或更新绑定关系
+                        $existing_mapping = DB::table('mp_script_product_mappings')
+                            ->where('script_id', $script_id)
+                            ->where('product_id', $product_id)
+                            ->where('episode_number', $episode_number)
+                            ->first();
+                        
+                        if (!$existing_mapping) {
+                            // 创建绑定关系
+                            DB::table('mp_script_product_mappings')->insert([
+                                'script_id' => $script_id,
+                                'product_id' => $product_id,
+                                'episode_number' => $episode_number,
+                                'created_at' => date('Y-m-d H:i:s'),
+                                'updated_at' => date('Y-m-d H:i:s')
+                            ]);
+                        }
+                    }
+                }
             }
         } catch (\Exception $e) {
             dLog('anime')->error('更新剧集角色失败', [
@@ -1150,6 +1279,15 @@ class AnimeService
         if (!$episode) Utils::throwError('20003:该剧集不存在');
         $scenes = json_decode(getProp($episode, 'scenes'), true);
 
+        // 获取anime信息,检查是否有关联的script_id
+        $anime = DB::table('mp_animes')->where('id', $anime_id)->first();
+        if (!$anime) Utils::throwError('20003:动漫不存在');
+        
+        $script_id = getProp($anime, 'script_id');
+        $episode_number = getProp($episode, 'episode_number', 1);
+        $uid = Site::getUid();
+        $cpid = Site::getCpid();
+
         try {
             $target_scene_name = getProp($target_scenes, 'scene');
             
@@ -1175,6 +1313,7 @@ class AnimeService
             } else {
                 // 新增或更新操作
                 $scene_found = false;
+                $is_new_scene = false;
                 
                 // 查找并更新已存在的场景
                 foreach($scenes as &$scene) {
@@ -1188,6 +1327,7 @@ class AnimeService
                 // 如果场景不存在,则新增
                 if (!$scene_found) {
                     $scenes[] = $target_scenes;
+                    $is_new_scene = true;
                 }
 
                 // 更新场景列表
@@ -1202,6 +1342,124 @@ class AnimeService
                 if ($result === false) {
                     Utils::throwError('20003:更新场景列表失败');
                 }
+
+                // 如果有关联的script_id,则同步到mp_products表
+                if ($script_id) {
+                    // 查询剧本信息
+                    $script = DB::table('mp_scripts')
+                        ->where('id', $script_id)
+                        ->where('is_deleted', 0)
+                        ->first();
+                    
+                    if ($script) {
+                        $script_name = $script->script_name ?? 'script_' . $script_id;
+                        $product_name = getProp($target_scenes, 'scene');
+                        $pic_prompt = getProp($target_scenes, 'pic_prompt', '');
+                        $url = getProp($target_scenes, 'url', '');
+                        $product_type = 2; // 2=场景
+                        
+                        // 查找或创建以script_name命名的文件夹
+                        $folder = DB::table('mp_products')
+                            ->where('cpid', $cpid)
+                            ->where('type', 2) // 文件夹类型
+                            ->where('product', $product_type) // 场景类型
+                            ->where('product_name', $script_name)
+                            ->where('parent_id', 0)
+                            ->where('is_deleted', 0)
+                            ->first();
+                        
+                        if (!$folder) {
+                            // 创建文件夹
+                            $folder_id = DB::table('mp_products')->insertGetId([
+                                'user_id' => $uid,
+                                'cpid' => $cpid,
+                                'type' => 2, // 文件夹
+                                'product' => $product_type, // 场景类型
+                                'parent_id' => 0,
+                                'level' => 1,
+                                'product_name' => $script_name,
+                                'sort_order' => time(),
+                                'is_deleted' => 0,
+                                'created_at' => date('Y-m-d H:i:s'),
+                                'updated_at' => date('Y-m-d H:i:s')
+                            ]);
+                        } else {
+                            $folder_id = $folder->id;
+                        }
+                        
+                        // 查找该文件夹下是否已存在同名资产
+                        $existing_product = DB::table('mp_products')
+                            ->where('cpid', $cpid)
+                            ->where('type', 1) // 资产类型
+                            ->where('product', $product_type)
+                            ->where('parent_id', $folder_id)
+                            ->where('product_name', $product_name)
+                            ->where('is_deleted', 0)
+                            ->first();
+                        
+                        if ($existing_product) {
+                            // 更新已存在的资产
+                            $updateData = [
+                                'pic_task_status' => '生成成功'
+                            ];
+                            if ($pic_prompt) $updateData['pic_prompt'] = $pic_prompt;
+                            if ($url) $updateData['url'] = $url;
+                            
+                            // 处理versions字段
+                            $versions = getProp($target_scenes, 'versions', []);
+                            if ($versions && is_array($versions)) {
+                                $updateData['versions'] = json_encode($versions, 256);
+                            }
+                            
+                            $updateData['updated_at'] = date('Y-m-d H:i:s');
+                            
+                            DB::table('mp_products')
+                                ->where('id', $existing_product->id)
+                                ->update($updateData);
+                            
+                            $product_id = $existing_product->id;
+                        } else {
+                            // 创建新资产
+                            $versions = getProp($target_scenes, 'versions', []);
+                            
+                            $product_id = DB::table('mp_products')->insertGetId([
+                                'user_id' => $uid,
+                                'cpid' => $cpid,
+                                'type' => 1, // 资产
+                                'product' => $product_type, // 场景
+                                'parent_id' => $folder_id,
+                                'level' => 2,
+                                'product_name' => $product_name,
+                                'url' => $url,
+                                'pic_prompt' => $pic_prompt,
+                                'versions' => is_array($versions) ? json_encode($versions, 256) : '[]',
+                                'sort_order' => time(),
+                                'is_deleted' => 0,
+                                'pic_task_status' => '生成成功',
+                                'created_at' => date('Y-m-d H:i:s'),
+                                'updated_at' => date('Y-m-d H:i:s')
+                            ]);
+                        }
+                        
+                        // 建立或更新绑定关系
+                        $existing_mapping = DB::table('mp_script_product_mappings')
+                            ->where('script_id', $script_id)
+                            ->where('product_id', $product_id)
+                            ->where('episode_number', $episode_number)
+                            ->first();
+                        
+                        if (!$existing_mapping) {
+                            // 创建绑定关系
+                            DB::table('mp_script_product_mappings')->insert([
+                                'script_id' => $script_id,
+                                'product_id' => $product_id,
+                                'episode_number' => $episode_number,
+                                'created_at' => date('Y-m-d H:i:s'),
+                                'updated_at' => date('Y-m-d H:i:s')
+                            ]);
+                        }
+                    }
+                }
             }
         } catch (\Exception $e) {
             dLog('anime')->error('更新剧集场景失败', [
@@ -6407,7 +6665,10 @@ class AnimeService
                 // 检查是否有图片生成任务
                 if (!empty($product->pic_task_id)) {
                     $productTaskMap[$product->id] = $product->pic_task_id;
-                } else {
+                } else if($product->url && $product->pic_task_status == '生成成功') {
+                    continue;
+                }
+                else {
                     // 有资产没有图片任务
                     $hasAllTasks = false;
                 }
@@ -6941,9 +7202,24 @@ class AnimeService
         while (time() - $startTime < $timeout) {
             sleep($pollInterval);
             
+            // 从 mp_script_product_mappings 表获取该剧本的所有资产ID
+            $mappings = DB::table('mp_script_product_mappings')
+                ->where('script_id', $script_id)
+                ->pluck('product_id')
+                ->unique()
+                ->toArray();
+            
+            if (empty($mappings)) {
+                dLog('anime')->warning('该剧本没有关联的资产', [
+                    'script_id' => $script_id,
+                    'script_name' => $script_name
+                ]);
+                break;
+            }
+            
             // 查询所有资产的当前状态
             $products = DB::table('mp_products')
-                ->whereIn('id', array_keys($productTaskMap))
+                ->whereIn('id', $mappings)
                 ->where('is_deleted', 0)
                 ->get();
             

+ 90 - 16
app/Services/DeepSeek/DeepSeekService.php

@@ -659,7 +659,7 @@ class DeepSeekService
         $rid = getProp($data, 'rid');
         $script_id = getProp($data, 'script_id');
         $sequence = getProp($data, 'sequence', 0);
-        $products = getProp($data, 'products', []);
+        $content = getProp($data, 'content');
         
         if (!$rid) {
             Utils::throwError('20003:请选择对话记录ID');
@@ -679,23 +679,9 @@ class DeepSeekService
             Utils::throwError('20003:剧本不存在');
         }
 
-        // 解析 messages(可能是 JSON 字符串或数组)
-        if (is_string($products)) {
-            $products = json_decode($products, true);
-            if (json_last_error() !== JSON_ERROR_NONE) {
-                Utils::throwError('20003:消息格式错误');
-            }
-        }
-
-        if (empty($products)) {
-            Utils::throwError('20003:消息不能为空');
-        }
-
-        $json = json_encode($products, 256);
-
         // 批量插入数据
         return DB::table('mp_script_records')->where('id', $rid)->update([
-            'products'      => $json,
+            'content'      => $content,
             'updated_at'    => date('Y-m-d H:i:s')
         ]);
     }
@@ -7500,6 +7486,94 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
         $extra_products = getProp($data, 'products', []);
         if (is_string($extra_products)) $extra_products = json_decode($extra_products, true);
 
+        // 如果anime有关联的script_id,则从mp_script_product_mappings中查询资产并合并到extra_products
+        $anime_script_id = getProp($anime, 'script_id');
+        if ($anime_script_id) {
+            $cpid = Site::getCpid();
+            $script_products_mappings = DB::table('mp_script_product_mappings as mapping')
+                ->join('mp_products as product', 'mapping.product_id', '=', 'product.id')
+                ->where('mapping.script_id', $anime_script_id)
+                ->where('product.cpid', $cpid)
+                ->where('product.is_deleted', 0);
+
+            // 如果提供了 episode_number,则过滤指定集数
+            if ($episode_number !== null && $episode_number !== '') {
+                $script_products_mappings->where('mapping.episode_number', $episode_number);
+            }
+
+            $mappings = $script_products_mappings->select(
+                    'mapping.product_id',
+                    'mapping.episode_number',
+                    'product.product_name',
+                    'product.type',
+                    'product.product',
+                    'product.pic_prompt',
+                    'product.url',
+                    'product.pic_task_id',
+                    'product.pic_task_status',
+                    'product.three_view_image_url'
+                )
+                ->get();
+
+            // 按 product_id 分组,合并 episode_number
+            $productMap = [];
+            foreach ($mappings as $item) {
+                $product_id = $item->product_id;
+                $product_name = $item->product_name;
+                
+                if (!isset($productMap[$product_id])) {
+                    $productMap[$product_id] = [
+                        'product_id' => $product_id,
+                        'product_name' => $product_name,
+                        'type' => (int)$item->type,
+                        'product' => (int)$item->product,
+                        'pic_prompt' => $item->pic_prompt,
+                        'url' => $item->url,
+                        'pic_task_id' => $item->pic_task_id,
+                        'pic_task_status' => $item->pic_task_status,
+                        'episode_numbers' => [],
+                    ];
+                }
+                
+                // 添加 episode_number(去重)
+                if (!in_array($item->episode_number, $productMap[$product_id]['episode_numbers'])) {
+                    $productMap[$product_id]['episode_numbers'][] = $item->episode_number;
+                }
+            }
+
+            // 将查询到的剧本资产合并到extra_products中
+            // 先构建extra_products的索引(以product_id+episode_number为key)
+            $extraProductsMap = [];
+            foreach ($extra_products as $item) {
+                $key = getProp($item, 'product_id') . '_' . getProp($item, 'episode_number', '');
+                $extraProductsMap[$key] = $item;
+            }
+
+            // 合并剧本资产(去重:product_id+episode_number)
+            foreach ($productMap as $product) {
+                foreach ($product['episode_numbers'] as $ep_num) {
+                    $key = $product['product_id'] . '_' . $ep_num;
+                    // 如果不存在则添加
+                    if (!isset($extraProductsMap[$key])) {
+                        $extraProductsMap[$key] = [
+                            'product_id' => $product['product_id'],
+                            'product_name' => $product['product_name'],
+                            'type' => $product['type'],
+                            'product' => $product['product'],
+                            'pic_prompt' => $product['pic_prompt'],
+                            'url' => $product['url'],
+                            'pic_task_id' => $product['pic_task_id'],
+                            'pic_task_status' => $product['pic_task_status'],
+                            'episode_number' => $ep_num,
+                        ];
+                    }
+                }
+            }
+
+            // 重新赋值给extra_products
+            $extra_products = array_values($extraProductsMap);
+        }
+
         // 处理提示词
         if ($prompt && $extra_products) {
             // 遍历extra_products,将prompt中的{product_name}替换为实际的product_name

+ 5 - 5
routes/api.php

@@ -219,14 +219,14 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
             Route::get('exportEpisodeImages', [AnimeController::class, 'exportEpisodeImages']);
 
             Route::get('globalProducts', [AnimeController::class, 'globalProducts']);     // 角色库
-            Route::post('createProduct', [AnimeController::class, 'createProduct']);      // 创建角色
-            Route::post('editProduct', [AnimeController::class, 'editProduct']);          // 编辑角色
-            // Route::get('getRoleVersions', [AnimeController::class, 'getRoleVersions']); // 获取角色版本历史
+            Route::post('createProduct', [AnimeController::class, 'createProduct']);      // 创建资产
+            Route::post('editProduct', [AnimeController::class, 'editProduct']);          // 编辑资产
+            // Route::get('getRoleVersions', [AnimeController::class, 'getRoleVersions']); // 获取资产版本历史
             // Route::post('restoreRoleVersion', [AnimeController::class, 'restoreRoleVersion']); // 恢复到指定版本
-            Route::get('deleteProduct', [AnimeController::class, 'deleteProduct']);       // 删除角色
+            Route::get('deleteProduct', [AnimeController::class, 'deleteProduct']);       // 删除资产
             Route::post('createFolder', [AnimeController::class, 'createFolder']);  // 新建文件夹
             Route::post('renameFolder', [AnimeController::class, 'renameFolder']); // 重命名文件夹
-            Route::post('moveRoleOrFolder', [AnimeController::class, 'moveProductOrFolder']); // 移动角色或文件夹
+            Route::post('moveRoleOrFolder', [AnimeController::class, 'moveProductOrFolder']); // 移动资产或文件夹
             Route::get('getFolderPath', [AnimeController::class, 'getFolderPath']); // 获取文件夹路径
             // 生成三视图(基于参考图生成主体的标准正面、侧面、后面三视图,主体完整。在最左侧添加主体正视图的特写,主体清晰完整。背景修改成纯白色,整体保持与参考图一致的美术风格和色彩搭配。画面无说明文字)
             Route::post('generateThreeView', [AnimeController::class, 'generateThreeView']);