Selaa lähdekoodia

调整分集相关代码,适配多版本业务,使用分集ID作为唯一值

lh 3 kuukautta sitten
vanhempi
commit
7f08f6e643

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

@@ -376,6 +376,468 @@ class AnimeController extends BaseController
         }
     }
 
+    /**
+     * 批量生成分镜视频
+     */
+    public function batchSetSegmentVideos(Request $request) {
+        $data = $request->all();
+        
+        // 验证参数
+        $validator = Validator::make($data, [
+            'anime_id' => 'required|string',
+            'episode_number' => 'required|integer',
+        ], [
+            'anime_id.required' => '动漫对话ID不能为空',
+            'episode_number.required' => '剧集序号不能为空',
+            'episode_number.integer' => '剧集序号必须是整数',
+        ]);
+        
+        if ($validator->fails()) {
+            Utils::throwError('1002:' . $validator->errors()->first());
+        }
+        
+        $animeId = $data['anime_id'];
+        $episodeId = $data['episode_id'];
+        $episodeNumber = $data['episode_number'];
+        
+        // 获取所有分镜信息
+        $segments = DB::table('mp_episode_segments')
+            ->where('anime_id', $animeId)
+            ->where('episode_id', $episodeId)
+            ->orderBy('segment_number')
+            ->get();
+            
+        if ($segments->isEmpty()) {
+            Utils::throwError('20003:未找到分镜数据');
+        }
+        
+        // 批量创建视频任务
+        $taskIds = [];
+        $segmentTasks = [];
+        
+        foreach ($segments as $segment) {
+            try {
+                // 检查是否已有视频或正在生成中
+                if (!empty($segment->video_url) || $segment->video_task_status === '生成中') {
+                    continue;
+                }
+                
+                // 获取分镜内容
+                $segmentContent = $segment->segment_content ?: '';
+                $tailFrame = $segment->tail_frame ?: '';
+                
+                // 构建完整的提示词
+                $fullPrompt = $segmentContent;
+                if ($tailFrame) {
+                    $fullPrompt .= "\n尾帧描述:$tailFrame";
+                }
+                
+                // 智能选择视频时长
+                $videoDuration = $this->calculateOptimalVideoDuration($segmentContent, $tailFrame);
+                
+                // 构建视频生成参数
+                $videoParams = [
+                    'model' => 'doubao-seedance-1-5-pro-251215',
+                    'prompt' => $fullPrompt,
+                    'video_duration' => $videoDuration,
+                    'video_resolution' => '720P',
+                    'seed' => -1,
+                    'ratio' => '16:9',
+                    'generate_audio' => false,
+                    'draft' => false,
+                    'watermark' => false,
+                    'camera_fixed' => false,
+                    'callback_url' => 'http://mpaudio.yqsd.cn'
+                ];
+                
+                // 如果分镜有图片,作为首帧
+                if (!empty($segment->img_url)) {
+                    $videoParams['first_frame_url'] = $segment->img_url;
+                }
+                
+                // 构建content数组
+                $videoParams['content'] = [
+                    [
+                        'type' => 'text',
+                        'text' => $videoParams['prompt'],
+                    ]
+                ];
+                
+                // 如果有首帧图片,添加到content中
+                if (isset($videoParams['first_frame_url'])) {
+                    $videoParams['content'][] = [
+                        'type' => 'image_url',
+                        'image_url' => [
+                            'url' => $videoParams['first_frame_url'],
+                        ],
+                        'role' => 'first_frame',
+                    ];
+                }
+                
+                // 创建视频任务
+                $task = $this->AIVideoGenerationService->createSeedanceTask($videoParams);
+                $taskIds[] = $task->id;
+                
+                // 更新分镜表的视频任务信息
+                DB::table('mp_episode_segments')
+                    ->where('segment_id', $segment->segment_id)
+                    ->update([
+                        'video_task_id' => $task->id,
+                        'video_task_status' => '生成中',
+                        'updated_at' => date('Y-m-d H:i:s')
+                    ]);
+                
+                $segmentTasks[] = [
+                    'segment_id' => $segment->segment_id,
+                    'task_id' => $task->id,
+                    'segment_number' => $segment->segment_number,
+                ];
+                
+            } catch (\Exception $e) {
+                dLog('anime')->error('创建分镜视频任务失败: ' . $e->getMessage(), [
+                    'segment_id' => $segment->segment_id,
+                    'anime_id' => $animeId,
+                    'episode_number' => $episodeNumber
+                ]);
+                continue;
+            }
+        }
+        
+        if (empty($taskIds)) {
+            Utils::throwError('20003:没有需要生成视频的分镜');
+        }
+        
+        // 记录开始时间(包含创建任务的时间)
+        $startTime = time();
+        $maxDuration = 1800; // 30分钟超时
+        
+        // 设置 SSE 响应头并开始长连接
+        return response()->stream(function () use ($taskIds, $segmentTasks, $animeId, $episodeNumber, $episodeId, $startTime, $maxDuration) {
+            // 发送初始任务创建信息
+            echo "data: " . json_encode([
+                'type' => 'tasks_created',
+                'data' => [
+                    'anime_id' => $animeId,
+                    'episode_id' => $episodeId,
+                    'episode_number' => $episodeNumber,
+                    'total_tasks' => count($taskIds),
+                    'task_ids' => $taskIds,
+                    'segments' => $segmentTasks,
+                    'start_time' => $startTime,
+                    'max_duration' => $maxDuration
+                ]
+            ]) . "\n\n";
+            ob_flush();
+            flush();
+            
+            $checkInterval = 10; // 每10秒检查一次
+            $completedTasks = [];
+            $failedTasks = [];
+            
+            // 检查是否已经超时(包含创建任务的时间)
+            while (time() - $startTime < $maxDuration) {
+                try {
+                    $allCompleted = true;
+                    $currentStatus = [];
+                    
+                    foreach ($segmentTasks as $segmentTask) {
+                        $taskId = $segmentTask['task_id'];
+                        $segmentId = $segmentTask['segment_id'];
+                        
+                        // 跳过已完成或失败的任务
+                        if (in_array($taskId, $completedTasks) || in_array($taskId, $failedTasks)) {
+                            continue;
+                        }
+                        
+                        // 查询任务状态
+                        $task = \App\Models\MpGenerateVideoTask::find($taskId);
+                        if (!$task) {
+                            $failedTasks[] = $taskId;
+                            continue;
+                        }
+                        
+                        // 如果任务还在处理中,查询最新状态
+                        if ($task->status === 'processing') {
+                            $statusResult = $this->AIVideoGenerationService->querySeedanceTaskStatus($task);
+                            if (isset($statusResult['status'])) {
+                                // 更新任务状态
+                                $task->update([
+                                    'status' => $statusResult['status'],
+                                    'result_url' => $statusResult['result_url'] ?? null,
+                                    'last_frame_url' => $statusResult['last_frame_url'] ?? '',
+                                    'error_message' => $statusResult['error_message'] ?? null,
+                                    'completed_at' => in_array($statusResult['status'], [
+                                        'success',
+                                        'failed'
+                                    ]) ? now() : null
+                                ]);
+                                
+                                // 如果任务成功,更新分镜表
+                                if ($statusResult['status'] === 'success' && isset($statusResult['result_url'])) {
+                                    DB::table('mp_episode_segments')
+                                        ->where('segment_id', $segmentId)
+                                        ->update([
+                                            'video_url' => $statusResult['result_url'],
+                                            'video_task_status' => '已完成',
+                                            'last_frame_url' => $statusResult['last_frame_url'] ?? '',
+                                            'updated_at' => date('Y-m-d H:i:s')
+                                        ]);
+                                    
+                                    $completedTasks[] = $taskId;
+                                    
+                                    // 发送单个任务完成通知
+                                    echo "data: " . json_encode([
+                                        'type' => 'task_completed',
+                                        'data' => [
+                                            'segment_id' => $segmentId,
+                                            'task_id' => $taskId,
+                                            'segment_number' => $segmentTask['segment_number'],
+                                            'status' => 'success',
+                                            'video_url' => $statusResult['result_url'],
+                                            'last_frame_url' => $statusResult['last_frame_url'] ?? '',
+                                            'completed_count' => count($completedTasks),
+                                            'total_count' => count($segmentTasks)
+                                        ]
+                                    ]) . "\n\n";
+                                    ob_flush();
+                                    flush();
+                                    
+                                } elseif ($statusResult['status'] === 'failed') {
+                                    DB::table('mp_episode_segments')
+                                        ->where('segment_id', $segmentId)
+                                        ->update([
+                                            'video_task_status' => '失败',
+                                            'updated_at' => date('Y-m-d H:i:s')
+                                        ]);
+                                    
+                                    $failedTasks[] = $taskId;
+                                    
+                                    // 发送任务失败通知
+                                    echo "data: " . json_encode([
+                                        'type' => 'task_failed',
+                                        'data' => [
+                                            'segment_id' => $segmentId,
+                                            'task_id' => $taskId,
+                                            'segment_number' => $segmentTask['segment_number'],
+                                            'status' => 'failed',
+                                            'error_message' => $statusResult['error_message'] ?? '视频生成失败',
+                                            'failed_count' => count($failedTasks),
+                                            'total_count' => count($segmentTasks)
+                                        ]
+                                    ]) . "\n\n";
+                                    ob_flush();
+                                    flush();
+                                }
+                            }
+                        }
+                        
+                        // 收集当前状态
+                        $currentStatus[] = [
+                            'segment_id' => $segmentId,
+                            'task_id' => $taskId,
+                            'segment_number' => $segmentTask['segment_number'],
+                            'status' => $task->status,
+                            'progress' => $this->getTaskProgress($task->status),
+                            'video_url' => $task->result_url,
+                            'error_message' => $task->error_message
+                        ];
+                        
+                        // 检查是否还有未完成的任务
+                        if (!in_array($task->status, ['success', 'failed'])) {
+                            $allCompleted = false;
+                        }
+                    }
+                    
+                    // 发送整体进度更新
+                    echo "data: " . json_encode([
+                        'type' => 'progress_update',
+                        'data' => [
+                            'anime_id' => $animeId,
+                            'episode_id' => $episodeId,
+                            'episode_number' => $episodeNumber,
+                            'completed_count' => count($completedTasks),
+                            'failed_count' => count($failedTasks),
+                            'total_count' => count($segmentTasks),
+                            'elapsed_time' => time() - $startTime,
+                            'remaining_time' => max(0, $maxDuration - (time() - $startTime)),
+                            'segments_status' => $currentStatus
+                        ]
+                    ]) . "\n\n";
+                    ob_flush();
+                    flush();
+                    
+                    // 如果所有任务都完成了,结束连接
+                    if ($allCompleted) {
+                        // 获取最终结果
+                        $finalSegments = DB::table('mp_episode_segments')
+                            ->where('anime_id', $animeId)
+                            ->where('episode_id', $episodeId)
+                            ->orderBy('segment_number')
+                            ->select('segment_id', 'segment_number', 'video_url', 'video_task_status', 'last_frame_url')
+                            ->get();
+                        
+                        echo "data: " . json_encode([
+                            'type' => 'all_completed',
+                            'data' => [
+                                'anime_id' => $animeId,
+                                'episode_id' => $episodeId,
+                                'episode_number' => $episodeNumber,
+                                'completed_count' => count($completedTasks),
+                                'failed_count' => count($failedTasks),
+                                'total_count' => count($segmentTasks),
+                                'total_elapsed_time' => time() - $startTime,
+                                'segments' => $finalSegments->map(function($segment) {
+                                    return [
+                                        'segment_id' => $segment->segment_id,
+                                        'segment_number' => $segment->segment_number,
+                                        'video_url' => $segment->video_url,
+                                        'status' => $segment->video_task_status,
+                                        'last_frame_url' => $segment->last_frame_url
+                                    ];
+                                })->toArray()
+                            ]
+                        ]) . "\n\n";
+                        ob_flush();
+                        flush();
+                        break;
+                    }
+                    
+                    // 在睡眠前再次检查是否超时,避免不必要的等待
+                    if (time() - $startTime >= $maxDuration) {
+                        break;
+                    }
+                    
+                    sleep($checkInterval);
+                    
+                } catch (\Exception $e) {
+                    echo "data: " . json_encode([
+                        'type' => 'error',
+                        'message' => '查询任务状态失败: ' . $e->getMessage(),
+                        'elapsed_time' => time() - $startTime,
+                        'remaining_time' => max(0, $maxDuration - (time() - $startTime))
+                    ]) . "\n\n";
+                    ob_flush();
+                    flush();
+                    
+                    // 检查是否超时,如果超时则停止循环
+                    if (time() - $startTime >= $maxDuration) {
+                        break;
+                    }
+                    
+                    sleep($checkInterval);
+                }
+            }
+            
+            // 超时处理 - 只有在真正超时时才执行
+            if (time() - $startTime >= $maxDuration) {
+                // 获取当前所有任务状态
+                $timeoutSegments = DB::table('mp_episode_segments')
+                    ->where('anime_id', $animeId)
+                    ->where('episode_id', $episodeId)
+                    ->orderBy('segment_number')
+                    ->select('segment_id', 'segment_number', 'video_task_id', 'video_task_status', 'video_url')
+                    ->get();
+                
+                echo "data: " . json_encode([
+                    'type' => 'timeout',
+                    'message' => '批量视频生成已超时30分钟,停止状态查询',
+                    'data' => [
+                        'anime_id' => $animeId,
+                        'episode_id' => $episodeId,
+                        'episode_number' => $episodeNumber,
+                        'completed_count' => count($completedTasks),
+                        'failed_count' => count($failedTasks),
+                        'total_count' => count($segmentTasks),
+                        'total_elapsed_time' => time() - $startTime,
+                        'timeout_duration' => $maxDuration,
+                        'segments' => $timeoutSegments->map(function($segment) {
+                            return [
+                                'segment_id' => $segment->segment_id,
+                                'segment_number' => $segment->segment_number,
+                                'task_id' => $segment->video_task_id,
+                                'status' => $segment->video_task_status,
+                                'video_url' => $segment->video_url
+                            ];
+                        })->toArray()
+                    ]
+                ]) . "\n\n";
+                ob_flush();
+                flush();
+            }
+            
+        }, 200, [
+            'Content-Type' => 'text/event-stream',
+            'Cache-Control' => 'no-cache',
+            'Connection' => 'keep-alive',
+            'X-Accel-Buffering' => 'no', // 禁用 Nginx 缓冲
+        ]);
+    }
+
+    /**
+     * 计算最优视频时长(从 AnimeService 复制)
+     */
+    private function calculateOptimalVideoDuration($segmentContent, $tailFrame = '') {
+        // 基础时长
+        $baseDuration = 4;
+        
+        // 根据内容长度调整
+        $contentLength = mb_strlen($segmentContent);
+        if ($contentLength > 200) {
+            $baseDuration += 2;
+        } elseif ($contentLength > 100) {
+            $baseDuration += 1;
+        }
+        
+        // 根据内容复杂度调整
+        $complexity = $this->analyzeContentComplexity($segmentContent);
+        if ($complexity > 0.7) {
+            $baseDuration += 2;
+        } elseif ($complexity > 0.5) {
+            $baseDuration += 1;
+        }
+        
+        // 如果有尾帧描述,增加时长
+        if (!empty($tailFrame)) {
+            $baseDuration += 1;
+        }
+        
+        // 限制在合理范围内
+        return min(max($baseDuration, 4), 12);
+    }
+
+    /**
+     * 分析内容复杂度(从 AnimeService 复制)
+     */
+    private function analyzeContentComplexity($text) {
+        $complexity = 0;
+        
+        // 动作词汇
+        $actionWords = ['跑', '跳', '飞', '战斗', '攻击', '移动', '转身', '冲刺', '闪避', '追逐'];
+        foreach ($actionWords as $word) {
+            if (strpos($text, $word) !== false) {
+                $complexity += 0.1;
+            }
+        }
+        
+        // 场景变化词汇
+        $sceneWords = ['切换', '转场', '变化', '移动', '远景', '近景', '特写'];
+        foreach ($sceneWords as $word) {
+            if (strpos($text, $word) !== false) {
+                $complexity += 0.15;
+            }
+        }
+        
+        // 情感词汇
+        $emotionWords = ['激动', '愤怒', '悲伤', '惊讶', '恐惧', '兴奋'];
+        foreach ($emotionWords as $word) {
+            if (strpos($text, $word) !== false) {
+                $complexity += 0.05;
+            }
+        }
+        
+        return min($complexity, 1.0);
+    }
+
     // public function scriptList(Request $request) {
     //     $data = $request->all();
     //     $result = $this->AnimeService->scriptList($data);

+ 22 - 17
app/Services/Anime/AnimeService.php

@@ -270,12 +270,12 @@ class AnimeService
 
     public function episodeInfo($data) {
         $anime_id = getProp($data, 'anime_id');
-        $episode_number = getProp($data, 'episode_number');
-        if (!$anime_id || !$episode_number) {
+        $episode_id = getProp($data, 'episode_id');
+        if (!$anime_id || !$episode_id) {
             Utils::throwError('1002:请选择剧集');
         }
 
-        $episode = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('is_default', 1)->select('id as episode_id', 'anime_id', 'episode_number', 'title', 'intro', 'art_style', 'roles', 'scenes')->first();
+        $episode = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_id', $episode_id)->where('is_default', 1)->select('id as episode_id', 'anime_id', 'episode_number', 'title', 'intro', 'art_style', 'roles', 'scenes')->first();
         if (!$episode) Utils::throwError('20003: 该剧集不存在!');
         $episode = (array)$episode;
         $episode['roles'] = json_decode($episode['roles'], true);
@@ -370,12 +370,12 @@ class AnimeService
 
     public function episodeVersions($data) {
         $anime_id = getProp($data, 'anime_id');
-        $episode_number = getProp($data, 'episode_number');
-        if (!$anime_id || !$episode_number) {
+        $episode_id = getProp($data, 'episode_id');
+        if (!$anime_id || !$episode_id) {
             Utils::throwError('1002:请选择剧集');
         }
 
-        $episodes = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->select('anime_id', 'episode_number', 'sequence', 'title', 'intro', 'art_style', 'roles', 'scenes')->get()->map(function($value) {
+        $episodes = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_id', $episode_id)->select('anime_id', 'episode_number', 'sequence', 'title', 'intro', 'art_style', 'roles', 'scenes')->get()->map(function($value) {
             return (array)$value;
         })->toArray();
         if (!$episodes) Utils::throwError('20003: 该剧集不存在!');
@@ -462,20 +462,20 @@ class AnimeService
 
     public function batchSetSegmentPics($data) {
         $anime_id = getProp($data, 'anime_id');
-        $episode_number = getProp($data, 'episode_number');
+        $episode_id = getProp($data, 'episode_id');
         $ratio = getProp($data, 'ratio');
         if (!in_array($ratio, ['1:1', '4:3', '3:2', '16:9', '21:9'])) {
             Utils::throwError('1002:画面比例选择不正确,只支持1:1、4:3、3:2、16:9、21:9');
         }
         
-        if (!$anime_id || !$episode_number) {
+        if (!$anime_id || !$episode_id) {
             Utils::throwError('1002:请选择剧集');
         }
 
         // 获取剧集信息
         $episode = DB::table('mp_anime_episodes')
             ->where('anime_id', $anime_id)
-            ->where('episode_number', $episode_number)
+            ->where('episode_id', $episode_id)
             ->where('is_default', 1)
             ->select('id as episode_id', 'anime_id', 'episode_number')
             ->first();
@@ -704,6 +704,7 @@ class AnimeService
         $segment_id = getProp($data, 'segment_id');
         $segment = DB::table('mp_episode_segments')->where('segment_id', $segment_id)->first();
         $anime_id = getProp($segment, 'anime_id');
+        $episode_id = getProp($segment, 'episode_id');
         $episode_number = getProp($segment, 'episode_number');
         $segment_content = getProp($data, 'segment_content');
         $ratio = getProp($data, 'ratio');
@@ -711,7 +712,7 @@ class AnimeService
             Utils::throwError('1002:画面比例选择不正确,只支持1:1、4:3、3:2、16:9、21:9');
         }
         
-        if (!$anime_id || !$episode_number) {
+        if (!$anime_id || !$episode_id) {
             Utils::throwError('1002:请选择分镜');
         }
 
@@ -884,6 +885,7 @@ class AnimeService
         $prev_segment_id = getProp($data, 'prev_segment_id');
         $segment = DB::table('mp_episode_segments')->where('segment_id', $prev_segment_id)->first();
         $anime_id = getProp($segment, 'anime_id');
+        $episode_id = getProp($segment, 'episode_id');
         $episode_number = getProp($segment, 'episode_number');
         $segment_number = getProp($segment, 'segment_number');
         $segment_content = getProp($data, 'segment_content');
@@ -894,7 +896,7 @@ class AnimeService
             Utils::throwError('1002:画面比例选择不正确,只支持1:1、4:3、3:2、16:9、21:9');
         }
         
-        if (!$anime_id || !$episode_number) {
+        if (!$anime_id || !$episode_id) {
             Utils::throwError('1002:请选择分镜');
         }
 
@@ -978,7 +980,7 @@ class AnimeService
             // 分镜剧本数组
             $insert_data = [
                 'anime_id'      => $anime_id,
-                'episode_id'    => getProp($segment, 'episode_id'),
+                'episode_id'    => $episode_id,
                 'episode_number' => $episode_number,
                 'act_number'    => getProp($segment, 'act_number'),
                 'act_title'     => getProp($segment, 'act_title'),
@@ -1061,7 +1063,7 @@ class AnimeService
             }
             
             // 先更新序号
-            $boolen = DB::table('mp_episode_segments')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('segment_number', '>', $segment_number)->increment('segment_number');
+            $boolen = DB::table('mp_episode_segments')->where('anime_id', $anime_id)->where('episode_id', $episode_id)->where('segment_number', '>', $segment_number)->increment('segment_number');
             if (!$boolen) {
                 Utils::throwError('20003:更新序号失败');
             }
@@ -1095,6 +1097,7 @@ class AnimeService
         $segment = DB::table('mp_episode_segments')->where('segment_id', $segment_id)->first();
         if (!$segment) Utils::throwError('20003:请选择分镜');
         $anime_id = getProp($segment, 'anime_id');
+        $episode_id = getProp($segment, 'episode_id');
         $episode_number = getProp($segment, 'episode_number');
         $segment_number = getProp($segment, 'segment_number');
 
@@ -1109,7 +1112,7 @@ class AnimeService
             $segment['created_at'] = $segment['updated_at'] = date('Y-m-d H:i:s');
 
             // 更新其他分镜序号
-            $boolen2 = DB::table('mp_episode_segments')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('segment_number', '>', $segment_number)->increment('segment_number');
+            $boolen2 = DB::table('mp_episode_segments')->where('anime_id', $anime_id)->where('episode_id', $episode_id)->where('segment_number', '>', $segment_number)->increment('segment_number');
             if (!$boolen2) {
                 Utils::throwError('20003:更新其他分镜序号失败');
             }
@@ -1143,6 +1146,7 @@ class AnimeService
         if (!$target_segment) Utils::throwError('20003:目标分镜不存在');
         
         $anime_id = getProp($source_segment, 'anime_id');
+        $episode_id = getProp($source_segment, 'episode_id');
         $episode_number = getProp($source_segment, 'episode_number');
         $source_segment_number = getProp($source_segment, 'segment_number');
         $target_segment_number = getProp($target_segment, 'segment_number');
@@ -1168,7 +1172,7 @@ class AnimeService
                 // 1. 将源分镜和目标分镜之间的所有分镜序号减1
                 DB::table('mp_episode_segments')
                     ->where('anime_id', $anime_id)
-                    ->where('episode_number', $episode_number)
+                    ->where('episode_id', $episode_id)
                     ->where('segment_number', '>', $source_segment_number)
                     ->where('segment_number', '<=', $target_segment_number)
                     ->decrement('segment_number');
@@ -1181,7 +1185,7 @@ class AnimeService
                 // 1. 将目标分镜之后到源分镜之前的所有分镜序号加1
                 DB::table('mp_episode_segments')
                     ->where('anime_id', $anime_id)
-                    ->where('episode_number', $episode_number)
+                    ->where('episode_id', $episode_id)
                     ->where('segment_number', '>', $target_segment_number)
                     ->where('segment_number', '<', $source_segment_number)
                     ->increment('segment_number');
@@ -1216,6 +1220,7 @@ class AnimeService
         $segment = DB::table('mp_episode_segments')->where('segment_id', $segment_id)->first();
         if (!$segment) Utils::throwError('20003:请选择分镜');
         $anime_id = getProp($segment, 'anime_id');
+        $episode_id = getProp($segment, 'episode_id');
         $episode_number = getProp($segment, 'episode_number');
         $segment_number = getProp($segment, 'segment_number');
 
@@ -1229,7 +1234,7 @@ class AnimeService
             }
 
             // 更新其他分镜序号
-            $boolen2 = DB::table('mp_episode_segments')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('segment_number', '>', $segment_number)->decrement('segment_number');
+            $boolen2 = DB::table('mp_episode_segments')->where('anime_id', $anime_id)->where('episode_id', $episode_id)->where('segment_number', '>', $segment_number)->decrement('segment_number');
             if (!$boolen2) {
                 Utils::throwError('20003:更新其他分镜序号失败');
             }

+ 2 - 2
app/Services/DeepSeek/DeepSeekService.php

@@ -2949,11 +2949,11 @@ EOD;
                 'updated_at' => date('Y-m-d H:i:s'),
             ];
 
-            $current_episode = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->select('id', 'sequence')->first();
+            $current_episode = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('is_default', 1)->select('id', 'sequence')->first();
             if ($current_episode) {
                 $episode['sequence'] = getProp($current_episode, 'sequence');
                 $episode_id = getProp($current_episode, 'id');
-                $boolen2 = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_number', $episode_number)->where('sequence', $episode['sequence'])->update($episode);
+                $boolen2 = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('episode_id', $episode_id)->update($episode);
             }else {
                 $episode['created_at'] = date('Y-m-d H:i:s');
                 $episode_id = DB::table('mp_anime_episodes')->insertGetId($episode);

+ 69 - 0
test_batch_segment_videos.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * 测试批量生成分镜视频接口
+ * 
+ * 使用方法:
+ * php test_batch_segment_videos.php
+ */
+
+// 测试参数
+$testData = [
+    'anime_id' => 'test_anime_001',
+    'episode_number' => 1
+];
+
+// API 端点
+$apiUrl = 'http://localhost/api/anime/batchSetSegmentVideos';
+
+// 构建 POST 数据
+$postData = http_build_query($testData);
+
+// 设置 cURL 选项
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, $apiUrl);
+curl_setopt($ch, CURLOPT_POST, true);
+curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
+curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) {
+    // 处理 SSE 数据
+    if (strpos($data, 'data: ') === 0) {
+        $jsonData = substr($data, 6);
+        $jsonData = trim($jsonData);
+        
+        if (!empty($jsonData)) {
+            $decoded = json_decode($jsonData, true);
+            if ($decoded) {
+                echo "收到数据: " . json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
+            }
+        }
+    }
+    
+    return strlen($data);
+});
+
+// 设置请求头
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'Accept: text/event-stream',
+    'Cache-Control: no-cache',
+    'Content-Type: application/x-www-form-urlencoded'
+]);
+
+echo "开始测试批量生成分镜视频接口...\n";
+echo "测试参数: " . json_encode($testData, JSON_UNESCAPED_UNICODE) . "\n";
+echo "API 地址: $apiUrl\n";
+echo "等待响应...\n\n";
+
+// 执行请求
+$result = curl_exec($ch);
+
+if (curl_error($ch)) {
+    echo "cURL 错误: " . curl_error($ch) . "\n";
+}
+
+$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+echo "\nHTTP 状态码: $httpCode\n";
+
+curl_close($ch);
+
+echo "\n测试完成。\n";
+?>