Przeglądaj źródła

优化生成视频任务的sse逻辑处理

lh 1 miesiąc temu
rodzic
commit
047868e247
1 zmienionych plików z 76 dodań i 272 usunięć
  1. 76 272
      app/Http/Controllers/Anime/AnimeController.php

+ 76 - 272
app/Http/Controllers/Anime/AnimeController.php

@@ -445,7 +445,6 @@ class AnimeController extends BaseController
     }
 
     public function createSegmentVideoTask(Request $request) {
-        $uid = Site::getUid();
         // 忽略所有超时限制
         set_time_limit(0);
         ini_set('max_execution_time', '0');
@@ -470,7 +469,7 @@ class AnimeController extends BaseController
         $taskId = $result['task_id'];
         
         // 设置 SSE 响应头
-        return response()->stream(function () use ($taskId, $result, $uid) {
+        return response()->stream(function () use ($taskId, $result) {
             // 设置 SSE 响应头
             echo "data: " . json_encode([
                 'type' => 'init',
@@ -484,6 +483,9 @@ class AnimeController extends BaseController
             $startTime = time();
             $maxDuration = 1800; // 5分钟超时
             $checkInterval = 5; // 每5秒检查一次
+            $lastTaskData = null; // 记录上一次推送的任务数据,仅在有变化时发送update
+            $lastQueueMessageTime = time(); // 记录上次发送队列消息的时间
+            $queueMessageInterval = 60; // 队列消息发送间隔(秒)
             
             while (time() - $startTime < $maxDuration) {
                 try {
@@ -501,147 +503,37 @@ class AnimeController extends BaseController
                         break;
                     }
                     
-                    // 如果任务还在处理中,查询最新状态
-                    if ($task->status === 'processing') {
-                        // 根据任务类型查询不同的状态
-                        if ($task->api_type === 'jimeng') {
-                            $statusResult = $this->AIVideoGenerationService->queryJimengTaskStatus($task);
-                        } elseif ($task->api_type === 'keling') {
-                            $statusResult = $this->AIVideoGenerationService->queryKelingOmniTaskStatus($task);
-                        } elseif ($task->api_type === 'zzengine') {
-                            $statusResult = $this->AIVideoGenerationService->queryUnifiedApiTaskStatus($task);
-                        } else {
-                            $statusResult = $this->AIVideoGenerationService->querySeedanceTaskStatus($task);
-                        }
-                        if (isset($statusResult['status'])) {
-                            // 更新任务状态
-                            $task->update([
-                                'status' => $statusResult['status'],
-                                'result_url' => $statusResult['result_url'] ?? null,
-                                'compressed_url' => $statusResult['compressed_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'])) {
-                                try {
-                                    DB::beginTransaction();
-                                    
-                                    $now = date('Y-m-d H:i:s');
-                                    
-                                    // 获取分镜ID
-                                    $segment = DB::table('mp_episode_segments')
-                                        ->where('video_task_id', $taskId)
-                                        ->first();
-                                    
-                                    if (!$segment) {
-                                        throw new \Exception('未找到对应的分镜记录');
-                                    }
-                                    
-                                    $segmentId = $segment->segment_id;
-                                    $anime_id = $segment->anime_id;
-                                    $episode_number = $segment->episode_number;
-                                    $tail_frame = $segment->tail_frame;
-                                    
-                                    // 更新分镜表
-                                    $segmentUpdateData = [
-                                        'origin_video_url' => $statusResult['result_url'],
-                                        'video_task_status' => '已完成',
-                                        'last_frame_url' => $statusResult['last_frame_url'] ?? '',
-                                        'current_type' => 2,
-                                        'updated_at' => $now
-                                    ];
-                                    $compressed_video_url = compressVideo($statusResult['result_url']);
-                                    $segmentUpdateData['video_url'] = $compressed_video_url ?: $statusResult['result_url'];
-                                    
-                                    // 只有当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'];
-                                        $segmentUpdateData['video_time_point_end'] = $segment->audio_duration ?? 0;
-                                    }
-                                    
-                                    $updateResult = DB::table('mp_episode_segments')
-                                        ->where('segment_id', $segmentId)
-                                        ->update($segmentUpdateData);
-                                    
-                                    if (!$updateResult) {
-                                        Utils::throwError('20003:更新分镜表失败');
-                                    }
-
-                                    // 更新分镜视频成功后新增对话记录
-                                    // 保存对话记录
-                                    $records = [
-                                        [
-                                            'uid'           => $uid,
-                                            'anime_id'      => $anime_id,
-                                            'sequence'      => $episode_number,
-                                            'role'          => 'user',
-                                            'content'       => '图片转视频',
-                                            'segment_id'    => $segmentId,
-                                            'video_url'     => '',
-                                            'created_at'    => $now,
-                                            'updated_at'    => $now
-                                        ],
-                                        [
-                                            'uid'           => $uid,
-                                            'anime_id'      => $anime_id,
-                                            'sequence'      => $episode_number,
-                                            '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();
-                                    
-                                } catch (\Exception $e) {
-                                    DB::rollBack();
-                                    
-                                    $logData = [
-                                        'task_id' => $taskId,
-                                        'error' => $e->getMessage()
-                                    ];
-                                    dLog('anime')->error('视频任务处理失败', $logData);
-                                    logDB('anime', 'error', '视频任务处理失败', $logData);
-                                }
-                            } elseif ($statusResult['status'] === 'failed') {
-                                DB::table('mp_episode_segments')
-                                    ->where('video_task_id', $taskId)
-                                    ->update([
-                                        'video_task_status' => '失败',
-                                        'updated_at' => date('Y-m-d H:i:s')
-                                    ]);
-                            }
-                        }
-                    }
+                    // 视频任务结果由定时任务实时更新,此处直接读取任务表状态
                     
-                    // 发送当前状态
-                    echo "data: " . json_encode([
-                        'type' => 'update',
-                        'data' => [
-                            'task_id' => $task->id,
-                            'status' => $task->status,
-                            'result_url' => $task->result_url,
-                            'error_message' => $task->error_message ? mapErrorMessage($task->error_message) : '',
-                            'elapsed_time' => time() - $startTime
-                        ]
-                    ]) . "\n\n";
-                    if (ob_get_level() > 0) {
-                        ob_flush();
+                    // 构建当前任务数据
+                    $taskData = [
+                        'status' => $task->status,
+                        'result_url' => $task->result_url,
+                        'error_message' => $task->error_message ? mapErrorMessage($task->error_message) : ''
+                    ];
+                    
+                    // 首次查询只记录状态,不发送update(init已推送任务创建信息)
+                    if ($lastTaskData === null) {
+                        $lastTaskData = $taskData;
+                    } elseif ($taskData != $lastTaskData) {
+                        $lastTaskData = $taskData;
+                        
+                        // 有数据更新才发送update
+                        echo "data: " . json_encode([
+                            'type' => 'update',
+                            'data' => [
+                                'task_id' => $task->id,
+                                'status' => $task->status,
+                                'result_url' => $task->result_url,
+                                'error_message' => $task->error_message ? mapErrorMessage($task->error_message) : '',
+                                'elapsed_time' => time() - $startTime
+                            ]
+                        ]) . "\n\n";
+                        if (ob_get_level() > 0) {
+                            ob_flush();
+                        }
+                        flush();
                     }
-                    flush();
                     
                     // 如果任务完成(成功或失败),结束连接
                     if (in_array($task->status, [
@@ -666,6 +558,25 @@ class AnimeController extends BaseController
                         break;
                     }
                     
+                    // 每分钟发送一次队列状态消息
+                    $currentTime = time();
+                    if ($currentTime - $lastQueueMessageTime >= $queueMessageInterval) {
+                        echo "data: " . json_encode([
+                            'type' => 'queue',
+                            'data' => [
+                                'task_id' => $task->id,
+                                'status' => $task->status,
+                                'elapsed_time' => $currentTime - $startTime,
+                                'message' => '任务正在队列中执行...'
+                            ]
+                        ]) . "\n\n";
+                        if (ob_get_level() > 0) {
+                            ob_flush();
+                        }
+                        flush();
+                        $lastQueueMessageTime = $currentTime;
+                    }
+                    
                     sleep($checkInterval);
                     
                 } catch (\Exception $e) {
@@ -1031,10 +942,11 @@ class AnimeController extends BaseController
         $startTime = time();
         $maxDuration = 1800; // 30分钟超时
         
-        $uid = Site::getUid();
         // 设置 SSE 响应头并开始长连接
-        return response()->stream(function () use ($taskIds, $segmentTasks, $animeId, $episodeNumber, $episodeId, $startTime, $maxDuration, $uid) {
+        return response()->stream(function () use ($taskIds, $segmentTasks, $episodeId, $startTime, $maxDuration) {
             $checkInterval = 10; // 每10秒检查一次
+            $lastQueueMessageTime = time(); // 记录上次发送队列消息的时间
+            $queueMessageInterval = 60; // 队列消息发送间隔(秒)
             
             // 初始化任务数组
             $totalTasks = $taskIds; // 所有任务ID
@@ -1069,135 +981,7 @@ class AnimeController extends BaseController
                             continue;
                         }
                         
-                        // 如果任务还在处理中,查询最新状态
-                        if ($task->status === 'processing') {
-                            // 根据任务类型查询不同的状态
-                            if ($task->api_type === 'jimeng') {
-                                $statusResult = $this->AIVideoGenerationService->queryJimengTaskStatus($task);
-                            } elseif ($task->api_type === 'keling') {
-                                $statusResult = $this->AIVideoGenerationService->queryKelingOmniTaskStatus($task);
-                            } elseif ($task->api_type === 'zzengine') {
-                                $statusResult = $this->AIVideoGenerationService->queryUnifiedApiTaskStatus($task);
-                            } else {
-                                $statusResult = $this->AIVideoGenerationService->querySeedanceTaskStatus($task);
-                            }
-                            
-                            if (isset($statusResult['status'])) {
-                                // 更新任务状态
-                                $task->update([
-                                    'status' => $statusResult['status'],
-                                    'result_json' => $statusResult['result_json'] ?? [],
-                                    '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'])) {
-                                    try {
-                                        DB::beginTransaction();
-                                        
-                                        $now = date('Y-m-d H:i:s');
-                                        
-                                        // 获取分镜ID
-                                        $segmentId = null;
-                                        foreach ($segmentTasks as $segmentTask) {
-                                            if ($segmentTask['task_id'] == $taskId) {
-                                                $segmentId = $segmentTask['segment_id'];
-                                                $tail_frame = $segmentTask['tail_frame'];
-                                                $audio_duration = $segmentTask['audio_duration'];
-                                                break;
-                                            }
-                                        }
-                                        
-                                        if ($segmentId) {
-                                            // 更新分镜表
-                                            $segmentUpdateData = [
-                                                'origin_video_url' => $statusResult['result_url'],
-                                                'video_task_status' => '已完成',
-                                                'last_frame_url' => $statusResult['last_frame_url'] ?? '',
-                                                'current_type' => 2,
-                                                'updated_at' => $now
-                                            ];
-                                            $compressed_video_url = compressVideo($statusResult['result_url']);
-                                            $segmentUpdateData['video_url'] = $compressed_video_url ?: $statusResult['result_url'];
-                                            
-                                            // 只有当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'];
-                                                $segmentUpdateData['video_time_point_end'] = $audio_duration ?? 0;
-                                            }
-                                            
-                                            $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);
-                                            }
-                                        }
-                                        
-                                        DB::commit();
-                                        
-                                    } catch (\Exception $e) {
-                                        DB::rollBack();
-                                        
-                                        $logData = [
-                                            'task_id' => $taskId,
-                                            'error' => $e->getMessage()
-                                        ];
-                                        dLog('anime')->error('视频任务处理失败', $logData);
-                                        logDB('anime', 'error', '视频任务处理失败', $logData);
-                                    }
-                                    
-                                } elseif ($statusResult['status'] === 'failed') {
-                                    // 获取分镜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;
-                                        }
-                                    }
-                                }
-                            }
-                        }
+                        // 视频任务结果由定时任务实时更新,此处直接读取任务表状态
                         
                         // 检查任务是否完成(成功或失败)
                         if (in_array($task->status, ['success', 'failed'])) {
@@ -1262,6 +1046,26 @@ class AnimeController extends BaseController
                         break;
                     }
                     
+                    // 每分钟发送一次队列状态消息
+                    $currentTime = time();
+                    if ($currentTime - $lastQueueMessageTime >= $queueMessageInterval) {
+                        echo "data: " . json_encode([
+                            'type' => 'queue',
+                            'data' => [
+                                'total_tasks_count' => count($totalTasks),
+                                'completed_tasks_count' => count($completeTasks),
+                                'success_tasks_count' => count($successTasks),
+                                'elapsed_time' => $currentTime - $startTime,
+                                'message' => '任务正在队列中执行...'
+                            ]
+                        ]) . "\n\n";
+                        if (ob_get_level() > 0) {
+                            ob_flush();
+                        }
+                        flush();
+                        $lastQueueMessageTime = $currentTime;
+                    }
+                    
                     // 检查是否超时
                     if (time() - $startTime >= $maxDuration) {
                         break;