aiVideoGenerationService = $aiVideoGenerationService; } /** * 创建视频生成任务 * * @param Request $request * @return JsonResponse */ public function createTask(Request $request): JsonResponse { $data = $request->all(); // 首先验证基本参数 $baseRules = [ 'prompt' => 'required|string|max:1000', 'seed' => 'required|integer', 'video_duration' => 'required|in:5,10', ]; $baseMessages = [ 'prompt.required' => '提示词不能为空', 'prompt.max' => '提示词不能超过1000个字符', 'video_duration.required' => '请选择视频时长', 'video_duration.in' => '视频时长只能是5s或10s', ]; // 根据传入参数决定验证规则 if (isset($data['first_frame_url']) && isset($data['tail_frame_url'])) { // URL 方式 $validationRules = array_merge($baseRules, [ 'first_frame_url' => 'required|url', 'tail_frame_url' => 'required|url', ]); $validationMessages = array_merge($baseMessages, [ 'first_frame_url.required' => '首帧图片URL不能为空', 'first_frame_url.url' => '首帧图片URL格式不正确', 'tail_frame_url.required' => '尾帧图片URL不能为空', 'tail_frame_url.url' => '尾帧图片URL格式不正确', ]); } else { // 上传文件方式 $validationRules = array_merge($baseRules, [ 'first_frame_file' => 'required|image|mimes:jpeg,png|max:4800', 'tail_frame_file' => 'required|image|mimes:jpeg,png|max:4800', ]); $validationMessages = array_merge($baseMessages, [ 'first_frame_file.required' => '首帧图片不能为空', 'first_frame_file.image' => '首帧必须是图片文件', 'first_frame_file.mimes' => '首帧图片必须是jpeg,png格式', 'first_frame_file.max' => '首帧图片大小不能超过4.7MB', 'tail_frame_file.required' => '尾帧图片不能为空', 'tail_frame_file.image' => '尾帧必须是图片文件', 'tail_frame_file.mimes' => '尾帧图片必须是jpeg,png格式', 'tail_frame_file.max' => '尾帧图片大小不能超过4.7MB', ]); } $validator = Validator::make($data, $validationRules, $validationMessages); if ($validator->fails()) { Utils::throwError('1002:'.$validator->errors()->first()); } // 处理上传的图片 if ($request->hasFile('first_frame_file') && $request->hasFile('tail_frame_file')) { $firstFrameFile = $request->file('first_frame_file'); $tailFrameFile = $request->file('tail_frame_file'); $firstFrameExtension = $firstFrameFile->getClientOriginalExtension(); $tailFrameExtension = $tailFrameFile->getClientOriginalExtension(); // 验证图片分辨率和比例 $firstFrameInfo = @getimagesize($firstFrameFile->getPathname()); $tailFrameInfo = @getimagesize($tailFrameFile->getPathname()); if (!$firstFrameInfo || !$tailFrameInfo) { Utils::throwError('1003:图片格式无效'); } $firstFrame = [ 'width' => $firstFrameInfo[0], 'height' => $firstFrameInfo[1], 'size' => $firstFrameFile->getSize(), ]; $tailFrame = [ 'width' => $tailFrameInfo[0], 'height' => $tailFrameInfo[1], 'size' => $tailFrameFile->getSize(), ]; // 本地保存 $firstFramePath = $firstFrameFile->store('video_frames', 'public'); $tailFramePath = $tailFrameFile->store('video_frames', 'public'); // 获取图片绝对路径 $firstFramePath = storage_path('app/public/' . $firstFramePath); $tailFramePath = storage_path('app/public/' . $tailFramePath); // 图片上传的方式需获取图片的图片文件base64编码 $data['first_frame_base64'] = 'data:image/' . $firstFrameExtension . ';base64,' . base64_encode(file_get_contents($firstFramePath)); $data['tail_frame_base64'] = 'data:image/' . $tailFrameExtension . ';base64,' . base64_encode(file_get_contents($tailFramePath)); unlink($firstFramePath); unlink($tailFramePath); } else { // 使用URL方式,验证远程图片 $firstFrame = Utils::getRemoteImageInfo($data['first_frame_url'], true); $tailFrame = Utils::getRemoteImageInfo($data['tail_frame_url'], true); if (!$firstFrame || !$tailFrame) { Utils::throwError('1003:图片获取失败'); } } // 判断首尾帧图片是否满足以下条件: // 1.图片文件最大4.7MB // 2.图片分辨率最大: 4096*4096, 最短边不低于320 // 3.图片长边与短边比例在3以内 // 4.尾帧图片与首帧图片比例相同 if ($firstFrame['size'] > 4.7 * 1024 * 1024) { Utils::throwError('1003:图片大小不能超过4.7MB'); } if ($firstFrame['width'] > 4096 || $firstFrame['height'] > 4096 || $firstFrame['width'] < 320 || $firstFrame['height'] < 320) { Utils::throwError('1003:图片分辨率不能超过4096*4096,且最短边不能低于320'); } if ($firstFrame['width'] / $firstFrame['height'] > 3 || $tailFrame['width'] / $tailFrame['height'] > 3) { Utils::throwError('1003:图片长边与短边比例不能超过3'); } if ($firstFrame['width'] / $firstFrame['height'] != $tailFrame['width'] / $tailFrame['height']) { Utils::throwError('1003:尾帧图片与首帧图片比例相同'); } dd($data); try { $task = $this->aiVideoGenerationService->createVideoGenerationTask($data); return $this->success(['task_id' => $task->task_id, 'status' => $task->status]); } catch (\Exception $e) { Utils::throwError('1001:'.$e->getMessage()); } } /** * 查询视频任务状态 * * @param string $taskId * @return JsonResponse */ public function taskStatus(string $taskId): JsonResponse { $task = \App\Models\MpGenerateVideoTask::where('task_id', $taskId)->first(); if (!$task) { return response()->json([ 'success' => false, 'message' => '任务不存在' ], 404); } return response()->json([ 'success' => true, 'data' => [ 'task_id' => $task->task_id, 'status' => $task->status, 'result_url' => $task->result_url, 'error_message' => $task->error_message, 'created_at' => $task->created_at, 'started_at' => $task->started_at, 'completed_at' => $task->completed_at ] ]); } /** * 获取视频任务列表 * * @param Request $request * @return mixed */ public function taskList(Request $request) { $data = $request->all(); $result = $this->aiVideoGenerationService->getTaskList($data); return $this->success($result, [new AIGenerationTransformer(), 'newBuildTaskList']); } }