Quellcode durchsuchen

【代码优化】AI:Image 图片的列表、详情等接口

YunaiV vor 11 Monaten
Ursprung
Commit
458f5acdf0

+ 24 - 25
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java

@@ -1,13 +1,14 @@
 package cn.iocoder.yudao.module.ai.controller.admin.image;
 
+import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageListReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageMyRespVO;
+import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageRespVO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
 import cn.iocoder.yudao.module.ai.service.image.AiImageService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -21,35 +22,30 @@ import org.springframework.web.bind.annotation.*;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
-@Tag(name = "管理后台 - Ai 绘画")
+@Tag(name = "管理后台 - AI 绘画")
 @RestController
 @RequestMapping("/ai/image")
 @Slf4j
 public class AiImageController {
 
     @Resource
-    private AiImageService aiImageService;
+    private AiImageService imageService;
 
     @Operation(summary = "获取【我的】绘图分页")
     @GetMapping("/my-page")
-    public CommonResult<PageResult<AiImagePageMyRespVO>> getImagePageMy(@Validated AiImageListReqVO req) {
-        // 转换 resp
-        PageResult<AiImageDO> pageResult = aiImageService.getImagePageMy(getLoginUserId(), req);
-        // 转换 PageResult<AiImageListRespVO> 返回
-        PageResult<AiImagePageMyRespVO> result = new PageResult<>();
-        result.setTotal(pageResult.getTotal());
-        result.setList(BeanUtils.toBean(pageResult.getList(), AiImagePageMyRespVO.class));
-        return success(result);
+    public CommonResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated PageParam pageReqVO) {
+        PageResult<AiImageDO> pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO);
+        return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
     }
 
-    // TODO @fan:类似 /my-page 的建议
-    @Operation(summary = "获取【我的】绘图记录", description = "...")
+    @Operation(summary = "获取【我的】绘图记录")
     @GetMapping("/get-my")
-    public CommonResult<AiImagePageMyRespVO> getMy(@RequestParam("id") Long id) {
-        // 获取 image 信息
-        AiImageDO imageDO = aiImageService.getMy(id);
-        // 转 resp 并返回
-        return CommonResult.success(BeanUtils.toBean(imageDO, AiImagePageMyRespVO.class));
+    public CommonResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) {
+        AiImageDO image = imageService.getImage(id);
+        if (image == null || ObjUtil.notEqual(getLoginUserId(), image.getUserId())) {
+            return success(null);
+        }
+        return success(BeanUtils.toBean(image, AiImageRespVO.class));
     }
 
     // TODO @fan:建议把 dallDrawing、midjourney 融合成一个 draw 接口,异步绘制;然后返回一个 id 给前端;前端通过 get 接口轮询,直到获取到生成成功
@@ -58,14 +54,15 @@ public class AiImageController {
     @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!")
     @PostMapping("/dall")
     public CommonResult<Long> dall(@Validated @RequestBody AiImageDallReqVO req) {
-        return success(aiImageService.dall(getLoginUserId(), req));
+        return success(imageService.dall(getLoginUserId(), req));
     }
 
     @Operation(summary = "删除【我的】绘画记录")
-    @DeleteMapping("/delete-id-my")
+    @DeleteMapping("/delete-my")
     @Parameter(name = "id", required = true, description = "绘画编号", example = "1024")
-    public CommonResult<Boolean> deleteIdMy(@RequestParam("id") Long id) {
-        return success(aiImageService.deleteIdMy(id, getLoginUserId()));
+    public CommonResult<Boolean> deleteImageMy(@RequestParam("id") Long id) {
+        imageService.deleteImageMy(id, getLoginUserId());
+        return success(true);
     }
 
     // ================ midjourney 接口
@@ -73,12 +70,14 @@ public class AiImageController {
     @Operation(summary = "midjourney-imagine 绘画", description = "...")
     @PostMapping("/midjourney/imagine")
     public CommonResult<Long> midjourneyImagine(@Validated @RequestBody AiImageMidjourneyImagineReqVO req) {
-        return success(aiImageService.midjourneyImagine(getLoginUserId(), req));
+        return success(imageService.midjourneyImagine(getLoginUserId(), req));
     }
 
+    // TODO @fan:可以考虑,复用 AiImageDallRespVO,统一成 AIImageRespVO
     @Operation(summary = "midjourney proxy - 回调通知")
     @RequestMapping("/midjourney-notify")
     public CommonResult<Boolean> midjourneyNotify(MidjourneyNotifyReqVO notifyReqVO) {
-        return success(aiImageService.midjourneyNotify(getLoginUserId(), notifyReqVO));
+        return success(imageService.midjourneyNotify(getLoginUserId(), notifyReqVO));
     }
+
 }

+ 0 - 18
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageListReqVO.java

@@ -1,18 +0,0 @@
-package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import lombok.Data;
-import lombok.experimental.Accessors;
-
-/**
- * AI Image 我的图片列表 req
- *
- * @author fansili
- * @time 2024/4/28 17:42
- * @since 1.0
- */
-@Data
-@Accessors(chain = true)
-public class AiImageListReqVO extends PageParam {
-
-}

+ 0 - 16
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageMidjourneyRes.java

@@ -1,16 +0,0 @@
-package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
-
-import lombok.Data;
-import lombok.experimental.Accessors;
-
-/**
- * midjourney
- *
- * @author fansili
- * @time 2024/4/28 17:42
- * @since 1.0
- */
-@Data
-@Accessors(chain = true)
-public class AiImageMidjourneyRes {
-}

+ 2 - 12
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImagePageMyRespVO.java → yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageRespVO.java

@@ -1,23 +1,13 @@
 package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
 
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
-import lombok.experimental.Accessors;
 
 import java.util.Map;
 
-// TODO @fan:可以考虑,复用 AiImageDallRespVO,统一成 AIImageRespVO
-/**
- * midjourney req
- *
- * @author fansili
- * @time 2024/4/28 17:42
- * @since 1.0
- */
+// TODO @芋艿:完善 swagger 注解
 @Data
-@Accessors(chain = true)
-public class AiImagePageMyRespVO extends PageParam {
+public class AiImageRespVO {
 
     @Schema(description = "id编号", example = "1")
     private Long id;

+ 8 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/image/AiImageMapper.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.ai.dal.mysql.image;
 
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
@@ -35,4 +37,10 @@ public interface AiImageMapper extends BaseMapperX<AiImageDO> {
         return this.selectOne(new LambdaQueryWrapperX<AiImageDO>().eq(AiImageDO::getJobId, id));
     }
 
+    default PageResult<AiImageDO> selectPage(Long userId, PageParam pageReqVO) {
+        return selectPage(pageReqVO, new LambdaQueryWrapperX<AiImageDO>()
+                .eq(AiImageDO::getUserId, userId)
+                .orderByDesc(AiImageDO::getId));
+    }
+
 }

+ 15 - 25
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java

@@ -1,38 +1,35 @@
 package cn.iocoder.yudao.module.ai.service.image;
 
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageListReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyOperateReqVO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
 
 /**
- * ai 作图
+ * AI 绘图 Service 接口
  *
  * @author fansili
- * @time 2024/4/25 15:50
- * @since 1.0
  */
 public interface AiImageService {
 
     /**
-     * ai绘画 - 列表
+     * 获取【我的】绘图分页
      *
-     * @param loginUserId
-     * @param req
-     * @return
+     * @param userId 用户编号
+     * @param pageReqVO 分页条件
+     * @return 绘图分页
      */
-    PageResult<AiImageDO> getImagePageMy(Long loginUserId, AiImageListReqVO req);
+    PageResult<AiImageDO> getImagePageMy(Long userId, PageParam pageReqVO);
 
     /**
-     * 获取 - image 信息
+     * 获得绘图记录
      *
-     * @param id
-     * @return
+     * @param id 绘图编号
+     * @return 绘图记录
      */
-    AiImageDO getMy(Long id);
+    AiImageDO getImage(Long id);
 
     /**
      * ai绘画 - dall2/dall3 绘画
@@ -52,19 +49,12 @@ public interface AiImageService {
     Long midjourneyImagine(Long loginUserId, AiImageMidjourneyImagineReqVO req);
 
     /**
-     * midjourney 操作(u1、u2、放大、换一批...)
-     *
-     * @param req
-     */
-    void midjourneyOperate(AiImageMidjourneyOperateReqVO req);
-
-    /**
-     * 删除 - image 记录
+     * 删除【我的】绘画记录
      *
-     * @param id
-     * @param loginUserId
+     * @param id 绘画编号
+     * @param userId 用户编号
      */
-    Boolean deleteIdMy(Long id, Long loginUserId);
+    void deleteImageMy(Long id, Long userId);
 
     /**
      * midjourney proxy - 回调通知

+ 34 - 54
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java

@@ -2,17 +2,17 @@ package cn.iocoder.yudao.module.ai.service.image;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.extra.spring.SpringUtil;
 import cn.hutool.http.HttpUtil;
 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
 import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageModelEnum;
 import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageStyleEnum;
 import cn.iocoder.yudao.framework.ai.core.exception.AiException;
-import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.ai.AiCommonConstants;
-import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
 import cn.iocoder.yudao.module.ai.client.MidjourneyProxyClient;
 import cn.iocoder.yudao.module.ai.client.enums.MidjourneyModelEnum;
 import cn.iocoder.yudao.module.ai.client.enums.MidjourneySubmitCodeEnum;
@@ -21,9 +21,7 @@ import cn.iocoder.yudao.module.ai.client.vo.MidjourneyImagineReqVO;
 import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO;
 import cn.iocoder.yudao.module.ai.client.vo.MidjourneySubmitRespVO;
 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageListReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyOperateReqVO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
 import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper;
 import cn.iocoder.yudao.module.ai.enums.AiImagePublicStatusEnum;
@@ -46,12 +44,12 @@ import org.springframework.transaction.annotation.Transactional;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 
 
+import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.AI_IMAGE_NOT_EXISTS;
+
 /**
- * AI 绘画(接入 dall2/dall3、midjourney)
+ * AI 绘画 Service 实现类
  *
  * @author fansili
- * @time 2024/4/25 15:51
- * @since 1.0
  */
 @Service
 @Slf4j
@@ -59,10 +57,13 @@ public class AiImageServiceImpl implements AiImageService {
 
     @Resource
     private AiImageMapper imageMapper;
+
     @Resource
     private FileApi fileApi;
+
     @Resource
     private OpenAiImageClient openAiImageClient;
+
     @Autowired
     private MidjourneyProxyClient midjourneyProxyClient;
 
@@ -70,16 +71,12 @@ public class AiImageServiceImpl implements AiImageService {
     private String midjourneyNotifyUrl;
 
     @Override
-    public PageResult<AiImageDO> getImagePageMy(Long loginUserId, AiImageListReqVO req) {
-        // 查询当前用户下所有的绘画记录
-        return imageMapper.selectPage(req,
-                new LambdaQueryWrapperX<AiImageDO>()
-                        .eq(AiImageDO::getUserId, loginUserId)
-                        .orderByDesc(AiImageDO::getId));
+    public PageResult<AiImageDO> getImagePageMy(Long userId, PageParam pageReqVO) {
+        return imageMapper.selectPage(userId, pageReqVO);
     }
 
     @Override
-    public AiImageDO getMy(Long id) {
+    public AiImageDO getImage(Long id) {
         return imageMapper.selectById(id);
     }
 
@@ -95,7 +92,7 @@ public class AiImageServiceImpl implements AiImageService {
                 .setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus());
         imageMapper.insert(aiImageDO);
         // 异步执行
-        doDall(aiImageDO, req);
+        getSelf().doDall(aiImageDO, req);
         // 转换 AiImageDallDrawingRespVO
         return aiImageDO.getId();
     }
@@ -185,42 +182,15 @@ public class AiImageServiceImpl implements AiImageService {
         return aiImageDO.getId();
     }
 
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public void midjourneyOperate(AiImageMidjourneyOperateReqVO req) {
-//        // 校验是否存在
-//        AiImageDO aiImageDO = validateExists(req.getId());
-//        // 获取 midjourneyOperations
-//        List<AiImageMidjourneyOperationsVO> midjourneyOperations = getMidjourneyOperations(aiImageDO);
-//        // 校验 OperateId 是否存在
-//        AiImageMidjourneyOperationsVO midjourneyOperationsVO = validateMidjourneyOperationsExists(midjourneyOperations, req.getOperateId());
-//        // 校验 messageId
-//        validateMessageId(aiImageDO.getMjNonceId(), req.getMessageId());
-//        // 获取 mjOperationName
-//        String mjOperationName = midjourneyOperationsVO.getLabel();
-//        // 保存一个 image 任务记录
-//        // todo
-////        doSave(aiImageDO.getPrompt(), aiImageDO.getSize(), aiImageDO.getModel(),
-////                null, null, AiImageStatusEnum.SUBMIT, null,
-////                req.getMessageId(), req.getOperateId(), mjOperationName);
-//        // 提交操作
-//        midjourneyInteractionsApi.reRoll(
-//                new ReRollReq()
-//                        .setCustomId(req.getOperateId())
-//                        .setMessageId(req.getMessageId())
-//        );
-    }
-
     @Override
-    public Boolean deleteIdMy(Long id, Long userId) {
-        // 校验是否存在,并获取 image
-        AiImageDO image = validateExists(id);
-        // 是否属于当前用户
-        if (!image.getUserId().equals(userId)) {
-            throw exception(ErrorCodeConstants.AI_IMAGE_NOT_EXISTS);
+    public void deleteImageMy(Long id, Long userId) {
+        // 1. 校验是否存在
+        AiImageDO image = validateImageExists(id);
+        if (ObjUtil.notEqual(image.getUserId(), userId)) {
+            throw exception(AI_IMAGE_NOT_EXISTS);
         }
         // 删除记录
-        return imageMapper.deleteById(id) > 0;
+        imageMapper.deleteById(id);
     }
 
     @Override
@@ -255,11 +225,21 @@ public class AiImageServiceImpl implements AiImageService {
         return true;
     }
 
-    private AiImageDO validateExists(Long id) {
-        AiImageDO aiImageDO = imageMapper.selectById(id);
-        if (aiImageDO == null) {
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MIDJOURNEY_IMAGINE_FAIL);
+    private AiImageDO validateImageExists(Long id) {
+        AiImageDO image = imageMapper.selectById(id);
+        if (image == null) {
+            throw exception(AI_IMAGE_NOT_EXISTS);
         }
-        return aiImageDO;
+        return image;
     }
+
+    /**
+     * 获得自身的代理对象,解决 AOP 生效问题
+     *
+     * @return 自己
+     */
+    private AiImageServiceImpl getSelf() {
+        return SpringUtil.getBean(getClass());
+    }
+
 }