diff --git a/src/main/java/com/youlai/boot/mini/controller/AiGenerationController.java b/src/main/java/com/youlai/boot/mini/controller/AiGenerationController.java index 0b69114..fe0bb3e 100644 --- a/src/main/java/com/youlai/boot/mini/controller/AiGenerationController.java +++ b/src/main/java/com/youlai/boot/mini/controller/AiGenerationController.java @@ -101,5 +101,4 @@ public class AiGenerationController { } //TODO: 后续在回调中 增加用户小程序订阅通知 - } diff --git a/src/main/java/com/youlai/boot/mini/model/vo/AiVideoCallbackVO.java b/src/main/java/com/youlai/boot/mini/model/vo/AiVideoCallbackVO.java index 76e6ff5..63798b8 100644 --- a/src/main/java/com/youlai/boot/mini/model/vo/AiVideoCallbackVO.java +++ b/src/main/java/com/youlai/boot/mini/model/vo/AiVideoCallbackVO.java @@ -1,5 +1,6 @@ package com.youlai.boot.mini.model.vo; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -10,19 +11,60 @@ import lombok.Data; * @author youlai */ @Data +@JsonInclude(JsonInclude.Include.NON_NULL) @Schema(description = "AI视频生成任务回调请求") public class AiVideoCallbackVO { - @Schema(description = "响应消息") - private String msg; + @Schema(description = "第三方视频任务唯一ID") + private String id; - @Schema(description = "响应码,0表示成功") - private Integer code; + @Schema(description = "使用的模型ID") + private String model; - @Schema(description = "回调数据") - private VideoCallbackData data; + @Schema(description = "任务状态:queued排队中/running处理中/succeeded成功/failed失败") + private String status; - @JsonProperty("request_id") - @Schema(description = "请求ID") - private String requestId; + @JsonProperty("created_at") + @Schema(description = "创建时间戳") + private Long createdAt; + + @JsonProperty("updated_at") + @Schema(description = "更新时间戳") + private Long updatedAt; + + @JsonProperty("service_tier") + @Schema(description = "服务等级") + private String serviceTier; + + @JsonProperty("execution_expires_after") + @Schema(description = "执行过期时间") + private Long executionExpiresAfter; + + @JsonProperty("generate_audio") + @Schema(description = "是否生成音频") + private Boolean generateAudio; + + @Schema(description = "是否为草稿") + private Boolean draft; + + @Schema(description = "生成结果,status=succeeded时返回") + private VideoCallbackContent content; + + @Schema(description = "资源消耗统计") + private VideoCallbackUsage usage; + + @Schema(description = "随机种子") + private Long seed; + + @Schema(description = "分辨率,比如720p") + private String resolution; + + @Schema(description = "比例,比如16:9") + private String ratio; + + @Schema(description = "视频时长,单位秒") + private Integer duration; + + @Schema(description = "帧率") + private Integer framespersecond; } diff --git a/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackContent.java b/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackContent.java index f66617d..34a321b 100644 --- a/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackContent.java +++ b/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackContent.java @@ -1,5 +1,6 @@ package com.youlai.boot.mini.model.vo; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -10,6 +11,7 @@ import lombok.Data; * @author youlai */ @Data +@JsonInclude(JsonInclude.Include.NON_NULL) @Schema(description = "AI视频生成回调结果内容") public class VideoCallbackContent { diff --git a/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackData.java b/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackData.java deleted file mode 100644 index 706ffb1..0000000 --- a/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackData.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.youlai.boot.mini.model.vo; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * AI视频生成回调数据 - * - * @author youlai - */ -@Data -@Schema(description = "AI视频生成回调数据") -public class VideoCallbackData { - - @Schema(description = "任务ID") - private String id; - - @Schema(description = "使用的模型ID") - private String model; - - @Schema(description = "任务状态: pending/running/succeeded/failed") - private String status; - - @Schema(description = "生成的结果内容") - private VideoCallbackContent content; - - @Schema(description = "资源消耗统计") - private VideoCallbackUsage usage; - - @JsonProperty("created_at") - @Schema(description = "创建时间戳") - private Long createdAt; - - @JsonProperty("updated_at") - @Schema(description = "更新时间戳") - private Long updatedAt; - - @Schema(description = "随机种子") - private Long seed; - - @Schema(description = "分辨率") - private String resolution; - - @Schema(description = "比例") - private String ratio; - - @Schema(description = "视频时长,单位秒") - private Integer duration; - - @Schema(description = "帧率") - private Integer framespersecond; - - @JsonProperty("service_tier") - @Schema(description = "服务等级") - private String serviceTier; - - @JsonProperty("execution_expires_after") - @Schema(description = "执行过期时间") - private Long executionExpiresAfter; -} diff --git a/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackUsage.java b/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackUsage.java index 2e4b752..c6c0d3e 100644 --- a/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackUsage.java +++ b/src/main/java/com/youlai/boot/mini/model/vo/VideoCallbackUsage.java @@ -1,16 +1,18 @@ package com.youlai.boot.mini.model.vo; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** - * AI视频生成资源消耗统计 + * 视频生成资源消耗统计 * * @author youlai */ @Data -@Schema(description = "AI视频生成资源消耗统计") +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "视频生成资源消耗统计") public class VideoCallbackUsage { @JsonProperty("completion_tokens") diff --git a/src/main/java/com/youlai/boot/mini/service/impl/AiGenerationServiceImpl.java b/src/main/java/com/youlai/boot/mini/service/impl/AiGenerationServiceImpl.java index 0309e49..be37209 100644 --- a/src/main/java/com/youlai/boot/mini/service/impl/AiGenerationServiceImpl.java +++ b/src/main/java/com/youlai/boot/mini/service/impl/AiGenerationServiceImpl.java @@ -32,13 +32,10 @@ import com.youlai.boot.mini.model.form.MiniDeductPointForm; import com.youlai.boot.mini.model.vo.AiVideoCallbackVO; import com.youlai.boot.mini.model.form.AiCallbackImage; import com.youlai.boot.mini.model.form.AiFourPanelCallbackForm; -import com.youlai.boot.mini.model.vo.VideoCallbackData; -import com.youlai.boot.common.exception.BusinessException; import com.youlai.boot.mini.service.AiGenerationService; import com.youlai.boot.mini.service.MiniPointRecordService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FilenameUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -49,9 +46,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.InputStream; import java.net.URL; -import java.time.LocalDateTime; import java.util.*; -import java.util.concurrent.CompletableFuture; @Slf4j @Service @@ -480,23 +475,11 @@ public class AiGenerationServiceImpl implements AiGenerationService { log.info("处理AI视频生成任务回调,请求参数:{}", JSONUtil.toJsonStr(vo)); boolean success = false; try { - // 校验回调响应是否成功 - if (!Integer.valueOf(0).equals(vo.getCode())) { - log.error("视频生成任务回调失败,错误信息:{}", vo.getMsg()); - return false; - } - - VideoCallbackData data = vo.getData(); - if (data == null) { - log.error("视频回调数据为空"); - return false; - } - - String videoTaskUuid = data.getId(); + String videoTaskUuid = vo.getId(); // 根据第三方返回的视频任务uuid查询对应的任务 MiniAiGenerationTask task = aiGenerationTaskMapper.selectOne(new LambdaQueryWrapper() - .eq(MiniAiGenerationTask::getVideoTaskUuid, videoTaskUuid) - .eq(MiniAiGenerationTask::getDeleted, false)); + .eq(MiniAiGenerationTask::getVideoTaskUuid, videoTaskUuid) + .eq(MiniAiGenerationTask::getDeleted, false)); if (task == null) { log.error("视频回调任务不存在,第三方视频任务UUID:{}", videoTaskUuid); return false; @@ -504,13 +487,14 @@ public class AiGenerationServiceImpl implements AiGenerationService { // 转换任务状态 Integer status; - if ("succeeded".equals(data.getStatus())) { + if ("succeeded".equals(vo.getStatus())) { status = 1; // 成功 - } else if ("failed".equals(data.getStatus())) { + } else if ("failed".equals(vo.getStatus())) { status = 2; // 失败 } else { - log.info("视频任务{}处于中间状态:{},不处理", task.getUuid(), data.getStatus()); - return true; // 中间状态直接返回成功,不更新任务 + // queued/running中间状态直接返回成功,不更新任务 + log.info("视频任务{}处于中间状态:{},不处理", task.getUuid(), vo.getStatus()); + return true; } // 更新任务状态 @@ -520,9 +504,9 @@ public class AiGenerationServiceImpl implements AiGenerationService { aiGenerationTaskMapper.updateById(task); // 如果生成成功,下载外部视频到OSS - if (status == 1 && data.getContent() != null && data.getContent().getVideoUrl() != null) { - String externalVideoUrl = data.getContent().getVideoUrl(); - // 调用下载方法,和图片下载逻辑一致,存储到视频目录 + if (status == 1 && vo.getContent() != null && vo.getContent().getVideoUrl() != null) { + String externalVideoUrl = vo.getContent().getVideoUrl(); + // 调用下载方法,存储到视频目录 String ossUrl = downloadExternalUrlToOss(externalVideoUrl, OSS_VIDEO_DIR); task.setResultResourceUrl(ossUrl); aiGenerationTaskMapper.updateById(task); @@ -536,11 +520,23 @@ public class AiGenerationServiceImpl implements AiGenerationService { .setFileSource("ai_generate") .setMediaType("video") .setSourceUrl(ossUrl) - .setDuration(data.getDuration()) + .setDuration(vo.getDuration()) .setCreateBy(task.getCreateBy()) .setCreateTimestamp(System.currentTimeMillis()) .setCreateTime(new Date()); aiTaskMediaMapper.insert(media); + + // 更新用户上传的参考文件:关联当前任务ID并软删除 + LambdaUpdateWrapper updateMediaWrapper = new LambdaUpdateWrapper<>(); + updateMediaWrapper.eq(MiniAiTaskMedia::getMiniUserId, task.getMiniUserId()) + .isNull(MiniAiTaskMedia::getTaskId) + .eq(MiniAiTaskMedia::getFileSource, "user_upload") + .eq(MiniAiTaskMedia::getDeleted, false) + .set(MiniAiTaskMedia::getTaskId, task.getId()) + .set(MiniAiTaskMedia::getDeleted, true) + .set(MiniAiTaskMedia::getUpdateTime, new Date()) + .set(MiniAiTaskMedia::getUpdateTimestamp, System.currentTimeMillis()); + aiTaskMediaMapper.update(null, updateMediaWrapper); } success = true; diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 51667a9..6c512aa 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -239,7 +239,7 @@ ai: single-image-callback-url: http://192.168.31.197:30101/backend/api/v1/mini/ai/generation/single-image/task/callback four-panel-callback-url: http://192.168.31.197:30101/backend/api/v1/mini/ai/generation/four-panel/task/callback #需要内网穿透工具 由火山方舟 api 回调,ngrok http 30101 替换为内网穿透工具地址 - video-url: http://192.168.31.197:30101/backend/api/v1/mini/ai/generation/video/task/callback + video-url: https://2dd0-153-34-180-144.ngrok-free.app/backend/api/v1/mini/ai/generation/video/task/callback default: image-model: doubao-seedream-5-0-260128 video-model: doubao-seedance-2-0-260128