Commit 4932ce60d24e0b9615df4314927a2f14ecd5861a

Authored by YunaiV
1 parent cfeb4bdc

【代码评审】AI:AI 绘图的逻辑

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;
14 14 @Getter
15 15 public enum AiImageStatusEnum {
16 16  
  17 + // TODO @fan:改成 10 生成中;20 成功;30 失败;其它可以去掉噢
17 18 SUBMIT("submit", "提交任务"),
18 19 WAITING("waiting", "等待"),
19 20 IN_PROGRESS("in_progress", "进行中"),
... ... @@ -22,6 +23,7 @@ public enum AiImageStatusEnum {
22 23  
23 24 ;
24 25  
  26 + // TODO @fan:final 一下
25 27 private String status;
26 28  
27 29 private String name;
... ...
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.*;
14 14 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
15 15  
16 16 // TODO @芋艿:整理接口定义
  17 +// TODO @fan:参考 AiChatMessageController 改下 swagger 注解、注释
17 18 /**
18 19 * ai作图
19 20 *
... ... @@ -28,20 +29,28 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
28 29 @AllArgsConstructor
29 30 public class AiImageController {
30 31  
  32 + // TODO @fan:使用 @Resource 注入哈;然后 aiImageService => imageService;
31 33 private final AiImageService aiImageService;
32 34  
  35 + // TODO @fan:分页列表,建议是 getImagePage,包括接口 path 也建议改下哈;
  36 + // TODO @fan:@ModelAttribute 不需要哈;
  37 + // TODO @fan:这个要不搞成 my-page?因为是我的哈
33 38 @Operation(summary = "获取image列表", description = "dall3、midjourney")
34 39 @GetMapping("/list")
35 40 public CommonResult<PageResult<AiImageListRespVO>> list(@Validated @ModelAttribute AiImageListReqVO req) {
  41 + // TODO @fan:import static,这样只要 success() 就行啦
36 42 return CommonResult.success(aiImageService.list(req));
37 43 }
38 44  
  45 + // TODO @fan:搞成 get-my?
  46 + // TODO @fan:方法名改下哈。
39 47 @Operation(summary = "获取image信息", description = "获取image信息")
40 48 @GetMapping("/get")
41 49 public CommonResult<AiImageListRespVO> get(@RequestParam("id") Long id) {
42 50 return CommonResult.success(aiImageService.get(id));
43 51 }
44 52  
  53 + // TODO @fan:建议把 dallDrawing、midjourney 融合成一个 draw 接口,异步绘制;然后返回一个 id 给前端;前端通过 get 接口轮询,直到获取到生成成功
45 54 @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!")
46 55 @PostMapping("/dall")
47 56 public AiImageDallRespVO dallDrawing(@Validated @RequestBody AiImageDallReqVO req) {
... ... @@ -62,6 +71,7 @@ public class AiImageController {
62 71 return success(null);
63 72 }
64 73  
  74 + // TODO @fan:要不先不要 midjourneyOperate、cancelMidjourney 接口哈
65 75 @Operation(summary = "取消 midjourney 绘画", description = "取消 midjourney 绘画")
66 76 @PostMapping("/cancel-midjourney")
67 77 public CommonResult<Void> cancelMidjourney(@RequestParam("id") Long id) {
... ... @@ -69,10 +79,12 @@ public class AiImageController {
69 79 return success(null);
70 80 }
71 81  
  82 + // TODO @fan:delete-my?需要校验是不是当前人哈
72 83 @Operation(summary = "删除绘画记录", description = "")
73 84 @DeleteMapping("/delete")
74 85 public CommonResult<Void> delete(@RequestParam("id") Long id) {
75 86 aiImageService.delete(id);
76 87 return success(null);
77 88 }
  89 +
78 90 }
... ...
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;
11 11  
12 12 import java.util.List;
13 13  
  14 +// TODO @fan:convert 可以考虑去掉,使用 BeanUtils.copy 替代
14 15 /**
15 16 * ai image convert
16 17 *
... ...
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 {
29 29 @Schema(description = "提示词")
30 30 private String prompt;
31 31  
  32 + // TODO @fan:要加一个平台字段;platform;因为一个平台,会有多种 model 模型;
  33 +
32 34 @Schema(description = "模型 dall2/dall3、MJ、NIJI")
33 35 private String model;
34 36  
... ...
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;
39 39 import java.util.concurrent.ThreadPoolExecutor;
40 40 import java.util.concurrent.TimeUnit;
41 41  
  42 +// TODO @fan:注释优化下哈
42 43 /**
43 44 * ai 作图
44 45 *
... ... @@ -51,14 +52,23 @@ import java.util.concurrent.TimeUnit;
51 52 @Slf4j
52 53 public class AiImageServiceImpl implements AiImageService {
53 54  
  55 + // TODO @fan:使用 @Resource 注入
  56 +
  57 + // TODO @fan:imageMapper
54 58 private final AiImageMapper aiImageMapper;
  59 +
55 60 private final FileApi fileApi;
  61 +
56 62 private final OpenAiImageClient openAiImageClient;
  63 +
57 64 private final MidjourneyWebSocketStarter midjourneyWebSocketStarter;
  65 +
58 66 private final MidjourneyInteractionsApi midjourneyInteractionsApi;
  67 +
59 68 private static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
60 69 3, 5, 1, TimeUnit.HOURS, new LinkedBlockingQueue<>(32));
61 70  
  71 + // TODO @fan:接 mj proxy
62 72 @PostConstruct
63 73 public void startMidjourney() {
64 74 log.info("midjourney web socket starter...");
... ... @@ -75,6 +85,7 @@ public class AiImageServiceImpl implements AiImageService {
75 85 });
76 86 }
77 87  
  88 + // TODO @fan:1)分页,然后 loginUser 通过参数传入,这样 Service 无状态;2)另外,返回 DO;VO 的翻译,交给 Controller;3:还有,使用 BeanUtils 替代哈
78 89 @Override
79 90 public PageResult<AiImageListRespVO> list(AiImageListReqVO req) {
80 91 // 获取登录用户
... ... @@ -92,29 +103,33 @@ public class AiImageServiceImpl implements AiImageService {
92 103 return result;
93 104 }
94 105  
  106 + // TODO @fan:1)返回 DO;VO 的翻译,交给 Controller;2)还有,使用 BeanUtils 替代哈
95 107 @Override
96 108 public AiImageListRespVO get(Long id) {
97 109 AiImageDO aiImageDO = aiImageMapper.selectById(id);
98 110 return AiImageConvert.INSTANCE.convertAiImageListRespVO(aiImageDO);
99 111 }
100 112  
  113 + // TODO @fan:1)loginUserId 通过 controller 传入;
101 114 @Override
102 115 public AiImageDallRespVO dallDrawing(AiImageDallReqVO req) {
103 116 Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
104 117 // 保存数据库
  118 + // TODO @fan:1)使用 BeanUtils;2)使用链式调用哈;
105 119 AiImageDO aiImageDO = AiImageConvert.INSTANCE.convertAiImageDO(req);
106 120 aiImageDO.setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus());
107 121 aiImageDO.setUserId(loginUserId);
108 122 aiImageMapper.insert(aiImageDO);
109 123 // 异步执行
  124 + // TODO @fan:使用 @Async 去调用哈;
110 125 EXECUTOR.execute(() -> {
111 126 try {
112   -
113 127 // 获取 model
114 128 OpenAiImageModelEnum openAiImageModelEnum = OpenAiImageModelEnum.valueOfModel(req.getModel());
115 129 OpenAiImageStyleEnum openAiImageStyleEnum = OpenAiImageStyleEnum.valueOfStyle(req.getStyle());
116 130  
117 131 // 转换openai 参数
  132 + // TODO @fan:需要考虑,不同平台,参数不同;
118 133 OpenAiImageOptions openAiImageOptions = new OpenAiImageOptions();
119 134 openAiImageOptions.setModel(openAiImageModelEnum.getModel());
120 135 openAiImageOptions.setStyle(openAiImageStyleEnum.getStyle());
... ... @@ -125,23 +140,16 @@ public class AiImageServiceImpl implements AiImageService {
125 140 // 图片保存到服务器
126 141 String filePath = fileApi.createFile(HttpUtil.downloadBytes(imageGeneration.getOutput().getUrl()));
127 142 // 更新数据库
128   - aiImageMapper.updateById(
129   - new AiImageDO()
130   - .setId(aiImageDO.getId())
131   - .setStatus(AiImageStatusEnum.COMPLETE.getStatus())
132   - .setPicUrl(filePath)
133   - .setOriginalPicUrl(imageGeneration.getOutput().getUrl())
  143 + aiImageMapper.updateById(new AiImageDO().setId(aiImageDO.getId()).setStatus(AiImageStatusEnum.COMPLETE.getStatus())
  144 + .setPicUrl(filePath).setOriginalPicUrl(imageGeneration.getOutput().getUrl())
134 145 );
135 146 } catch (AiException aiException) {
136   - // 更新错误信息
137   - aiImageMapper.updateById(
138   - new AiImageDO()
139   - .setId(aiImageDO.getId())
140   - .setStatus(AiImageStatusEnum.FAIL.getStatus())
141   - .setErrorMessage(aiException.getMessage())
142   - );
  147 + // TODO @fan:错误日志,也打印下哈;因为 aiException.getMessage() 比较精简;
  148 + aiImageMapper.updateById(new AiImageDO().setId(aiImageDO.getId()).setStatus(AiImageStatusEnum.FAIL.getStatus())
  149 + .setErrorMessage(aiException.getMessage()));
143 150 }
144 151 });
  152 + // TODO @fan:返回 id 就可以啦
145 153 // 转换 AiImageDallDrawingRespVO
146 154 return AiImageConvert.INSTANCE.convertAiImageDallDrawingRespVO(aiImageDO);
147 155 }
... ... @@ -188,6 +196,7 @@ public class AiImageServiceImpl implements AiImageService {
188 196 );
189 197 }
190 198  
  199 + // TODO @fan:1)需要校验存在;2)需要校验属于我;
191 200 @Override
192 201 public void delete(Long id) {
193 202 // 校验记录是否存在
... ...