Преглед изворни кода

优化一键转视频sse获取结果的代码逻辑

lh пре 2 месеци
родитељ
комит
9ca21a4fdd
2 измењених фајлова са 146 додато и 220 уклоњено
  1. 141 219
      app/Http/Controllers/Anime/AnimeController.php
  2. 5 1
      app/Services/Anime/AnimeService.php

+ 141 - 219
app/Http/Controllers/Anime/AnimeController.php

@@ -639,6 +639,7 @@ class AnimeController extends BaseController
         $episode = DB::table('mp_anime_episodes')->where('id', $episodeId)->where('anime_id', $animeId)->first();
         if (!$episode) Utils::throwError('20003:分集不存在');
         $episodeNumber = $episode->episode_number;        
+        $ratio = !empty($episode->ratio) ? $episode->ratio : '9:16';
         // 获取所有分镜信息
         $segments = DB::table('mp_episode_segments')
             ->where('anime_id', $animeId)
@@ -702,7 +703,7 @@ class AnimeController extends BaseController
                     'video_duration' => $videoDuration,
                     'video_resolution' => '720P',
                     'seed' => -1,
-                    'ratio' => '9:16',
+                    'ratio' => $ratio,
                     'generate_audio' => false,
                     'draft' => false,
                     'watermark' => false,
@@ -841,47 +842,36 @@ class AnimeController extends BaseController
         $uid = Site::getUid();
         // 设置 SSE 响应头并开始长连接
         return response()->stream(function () use ($taskIds, $segmentTasks, $animeId, $episodeNumber, $episodeId, $startTime, $maxDuration, $uid) {
+            $checkInterval = 10; // 每10秒检查一次
+            
+            // 初始化任务数组
+            $totalTasks = $taskIds; // 所有任务ID
+            $completeTasks = []; // 已完成的任务ID(包含失败)
+            $successTasks = []; // 成功的任务ID
+            
             // 发送初始任务创建信息
             echo "data: " . json_encode([
                 'type' => 'init',
-                '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
-                ]
+                'total_tasks_count' => count($totalTasks),
+                'completed_tasks_count' => count($completeTasks),
+                'success_tasks_count' => count($successTasks)
             ]) . "\n\n";
             ob_flush();
             flush();
             
-            $checkInterval = 10; // 每10秒检查一次
-            $completedTasks = [];
-            $failedTasks = [];
-            
-            // 检查是否已经超时(包含创建任务的时间)
             while (time() - $startTime < $maxDuration) {
                 try {
-                    $allCompleted = true;
-                    $currentStatus = [];
+                    $hasUpdate = false; // 标记是否有更新
                     
-                    foreach ($segmentTasks as $segmentTask) {
-                        $taskId = $segmentTask['task_id'];
-                        $segmentId = $segmentTask['segment_id'];
-                        $tail_frame = $segmentTasks['tail_frame'];
-                        
-                        // 跳过已完成或失败的任务
-                        if (in_array($taskId, $completedTasks) || in_array($taskId, $failedTasks)) {
+                    // 获取所有任务的最新状态
+                    foreach ($totalTasks as $taskId) {
+                        // 如果任务已经在完成列表中,跳过
+                        if (in_array($taskId, $completeTasks)) {
                             continue;
                         }
                         
-                        // 查询任务状态
                         $task = \App\Models\MpGenerateVideoTask::find($taskId);
                         if (!$task) {
-                            $failedTasks[] = $taskId;
                             continue;
                         }
                         
@@ -895,6 +885,7 @@ class AnimeController extends BaseController
                             } else {
                                 $statusResult = $this->AIVideoGenerationService->querySeedanceTaskStatus($task);
                             }
+                            
                             if (isset($statusResult['status'])) {
                                 // 更新任务状态
                                 $task->update([
@@ -915,205 +906,159 @@ class AnimeController extends BaseController
                                         DB::beginTransaction();
                                         
                                         $now = date('Y-m-d H:i:s');
-                                        // 更新分镜表
-                                        $segmentUpdateData = [
-                                            'video_url' => $statusResult['result_url'],
-                                            'video_task_status' => '已完成',
-                                            'last_frame_url' => $statusResult['last_frame_url'] ?? '',
-                                            'current_type' => 2,
-                                            'updated_at' => $now
-                                        ];
                                         
-                                        // 只有当video_duration存在且大于0时才更新
-                                        if (isset($statusResult['video_duration']) && $statusResult['video_duration'] > 0) {
-                                            $segmentUpdateData['video_duration'] = $statusResult['video_duration'];
-                                            $segmentUpdateData['video_time_point_start'] = 0;
-                                            $segmentUpdateData['video_time_point_end'] = $statusResult['video_duration'];
+                                        // 获取分镜ID
+                                        $segmentId = null;
+                                        foreach ($segmentTasks as $segmentTask) {
+                                            if ($segmentTask['task_id'] == $taskId) {
+                                                $segmentId = $segmentTask['segment_id'];
+                                                $tail_frame = $segmentTask['tail_frame'];
+                                                break;
+                                            }
                                         }
                                         
-                                        $updateResult = DB::table('mp_episode_segments')
-                                            ->where('segment_id', $segmentId)
-                                            ->update($segmentUpdateData);
-                                        
-                                        if (!$updateResult) {
-                                            Utils::throwError('20003:更新分镜表失败');
+                                        if ($segmentId) {
+                                            // 更新分镜表
+                                            $segmentUpdateData = [
+                                                'video_url' => $statusResult['result_url'],
+                                                'video_task_status' => '已完成',
+                                                'last_frame_url' => $statusResult['last_frame_url'] ?? '',
+                                                'current_type' => 2,
+                                                'updated_at' => $now
+                                            ];
+                                            
+                                            // 只有当video_duration存在且大于0时才更新
+                                            if (isset($statusResult['video_duration']) && $statusResult['video_duration'] > 0) {
+                                                $segmentUpdateData['video_duration'] = $statusResult['video_duration'];
+                                                $segmentUpdateData['video_time_point_start'] = 0;
+                                                $segmentUpdateData['video_time_point_end'] = $statusResult['video_duration'];
+                                            }
+                                            
+                                            $updateResult = DB::table('mp_episode_segments')
+                                                ->where('segment_id', $segmentId)
+                                                ->update($segmentUpdateData);
+                                            
+                                            if ($updateResult) {
+                                                // 更新分镜视频成功后新增对话记录
+                                                $records = [
+                                                    [
+                                                        'uid'           => $uid,
+                                                        'anime_id'      => $animeId,
+                                                        'sequence'      => $episodeNumber,
+                                                        'role'          => 'user',
+                                                        'content'       => '图片转视频',
+                                                        'segment_id'    => $segmentId,
+                                                        'video_url'     => '',
+                                                        'created_at'    => $now,
+                                                        'updated_at'    => $now
+                                                    ],
+                                                    [
+                                                        'uid'           => $uid,
+                                                        'anime_id'      => $animeId,
+                                                        'sequence'      => $episodeNumber,
+                                                        'role'          => 'assistant',
+                                                        'content'       => $tail_frame ?? '',
+                                                        'segment_id'    => $segmentId,
+                                                        'video_url'     => $statusResult['result_url'],
+                                                        'created_at'    => $now,
+                                                        'updated_at'    => $now
+                                                    ]
+                                                ];
+                                                
+                                                DB::table('mp_anime_records')->insert($records);
+                                            }
                                         }
-
-                                        // 更新分镜视频成功后新增对话记录
-                                        // 保存对话记录
-                                        $records = [
-                                            [
-                                                'uid'           => $uid,
-                                                'anime_id'      => $animeId,
-                                                'sequence'      => $episodeNumber,
-                                                'role'          => 'user',
-                                                'content'       => '图片转视频',
-                                                'segment_id'    => $segmentId,
-                                                'video_url'     => '',
-                                                'created_at'    => $now,
-                                                'updated_at'    => $now
-                                            ],
-                                            [
-                                                'uid'           => $uid,
-                                                'anime_id'      => $animeId,
-                                                'sequence'      => $episodeNumber,
-                                                'role'          => 'assistant',
-                                                'content'       => $tail_frame,
-                                                'segment_id'    => $segmentId,
-                                                'video_url'     => $statusResult['result_url'],
-                                                'created_at'    => $now,
-                                                'updated_at'    => $now
-                                            ]
-                                        ];
-
-                                        DB::table('mp_anime_records')->insert($records);
                                         
                                         DB::commit();
                                         
-                                        $completedTasks[] = $taskId;
-                                        
-                                        // 发送单个任务完成通知
-                                        echo "data: " . json_encode([
-                                            'type' => 'update',
-                                            '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();
-                                        
                                     } catch (\Exception $e) {
                                         DB::rollBack();
                                         
                                         $logData = [
-                                            'segment_id' => $segmentId,
                                             'task_id' => $taskId,
                                             'error' => $e->getMessage()
                                         ];
                                         dLog('anime')->error('视频任务处理失败', $logData);
                                         logDB('anime', 'error', '视频任务处理失败', $logData);
-                                        
-                                        // 发送任务处理失败通知
-                                        echo "data: " . json_encode([
-                                            'type' => 'error',
-                                            'data' => [
-                                                'segment_id' => $segmentId,
-                                                'task_id' => $taskId,
-                                                'segment_number' => $segmentTask['segment_number'],
-                                                'error_message' => '任务处理失败: ' . $e->getMessage()
-                                            ]
-                                        ]) . "\n\n";
-                                        ob_flush();
-                                        flush();
                                     }
                                     
                                 } elseif ($statusResult['status'] === 'failed') {
-                                    $updateResult = 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' => 'update',
-                                        '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();
+                                    // 获取分镜ID并更新失败状态
+                                    foreach ($segmentTasks as $segmentTask) {
+                                        if ($segmentTask['task_id'] == $taskId) {
+                                            DB::table('mp_episode_segments')
+                                                ->where('segment_id', $segmentTask['segment_id'])
+                                                ->update([
+                                                    'video_task_status' => '失败',
+                                                    'updated_at' => date('Y-m-d H:i:s')
+                                                ]);
+                                            break;
+                                        }
+                                    }
                                 }
                             }
                         }
                         
-                        // 收集当前状态
-                        $currentStatus[] = [
-                            'segment_id' => $segmentId,
-                            'task_id' => $taskId,
-                            'segment_number' => $segmentTask['segment_number'],
-                            'status' => $task->status,
-                            'video_url' => $task->result_url,
-                            'error_message' => $task->error_message
-                        ];
-                        
-                        // 检查是否还有未完成的任务
-                        if (!in_array($task->status, ['success', 'failed'])) {
-                            $allCompleted = false;
+                        // 检查任务是否完成(成功或失败)
+                        if (in_array($task->status, ['success', 'failed'])) {
+                            $completeTasks[] = $taskId;
+                            $hasUpdate = true;
+                            
+                            if ($task->status === 'success') {
+                                $successTasks[] = $taskId;
+                            }
                         }
                     }
                     
-                    // 发送整体进度更新
-                    echo "data: " . json_encode([
-                        'type' => '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();
+                    // 如果有更新,发送update通知
+                    if ($hasUpdate) {
+                        echo "data: " . json_encode([
+                            'type' => 'update',
+                            'total_tasks_count' => count($totalTasks),
+                            'completed_tasks_count' => count($completeTasks),
+                            'success_tasks_count' => count($successTasks)
+                        ]) . "\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();
+                    if (count($completeTasks) >= count($totalTasks)) {
+                        // 获取所有成功任务的分镜信息
+                        $successSegments = [];
+                        foreach ($successTasks as $taskId) {
+                            // 通过taskId找到对应的segmentTask
+                            foreach ($segmentTasks as $segmentTask) {
+                                if ($segmentTask['task_id'] == $taskId) {
+                                    $segment = DB::table('mp_episode_segments')
+                                        ->where('segment_id', $segmentTask['segment_id'])
+                                        ->select('segment_id', 'video_url')
+                                        ->first();
+                                    
+                                    if ($segment && !empty($segment->video_url)) {
+                                        $successSegments[] = [
+                                            'segment_id' => $segment->segment_id,
+                                            'video_url' => $segment->video_url
+                                        ];
+                                    }
+                                    break;
+                                }
+                            }
+                        }
                         
                         echo "data: " . json_encode([
                             'type' => '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()
-                            ]
+                            'total_tasks_count' => count($totalTasks),
+                            'completed_tasks_count' => count($completeTasks),
+                            'success_tasks_count' => count($successTasks),
+                            'success_segments' => $successSegments
                         ]) . "\n\n";
                         ob_flush();
                         flush();
                         break;
                     }
                     
-                    // 在睡眠前再次检查是否超时,避免不必要的等待
+                    // 检查是否超时
                     if (time() - $startTime >= $maxDuration) {
                         break;
                     }
@@ -1124,8 +1069,9 @@ class AnimeController extends BaseController
                     echo "data: " . json_encode([
                         'type' => 'error',
                         'message' => '查询任务状态失败: ' . $e->getMessage(),
-                        'elapsed_time' => time() - $startTime,
-                        'remaining_time' => max(0, $maxDuration - (time() - $startTime))
+                        'total_tasks_count' => count($totalTasks),
+                        'completed_tasks_count' => count($completeTasks),
+                        'success_tasks_count' => count($successTasks)
                     ]) . "\n\n";
                     ob_flush();
                     flush();
@@ -1139,38 +1085,14 @@ class AnimeController extends BaseController
                 }
             }
             
-            // 超时处理 - 只有在真正超时时才执行
+            // 超时处理
             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' => 'time_out',
                     '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()
-                    ]
+                    'total_tasks_count' => count($totalTasks),
+                    'completed_tasks_count' => count($completeTasks),
+                    'success_tasks_count' => count($successTasks)
                 ]) . "\n\n";
                 ob_flush();
                 flush();

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

@@ -3023,6 +3023,10 @@ class AnimeService
         }
         
         $segment = (array)$segment;
+
+        $episode_id = getProp($segment, 'episode_id');
+        $ratio = DB::table('mp_anime_episodes')->where('id', $episode_id)->value('ratio');
+        if (!$ratio) $ratio = '9:16';
         
         // 获取分镜内容
         $segmentContent = getProp($segment, 'segment_content', '');
@@ -3072,7 +3076,7 @@ class AnimeService
             'video_duration' => $videoDuration,
             'video_resolution' => '720P',
             'seed' => -1,
-            'ratio' => '9:16',
+            'ratio' => $ratio,
             'generate_audio' => false,
             'draft' => false,
             'watermark' => false,