info('====================开始检查分镜音频信息===================='); $time_start = microtime(true); $timeout = 50; // 超时时间50秒 $check_interval = 3; // 每3秒检查一次 while (true) { // 检查是否超时 $elapsed_time = microtime(true) - $time_start; if ($elapsed_time >= $timeout) { dLog('command')->info('检查超时,退出循环'); break; } // 1. 查询mp_dub_video_tasks表中1分钟之前创建的generate_status=执行中的任务,并重新调用API $oneMinuteAgo = date('Y-m-d H:i:s', strtotime('-1 minute')); $pendingTasks = DB::table('mp_dub_video_tasks') ->where('generate_status', '执行中') ->where('created_at', '<=', $oneMinuteAgo) ->limit(10) // 每次处理10个任务 ->get(); if ($pendingTasks->isNotEmpty()) { dLog('command')->info('找到待重试的音频任务', ['count' => $pendingTasks->count()]); foreach ($pendingTasks as $task) { try { $dubTaskId = $task->id; sleep(1); // 请求远程服务器执行生成 $client = new Client(['timeout' => 300, 'verify' => false]); $result = $client->get("http://122.9.129.83:5000/api/anime/genAudio?taskId={$dubTaskId}"); $response = $result->getBody()->getContents(); $response_arr = json_decode($response, true); if (!isset($response_arr['code']) || (int)$response_arr['code'] !== 0) { $error_msg = isset($response_arr['msg']) ? $response_arr['msg'] : '未知错误'; dLog('command')->error('火山生成音频失败', ['error' => $error_msg, 'task_id' => $dubTaskId]); logDB('command', 'error', '火山生成音频失败', ['error' => $error_msg, 'task_id' => $dubTaskId]); // 标记任务为失败 DB::table('mp_dub_video_tasks') ->where('id', $dubTaskId) ->update([ 'generate_status' => '失败', 'updated_at' => date('Y-m-d H:i:s') ]); } else { dLog('command')->info('音频任务重试成功', ['task_id' => $dubTaskId]); } } catch (\Exception $e) { dLog('command')->error('重试音频任务异常', [ 'task_id' => $task->id, 'error' => $e->getMessage() ]); } } } // 2. 查询mp_episode_segments表中img_url不为空但audio_url为空的分镜 $segmentsNeedAudio = DB::table('mp_episode_segments') ->whereNotNull('img_url') ->where('img_url', '!=', '') ->where('voice_type', '!=', '') ->where(function($query) { $query->whereNull('audio_url') ->orWhere('audio_url', ''); }) ->limit(10) // 每次处理2个分镜 ->get(); if ($segmentsNeedAudio->isNotEmpty()) { dLog('command')->info('找到需要生成音频的分镜', ['count' => $segmentsNeedAudio->count()]); foreach ($segmentsNeedAudio as $segment) { try { $segment_id = $segment->segment_id; $dialogue = getProp($segment, 'dialogue'); $now = date('Y-m-d H:i:s'); // 如果有对话内容,创建视频配音合成任务 if (!empty($dialogue)) { $generate_json = [ 'text' => $dialogue, 'role' => getProp($segment, 'voice_actor'), 'voice_type' => getProp($segment, 'voice_type'), 'voice_name' => getProp($segment, 'voice_name'), 'emotion' => getProp($segment, 'emotion'), 'emotion_type' => getProp($segment, 'emotion_type'), 'gender' => getProp($segment, 'gender'), 'speed_ratio' => getProp($segment, 'speed_ratio', 0), 'loudness_ratio' => getProp($segment, 'loudness_ratio', 0), 'emotion_scale' => getProp($segment, 'emotion_scale', 0), 'pitch' => getProp($segment, 'pitch', 0), ]; // 插入视频配音合成任务 $dubTaskId = DB::table('mp_dub_video_tasks')->insertGetId([ 'alias_segment_id' => $segment_id, 'generate_status' => '执行中', 'audio_url' => '', 'generate_json' => json_encode($generate_json, 256), 'created_at' => $now, 'updated_at' => $now, ]); if (!$dubTaskId) { dLog('command')->error('创建配音任务失败', ['segment_id' => $segment_id]); continue; } // 先更新分镜表,将audio_url设置为空字符串(标记正在生成) DB::table('mp_episode_segments') ->where('segment_id', $segment_id) ->update([ 'audio_url' => '', 'updated_at' => $now ]); dLog('command')->info('开始请求远程服务器生成音频', ['task_id' => $dubTaskId, 'segment_id' => $segment_id]); sleep(1); // 请求远程服务器执行生成(远程服务器会更新audio_url字段) $client = new Client(['timeout' => 300, 'verify' => false]); $result = $client->get("http://122.9.129.83:5000/api/anime/genAudio?taskId={$dubTaskId}"); $response = $result->getBody()->getContents(); $response_arr = json_decode($response, true); if (!isset($response_arr['code']) || (int)$response_arr['code'] !== 0) { $error_msg = isset($response_arr['msg']) ? $response_arr['msg'] : '未知错误'; dLog('command')->error('火山生成音频失败', ['error' => $error_msg, 'task_id' => $dubTaskId, 'segment_id' => $segment_id]); logDB('command', 'error', '火山生成音频失败', ['error' => $error_msg, 'task_id' => $dubTaskId, 'segment_id' => $segment_id]); } else { dLog('command')->info('音频任务创建成功', ['task_id' => $dubTaskId, 'segment_id' => $segment_id]); } } else { // dialogue为空时,直接写入默认音频信息 DB::table('mp_episode_segments') ->where('segment_id', $segment_id) ->update([ 'audio_url' => 'https://zw-audiobook.tos-cn-beijing.volces.com/effects/ellipses_2s.mp3', 'audio_duration' => 2.0, 'subtitle_info' => json_encode(['duration' => 2.0, 'words' => []], 256), 'updated_at' => $now ]); dLog('command')->info('分镜无对话,写入默认音频', ['segment_id' => $segment_id]); } } catch (\Exception $e) { dLog('command')->error('处理分镜音频异常', [ 'segment_id' => $segment->segment_id, 'error' => $e->getMessage() ]); } } } // 如果没有待处理的任务,退出循环 if ($pendingTasks->isEmpty() && $segmentsNeedAudio->isEmpty()) { dLog('command')->info('没有待处理的音频任务,退出循环'); break; } // 等待3秒后继续下一次检查 sleep($check_interval); } $time_end = microtime(true); $execution_time = round($time_end - $time_start, 2); dLog('command')->info('脚本执行时间: '.round($time_end-$time_start, 2).'秒'); dLog('command')->info('====================结束检查分镜音频信息===================='); } }