Forráskód Böngészése

1.新建对话接口针对未给出明确剧本内容的提示词做兼容2.优化解析剧本内容的公共方法

lh 3 hónapja
szülő
commit
0e458cfd8a

+ 0 - 1
app/Http/Controllers/Anime/AnimeController.php

@@ -582,7 +582,6 @@ class AnimeController extends BaseController
             ->where('episode_id', $episodeId)
             ->whereNotIn('video_task_status', ['已完成', '生成中'])
             ->orderBy('segment_number')
-            ->limit(2)
             ->get();
             
         if ($segments->isEmpty()) {

+ 26 - 19
app/Libs/Helpers.php

@@ -2351,43 +2351,50 @@ function handleScriptContent($originalContent) {
     //     $originalContent = mb_convert_encoding($originalContent, 'UTF-8', 'auto');
     // }
     
-    // 提取剧本名(###剧本名:后面的内容)
-    if (preg_match('/###剧本名[::]\s*(.*?)(?=\n|$)/u', $originalContent, $summaryMatch)) {
+    // 提取剧本名(###剧本名:后面的内容,支持多个空格
+    if (preg_match('/###\s*剧本名\s*[::]\s*(.*?)(?=\n|$)/u', $originalContent, $summaryMatch)) {
         $parts['script_name'] = isset($summaryMatch[1]) ? trim($summaryMatch[1]) : '';
     }
-    // 提取故事梗概(直到遇到下一个###标记)
-    preg_match('/###故事梗概\s*\n(.*?)(?=\n###|$)/s', $originalContent, $summaryMatch);
+    // 提取故事梗概(直到遇到下一个###标记,支持多个空格
+    preg_match('/###\s*故事梗概\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $summaryMatch);
     $parts['intro'] = isset($summaryMatch[1]) ? trim($summaryMatch[1]) : '';
         
-    // 提取剧本亮点
-    preg_match('/###剧本亮点\s*\n(.*?)(?=\n###|$)/s', $originalContent, $highlightsMatch);
+    // 提取剧本亮点(支持多个空格)
+    preg_match('/###\s*剧本亮点\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $highlightsMatch);
     $parts['highlights'] = isset($highlightsMatch[1]) ? trim($highlightsMatch[1]) : '';
         
-    // 提取人物关系
-    preg_match('/###人物关系\s*\n(.*?)(?=\n###|$)/s', $originalContent, $relationsMatch);
+    // 提取人物关系(支持多个空格)
+    preg_match('/###\s*人物关系\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $relationsMatch);
     $parts['role_relationship'] = isset($relationsMatch[1]) ? trim($relationsMatch[1]) : '';
         
-    // 提取核心矛盾
-    preg_match('/###核心矛盾\s*\n(.*?)(?=\n###|$)/s', $originalContent, $contradictionsMatch);
+    // 提取核心矛盾(支持多个空格)
+    preg_match('/###\s*核心矛盾\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $contradictionsMatch);
     $parts['core_contradiction'] = isset($contradictionsMatch[1]) ? trim($contradictionsMatch[1]) : '';
         
-    // 提取主体列表
-    preg_match('/###主体列表\s*\n(.*?)(?=\n###|$)/s', $originalContent, $subjectsMatch);
+    // 提取主体列表(支持多个空格)
+    preg_match('/###\s*主体列表\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $subjectsMatch);
     $rolesText = isset($subjectsMatch[1]) ? trim($subjectsMatch[1]) : '';
     $parts['roles'] = parseRolesFromText($rolesText);
         
-    // 提取美术风格
-    preg_match('/###美术风格\s*\n(.*?)(?=\n###|$)/s', $originalContent, $artStyleMatch);
+    // 提取美术风格(支持多个空格)
+    preg_match('/###\s*美术风格\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $artStyleMatch);
     $parts['art_style'] = isset($artStyleMatch[1]) ? trim($artStyleMatch[1]) : '';
         
-    // 提取场景列表
-    preg_match('/###场景列表\s*\n(.*?)(?=\n###|$)/s', $originalContent, $scenesMatch);
+    // 提取场景列表(支持多个空格)
+    preg_match('/###\s*场景列表\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $scenesMatch);
     $scenesText = isset($scenesMatch[1]) ? trim($scenesMatch[1]) : '';
     $parts['scenes'] = parseScenesFromText($scenesText);
 
-    // 提取分集详细内容
-    preg_match('/###分集详细内容\s*\n(.*?)(?=\n###|$)/s', $originalContent, $contentMatch);
-    $parts['content'] = isset($contentMatch[1]) ? trim($contentMatch[1]) : '';
+    // 提取分集详细内容(多剧集模式,支持多个空格)
+    preg_match('/###\s*分集详细内容\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $contentMatch);
+    $detailedContent = isset($contentMatch[1]) ? trim($contentMatch[1]) : '';
+    
+    // 提取原文内容(单剧集模式,AI生成的原文,支持多个空格)
+    preg_match('/###\s*原文内容\s*\n(.*?)(?=\n\s*###|$)/s', $originalContent, $originalContentMatch);
+    $generatedContent = isset($originalContentMatch[1]) ? trim($originalContentMatch[1]) : '';
+    
+    // 优先使用原文内容,其次使用分集详细内容
+    $parts['content'] = $generatedContent ?: $detailedContent;
 
     $parts['episode_title'] = '';
     $parts['acts'] = [];

+ 1 - 1
app/Services/AIGeneration/AIVideoGenerationService.php

@@ -400,7 +400,7 @@ class AIVideoGenerationService
                 'return_last_frame' => $params['return_last_frame'] ?? true,
                 'service_tier' => $params['service_tier'] ?? 'default',
                 'execution_expires_after' => $params['execution_expires_after'] ?? 172800,
-                'generate_audio' => $params['generate_audio'] ?? true,
+                'generate_audio' => $params['generate_audio'] ?? false,
                 'draft' => $params['draft'] ?? false,
                 'ratio' => $params['ratio'] ?? '16:9',
                 'duration' => $params['video_duration'] ?? 5,

+ 22 - 4
app/Services/DeepSeek/DeepSeekService.php

@@ -2219,7 +2219,9 @@ class DeepSeekService
         } elseif ($content) { 
             $content = filterContent($content);
         } elseif ($prompt) {
-            $content = filterContent($prompt);
+            // 只有prompt的情况,需要生成原文内容
+            $content = '';
+            $need_generate_content = true;
         } else {
             Utils::throwError('20003:请上传文件或选择书籍或输入内容');
         }
@@ -2234,13 +2236,21 @@ class DeepSeekService
 老年女:婆婆
 萌娃:奶气萌娃";
 
+        // 判断是否需要生成原文内容
+        $need_generate_content = isset($need_generate_content) && $need_generate_content;
+        
+        // 如果需要生成原文内容,添加额外的要求
+        $content_generation_requirement = $need_generate_content 
+            ? "\n5.如果用户只提供了创作要求而没有提供具体文档内容,你需要根据要求创作完整的原文内容(小说形式,包含对话和叙述),并将原文内容放在最后一个板块###原文内容中输出。原文内容应该详细、生动,如果用户没有明确生成的字数,则字数不少于1000字。" 
+            : "";
+        
         $systemPrompt = $is_single
             ? "你是一个专业的文档分析助手及资深编剧,请根据用户提供的文档内容输出单剧集完整策划稿。单剧集模式下,必须一次性输出可直接保存的大纲与完整分镜,不允许只输出大纲。
             强制要求:
             1.你只负责与剧本相关的内容,如果用户输入与剧本无关的内容,请告知用户并拒绝继续回答,此为第一优先原则,不满足此原则就忽略其他要求并停止继续输出
             2.如果用户输入修改美术风格、修改画风这类内容,请告知用户不可修改美术风格,并拒绝继续回答
             3.以上两条要求对修改主体角色或场景不生效,允许用户调整主体角色说明和场景描述等
-            4.用户如果要求你帮忙写一个故事或者剧本,此类要求不属于与剧本无关,请帮助用户完成请求\n
+            4.用户如果要求你帮忙写一个故事或者剧本,此类要求不属于与剧本无关,请帮助用户完成请求{$content_generation_requirement}\n
             普通要求:
             1.剧集标题必须与文档内容高度相关,剧集序号是1。
             2.<主体列表>中出现的主体必须尽可能统一,只允许同一个角色年龄段相差较大的情况下可重复,比如角色-少年、角色-青年、角色-中年、角色-老年这种情况,不得出现角色-愤怒、角色-隐忍、角色-求生等情绪和状态变化的同一角色;并且角色的样貌、形体及穿着描述尽可能详细
@@ -2350,7 +2360,7 @@ class DeepSeekService
                 1.你只负责与剧本相关的内容,如果用户输入与剧本无关的内容,请告知用户并拒绝继续回答,此为第一优先原则,不满足此原则就忽略其他要求并停止继续输出
                 2.如果用户输入修改美术风格、修改画风这类内容,请告知用户不可修改美术风格,并拒绝继续回答
                 3.以上两条要求对修改主体角色或场景不生效,允许用户调整主体角色说明和场景描述等
-                4.用户如果要求你帮忙写一个故事或者剧本,此类要求不属于与剧本无关,请帮助用户完成请求\n
+                4.用户如果要求你帮忙写一个故事或者剧本,此类要求不属于与剧本无关,请帮助用户完成请求{$content_generation_requirement}\n
                 普通要求:\n
                 1.<主体列表>中出现的主体必须尽可能统一,只允许同一个角色年龄段相差较大的情况下可重复,比如梁萧-少年、梁萧-青年、梁萧-中年、梁萧-老年这种情况,不得出现梁萧-愤怒、梁萧-隐忍、梁萧-求生等情绪和状态变化的同一角色;并且角色的样貌、形体及穿着描述尽可能详细\n
                 2.<场景列表>与主体列表同理,需尽可能的对场景环境进行详细描述\n\n
@@ -2455,12 +2465,19 @@ class DeepSeekService
         $script_arr = [];
         if ($fullContent) {
             $script_arr = handleScriptContent($fullContent);
+            dLog('deepseek')->info('解析内容', $script_arr);
         }
 
         if (empty($script_arr['roles'])) {
             Utils::throwError('20003:未生成剧本相关的内容');
         }
 
+        // 如果需要生成原文内容,从script_arr中提取
+        if ($need_generate_content && isset($script_arr['content']) && $script_arr['content']) {
+            $content = $script_arr['content'];
+            dLog('deepseek')->info('从AI生成结果中提取原文内容', ['content_length' => strlen($content)]);
+        }
+
         // 替换美术风格
         $mappedArtStyle = $this->getArtStylePromptByInput($input_art_style);
         if ($mappedArtStyle !== '') {
@@ -2486,7 +2503,6 @@ class DeepSeekService
         if (DB::table('mp_animes')->where('anime_name', $anime_name)->value('id')) {
             $anime_name = $anime_name . '_' . date('YmdHis');
         }
-        
 
         $table_data = [
             'user_id' => $uid,
@@ -2632,6 +2648,7 @@ class DeepSeekService
         }
 
         DB::commit();
+        dLog('deepseek')->info('保存完毕');
         if ($is_single && !empty($single_episode)) {
             $this->batchSetGlobalRoleImg([
                 'anime_id' => $anime_id,
@@ -2647,6 +2664,7 @@ class DeepSeekService
         unset($table_data['created_at']);
         unset($table_data['updated_at']);
         unset($table_data['status']);
+        dLog('deepseek')->info('开始返回');
         yield [
             'type' => 'done',
             'script' => $table_data,