From 4932ce60d24e0b9615df4314927a2f14ecd5861a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 May 2024 22:09:35 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84=E5=AE=A1?= =?UTF-8?q?=E3=80=91AI=EF=BC=9AAI=20=E7=BB=98=E5=9B=BE=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/ai/enums/AiImageStatusEnum.java | 2 + .../admin/image/AiImageController.java | 12 ++++++ .../module/ai/convert/AiImageConvert.java | 1 + .../ai/dal/dataobject/image/AiImageDO.java | 2 + .../ai/service/image/AiImageServiceImpl.java | 37 ++++++++++++------- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiImageStatusEnum.java b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiImageStatusEnum.java index a5231a3bf..534ad7e3f 100644 --- a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiImageStatusEnum.java +++ b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiImageStatusEnum.java @@ -14,6 +14,7 @@ import lombok.Getter; @Getter public enum AiImageStatusEnum { + // TODO @fan:改成 10 生成中;20 成功;30 失败;其它可以去掉噢 SUBMIT("submit", "提交任务"), WAITING("waiting", "等待"), IN_PROGRESS("in_progress", "进行中"), @@ -22,6 +23,7 @@ public enum AiImageStatusEnum { ; + // TODO @fan:final 一下 private String status; private String name; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java index e64edec2c..038b02454 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; // TODO @芋艿:整理接口定义 +// TODO @fan:参考 AiChatMessageController 改下 swagger 注解、注释 /** * ai作图 * @@ -28,20 +29,28 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @AllArgsConstructor public class AiImageController { + // TODO @fan:使用 @Resource 注入哈;然后 aiImageService => imageService; private final AiImageService aiImageService; + // TODO @fan:分页列表,建议是 getImagePage,包括接口 path 也建议改下哈; + // TODO @fan:@ModelAttribute 不需要哈; + // TODO @fan:这个要不搞成 my-page?因为是我的哈 @Operation(summary = "获取image列表", description = "dall3、midjourney") @GetMapping("/list") public CommonResult> list(@Validated @ModelAttribute AiImageListReqVO req) { + // TODO @fan:import static,这样只要 success() 就行啦 return CommonResult.success(aiImageService.list(req)); } + // TODO @fan:搞成 get-my? + // TODO @fan:方法名改下哈。 @Operation(summary = "获取image信息", description = "获取image信息") @GetMapping("/get") public CommonResult get(@RequestParam("id") Long id) { return CommonResult.success(aiImageService.get(id)); } + // TODO @fan:建议把 dallDrawing、midjourney 融合成一个 draw 接口,异步绘制;然后返回一个 id 给前端;前端通过 get 接口轮询,直到获取到生成成功 @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!") @PostMapping("/dall") public AiImageDallRespVO dallDrawing(@Validated @RequestBody AiImageDallReqVO req) { @@ -62,6 +71,7 @@ public class AiImageController { return success(null); } + // TODO @fan:要不先不要 midjourneyOperate、cancelMidjourney 接口哈 @Operation(summary = "取消 midjourney 绘画", description = "取消 midjourney 绘画") @PostMapping("/cancel-midjourney") public CommonResult cancelMidjourney(@RequestParam("id") Long id) { @@ -69,10 +79,12 @@ public class AiImageController { return success(null); } + // TODO @fan:delete-my?需要校验是不是当前人哈 @Operation(summary = "删除绘画记录", description = "") @DeleteMapping("/delete") public CommonResult delete(@RequestParam("id") Long id) { aiImageService.delete(id); return success(null); } + } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiImageConvert.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiImageConvert.java index 0f9271061..d094f489d 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiImageConvert.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiImageConvert.java @@ -11,6 +11,7 @@ import org.mapstruct.factory.Mappers; import java.util.List; +// TODO @fan:convert 可以考虑去掉,使用 BeanUtils.copy 替代 /** * ai image convert * diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java index cb3aedda1..eb901e23f 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java @@ -29,6 +29,8 @@ public class AiImageDO extends BaseDO { @Schema(description = "提示词") private String prompt; + // TODO @fan:要加一个平台字段;platform;因为一个平台,会有多种 model 模型; + @Schema(description = "模型 dall2/dall3、MJ、NIJI") private String model; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java index 6a0aea299..77299fceb 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java @@ -39,6 +39,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +// TODO @fan:注释优化下哈 /** * ai 作图 * @@ -51,14 +52,23 @@ import java.util.concurrent.TimeUnit; @Slf4j public class AiImageServiceImpl implements AiImageService { + // TODO @fan:使用 @Resource 注入 + + // TODO @fan:imageMapper private final AiImageMapper aiImageMapper; + private final FileApi fileApi; + private final OpenAiImageClient openAiImageClient; + private final MidjourneyWebSocketStarter midjourneyWebSocketStarter; + private final MidjourneyInteractionsApi midjourneyInteractionsApi; + private static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor( 3, 5, 1, TimeUnit.HOURS, new LinkedBlockingQueue<>(32)); + // TODO @fan:接 mj proxy @PostConstruct public void startMidjourney() { log.info("midjourney web socket starter..."); @@ -75,6 +85,7 @@ public class AiImageServiceImpl implements AiImageService { }); } + // TODO @fan:1)分页,然后 loginUser 通过参数传入,这样 Service 无状态;2)另外,返回 DO;VO 的翻译,交给 Controller;3:还有,使用 BeanUtils 替代哈 @Override public PageResult list(AiImageListReqVO req) { // 获取登录用户 @@ -92,29 +103,33 @@ public class AiImageServiceImpl implements AiImageService { return result; } + // TODO @fan:1)返回 DO;VO 的翻译,交给 Controller;2)还有,使用 BeanUtils 替代哈 @Override public AiImageListRespVO get(Long id) { AiImageDO aiImageDO = aiImageMapper.selectById(id); return AiImageConvert.INSTANCE.convertAiImageListRespVO(aiImageDO); } + // TODO @fan:1)loginUserId 通过 controller 传入; @Override public AiImageDallRespVO dallDrawing(AiImageDallReqVO req) { Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); // 保存数据库 + // TODO @fan:1)使用 BeanUtils;2)使用链式调用哈; AiImageDO aiImageDO = AiImageConvert.INSTANCE.convertAiImageDO(req); aiImageDO.setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()); aiImageDO.setUserId(loginUserId); aiImageMapper.insert(aiImageDO); // 异步执行 + // TODO @fan:使用 @Async 去调用哈; EXECUTOR.execute(() -> { try { - // 获取 model OpenAiImageModelEnum openAiImageModelEnum = OpenAiImageModelEnum.valueOfModel(req.getModel()); OpenAiImageStyleEnum openAiImageStyleEnum = OpenAiImageStyleEnum.valueOfStyle(req.getStyle()); // 转换openai 参数 + // TODO @fan:需要考虑,不同平台,参数不同; OpenAiImageOptions openAiImageOptions = new OpenAiImageOptions(); openAiImageOptions.setModel(openAiImageModelEnum.getModel()); openAiImageOptions.setStyle(openAiImageStyleEnum.getStyle()); @@ -125,23 +140,16 @@ public class AiImageServiceImpl implements AiImageService { // 图片保存到服务器 String filePath = fileApi.createFile(HttpUtil.downloadBytes(imageGeneration.getOutput().getUrl())); // 更新数据库 - aiImageMapper.updateById( - new AiImageDO() - .setId(aiImageDO.getId()) - .setStatus(AiImageStatusEnum.COMPLETE.getStatus()) - .setPicUrl(filePath) - .setOriginalPicUrl(imageGeneration.getOutput().getUrl()) + aiImageMapper.updateById(new AiImageDO().setId(aiImageDO.getId()).setStatus(AiImageStatusEnum.COMPLETE.getStatus()) + .setPicUrl(filePath).setOriginalPicUrl(imageGeneration.getOutput().getUrl()) ); } catch (AiException aiException) { - // 更新错误信息 - aiImageMapper.updateById( - new AiImageDO() - .setId(aiImageDO.getId()) - .setStatus(AiImageStatusEnum.FAIL.getStatus()) - .setErrorMessage(aiException.getMessage()) - ); + // TODO @fan:错误日志,也打印下哈;因为 aiException.getMessage() 比较精简; + aiImageMapper.updateById(new AiImageDO().setId(aiImageDO.getId()).setStatus(AiImageStatusEnum.FAIL.getStatus()) + .setErrorMessage(aiException.getMessage())); } }); + // TODO @fan:返回 id 就可以啦 // 转换 AiImageDallDrawingRespVO return AiImageConvert.INSTANCE.convertAiImageDallDrawingRespVO(aiImageDO); } @@ -188,6 +196,7 @@ public class AiImageServiceImpl implements AiImageService { ); } + // TODO @fan:1)需要校验存在;2)需要校验属于我; @Override public void delete(Long id) { // 校验记录是否存在