Commit e8cf40a82a0db2b136fd481971b719415442dfd3
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() |