Browse Source

增加首页用户作品展示

glx
glx 2 days ago
parent
commit
481d72888d
  1. 30
      src/main/java/com/youlai/boot/mini/controller/AiGenerationController.java
  2. 23
      src/main/java/com/youlai/boot/mini/model/form/AiTaskVisibilityForm.java
  3. 15
      src/main/java/com/youlai/boot/mini/model/query/DiscoveryPublicWorkQuery.java
  4. 38
      src/main/java/com/youlai/boot/mini/model/vo/DiscoveryPublicWorkVO.java
  5. 7
      src/main/java/com/youlai/boot/mini/service/AiGenerationService.java
  6. 100
      src/main/java/com/youlai/boot/mini/service/impl/AiGenerationServiceImpl.java
  7. 2
      src/main/resources/application-dev.yml

30
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.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.boot.mini.model.query.AiTaskMediaQuery; 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.AiGenerationTaskVO;
import com.youlai.boot.mini.model.vo.DiscoveryPublicWorkVO;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import java.util.List; import java.util.List;
import com.youlai.boot.mini.model.vo.UserUploadMediaVO; import com.youlai.boot.mini.model.vo.UserUploadMediaVO;
@ -160,17 +162,21 @@ public class AiGenerationController {
return Result.success(); return Result.success();
} }
//需要在三个回调接口中控制状态,更新其他状态; 更新状态时需要判断 当前状态已是成功或失败时不能再更新状态,当状态是失败时需要退还补偿积分; @Operation(summary = "更新任务可见范围")
// mini_point_rule积分规则表,每个回调回退的积分是对应的规则扣减积分的负数值;mini_point_record积分记录表;mini_point_account用户积分账户 @PutMapping("/my/task/visibility")
@Log(module = LogModuleEnum.AI_GENERATION_TASK, value = ActionTypeEnum.UPDATE)
public Result<Void> updateTaskVisibility(@Valid @RequestBody AiTaskVisibilityForm form) {
// 当外部服务挂掉,不回调我的接口时,需要根据时间段判断,如果超过一定时间未回调,则更新状态为失败,并退还积分; Long userId = SecurityUtils.getUserId();
aiGenerationService.updateTaskVisibility(userId, form);
//TODO 现在 用户生成内容时,需要增加一个参数,同意或不同意公开生成的作品内容 return Result.success();
//TODO mini 中增加 查询 用户公开生成作品的接口,考虑设计一下查询规则 满足平台前中后期运营需求 }
//TODO admin 中 后台管理中增加 查询用户生成任务历史的接口
//TODO admin 中 编辑用户生成作品历史接口
//TODO admin 中 增加 手动查询生成任务接口,手动跳转生成失败任务,或做个接口给用户手动刷新查看,需要注意状态流转,只有超时未完成任务可出现刷新按钮
@Operation(summary = "查询公开作品发现页")
@GetMapping("/discovery/feed")
@Log(module = LogModuleEnum.AI_GENERATION_TASK, value = ActionTypeEnum.LIST)
public Result<IPage<DiscoveryPublicWorkVO>> getPublicDiscoveryFeed(@Valid DiscoveryPublicWorkQuery query) {
IPage<DiscoveryPublicWorkVO> result = aiGenerationService.getPublicDiscoveryFeed(query);
return Result.success(result);
}
} }

23
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;
}

15
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;
}

38
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<MiniAiTaskMediaVO> generateContent;
@Schema(description = "创作者用户UUID")
private String userUuid;
@Schema(description = "创作者昵称")
private String nickname;
@Schema(description = "创作者头像")
private String avatar;
}

7
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.form.AiVideoGenerateForm;
import com.youlai.boot.mini.model.entity.MiniAiGenerationTask; import com.youlai.boot.mini.model.entity.MiniAiGenerationTask;
import com.youlai.boot.mini.model.form.AiFourPanelCallbackForm; 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.youlai.boot.mini.model.vo.AiVideoCallbackVO;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.boot.mini.model.query.AiTaskMediaQuery; 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.AiGenerationTaskVO;
import com.youlai.boot.mini.model.vo.DiscoveryPublicWorkVO;
import com.youlai.boot.mini.model.vo.UserUploadMediaVO; import com.youlai.boot.mini.model.vo.UserUploadMediaVO;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -44,4 +47,8 @@ public interface AiGenerationService {
void handleTimeoutTasks(); void handleTimeoutTasks();
IPage<DiscoveryPublicWorkVO> getPublicDiscoveryFeed(DiscoveryPublicWorkQuery query);
void updateTaskVisibility(Long userId, AiTaskVisibilityForm form);
} }

100
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.entity.MiniAiTaskMedia;
import com.youlai.boot.mini.model.form.*; import com.youlai.boot.mini.model.form.*;
import com.youlai.boot.mini.model.query.AiTaskMediaQuery; 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.AiGenerationTaskVO;
import com.youlai.boot.mini.model.vo.AiVideoCallbackVO; 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.MiniAiTaskMediaVO;
import com.youlai.boot.mini.model.vo.UserUploadMediaVO; 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.model.form.AdjustUserPointForm;
import com.youlai.boot.admin.service.PointManageService; import com.youlai.boot.admin.service.PointManageService;
import com.youlai.boot.mini.service.AiGenerationService; import com.youlai.boot.mini.service.AiGenerationService;
@ -70,6 +74,7 @@ public class AiGenerationServiceImpl implements AiGenerationService {
private final WxSubscribeService wxSubscribeService; private final WxSubscribeService wxSubscribeService;
private final StringRedisTemplate stringRedisTemplate; private final StringRedisTemplate stringRedisTemplate;
private final PointManageService pointManageService; private final PointManageService pointManageService;
private final UserMapper userMapper;
// Redis key 存储微信订阅消息跳转版本 // Redis key 存储微信订阅消息跳转版本
private static final String WX_MINI_PROGRAM_STATE_KEY = "wx:subscribe:mini_program_state"; 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; return vo;
} }
@Override
public void updateTaskVisibility(Long userId, AiTaskVisibilityForm form) {
MiniAiGenerationTask task = aiGenerationTaskMapper.selectOne(
new LambdaQueryWrapper<MiniAiGenerationTask>()
.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 @Override
public boolean deleteUploadMedia(Long userId, String uuid) { public boolean deleteUploadMedia(Long userId, String uuid) {
// 校验是否是当前用户的上传媒体 // 校验是否是当前用户的上传媒体
@ -933,6 +956,83 @@ public class AiGenerationServiceImpl implements AiGenerationService {
} }
@Override
public IPage<DiscoveryPublicWorkVO> getPublicDiscoveryFeed(DiscoveryPublicWorkQuery query) {
// 1. 分页查询公开且已生成成功的任务
LambdaQueryWrapper<MiniAiGenerationTask> 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<MiniAiGenerationTask> taskPage = aiGenerationTaskMapper.selectPage(
new Page<>(query.getPageNum(), query.getPageSize()), taskWrapper);
if (taskPage.getRecords().isEmpty()) {
return new Page<>(query.getPageNum(), query.getPageSize());
}
// 2. 批量查询媒体和用户
List<Long> taskIds = taskPage.getRecords().stream()
.map(MiniAiGenerationTask::getId)
.toList();
List<MiniAiTaskMedia> mediaList = aiTaskMediaMapper.selectList(
new LambdaQueryWrapper<MiniAiTaskMedia>()
.in(MiniAiTaskMedia::getTaskId, taskIds)
.eq(MiniAiTaskMedia::getFileSource, "ai_generated")
.eq(MiniAiTaskMedia::getDeleted, false));
Map<Long, List<MiniAiTaskMediaVO>> 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<Long> userIds = taskPage.getRecords().stream()
.map(MiniAiGenerationTask::getMiniUserId)
.collect(Collectors.toSet());
Map<Long, SysUser> userMap = userMapper.selectList(
new LambdaQueryWrapper<SysUser>()
.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 @Override
public IPage<AiGenerationTaskVO> getMyAiGenerateHistory(AiTaskMediaQuery query, Long userId) { public IPage<AiGenerationTaskVO> getMyAiGenerateHistory(AiTaskMediaQuery query, Long userId) {
// 1. 分页查询当前用户的生成任务 // 1. 分页查询当前用户的生成任务

2
src/main/resources/application-dev.yml

@ -246,7 +246,7 @@ ai:
video-model: doubao-seedance-2-0-260128 video-model: doubao-seedance-2-0-260128
task: task:
# AI任务超时时间 单位分钟,默认300分钟 # AI任务超时时间 单位分钟,默认300分钟
timeout: 300 timeout-minutes: 300
# 订阅模板配置 # 订阅模板配置
subscribe: subscribe:

Loading…
Cancel
Save