Commit e8cf40a82a0db2b136fd481971b719415442dfd3

Authored by cherishsince
1 parent 16a47bde

【增加】1、mj components 相关操作任务提交 2、增加ai image 列表查询

Showing 12 changed files with 240 additions and 57 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java
@@ -14,29 +14,26 @@ public interface ErrorCodeConstants { @@ -14,29 +14,26 @@ public interface ErrorCodeConstants {
14 // chat 14 // chat
15 15
16 ErrorCode AI_MODULE_NOT_SUPPORTED = new ErrorCode(1_022_000_000, "AI 模型暂不支持!"); 16 ErrorCode AI_MODULE_NOT_SUPPORTED = new ErrorCode(1_022_000_000, "AI 模型暂不支持!");
17 - ErrorCode AI_CHAT_ROLE_NOT_EXISTENT = new ErrorCode(1_022_000_001, "AI Role 不存在!");;  
18 17
19 // conversation 18 // conversation
20 19
21 ErrorCode AI_CONVERSATION_NOT_EXISTS = new ErrorCode(1_022_000_002, "AI 对话不存在!");; 20 ErrorCode AI_CONVERSATION_NOT_EXISTS = new ErrorCode(1_022_000_002, "AI 对话不存在!");;
22 - ErrorCode AI_CHAT_CONTINUE_CONVERSATION_ID_NOT_NULL = new ErrorCode(1_022_000_002, "chat 继续对话,对话 id 不能为空!");;  
23 - ErrorCode AI_CHAT_CONTINUE_NOT_EXIST = new ErrorCode(1_022_000_020, "chat 对话不存在!");  
24 - ErrorCode AI_CHAT_CONVERSATION_NOT_YOURS = new ErrorCode(1_022_000_021, "这条 chat 对话不是你的!");  
25 21
26 // midjourney 22 // midjourney
27 23
28 ErrorCode AI_MIDJOURNEY_IMAGINE_FAIL = new ErrorCode(1_022_000_040, "midjourney imagine 操作失败!"); 24 ErrorCode AI_MIDJOURNEY_IMAGINE_FAIL = new ErrorCode(1_022_000_040, "midjourney imagine 操作失败!");
  25 + ErrorCode AI_MIDJOURNEY_OPERATION_NOT_EXISTS = new ErrorCode(1_022_000_040, "midjourney 操作不存在!");
  26 + ErrorCode AI_MIDJOURNEY_MESSAGE_ID_INCORRECT = new ErrorCode(1_022_000_040, "midjourney message id 不正确!");
29 27
30 // role 28 // role
31 29
32 - ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "chatRole 不存在!"); 30 + ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "AI 角色不存在!");
33 ErrorCode AI_CHAT_ROLE_NOT_PUBLIC = new ErrorCode(1_022_000_060, "AI 角色未公开!"); 31 ErrorCode AI_CHAT_ROLE_NOT_PUBLIC = new ErrorCode(1_022_000_060, "AI 角色未公开!");
34 32
35 // modal 33 // modal
36 34
37 ErrorCode AI_MODAL_NOT_EXIST = new ErrorCode(1_022_000_080, "AI 模型不存在!"); 35 ErrorCode AI_MODAL_NOT_EXIST = new ErrorCode(1_022_000_080, "AI 模型不存在!");
38 ErrorCode AI_MODAL_CONFIG_PARAMS_INCORRECT = new ErrorCode(1_022_000_081, "AI 模型 config 参数不正确! {} "); 36 ErrorCode AI_MODAL_CONFIG_PARAMS_INCORRECT = new ErrorCode(1_022_000_081, "AI 模型 config 参数不正确! {} ");
39 - ErrorCode AI_MODAL_NOT_SUPPORTED_MODAL = new ErrorCode(1_022_000_082, "AI 模型不支持的 modal! {} ");  
40 ErrorCode AI_MODAL_PLATFORM_PARAMS_INCORRECT = new ErrorCode(1_022_000_083, "AI 平台参数不正确! {} "); 37 ErrorCode AI_MODAL_PLATFORM_PARAMS_INCORRECT = new ErrorCode(1_022_000_083, "AI 平台参数不正确! {} ");
41 ErrorCode AI_MODAL_DISABLE_NOT_USED = new ErrorCode(1_022_000_084, "AI 模型禁用不能使用!"); 38 ErrorCode AI_MODAL_DISABLE_NOT_USED = new ErrorCode(1_022_000_084, "AI 模型禁用不能使用!");
42 39
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatDrawingStatusEnum.java renamed to yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiImageDrawingStatusEnum.java
@@ -12,7 +12,7 @@ import lombok.Getter; @@ -12,7 +12,7 @@ import lombok.Getter;
12 */ 12 */
13 @AllArgsConstructor 13 @AllArgsConstructor
14 @Getter 14 @Getter
15 -public enum AiChatDrawingStatusEnum { 15 +public enum AiImageDrawingStatusEnum {
16 16
17 SUBMIT("submit", "提交任务"), 17 SUBMIT("submit", "提交任务"),
18 WAITING("waiting", "等待"), 18 WAITING("waiting", "等待"),
@@ -27,8 +27,8 @@ public enum AiChatDrawingStatusEnum { @@ -27,8 +27,8 @@ public enum AiChatDrawingStatusEnum {
27 private String name; 27 private String name;
28 28
29 29
30 - public static AiChatDrawingStatusEnum valueOfStatus(String status) {  
31 - for (AiChatDrawingStatusEnum itemEnum : AiChatDrawingStatusEnum.values()) { 30 + public static AiImageDrawingStatusEnum valueOfStatus(String status) {
  31 + for (AiImageDrawingStatusEnum itemEnum : AiImageDrawingStatusEnum.values()) {
32 if (itemEnum.getStatus().equals(status)) { 32 if (itemEnum.getStatus().equals(status)) {
33 return itemEnum; 33 return itemEnum;
34 } 34 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java
1 package cn.iocoder.yudao.module.ai.controller.admin.image; 1 package cn.iocoder.yudao.module.ai.controller.admin.image;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReqVO;  
5 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingRespVO;  
6 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReqVO; 4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.*;
7 import cn.iocoder.yudao.module.ai.service.AiImageService; 6 import cn.iocoder.yudao.module.ai.service.AiImageService;
8 import io.swagger.v3.oas.annotations.Operation; 7 import io.swagger.v3.oas.annotations.Operation;
9 import io.swagger.v3.oas.annotations.tags.Tag; 8 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -31,6 +30,12 @@ public class AiImageController { @@ -31,6 +30,12 @@ public class AiImageController {
31 30
32 private final AiImageService aiImageService; 31 private final AiImageService aiImageService;
33 32
  33 + @Operation(summary = "获取image列表", description = "dall3、midjourney")
  34 + @GetMapping("/list")
  35 + public PageResult<AiImageListRespVO> list(@Validated @RequestBody AiImageListReqVO req) {
  36 + return aiImageService.list(req);
  37 + }
  38 +
34 @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!") 39 @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!")
35 @PostMapping("/dallDrawing") 40 @PostMapping("/dallDrawing")
36 public AiImageDallDrawingRespVO dallDrawing(@Validated @RequestBody AiImageDallDrawingReqVO req) { 41 public AiImageDallDrawingRespVO dallDrawing(@Validated @RequestBody AiImageDallDrawingReqVO req) {
@@ -46,13 +51,8 @@ public class AiImageController { @@ -46,13 +51,8 @@ public class AiImageController {
46 51
47 @Operation(summary = "midjourney绘画操作", description = "一般有选择图片、放大、换一批...") 52 @Operation(summary = "midjourney绘画操作", description = "一般有选择图片、放大、换一批...")
48 @PostMapping("/midjourney-operate") 53 @PostMapping("/midjourney-operate")
49 - public CommonResult<Void> midjourneyOperate(@Validated @RequestBody AiImageMidjourneyReqVO req) {  
50 - return success(null);  
51 - }  
52 -  
53 - @Operation(summary = "获取midjourney绘画列表", description = "获取 Midjourney 绘画列表")  
54 - @GetMapping("/get-midjourney-list")  
55 - public CommonResult<Void> getMidjourneyList(@Validated @RequestBody AiImageMidjourneyReqVO req) { 54 + public CommonResult<Void> midjourneyOperate(@Validated @RequestBody AiImageMidjourneyOperateReqVO req) {
  55 + aiImageService.midjourneyOperate(req);
56 return success(null); 56 return success(null);
57 } 57 }
58 58
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageMidjourneyListRespVO.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageListReqVO.java
@@ -13,6 +13,6 @@ import lombok.experimental.Accessors; @@ -13,6 +13,6 @@ import lombok.experimental.Accessors;
13 */ 13 */
14 @Data 14 @Data
15 @Accessors(chain = true) 15 @Accessors(chain = true)
16 -public class AiImageMidjourneyListRespVO extends PageParam { 16 +public class AiImageListReqVO extends PageParam {
17 17
18 } 18 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageMidjourneyListReqVO.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageListRespVO.java
1 package cn.iocoder.yudao.module.ai.controller.admin.image.vo; 1 package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 -import io.swagger.v3.oas.annotations.media.Schema;  
5 import lombok.Data; 4 import lombok.Data;
6 import lombok.experimental.Accessors; 5 import lombok.experimental.Accessors;
7 6
@@ -14,6 +13,6 @@ import lombok.experimental.Accessors; @@ -14,6 +13,6 @@ import lombok.experimental.Accessors;
14 */ 13 */
15 @Data 14 @Data
16 @Accessors(chain = true) 15 @Accessors(chain = true)
17 -public class AiImageMidjourneyListReqVO extends PageParam { 16 +public class AiImageListRespVO extends PageParam {
18 17
19 } 18 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageMidjourneyOperateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +import lombok.experimental.Accessors;
  7 +
  8 +/**
  9 + * midjourney req
  10 + *
  11 + * @author fansili
  12 + * @time 2024/4/28 17:42
  13 + * @since 1.0
  14 + */
  15 +@Data
  16 +@Accessors(chain = true)
  17 +public class AiImageMidjourneyOperateReqVO {
  18 +
  19 +
  20 + @NotNull(message = "图片编号不能为空")
  21 + @Schema(description = "编号")
  22 + private String id;
  23 +
  24 + @NotNull(message = "消息编号不能为空")
  25 + @Schema(description = "消息编号")
  26 + private String messageId;
  27 +
  28 + @NotNull(message = "操作编号不能为空")
  29 + @Schema(description = "操作编号")
  30 + private String operateId;
  31 +}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageMidjourneyOperationsVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
  2 +
  3 +import lombok.Data;
  4 +import lombok.experimental.Accessors;
  5 +
  6 +/**
  7 + * mj 保存 components 记录
  8 + *
  9 + * "components": [
  10 + * {
  11 + * "custom_id": "MJ::JOB::upsample::1::5d32f4e8-8d2f-4bef-82d8-bf517e3c3660",
  12 + * "style": 2,
  13 + * "label": "U1",
  14 + * "type": 2
  15 + * },
  16 + * ]
  17 + *
  18 + * @author fansili
  19 + * @time 2024/5/8 14:44
  20 + * @since 1.0
  21 + */
  22 +@Data
  23 +@Accessors(chain = true)
  24 +public class AiImageMidjourneyOperationsVO {
  25 +
  26 + private String custom_id;
  27 + private String style;
  28 + private String label;
  29 + private String type;
  30 +}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiImageConvert.java
@@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.ai.convert; @@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.ai.convert;
2 2
3 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReqVO; 3 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReqVO;
4 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingRespVO; 4 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingRespVO;
  5 +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageListRespVO;
  6 +import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
5 import org.mapstruct.Mapper; 7 import org.mapstruct.Mapper;
6 import org.mapstruct.factory.Mappers; 8 import org.mapstruct.factory.Mappers;
7 9
  10 +import java.util.List;
  11 +
8 /** 12 /**
9 * ai image convert 13 * ai image convert
10 * 14 *
@@ -24,4 +28,12 @@ public interface AiImageConvert { @@ -24,4 +28,12 @@ public interface AiImageConvert {
24 * @return 28 * @return
25 */ 29 */
26 AiImageDallDrawingRespVO convertAiImageDallDrawingRespVO(AiImageDallDrawingReqVO req); 30 AiImageDallDrawingRespVO convertAiImageDallDrawingRespVO(AiImageDallDrawingReqVO req);
  31 +
  32 + /**
  33 + * 转换 - AiImageListRespVO
  34 + *
  35 + * @param list
  36 + * @return
  37 + */
  38 + List<AiImageListRespVO> convertAiImageListRespVO(List<AiImageDO> list);
27 } 39 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java
@@ -29,20 +29,37 @@ public class AiImageDO extends BaseDO { @@ -29,20 +29,37 @@ public class AiImageDO extends BaseDO {
29 @Schema(description = "提示词") 29 @Schema(description = "提示词")
30 private String prompt; 30 private String prompt;
31 31
32 - @Schema(description = "模型") 32 + @Schema(description = "模型 dall2/dall3、MJ、NIJI")
33 private String modal; 33 private String modal;
34 34
35 @Schema(description = "生成图像的尺寸大小。对于dall-e-2模型,尺寸可为256x256, 512x512, 或 1024x1024。对于dall-e-3模型,尺寸可为1024x1024, 1792x1024, 或 1024x1792。") 35 @Schema(description = "生成图像的尺寸大小。对于dall-e-2模型,尺寸可为256x256, 512x512, 或 1024x1024。对于dall-e-3模型,尺寸可为1024x1024, 1792x1024, 或 1024x1792。")
36 private String size; 36 private String size;
37 37
  38 + @Schema(description = "图片地址(自己服务器)")
  39 + private String imageUrl;
  40 +
38 @Schema(description = "绘画状态:提交、排队、绘画中、绘画完成、绘画失败") 41 @Schema(description = "绘画状态:提交、排队、绘画中、绘画完成、绘画失败")
39 private String drawingStatus; 42 private String drawingStatus;
40 43
41 - @Schema(description = "绘画图片地址") 44 + @Schema(description = "绘画图片地址(绘画好的服务器)")
42 private String drawingImageUrl; 45 private String drawingImageUrl;
43 46
44 @Schema(description = "绘画错误信息") 47 @Schema(description = "绘画错误信息")
45 - private String drawingError; 48 + private String drawingErrorMessage;
  49 +
  50 + // ============ mj 需要字段
  51 +
  52 + @Schema(description = "用户操作的消息编号(MJ返回)")
  53 + private String mjMessageId;
  54 +
  55 + @Schema(description = "用户操作的操作编号(MJ返回)")
  56 + private String mjOperationId;
  57 +
  58 + @Schema(description = "用户操作的操作名字(MJ返回)")
  59 + private String mjOperationName;
  60 +
  61 + @Schema(description = "mj图片生产成功保存的 components json 数组")
  62 + private String mjOperations;
46 63
47 } 64 }
48 65
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiImageService.java
1 package cn.iocoder.yudao.module.ai.service; 1 package cn.iocoder.yudao.module.ai.service;
2 2
3 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReqVO;  
4 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingRespVO;  
5 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReqVO; 3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.*;
  5 +
  6 +import java.util.List;
6 7
7 /** 8 /**
8 * ai 作图 9 * ai 作图
@@ -14,6 +15,14 @@ import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReq @@ -14,6 +15,14 @@ import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReq
14 public interface AiImageService { 15 public interface AiImageService {
15 16
16 /** 17 /**
  18 + * ai绘画 - 列表
  19 + *
  20 + * @param req
  21 + * @return
  22 + */
  23 + PageResult<AiImageListRespVO> list(AiImageListReqVO req);
  24 +
  25 + /**
17 * ai绘画 - dall2/dall3 绘画 26 * ai绘画 - dall2/dall3 绘画
18 * 27 *
19 * @param req 28 * @param req
@@ -27,4 +36,12 @@ public interface AiImageService { @@ -27,4 +36,12 @@ public interface AiImageService {
27 * @return 36 * @return
28 */ 37 */
29 void midjourney(AiImageMidjourneyReqVO req); 38 void midjourney(AiImageMidjourneyReqVO req);
  39 +
  40 + /**
  41 + * midjourney 操作(u1、u2、放大、换一批...)
  42 + *
  43 + * @param req
  44 + */
  45 + void midjourneyOperate(AiImageMidjourneyOperateReqVO req);
  46 +
30 } 47 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiImageServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.impl; 1 package cn.iocoder.yudao.module.ai.service.impl;
2 2
  3 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.framework.ai.exception.AiException; 4 import cn.iocoder.yudao.framework.ai.exception.AiException;
4 import cn.iocoder.yudao.framework.ai.image.ImageGeneration; 5 import cn.iocoder.yudao.framework.ai.image.ImageGeneration;
5 import cn.iocoder.yudao.framework.ai.image.ImagePrompt; 6 import cn.iocoder.yudao.framework.ai.image.ImagePrompt;
@@ -9,18 +10,20 @@ import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions; @@ -9,18 +10,20 @@ import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions;
9 import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum; 10 import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum;
10 import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum; 11 import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum;
11 import cn.iocoder.yudao.framework.ai.midjourney.api.MidjourneyInteractionsApi; 12 import cn.iocoder.yudao.framework.ai.midjourney.api.MidjourneyInteractionsApi;
  13 +import cn.iocoder.yudao.framework.ai.midjourney.api.req.ReRollReq;
12 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyWebSocketStarter; 14 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyWebSocketStarter;
13 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.WssNotify; 15 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.WssNotify;
14 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 16 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
  17 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  18 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  19 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
15 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; 20 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
16 import cn.iocoder.yudao.module.ai.ErrorCodeConstants; 21 import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
17 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReqVO;  
18 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingRespVO;  
19 -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReqVO; 22 +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.*;
20 import cn.iocoder.yudao.module.ai.convert.AiImageConvert; 23 import cn.iocoder.yudao.module.ai.convert.AiImageConvert;
21 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; 24 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
22 import cn.iocoder.yudao.module.ai.dal.mysql.AiImageMapper; 25 import cn.iocoder.yudao.module.ai.dal.mysql.AiImageMapper;
23 -import cn.iocoder.yudao.module.ai.enums.AiChatDrawingStatusEnum; 26 +import cn.iocoder.yudao.module.ai.enums.AiImageDrawingStatusEnum;
24 import cn.iocoder.yudao.module.ai.service.AiImageService; 27 import cn.iocoder.yudao.module.ai.service.AiImageService;
25 import jakarta.annotation.PostConstruct; 28 import jakarta.annotation.PostConstruct;
26 import lombok.AllArgsConstructor; 29 import lombok.AllArgsConstructor;
@@ -28,6 +31,9 @@ import lombok.extern.slf4j.Slf4j; @@ -28,6 +31,9 @@ import lombok.extern.slf4j.Slf4j;
28 import org.springframework.stereotype.Service; 31 import org.springframework.stereotype.Service;
29 import org.springframework.transaction.annotation.Transactional; 32 import org.springframework.transaction.annotation.Transactional;
30 33
  34 +import java.util.Collections;
  35 +import java.util.List;
  36 +
31 /** 37 /**
32 * ai 作图 38 * ai 作图
33 * 39 *
@@ -62,6 +68,23 @@ public class AiImageServiceImpl implements AiImageService { @@ -62,6 +68,23 @@ public class AiImageServiceImpl implements AiImageService {
62 } 68 }
63 69
64 @Override 70 @Override
  71 + public PageResult<AiImageListRespVO> list(AiImageListReqVO req) {
  72 + // 获取登录用户
  73 + Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
  74 + // 查询当前用户下所有的绘画记录
  75 + PageResult<AiImageDO> pageResult = aiImageMapper.selectPage(req,
  76 + new LambdaQueryWrapperX<AiImageDO>()
  77 + .eq(AiImageDO::getUserId, loginUserId)
  78 + .orderByDesc(AiImageDO::getId)
  79 + );
  80 + // 转换 PageResult<AiImageListRespVO> 返回
  81 + PageResult<AiImageListRespVO> result = new PageResult<>();
  82 + result.setTotal(pageResult.getTotal());
  83 + result.setList(AiImageConvert.INSTANCE.convertAiImageListRespVO(pageResult.getList()));
  84 + return result;
  85 + }
  86 +
  87 + @Override
65 public AiImageDallDrawingRespVO dallDrawing(AiImageDallDrawingReqVO req) { 88 public AiImageDallDrawingRespVO dallDrawing(AiImageDallDrawingReqVO req) {
66 // 获取 model 89 // 获取 model
67 OpenAiImageModelEnum openAiImageModelEnum = OpenAiImageModelEnum.valueOfModel(req.getModal()); 90 OpenAiImageModelEnum openAiImageModelEnum = OpenAiImageModelEnum.valueOfModel(req.getModal());
@@ -79,7 +102,8 @@ public class AiImageServiceImpl implements AiImageService { @@ -79,7 +102,8 @@ public class AiImageServiceImpl implements AiImageService {
79 ImageGeneration imageGeneration = imageResponse.getResult(); 102 ImageGeneration imageGeneration = imageResponse.getResult();
80 // 保存数据库 103 // 保存数据库
81 doSave(req.getPrompt(), req.getSize(), req.getModal(), 104 doSave(req.getPrompt(), req.getSize(), req.getModal(),
82 - imageGeneration.getOutput().getUrl(), AiChatDrawingStatusEnum.COMPLETE, null); 105 + imageGeneration.getOutput().getUrl(), AiImageDrawingStatusEnum.COMPLETE, null,
  106 + null, null, null);
83 // 返回 flex 107 // 返回 flex
84 respVO.setUrl(imageGeneration.getOutput().getUrl()); 108 respVO.setUrl(imageGeneration.getOutput().getUrl());
85 respVO.setBase64(imageGeneration.getOutput().getB64Json()); 109 respVO.setBase64(imageGeneration.getOutput().getB64Json());
@@ -87,7 +111,8 @@ public class AiImageServiceImpl implements AiImageService { @@ -87,7 +111,8 @@ public class AiImageServiceImpl implements AiImageService {
87 } catch (AiException aiException) { 111 } catch (AiException aiException) {
88 // 保存数据库 112 // 保存数据库
89 doSave(req.getPrompt(), req.getSize(), req.getModal(), 113 doSave(req.getPrompt(), req.getSize(), req.getModal(),
90 - null, AiChatDrawingStatusEnum.FAIL, aiException.getMessage()); 114 + null, AiImageDrawingStatusEnum.FAIL, aiException.getMessage(),
  115 + null, null, null);
91 // 发送错误信息 116 // 发送错误信息
92 respVO.setErrorMessage(aiException.getMessage()); 117 respVO.setErrorMessage(aiException.getMessage());
93 return respVO; 118 return respVO;
@@ -99,7 +124,8 @@ public class AiImageServiceImpl implements AiImageService { @@ -99,7 +124,8 @@ public class AiImageServiceImpl implements AiImageService {
99 public void midjourney(AiImageMidjourneyReqVO req) { 124 public void midjourney(AiImageMidjourneyReqVO req) {
100 // 保存数据库 125 // 保存数据库
101 AiImageDO aiImageDO = doSave(req.getPrompt(), null, "midjoureny", 126 AiImageDO aiImageDO = doSave(req.getPrompt(), null, "midjoureny",
102 - null, AiChatDrawingStatusEnum.SUBMIT, null); 127 + null, AiImageDrawingStatusEnum.SUBMIT, null,
  128 + null, null, null);
103 // 提交 midjourney 任务 129 // 提交 midjourney 任务
104 Boolean imagine = midjourneyInteractionsApi.imagine(aiImageDO.getId(), req.getPrompt()); 130 Boolean imagine = midjourneyInteractionsApi.imagine(aiImageDO.getId(), req.getPrompt());
105 if (!imagine) { 131 if (!imagine) {
@@ -107,23 +133,71 @@ public class AiImageServiceImpl implements AiImageService { @@ -107,23 +133,71 @@ public class AiImageServiceImpl implements AiImageService {
107 } 133 }
108 } 134 }
109 135
110 -// private static void sendSseEmitter(Utf8SseEmitter sseEmitter, Object object) {  
111 -// try {  
112 -// sseEmitter.send(object, MediaType.APPLICATION_JSON);  
113 -// } catch (IOException e) {  
114 -// throw new RuntimeException(e);  
115 -// } finally {  
116 -// // 发送 complete  
117 -// sseEmitter.complete();  
118 -// }  
119 -// } 136 + @Transactional(rollbackFor = Exception.class)
  137 + @Override
  138 + public void midjourneyOperate(AiImageMidjourneyOperateReqVO req) {
  139 + // 校验是否存在
  140 + AiImageDO aiImageDO = validateExists(req);
  141 + // 获取 midjourneyOperations
  142 + List<AiImageMidjourneyOperationsVO> midjourneyOperations = getMidjourneyOperations(aiImageDO);
  143 + // 校验 OperateId 是否存在
  144 + AiImageMidjourneyOperationsVO midjourneyOperationsVO = validateMidjourneyOperationsExists(midjourneyOperations, req.getOperateId());
  145 + // 校验 messageId
  146 + validateMessageId(aiImageDO.getMjMessageId(), req.getMessageId());
  147 + // 获取 mjOperationName
  148 + String mjOperationName = midjourneyOperationsVO.getLabel();
  149 + // 保存一个 image 任务记录
  150 + doSave(aiImageDO.getPrompt(), aiImageDO.getSize(), aiImageDO.getModal(),
  151 + null, AiImageDrawingStatusEnum.SUBMIT, null,
  152 + req.getMessageId(), req.getOperateId(), mjOperationName);
  153 + // 提交操作
  154 + midjourneyInteractionsApi.reRoll(
  155 + new ReRollReq()
  156 + .setCustomId(req.getOperateId())
  157 + .setMessageId(req.getMessageId())
  158 + );
  159 + }
  160 +
  161 + private void validateMessageId(String mjMessageId, String messageId) {
  162 + if (!mjMessageId.equals(messageId)) {
  163 + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MIDJOURNEY_MESSAGE_ID_INCORRECT);
  164 + }
  165 + }
  166 +
  167 + private AiImageMidjourneyOperationsVO validateMidjourneyOperationsExists(List<AiImageMidjourneyOperationsVO> midjourneyOperations, String operateId) {
  168 + for (AiImageMidjourneyOperationsVO midjourneyOperation : midjourneyOperations) {
  169 + if (midjourneyOperation.getCustom_id().equals(operateId)) {
  170 + return midjourneyOperation;
  171 + }
  172 + }
  173 + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MIDJOURNEY_OPERATION_NOT_EXISTS);
  174 + }
  175 +
  176 +
  177 + private List<AiImageMidjourneyOperationsVO> getMidjourneyOperations(AiImageDO aiImageDO) {
  178 + if (StrUtil.isBlank(aiImageDO.getMjOperations())) {
  179 + return Collections.emptyList();
  180 + }
  181 + return JsonUtils.parseArray(aiImageDO.getMjOperations(), AiImageMidjourneyOperationsVO.class);
  182 + }
  183 +
  184 + private AiImageDO validateExists(AiImageMidjourneyOperateReqVO req) {
  185 + AiImageDO aiImageDO = aiImageMapper.selectById(req.getId());
  186 + if (aiImageDO == null) {
  187 + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MIDJOURNEY_IMAGINE_FAIL);
  188 + }
  189 + return aiImageDO;
  190 + }
120 191
121 private AiImageDO doSave(String prompt, 192 private AiImageDO doSave(String prompt,
122 - String size,  
123 - String model,  
124 - String imageUrl,  
125 - AiChatDrawingStatusEnum drawingStatusEnum,  
126 - String drawingError) { 193 + String size,
  194 + String model,
  195 + String drawingImageUrl,
  196 + AiImageDrawingStatusEnum drawingStatusEnum,
  197 + String drawingErrorMessage,
  198 + String mjMessageId,
  199 + String mjOperationId,
  200 + String mjOperationName) {
127 // 保存数据库 201 // 保存数据库
128 Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); 202 Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
129 AiImageDO aiImageDO = new AiImageDO(); 203 AiImageDO aiImageDO = new AiImageDO();
@@ -132,9 +206,15 @@ public class AiImageServiceImpl implements AiImageService { @@ -132,9 +206,15 @@ public class AiImageServiceImpl implements AiImageService {
132 aiImageDO.setSize(size); 206 aiImageDO.setSize(size);
133 aiImageDO.setModal(model); 207 aiImageDO.setModal(model);
134 aiImageDO.setUserId(loginUserId); 208 aiImageDO.setUserId(loginUserId);
135 - aiImageDO.setDrawingImageUrl(imageUrl); 209 + // TODO @芋艿 如何上传到自己服务器
  210 + aiImageDO.setImageUrl(null);
136 aiImageDO.setDrawingStatus(drawingStatusEnum.getStatus()); 211 aiImageDO.setDrawingStatus(drawingStatusEnum.getStatus());
137 - aiImageDO.setDrawingError(drawingError); 212 + aiImageDO.setDrawingImageUrl(drawingImageUrl);
  213 + aiImageDO.setDrawingErrorMessage(drawingErrorMessage);
  214 + //
  215 + aiImageDO.setMjMessageId(mjMessageId);
  216 + aiImageDO.setMjOperationId(mjOperationId);
  217 + aiImageDO.setMjOperationName(mjOperationName);
138 aiImageMapper.insert(aiImageDO); 218 aiImageMapper.insert(aiImageDO);
139 return aiImageDO; 219 return aiImageDO;
140 } 220 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/midjourneyHandler/YuDaoMidjourneyMessageHandler.java
@@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyMessage; @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyMessage;
6 import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyGennerateStatusEnum; 6 import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyGennerateStatusEnum;
7 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyMessageHandler; 7 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyMessageHandler;
8 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; 8 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
9 -import cn.iocoder.yudao.module.ai.enums.AiChatDrawingStatusEnum; 9 +import cn.iocoder.yudao.module.ai.enums.AiImageDrawingStatusEnum;
10 import cn.iocoder.yudao.module.ai.dal.mysql.AiImageMapper; 10 import cn.iocoder.yudao.module.ai.dal.mysql.AiImageMapper;
11 import com.alibaba.fastjson2.JSON; 11 import com.alibaba.fastjson2.JSON;
12 import lombok.AllArgsConstructor; 12 import lombok.AllArgsConstructor;
@@ -53,14 +53,14 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler { @@ -53,14 +53,14 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler {
53 imageUrl = midjourneyMessage.getAttachments().get(0).getUrl(); 53 imageUrl = midjourneyMessage.getAttachments().get(0).getUrl();
54 } 54 }
55 // 转换状态 55 // 转换状态
56 - AiChatDrawingStatusEnum drawingStatusEnum = null; 56 + AiImageDrawingStatusEnum drawingStatusEnum = null;
57 String generateStatus = midjourneyMessage.getGenerateStatus(); 57 String generateStatus = midjourneyMessage.getGenerateStatus();
58 if (MidjourneyGennerateStatusEnum.COMPLETED.getStatus().equals(generateStatus)) { 58 if (MidjourneyGennerateStatusEnum.COMPLETED.getStatus().equals(generateStatus)) {
59 - drawingStatusEnum = AiChatDrawingStatusEnum.COMPLETE; 59 + drawingStatusEnum = AiImageDrawingStatusEnum.COMPLETE;
60 } else if (MidjourneyGennerateStatusEnum.IN_PROGRESS.getStatus().equals(generateStatus)) { 60 } else if (MidjourneyGennerateStatusEnum.IN_PROGRESS.getStatus().equals(generateStatus)) {
61 - drawingStatusEnum = AiChatDrawingStatusEnum.IN_PROGRESS; 61 + drawingStatusEnum = AiImageDrawingStatusEnum.IN_PROGRESS;
62 } else if (MidjourneyGennerateStatusEnum.WAITING.getStatus().equals(generateStatus)) { 62 } else if (MidjourneyGennerateStatusEnum.WAITING.getStatus().equals(generateStatus)) {
63 - drawingStatusEnum = AiChatDrawingStatusEnum.WAITING; 63 + drawingStatusEnum = AiImageDrawingStatusEnum.WAITING;
64 } 64 }
65 aiImageMapper.updateById( 65 aiImageMapper.updateById(
66 new AiImageDO() 66 new AiImageDO()