Explorar el Código

动漫对话(全能模式)和重新生成分段剧本增加对道具的支持,优化提示词和调整格式化匹配规则

lh hace 2 días
padre
commit
165d0309a7
Se han modificado 2 ficheros con 303 adiciones y 16 borrados
  1. 127 5
      app/Services/Anime/AnimeService.php
  2. 176 11
      app/Services/DeepSeek/DeepSeekService.php

+ 127 - 5
app/Services/Anime/AnimeService.php

@@ -8370,13 +8370,15 @@ class AnimeService
         }
         $roles = json_decode(getProp($episode, 'roles'), true) ?: [];
         $scenes = json_decode(getProp($episode, 'scenes'), true) ?: [];
+        $props = json_decode(getProp($episode, 'props'), true) ?: [];
 
         // 获取所有片段数据
         $acts = DB::table('mp_episode_segments')->where('episode_id', $episode_id)->orderBy('act_number')->get();
         
-        // 构建角色和场景名称数组
+        // 构建角色、场景和道具名称数组
         $role_names = [];
         $scene_names = [];
+        $prop_names = [];
         
         foreach ($roles as $role) {
             $role_name = getProp($role, 'role');
@@ -8392,6 +8394,13 @@ class AnimeService
             }
         }
         
+        foreach ($props as $prop) {
+            $prop_name = getProp($prop, 'prop');
+            if ($prop_name) {
+                $prop_names[] = $prop_name;
+            }
+        }
+        
         // 按照字符长度降序排序,确保先匹配长的名称(避免部分匹配问题)
         usort($role_names, function($a, $b) {
             return mb_strlen($b) - mb_strlen($a);
@@ -8399,6 +8408,9 @@ class AnimeService
         usort($scene_names, function($a, $b) {
             return mb_strlen($b) - mb_strlen($a);
         });
+        usort($prop_names, function($a, $b) {
+            return mb_strlen($b) - mb_strlen($a);
+        });
 
         try {
             DB::beginTransaction();
@@ -8432,12 +8444,32 @@ class AnimeService
                     }, $processed_content);
                 }
                 
-                // 再匹配角色名称(只在"画面:"部分)
+                // 匹配道具(在"道具:"后面,逻辑与场景一致)
+                foreach ($prop_names as $prop_name) {
+                    // 转义特殊字符
+                    $escaped_prop = preg_quote($prop_name, '/');
+                    // 匹配道具:后面的道具名称(可能换行,也可能不换行)
+                    $pattern = '/(道具:[\s\r\n]*)(' . $escaped_prop . ')/u';
+                    
+                    $processed_content = preg_replace_callback($pattern, function($matches) use (&$marked_positions) {
+                        $full_match = $matches[0];
+                        $prefix = $matches[1];
+                        $prop_name = $matches[2];
+                        
+                        // 检查是否已经被标记
+                        if (strpos($prop_name, '{') === false && strpos($prop_name, '}') === false) {
+                            return $prefix . '{' . $prop_name . '}';
+                        }
+                        return $full_match;
+                    }, $processed_content);
+                }
+                
+                // 再匹配角色名称(在"画面:"部分和"角色:"部分)
                 foreach ($role_names as $role_name) {
                     // 转义特殊字符
                     $escaped_role = preg_quote($role_name, '/');
                     
-                    // 只匹配"画面:"开始到换行之前的内容
+                    // 1. 匹配"画面:"开始到换行之前的内容
                     $pattern = '/(画面:[^\n]*)/u';
                     $processed_content = preg_replace_callback($pattern, function($matches) use ($escaped_role) {
                         $line = $matches[1]; // 整行"画面:xxxxx"
@@ -8451,6 +8483,84 @@ class AnimeService
                         
                         return $new_line;
                     }, $processed_content);
+                    
+                    // 2. 匹配"角色:"或"出场角色:"这一整行内的角色名称
+                    $pattern = '/((?:出场)?角色:[^\n]*)/u';
+                    $processed_content = preg_replace_callback($pattern, function($matches) use ($escaped_role) {
+                        $line = $matches[1]; // 整行"角色:xxxxx"或"出场角色:xxxxx"
+                        
+                        // 在这一行中匹配所有角色名(避免重复标记)
+                        $new_line = preg_replace(
+                            '/(?<![{])(' . $escaped_role . ')(?![}])/u',
+                            '{$1}',
+                            $line
+                        );
+                        
+                        return $new_line;
+                    }, $processed_content);
+                }
+                
+                // 匹配道具名称(在"画面:"部分,逻辑与角色一致)
+                foreach ($prop_names as $prop_name) {
+                    // 转义特殊字符
+                    $escaped_prop = preg_quote($prop_name, '/');
+                    
+                    // 匹配"画面:"开始到换行之前的内容
+                    $pattern = '/(画面:[^\n]*)/u';
+                    $processed_content = preg_replace_callback($pattern, function($matches) use ($escaped_prop) {
+                        $line = $matches[1]; // 整行"画面:xxxxx"
+                        
+                        // 在这一行中匹配所有道具名(避免重复标记)
+                        $new_line = preg_replace(
+                            '/(?<![{])(' . $escaped_prop . ')(?![}])/u',
+                            '{$1}',
+                            $line
+                        );
+                        
+                        return $new_line;
+                    }, $processed_content);
+                }
+                
+                // 匹配角色名称(在"运镜:"部分)
+                foreach ($role_names as $role_name) {
+                    // 转义特殊字符
+                    $escaped_role = preg_quote($role_name, '/');
+                    
+                    // 匹配"运镜:"开始到换行之前的内容
+                    $pattern = '/(运镜:[^\n]*)/u';
+                    $processed_content = preg_replace_callback($pattern, function($matches) use ($escaped_role) {
+                        $line = $matches[1]; // 整行"运镜:xxxxx"
+                        
+                        // 在这一行中匹配所有角色名(避免重复标记)
+                        $new_line = preg_replace(
+                            '/(?<![{])(' . $escaped_role . ')(?![}])/u',
+                            '{$1}',
+                            $line
+                        );
+                        
+                        return $new_line;
+                    }, $processed_content);
+                }
+                
+                // 匹配道具名称(在"运镜:"部分)
+                foreach ($prop_names as $prop_name) {
+                    // 转义特殊字符
+                    $escaped_prop = preg_quote($prop_name, '/');
+                    
+                    // 匹配"运镜:"开始到换行之前的内容
+                    $pattern = '/(运镜:[^\n]*)/u';
+                    $processed_content = preg_replace_callback($pattern, function($matches) use ($escaped_prop) {
+                        $line = $matches[1]; // 整行"运镜:xxxxx"
+                        
+                        // 在这一行中匹配所有道具名(避免重复标记)
+                        $new_line = preg_replace(
+                            '/(?<![{])(' . $escaped_prop . ')(?![}])/u',
+                            '{$1}',
+                            $line
+                        );
+                        
+                        return $new_line;
+                    }, $processed_content);
                 }
                 
                 // 处理【镜头X】或【分镜X】重新编号为从1开始的连续整数【镜头X】
@@ -8494,8 +8604,8 @@ class AnimeService
         // 重新查询更新后的片段数据
         $acts = DB::table('mp_episode_segments')->where('episode_id', $episode_id)->orderBy('act_number')->get();
 
-        // 合并角色、场景和extra_products作为products,统一字段名为product_name
-        // extra_products优先级更高,会覆盖同名的roles和scenes
+        // 合并角色、场景、道具和extra_products作为products,统一字段名为product_name
+        // extra_products优先级更高,会覆盖同名的roles、scenes和props
         $products = [];
         
         // 先处理角色数组
@@ -8522,6 +8632,18 @@ class AnimeService
             $products[$product['product_name']] = $product; // 使用product_name作为key便于后续覆盖
         }
         
+        // 处理道具数组(逻辑与场景一致)
+        foreach ($props as $prop) {
+            $product = $prop;
+            // 将prop字段重命名为product_name
+            if (isset($product['prop'])) {
+                $product['product_name'] = $product['prop'];
+                unset($product['prop']);
+            }
+            $product['product'] = 3; // 标记类型为道具
+            $products[$product['product_name']] = $product; // 使用product_name作为key便于后续覆盖
+        }
+        
         // extra_products优先级更高,直接覆盖同名的roles和scenes
         $extra_products = json_decode(getProp($episode, 'extra_products', '[]'), true) ?: [];
         foreach ($extra_products as $extra_product) {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 176 - 11
app/Services/DeepSeek/DeepSeekService.php