From 481d72888dffa05af60762f54557322d0ca2f661 Mon Sep 17 00:00:00 2001 From: glx <783262171@qq.com> Date: Thu, 28 May 2026 13:46:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A6=96=E9=A1=B5=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=BD=9C=E5=93=81=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AiGenerationController.java | 30 +++--- .../mini/model/form/AiTaskVisibilityForm.java | 23 ++++ .../model/query/DiscoveryPublicWorkQuery.java | 15 +++ .../mini/model/vo/DiscoveryPublicWorkVO.java | 38 +++++++ .../mini/service/AiGenerationService.java | 7 ++ .../service/impl/AiGenerationServiceImpl.java | 100 ++++++++++++++++++ src/main/resources/application-dev.yml | 2 +- 7 files changed, 202 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/youlai/boot/mini/model/form/AiTaskVisibilityForm.java create mode 100644 src/main/java/com/youlai/boot/mini/model/query/DiscoveryPublicWorkQuery.java create mode 100644 src/main/java/com/youlai/boot/mini/model/vo/DiscoveryPublicWorkVO.java 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 db2a621..7f4c75d 100644 --- a/src/main/java/com/youlai/boot/mini/controller/AiGenerationController.java +++ b/src/main/java/com/youlai/boot/mini/controller/AiGenerationController.java @@ -24,7 +24,9 @@ import org.springframework.security.access.prepost.PreAuthorize; import com.baomidou.mybatisplus.core.metadata.IPage; import com.youlai.boot.mini.model.query.AiTaskMediaQuery; +import com.youlai.boot.mini.model.query.DiscoveryPublicWorkQuery; import com.youlai.boot.mini.model.vo.AiGenerationTaskVO; +import com.youlai.boot.mini.model.vo.DiscoveryPublicWorkVO; import cn.hutool.core.util.StrUtil; import java.util.List; import com.youlai.boot.mini.model.vo.UserUploadMediaVO; @@ -160,17 +162,21 @@ public class AiGenerationController { return Result.success(); } - //需要在三个回调接口中控制状态,更新其他状态; 更新状态时需要判断 当前状态已是成功或失败时不能再更新状态,当状态是失败时需要退还补偿积分; - // mini_point_rule积分规则表,每个回调回退的积分是对应的规则扣减积分的负数值;mini_point_record积分记录表;mini_point_account用户积分账户 - - - // 当外部服务挂掉,不回调我的接口时,需要根据时间段判断,如果超过一定时间未回调,则更新状态为失败,并退还积分; - - //TODO 现在 用户生成内容时,需要增加一个参数,同意或不同意公开生成的作品内容 - //TODO mini 中增加 查询 用户公开生成作品的接口,考虑设计一下查询规则 满足平台前中后期运营需求 - - //TODO admin 中 后台管理中增加 查询用户生成任务历史的接口 - //TODO admin 中 编辑用户生成作品历史接口 - //TODO admin 中 增加 手动查询生成任务接口,手动跳转生成失败任务,或做个接口给用户手动刷新查看,需要注意状态流转,只有超时未完成任务可出现刷新按钮 + @Operation(summary = "更新任务可见范围") + @PutMapping("/my/task/visibility") + @Log(module = LogModuleEnum.AI_GENERATION_TASK, value = ActionTypeEnum.UPDATE) + public Result updateTaskVisibility(@Valid @RequestBody AiTaskVisibilityForm form) { + Long userId = SecurityUtils.getUserId(); + aiGenerationService.updateTaskVisibility(userId, form); + return Result.success(); + } + @Operation(summary = "查询公开作品发现页") + @GetMapping("/discovery/feed") + @Log(module = LogModuleEnum.AI_GENERATION_TASK, value = ActionTypeEnum.LIST) + public Result> getPublicDiscoveryFeed(@Valid DiscoveryPublicWorkQuery query) { + IPage result = aiGenerationService.getPublicDiscoveryFeed(query); + return Result.success(result); + } + } diff --git a/src/main/java/com/youlai/boot/mini/model/form/AiTaskVisibilityForm.java b/src/main/java/com/youlai/boot/mini/model/form/AiTaskVisibilityForm.java new file mode 100644 index 0000000..8c150db --- /dev/null +++ b/src/main/java/com/youlai/boot/mini/model/form/AiTaskVisibilityForm.java @@ -0,0 +1,23 @@ +package com.youlai.boot.mini.model.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Schema(description = "更新任务可见范围表单") +public class AiTaskVisibilityForm { + + @NotBlank(message = "任务UUID不能为空") + @Schema(description = "任务UUID") + private String uuid; + + @NotBlank(message = "可见范围不能为空") + @Pattern(regexp = "^(public|private|friends)$", message = "可见范围只能是public/private/friends") + @Schema(description = "可见范围:public-公开,private-仅自己可见") + private String visibility; + +} diff --git a/src/main/java/com/youlai/boot/mini/model/query/DiscoveryPublicWorkQuery.java b/src/main/java/com/youlai/boot/mini/model/query/DiscoveryPublicWorkQuery.java new file mode 100644 index 0000000..3428ff3 --- /dev/null +++ b/src/main/java/com/youlai/boot/mini/model/query/DiscoveryPublicWorkQuery.java @@ -0,0 +1,15 @@ +package com.youlai.boot.mini.model.query; + +import com.youlai.boot.common.base.BaseQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Schema(description = "发现页公开作品查询参数") +public class DiscoveryPublicWorkQuery extends BaseQuery { + + @Schema(description = "生成类型:img_single(单图), img_grid_4(四宫格), video(视频),不传查全部") + private String type; +} diff --git a/src/main/java/com/youlai/boot/mini/model/vo/DiscoveryPublicWorkVO.java b/src/main/java/com/youlai/boot/mini/model/vo/DiscoveryPublicWorkVO.java new file mode 100644 index 0000000..e11f0e1 --- /dev/null +++ b/src/main/java/com/youlai/boot/mini/model/vo/DiscoveryPublicWorkVO.java @@ -0,0 +1,38 @@ +package com.youlai.boot.mini.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; +import java.util.List; + +@Getter +@Setter +@Schema(description = "发现页公开作品VO") +public class DiscoveryPublicWorkVO { + + @Schema(description = "任务唯一标识") + private String uuid; + + @Schema(description = "生成类型:img_single(单图), img_grid_4(四宫格), video(视频)") + private String type; + + @Schema(description = "消耗积分") + private Integer pointsConsumed; + + @Schema(description = "创建时间") + private Date createTime; + + @Schema(description = "生成内容列表") + private List generateContent; + + @Schema(description = "创作者用户UUID") + private String userUuid; + + @Schema(description = "创作者昵称") + private String nickname; + + @Schema(description = "创作者头像") + private String avatar; +} diff --git a/src/main/java/com/youlai/boot/mini/service/AiGenerationService.java b/src/main/java/com/youlai/boot/mini/service/AiGenerationService.java index 22306b3..eeea838 100644 --- a/src/main/java/com/youlai/boot/mini/service/AiGenerationService.java +++ b/src/main/java/com/youlai/boot/mini/service/AiGenerationService.java @@ -7,10 +7,13 @@ import com.youlai.boot.mini.model.form.AiSingleImageGenerateForm; import com.youlai.boot.mini.model.form.AiVideoGenerateForm; import com.youlai.boot.mini.model.entity.MiniAiGenerationTask; import com.youlai.boot.mini.model.form.AiFourPanelCallbackForm; +import com.youlai.boot.mini.model.form.AiTaskVisibilityForm; import com.youlai.boot.mini.model.vo.AiVideoCallbackVO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.youlai.boot.mini.model.query.AiTaskMediaQuery; +import com.youlai.boot.mini.model.query.DiscoveryPublicWorkQuery; import com.youlai.boot.mini.model.vo.AiGenerationTaskVO; +import com.youlai.boot.mini.model.vo.DiscoveryPublicWorkVO; import com.youlai.boot.mini.model.vo.UserUploadMediaVO; import org.springframework.web.multipart.MultipartFile; @@ -44,4 +47,8 @@ public interface AiGenerationService { void handleTimeoutTasks(); + IPage getPublicDiscoveryFeed(DiscoveryPublicWorkQuery query); + + void updateTaskVisibility(Long userId, AiTaskVisibilityForm form); + } 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 8921c81..f5d271e 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 @@ -26,10 +26,14 @@ import com.youlai.boot.mini.model.entity.MiniAiGenerationTask; import com.youlai.boot.mini.model.entity.MiniAiTaskMedia; import com.youlai.boot.mini.model.form.*; import com.youlai.boot.mini.model.query.AiTaskMediaQuery; +import com.youlai.boot.mini.model.query.DiscoveryPublicWorkQuery; import com.youlai.boot.mini.model.vo.AiGenerationTaskVO; import com.youlai.boot.mini.model.vo.AiVideoCallbackVO; +import com.youlai.boot.mini.model.vo.DiscoveryPublicWorkVO; import com.youlai.boot.mini.model.vo.MiniAiTaskMediaVO; import com.youlai.boot.mini.model.vo.UserUploadMediaVO; +import com.youlai.boot.system.mapper.UserMapper; +import com.youlai.boot.system.model.entity.SysUser; import com.youlai.boot.admin.model.form.AdjustUserPointForm; import com.youlai.boot.admin.service.PointManageService; import com.youlai.boot.mini.service.AiGenerationService; @@ -70,6 +74,7 @@ public class AiGenerationServiceImpl implements AiGenerationService { private final WxSubscribeService wxSubscribeService; private final StringRedisTemplate stringRedisTemplate; private final PointManageService pointManageService; + private final UserMapper userMapper; // Redis key 存储微信订阅消息跳转版本 private static final String WX_MINI_PROGRAM_STATE_KEY = "wx:subscribe:mini_program_state"; @@ -912,6 +917,24 @@ public class AiGenerationServiceImpl implements AiGenerationService { return vo; } + @Override + public void updateTaskVisibility(Long userId, AiTaskVisibilityForm form) { + MiniAiGenerationTask task = aiGenerationTaskMapper.selectOne( + new LambdaQueryWrapper() + .eq(MiniAiGenerationTask::getUuid, form.getUuid()) + .eq(MiniAiGenerationTask::getMiniUserId, userId) + .eq(MiniAiGenerationTask::getDeleted, false)); + + if (task == null) { + throw new MsgException("任务不存在或无权限"); + } + + task.setVisibility(form.getVisibility()); + task.setUpdateTime(new Date()); + task.setUpdateTimestamp(System.currentTimeMillis()); + aiGenerationTaskMapper.updateById(task); + } + @Override public boolean deleteUploadMedia(Long userId, String uuid) { // 校验是否是当前用户的上传媒体 @@ -933,6 +956,83 @@ public class AiGenerationServiceImpl implements AiGenerationService { } + @Override + public IPage getPublicDiscoveryFeed(DiscoveryPublicWorkQuery query) { + // 1. 分页查询公开且已生成成功的任务 + LambdaQueryWrapper taskWrapper = new LambdaQueryWrapper<>(); + taskWrapper.eq(MiniAiGenerationTask::getVisibility, "public") + .eq(MiniAiGenerationTask::getStatus, 1) + .eq(MiniAiGenerationTask::getDeleted, false); + if (query.getType() != null) { + taskWrapper.eq(MiniAiGenerationTask::getType, query.getType()); + } + taskWrapper.orderByDesc(MiniAiGenerationTask::getCreateTimestamp); + + IPage taskPage = aiGenerationTaskMapper.selectPage( + new Page<>(query.getPageNum(), query.getPageSize()), taskWrapper); + + if (taskPage.getRecords().isEmpty()) { + return new Page<>(query.getPageNum(), query.getPageSize()); + } + + // 2. 批量查询媒体和用户 + List taskIds = taskPage.getRecords().stream() + .map(MiniAiGenerationTask::getId) + .toList(); + + List mediaList = aiTaskMediaMapper.selectList( + new LambdaQueryWrapper() + .in(MiniAiTaskMedia::getTaskId, taskIds) + .eq(MiniAiTaskMedia::getFileSource, "ai_generated") + .eq(MiniAiTaskMedia::getDeleted, false)); + + Map> mediaGroupMap = mediaList.stream() + .collect(Collectors.groupingBy( + MiniAiTaskMedia::getTaskId, + Collectors.mapping(media -> { + MiniAiTaskMediaVO vo = new MiniAiTaskMediaVO(); + vo.setUuid(media.getUuid()); + vo.setMediaType(media.getMediaType()); + vo.setSourceUrl(media.getSourceUrl()); + vo.setThumbnailUrl(media.getThumbnailUrl()); + vo.setWidth(media.getWidth()); + vo.setHeight(media.getHeight()); + vo.setDuration(media.getDuration()); + vo.setCreateTime(media.getCreateTime()); + return vo; + }, Collectors.toList()) + )); + + Set userIds = taskPage.getRecords().stream() + .map(MiniAiGenerationTask::getMiniUserId) + .collect(Collectors.toSet()); + + Map userMap = userMapper.selectList( + new LambdaQueryWrapper() + .in(SysUser::getId, userIds) + .eq(SysUser::getIsDeleted, 0)) + .stream() + .collect(Collectors.toMap(SysUser::getId, u -> u)); + + // 3. 组装VO + return taskPage.convert(task -> { + DiscoveryPublicWorkVO vo = new DiscoveryPublicWorkVO(); + vo.setUuid(task.getUuid()); + vo.setType(task.getType()); + vo.setPointsConsumed(task.getPointsConsumed()); + vo.setCreateTime(task.getCreateTime()); + vo.setGenerateContent(mediaGroupMap.getOrDefault(task.getId(), Collections.emptyList())); + + SysUser user = userMap.get(task.getMiniUserId()); + if (user != null) { + vo.setUserUuid(user.getUuid()); + vo.setNickname(user.getNickname()); + vo.setAvatar(user.getAvatar()); + } + return vo; + }); + } + @Override public IPage getMyAiGenerateHistory(AiTaskMediaQuery query, Long userId) { // 1. 分页查询当前用户的生成任务 diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index cf789ce..c45443c 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -246,7 +246,7 @@ ai: video-model: doubao-seedance-2-0-260128 task: # AI任务超时时间 单位分钟,默认300分钟 - timeout: 300 + timeout-minutes: 300 # 订阅模板配置 subscribe: