|
@@ -10,6 +10,7 @@ use Illuminate\Http\Request;
|
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\JsonResponse;
|
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Support\Facades\Validator;
|
|
|
use App\Libs\ApiResponse;
|
|
use App\Libs\ApiResponse;
|
|
|
|
|
+use App\Models\AIElement;
|
|
|
|
|
|
|
|
class VideoGenerationController extends BaseController
|
|
class VideoGenerationController extends BaseController
|
|
|
{
|
|
{
|
|
@@ -755,4 +756,355 @@ class VideoGenerationController extends BaseController
|
|
|
$result = $this->aiVideoGenerationService->getTaskList($data);
|
|
$result = $this->aiVideoGenerationService->getTaskList($data);
|
|
|
return $this->success($result, [new AIGenerationTransformer(), 'newBuildTaskList']);
|
|
return $this->success($result, [new AIGenerationTransformer(), 'newBuildTaskList']);
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 主体管理相关接口 ====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建主体
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param Request $request
|
|
|
|
|
+ * @return JsonResponse
|
|
|
|
|
+ */
|
|
|
|
|
+ public function createElement(Request $request): JsonResponse
|
|
|
|
|
+ {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 验证请求参数
|
|
|
|
|
+ $validated = $request->validate([
|
|
|
|
|
+ 'element_name' => 'required|string|max:20',
|
|
|
|
|
+ 'element_description' => 'required|string|max:100',
|
|
|
|
|
+ 'reference_type' => 'required|in:image_refer,video_refer',
|
|
|
|
|
+ 'element_image_list' => 'required_if:reference_type,image_refer|array',
|
|
|
|
|
+ 'element_image_list.frontal_image' => 'required_if:reference_type,image_refer|string',
|
|
|
|
|
+ 'element_image_list.refer_images' => 'required_if:reference_type,image_refer|array|min:1|max:3',
|
|
|
|
|
+ 'element_image_list.refer_images.*.image_url' => 'required|string',
|
|
|
|
|
+ 'element_video_list' => 'required_if:reference_type,video_refer|array',
|
|
|
|
|
+ 'element_video_list.refer_videos' => 'required_if:reference_type,video_refer|array|size:1',
|
|
|
|
|
+ 'element_video_list.refer_videos.*.video_url' => 'required|string',
|
|
|
|
|
+ 'element_voice_id' => 'nullable|string',
|
|
|
|
|
+ 'tag_list' => 'nullable|array',
|
|
|
|
|
+ 'tag_list.*.tag_id' => 'required|in:o_101,o_102,o_103,o_104,o_105,o_106,o_107,o_108',
|
|
|
|
|
+ 'callback_url' => 'nullable|url',
|
|
|
|
|
+ 'external_task_id' => 'nullable|string',
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ // 调用服务层创建主体
|
|
|
|
|
+ $element = $this->aiVideoGenerationService->createElement($validated);
|
|
|
|
|
+
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 0,
|
|
|
|
|
+ 'message' => '主体创建任务已提交',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ 'data' => [
|
|
|
|
|
+ 'task_id' => $element->task_id,
|
|
|
|
|
+ 'task_info' => [
|
|
|
|
|
+ 'external_task_id' => $element->external_task_id,
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'task_status' => $element->task_status,
|
|
|
|
|
+ 'created_at' => $element->created_at->timestamp * 1000,
|
|
|
|
|
+ 'updated_at' => $element->updated_at->timestamp * 1000,
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (\Illuminate\Validation\ValidationException $e) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 400,
|
|
|
|
|
+ 'message' => '参数验证失败',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ 'errors' => $e->errors()
|
|
|
|
|
+ ], 400);
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('generate')->error('创建主体失败: ' . $e->getMessage());
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 500,
|
|
|
|
|
+ 'message' => '创建主体失败: ' . $e->getMessage(),
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 查询单个主体状态
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param string $taskId
|
|
|
|
|
+ * @param Request $request
|
|
|
|
|
+ * @return JsonResponse
|
|
|
|
|
+ */
|
|
|
|
|
+ public function getElementStatus(string $taskId, Request $request): JsonResponse
|
|
|
|
|
+ {
|
|
|
|
|
+ try {
|
|
|
|
|
+ $externalTaskId = $request->get('external_task_id');
|
|
|
|
|
+
|
|
|
|
|
+ // 先查询本地数据库
|
|
|
|
|
+ $query = AIElement::where('task_id', $taskId);
|
|
|
|
|
+ if ($externalTaskId) {
|
|
|
|
|
+ $query->orWhere('external_task_id', $externalTaskId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $localElement = $query->first();
|
|
|
|
|
+
|
|
|
|
|
+ if (!$localElement) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 404,
|
|
|
|
|
+ 'message' => '主体任务不存在',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 404);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果任务还在处理中,查询最新状态
|
|
|
|
|
+ if ($localElement->task_status === AIElement::STATUS_PROCESSING) {
|
|
|
|
|
+ $apiResult = $this->aiVideoGenerationService->queryElementStatus($taskId, $externalTaskId);
|
|
|
|
|
+ if ($apiResult['success'] && isset($apiResult['data'])) {
|
|
|
|
|
+ $localElement->refresh(); // 重新加载数据
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 构建响应数据
|
|
|
|
|
+ $responseData = [
|
|
|
|
|
+ 'task_id' => $localElement->task_id,
|
|
|
|
|
+ 'task_status' => $localElement->task_status,
|
|
|
|
|
+ 'task_status_msg' => $localElement->task_status_msg,
|
|
|
|
|
+ 'task_info' => [
|
|
|
|
|
+ 'external_task_id' => $localElement->external_task_id,
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'created_at' => $localElement->created_at->timestamp * 1000,
|
|
|
|
|
+ 'updated_at' => $localElement->updated_at->timestamp * 1000,
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ // 如果任务成功,添加主体结果信息
|
|
|
|
|
+ if ($localElement->task_status === AIElement::STATUS_SUCCEED && $localElement->element_id) {
|
|
|
|
|
+ $responseData['task_result'] = [
|
|
|
|
|
+ 'elements' => [
|
|
|
|
|
+ [
|
|
|
|
|
+ 'element_id' => $localElement->element_id,
|
|
|
|
|
+ 'element_name' => $localElement->element_name,
|
|
|
|
|
+ 'element_description' => $localElement->element_description,
|
|
|
|
|
+ 'reference_type' => $localElement->reference_type,
|
|
|
|
|
+ 'element_image_list' => $localElement->element_image_list,
|
|
|
|
|
+ 'element_video_list' => $localElement->element_video_list,
|
|
|
|
|
+ 'element_voice_info' => $localElement->element_voice_info,
|
|
|
|
|
+ 'tag_list' => $localElement->tag_list,
|
|
|
|
|
+ 'owned_by' => $localElement->owned_by,
|
|
|
|
|
+ 'status' => $localElement->status,
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]
|
|
|
|
|
+ ];
|
|
|
|
|
+ $responseData['final_unit_deduction'] = $localElement->final_unit_deduction;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 0,
|
|
|
|
|
+ 'message' => 'success',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ 'data' => $responseData
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('generate')->error('查询主体状态失败: ' . $e->getMessage());
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 500,
|
|
|
|
|
+ 'message' => '查询主体状态失败: ' . $e->getMessage(),
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 查询所有主体列表(包含自定义和官方)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param Request $request
|
|
|
|
|
+ * @return JsonResponse
|
|
|
|
|
+ */
|
|
|
|
|
+ public function getElementsList(Request $request): JsonResponse
|
|
|
|
|
+ {
|
|
|
|
|
+ try {
|
|
|
|
|
+ $pageNum = (int)$request->get('pageNum', 1);
|
|
|
|
|
+ $pageSize = (int)$request->get('pageSize', 30);
|
|
|
|
|
+ $type = $request->get('type', 'all'); // all, custom, official
|
|
|
|
|
+
|
|
|
|
|
+ // 限制分页参数范围
|
|
|
|
|
+ $pageNum = max(1, min($pageNum, 1000));
|
|
|
|
|
+ $pageSize = max(1, min($pageSize, 500));
|
|
|
|
|
+
|
|
|
|
|
+ $customElements = [];
|
|
|
|
|
+ $officialElements = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 查询自定义主体
|
|
|
|
|
+ if (in_array($type, ['all', 'custom'])) {
|
|
|
|
|
+ $customResult = $this->aiVideoGenerationService->queryCustomElementsList($pageNum, $pageSize);
|
|
|
|
|
+ if ($customResult['success']) {
|
|
|
|
|
+ $customElements = $customResult['data'];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询官方主体
|
|
|
|
|
+ if (in_array($type, ['all', 'official'])) {
|
|
|
|
|
+ $officialResult = $this->aiVideoGenerationService->queryOfficialElementsList($pageNum, $pageSize);
|
|
|
|
|
+ if ($officialResult['success']) {
|
|
|
|
|
+ $officialElements = $officialResult['data'];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 合并结果
|
|
|
|
|
+ $allElements = array_merge($customElements, $officialElements);
|
|
|
|
|
+
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 0,
|
|
|
|
|
+ 'message' => 'success',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ 'data' => $allElements
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('generate')->error('查询主体列表失败: ' . $e->getMessage());
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 500,
|
|
|
|
|
+ 'message' => '查询主体列表失败: ' . $e->getMessage(),
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 删除自定义主体
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param Request $request
|
|
|
|
|
+ * @return JsonResponse
|
|
|
|
|
+ */
|
|
|
|
|
+ public function deleteElement(Request $request): JsonResponse
|
|
|
|
|
+ {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 验证请求参数
|
|
|
|
|
+ $validated = $request->validate([
|
|
|
|
|
+ 'element_id' => 'required|string',
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ // 检查主体是否存在且为自定义主体
|
|
|
|
|
+ $element = AIElement::where('element_id', $validated['element_id'])->first();
|
|
|
|
|
+ if (!$element) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 404,
|
|
|
|
|
+ 'message' => '主体不存在',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 404);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ($element->owned_by === 'kling') {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 400,
|
|
|
|
|
+ 'message' => '不能删除官方主体',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 400);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 调用服务层删除主体
|
|
|
|
|
+ $result = $this->aiVideoGenerationService->deleteElement($validated['element_id']);
|
|
|
|
|
+
|
|
|
|
|
+ if ($result['success']) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 0,
|
|
|
|
|
+ 'message' => $result['message'],
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ 'data' => $result['data']
|
|
|
|
|
+ ]);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 500,
|
|
|
|
|
+ 'message' => $result['message'],
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 500);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } catch (\Illuminate\Validation\ValidationException $e) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 400,
|
|
|
|
|
+ 'message' => '参数验证失败',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ 'errors' => $e->errors()
|
|
|
|
|
+ ], 400);
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('generate')->error('删除主体失败: ' . $e->getMessage());
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 500,
|
|
|
|
|
+ 'message' => '删除主体失败: ' . $e->getMessage(),
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取本地主体列表(用于内部管理)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param Request $request
|
|
|
|
|
+ * @return JsonResponse
|
|
|
|
|
+ */
|
|
|
|
|
+ public function getLocalElementsList(Request $request): JsonResponse
|
|
|
|
|
+ {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 构建筛选条件
|
|
|
|
|
+ $filters = [
|
|
|
|
|
+ 'owned_by' => $request->get('owned_by'),
|
|
|
|
|
+ 'reference_type' => $request->get('reference_type'),
|
|
|
|
|
+ 'status' => $request->get('status'),
|
|
|
|
|
+ 'task_status' => $request->get('task_status'),
|
|
|
|
|
+ 'keyword' => $request->get('keyword'),
|
|
|
|
|
+ 'page_size' => (int)$request->get('page_size', 20),
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ // 移除空值
|
|
|
|
|
+ $filters = array_filter($filters, function($value) {
|
|
|
|
|
+ return $value !== null && $value !== '';
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 调用服务层获取列表
|
|
|
|
|
+ $elements = $this->aiVideoGenerationService->getLocalElementsList($filters);
|
|
|
|
|
+
|
|
|
|
|
+ // 转换数据格式
|
|
|
|
|
+ $data = $elements->map(function ($element) {
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'id' => $element->id,
|
|
|
|
|
+ 'task_id' => $element->task_id,
|
|
|
|
|
+ 'external_task_id' => $element->external_task_id,
|
|
|
|
|
+ 'task_status' => $element->task_status,
|
|
|
|
|
+ 'task_status_msg' => $element->task_status_msg,
|
|
|
|
|
+ 'element_id' => $element->element_id,
|
|
|
|
|
+ 'element_name' => $element->element_name,
|
|
|
|
|
+ 'element_description' => $element->element_description,
|
|
|
|
|
+ 'reference_type' => $element->reference_type,
|
|
|
|
|
+ 'element_image_list' => $element->element_image_list,
|
|
|
|
|
+ 'element_video_list' => $element->element_video_list,
|
|
|
|
|
+ 'element_voice_id' => $element->element_voice_id,
|
|
|
|
|
+ 'element_voice_info' => $element->element_voice_info,
|
|
|
|
|
+ 'tag_list' => $element->tag_list,
|
|
|
|
|
+ 'tag_names' => $element->tag_names, // 使用模型的访问器
|
|
|
|
|
+ 'owned_by' => $element->owned_by,
|
|
|
|
|
+ 'status' => $element->status,
|
|
|
|
|
+ 'final_unit_deduction' => $element->final_unit_deduction,
|
|
|
|
|
+ 'created_at' => $element->created_at->format('Y-m-d H:i:s'),
|
|
|
|
|
+ 'updated_at' => $element->updated_at->format('Y-m-d H:i:s'),
|
|
|
|
|
+ ];
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 0,
|
|
|
|
|
+ 'message' => 'success',
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ 'data' => [
|
|
|
|
|
+ 'data' => $data,
|
|
|
|
|
+ 'current_page' => $elements->currentPage(),
|
|
|
|
|
+ 'last_page' => $elements->lastPage(),
|
|
|
|
|
+ 'per_page' => $elements->perPage(),
|
|
|
|
|
+ 'total' => $elements->total(),
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ dLog('generate')->error('获取本地主体列表失败: ' . $e->getMessage());
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'code' => 500,
|
|
|
|
|
+ 'message' => '获取本地主体列表失败: ' . $e->getMessage(),
|
|
|
|
|
+ 'request_id' => uniqid(),
|
|
|
|
|
+ ], 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|