mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	【代码评审】AI:AI 绘图的逻辑
This commit is contained in:
		| @@ -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; | ||||
|   | ||||
| @@ -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<PageResult<AiImageListRespVO>> 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<AiImageListRespVO> 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<Void> 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<Void> delete(@RequestParam("id") Long id) { | ||||
|         aiImageService.delete(id); | ||||
|         return success(null); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import org.mapstruct.factory.Mappers; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| // TODO @fan:convert 可以考虑去掉,使用 BeanUtils.copy 替代 | ||||
| /** | ||||
|  * ai image convert | ||||
|  * | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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<AiImageListRespVO> 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) { | ||||
|         // 校验记录是否存在 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV