Commit 6856f5f192d4c726a67ef3b45c9e744a49c735ae
1 parent
05635031
【新增】AI:进一步统一 DALL、SD 的绘制实现
Showing
34 changed files
with
220 additions
and
587 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/AiCommonConstants.java deleted
| 1 | -package cn.iocoder.yudao.module.ai; | ||
| 2 | - | ||
| 3 | -/** | ||
| 4 | - * ai 常用的常量 | ||
| 5 | - * | ||
| 6 | - * @author fansili | ||
| 7 | - * @time 2024/5/7 09:29 | ||
| 8 | - * @since 1.0 | ||
| 9 | - */ | ||
| 10 | -public class AiCommonConstants { | ||
| 11 | - | ||
| 12 | - /** | ||
| 13 | - * 绘画 request - style | ||
| 14 | - */ | ||
| 15 | - public static final String DRAW_REQ_KEY_STYLE = "style"; | ||
| 16 | - /** | ||
| 17 | - * dall size - 模板(1024x1024) | ||
| 18 | - */ | ||
| 19 | - public static final String DALL_SIZE_TEMPLATE = "%sx%s"; | ||
| 20 | - | ||
| 21 | -} |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/api/package-info.java
0 → 100644
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatConversationTypeEnum.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.enums; | ||
| 2 | - | ||
| 3 | -import lombok.AllArgsConstructor; | ||
| 4 | -import lombok.Getter; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * 对话类型 | ||
| 8 | - * 创建对话、继续对话 | ||
| 9 | - * | ||
| 10 | - * @author fansili | ||
| 11 | - * @time 2024/4/14 18:15 | ||
| 12 | - * @since 1.0 | ||
| 13 | - */ | ||
| 14 | -@AllArgsConstructor | ||
| 15 | -@Getter | ||
| 16 | -public enum AiChatConversationTypeEnum { | ||
| 17 | - | ||
| 18 | - // roleChat、userChat | ||
| 19 | - ROLE_CHAT("roleChat", "角色对话"), | ||
| 20 | - USER_CHAT("userChat", "用户对话"), | ||
| 21 | - | ||
| 22 | - ; | ||
| 23 | - | ||
| 24 | - private String type; | ||
| 25 | - | ||
| 26 | - private String name; | ||
| 27 | - | ||
| 28 | - public static AiChatConversationTypeEnum valueOfType(String type) { | ||
| 29 | - for (AiChatConversationTypeEnum itemEnum : AiChatConversationTypeEnum.values()) { | ||
| 30 | - if (itemEnum.getType().equals(type)) { | ||
| 31 | - return itemEnum; | ||
| 32 | - } | ||
| 33 | - } | ||
| 34 | - throw new IllegalArgumentException("Invalid MessageType value: " + type); | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | -} |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatRoleCategoryEnum.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.enums; | ||
| 2 | - | ||
| 3 | -import lombok.AllArgsConstructor; | ||
| 4 | -import lombok.Getter; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * 聊天role 分类 | ||
| 8 | - * | ||
| 9 | - * @author fansili | ||
| 10 | - * @time 2024/4/24 16:41 | ||
| 11 | - * @since 1.0 | ||
| 12 | - */ | ||
| 13 | -@AllArgsConstructor | ||
| 14 | -@Getter | ||
| 15 | -public enum AiChatRoleCategoryEnum { | ||
| 16 | - | ||
| 17 | - WRITING("writing", "写作"), | ||
| 18 | - | ||
| 19 | - ENTERTAINMENT("entertainment", "娱乐"), | ||
| 20 | - | ||
| 21 | - ; | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - private String category; | ||
| 25 | - | ||
| 26 | - private String name; | ||
| 27 | - | ||
| 28 | - | ||
| 29 | - public static AiChatRoleCategoryEnum valueOfCategory(String category) { | ||
| 30 | - for (AiChatRoleCategoryEnum itemEnum : AiChatRoleCategoryEnum.values()) { | ||
| 31 | - if (itemEnum.getCategory().equals(category)) { | ||
| 32 | - return itemEnum; | ||
| 33 | - } | ||
| 34 | - } | ||
| 35 | - throw new IllegalArgumentException("Invalid MessageType value: " + category); | ||
| 36 | - } | ||
| 37 | -} |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiImagePublicStatusEnum.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.enums; | ||
| 2 | - | ||
| 3 | -import lombok.AllArgsConstructor; | ||
| 4 | -import lombok.Getter; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * ai绘画 public 状态 | ||
| 8 | - * | ||
| 9 | - * @author fansili | ||
| 10 | - * @time 2024/4/28 17:05 | ||
| 11 | - * @since 1.0 | ||
| 12 | - */ | ||
| 13 | -@AllArgsConstructor | ||
| 14 | -@Getter | ||
| 15 | -public enum AiImagePublicStatusEnum { | ||
| 16 | - | ||
| 17 | - PRIVATE("private", "私有"), | ||
| 18 | - PUBLIC("public", "公开"), | ||
| 19 | - | ||
| 20 | - ; | ||
| 21 | - | ||
| 22 | - // TODO @fan:final 一下 | ||
| 23 | - private final String status; | ||
| 24 | - | ||
| 25 | - private final String name; | ||
| 26 | - | ||
| 27 | - | ||
| 28 | - public static AiImagePublicStatusEnum valueOfStatus(String status) { | ||
| 29 | - for (AiImagePublicStatusEnum itemEnum : AiImagePublicStatusEnum.values()) { | ||
| 30 | - if (itemEnum.getStatus().equals(status)) { | ||
| 31 | - return itemEnum; | ||
| 32 | - } | ||
| 33 | - } | ||
| 34 | - throw new IllegalArgumentException("Invalid MessageType value: " + status); | ||
| 35 | - } | ||
| 36 | -} |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java renamed to yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiImageStatusEnum.java renamed to yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/image/AiImageStatusEnum.java
| 1 | -package cn.iocoder.yudao.module.ai.enums; | 1 | +package cn.iocoder.yudao.module.ai.enums.image; |
| 2 | 2 | ||
| 3 | import lombok.AllArgsConstructor; | 3 | import lombok.AllArgsConstructor; |
| 4 | import lombok.Getter; | 4 | import lombok.Getter; |
| @@ -13,7 +13,7 @@ import lombok.Getter; | @@ -13,7 +13,7 @@ import lombok.Getter; | ||
| 13 | public enum AiImageStatusEnum { | 13 | public enum AiImageStatusEnum { |
| 14 | 14 | ||
| 15 | IN_PROGRESS("10", "进行中"), | 15 | IN_PROGRESS("10", "进行中"), |
| 16 | - COMPLETE("20", "完成"), | 16 | + SUCCESS("20", "完成"), |
| 17 | FAIL("30", "失败"); | 17 | FAIL("30", "失败"); |
| 18 | 18 | ||
| 19 | /** | 19 | /** |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiModelEnum.java renamed to yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiModelEnum.java
yudao-module-ai/yudao-module-ai-biz/src/main/resources/http/image.http renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.http
| 1 | 1 | ||
| 2 | -### chat dallDrawing | ||
| 3 | - | ||
| 4 | -POST {{baseUrl}}/admin-api/ai/image/dallDrawing | 2 | +### 生成图片:OpenAI(DALL) |
| 3 | +POST {{baseUrl}}/ai/image/draw | ||
| 5 | Content-Type: application/json | 4 | Content-Type: application/json |
| 6 | Authorization: {{token}} | 5 | Authorization: {{token}} |
| 7 | 6 | ||
| 8 | { | 7 | { |
| 9 | - "modal": "dall-e-3", | ||
| 10 | - "size": "1024x1024", | ||
| 11 | - "style": "vivid", | ||
| 12 | - "prompt": "中国长城" | 8 | + "platform": "OpenAI", |
| 9 | + "prompt": "可爱的小喵星人", | ||
| 10 | + "model": "dall-e-3", | ||
| 11 | + "height": "1024", | ||
| 12 | + "width": "1024", | ||
| 13 | + "options": { | ||
| 14 | + "style": "vivid" | ||
| 15 | + } | ||
| 13 | } | 16 | } |
| 14 | 17 | ||
| 18 | +### 生成图片:StableDiffusion | ||
| 19 | +POST {{baseUrl}}/ai/image/draw | ||
| 20 | +Content-Type: application/json | ||
| 21 | +Authorization: {{token}} | ||
| 22 | + | ||
| 23 | +{ | ||
| 24 | + "platform": "StableDiffusion", | ||
| 25 | + "prompt": "中国长城", | ||
| 26 | + "model": "stable-diffusion-v1-6", | ||
| 27 | + "height": "1024", | ||
| 28 | + "width": "1024", | ||
| 29 | + "style": "vivid" | ||
| 30 | +} | ||
| 15 | 31 | ||
| 16 | ### chat midjourney | 32 | ### chat midjourney |
| 17 | 33 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java
| @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; | @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 8 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO; | 8 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO; |
| 9 | -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallReqVO; | 9 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO; |
| 10 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO; | 10 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO; |
| 11 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageRespVO; | 11 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageRespVO; |
| 12 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | 12 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; |
| @@ -48,13 +48,10 @@ public class AiImageController { | @@ -48,13 +48,10 @@ public class AiImageController { | ||
| 48 | return success(BeanUtils.toBean(image, AiImageRespVO.class)); | 48 | return success(BeanUtils.toBean(image, AiImageRespVO.class)); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | - // TODO @fan:建议把 dallDrawing、midjourney 融合成一个 draw 接口,异步绘制;然后返回一个 id 给前端;前端通过 get 接口轮询,直到获取到生成成功 | ||
| 52 | - // TODO @芋艿: 参数差异较大 | ||
| 53 | - // TODO @fan:直接参数平铺?写好注释,要么? | ||
| 54 | - @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!") | ||
| 55 | - @PostMapping("/dall") | ||
| 56 | - public CommonResult<Long> dall(@Validated @RequestBody AiImageDallReqVO req) { | ||
| 57 | - return success(imageService.dall(getLoginUserId(), req)); | 51 | + @Operation(summary = "生成图片") |
| 52 | + @PostMapping("/draw") | ||
| 53 | + public CommonResult<Long> drawImage(@Validated @RequestBody AiImageDrawReqVO drawReqVO) { | ||
| 54 | + return success(imageService.drawImage(getLoginUserId(), drawReqVO)); | ||
| 58 | } | 55 | } |
| 59 | 56 | ||
| 60 | @Operation(summary = "删除【我的】绘画记录") | 57 | @Operation(summary = "删除【我的】绘画记录") |
| @@ -73,11 +70,11 @@ public class AiImageController { | @@ -73,11 +70,11 @@ public class AiImageController { | ||
| 73 | return success(imageService.midjourneyImagine(getLoginUserId(), req)); | 70 | return success(imageService.midjourneyImagine(getLoginUserId(), req)); |
| 74 | } | 71 | } |
| 75 | 72 | ||
| 76 | - // TODO @fan:可以考虑,复用 AiImageDallRespVO,统一成 AIImageRespVO | 73 | + // TODO @芋艿:不拦截 |
| 77 | @Operation(summary = "midjourney proxy - 回调通知") | 74 | @Operation(summary = "midjourney proxy - 回调通知") |
| 78 | @RequestMapping("/midjourney-notify") | 75 | @RequestMapping("/midjourney-notify") |
| 79 | public CommonResult<Boolean> midjourneyNotify(MidjourneyNotifyReqVO notifyReqVO) { | 76 | public CommonResult<Boolean> midjourneyNotify(MidjourneyNotifyReqVO notifyReqVO) { |
| 80 | return success(imageService.midjourneyNotify(getLoginUserId(), notifyReqVO)); | 77 | return success(imageService.midjourneyNotify(getLoginUserId(), notifyReqVO)); |
| 81 | } | 78 | } |
| 82 | 79 | ||
| 83 | -} | 80 | -} |
| 81 | +} | ||
| 84 | \ No newline at end of file | 82 | \ No newline at end of file |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageDallReqVO.java deleted
| 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 jakarta.validation.constraints.Size; | ||
| 6 | -import lombok.Data; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * dall2/dall2 绘画 | ||
| 10 | - * | ||
| 11 | - * @author fansili | ||
| 12 | - * @time 2024/4/25 16:24 | ||
| 13 | - * @since 1.0 | ||
| 14 | - */ | ||
| 15 | -@Data | ||
| 16 | -public class AiImageDallReqVO { | ||
| 17 | - | ||
| 18 | - @Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 19 | - private String platform; // 参见 AiPlatformEnum 枚举 | ||
| 20 | - | ||
| 21 | - @Schema(description = "提示词") | ||
| 22 | - @NotNull(message = "提示词不能为空!") | ||
| 23 | - @Size(max = 1200, message = "提示词最大1200") | ||
| 24 | - private String prompt; | ||
| 25 | - | ||
| 26 | - @Schema(description = "模型(dall2、dall3)") | ||
| 27 | - @NotNull(message = "模型不能为空") | ||
| 28 | - private String model; | ||
| 29 | - | ||
| 30 | - @Schema(description = "图像生成的风格。可为vivid(生动)或natural(自然)") | ||
| 31 | - private String style; | ||
| 32 | - | ||
| 33 | - @Schema(description = "图片高度。对于dall-e-2模型,尺寸可为256x256, 512x512, 或 1024x1024。对于dall-e-3模型,尺寸可为1024x1024, 1792x1024, 或 1024x1792。") | ||
| 34 | - @NotNull(message = "图片高度不能为空!") | ||
| 35 | - private Integer height; | ||
| 36 | - | ||
| 37 | - @Schema(description = "图片宽度。对于dall-e-2模型,尺寸可为256x256, 512x512, 或 1024x1024。对于dall-e-3模型,尺寸可为1024x1024, 1792x1024, 或 1024x1792。") | ||
| 38 | - @NotNull(message = "图片宽度不能为空!") | ||
| 39 | - private Integer width; | ||
| 40 | - | ||
| 41 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageDrawReqVO.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.NotEmpty; | ||
| 5 | +import jakarta.validation.constraints.NotNull; | ||
| 6 | +import jakarta.validation.constraints.Size; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import org.springframework.ai.openai.OpenAiImageOptions; | ||
| 9 | +import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; | ||
| 10 | + | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | +@Schema(description = "管理后台 - 绘画 Request VO") | ||
| 14 | +@Data | ||
| 15 | +public class AiImageDrawReqVO { | ||
| 16 | + | ||
| 17 | + @Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI") | ||
| 18 | + private String platform; // 参见 AiPlatformEnum 枚举 | ||
| 19 | + | ||
| 20 | + @Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "画一个长城") | ||
| 21 | + @NotEmpty(message = "提示词不能为空") | ||
| 22 | + @Size(max = 1200, message = "提示词最大 1200") | ||
| 23 | + private String prompt; | ||
| 24 | + | ||
| 25 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "stable-diffusion-v1-6") | ||
| 26 | + @NotEmpty(message = "模型不能为空") | ||
| 27 | + private String model; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 1. dall-e-2 模型:256x256、512x512、1024x1024 | ||
| 31 | + * 2. dall-e-3 模型:1024x1024, 1792x1024, 或 1024x1792 | ||
| 32 | + */ | ||
| 33 | + @Schema(description = "图片高度") | ||
| 34 | + @NotNull(message = "图片高度不能为空") | ||
| 35 | + private Integer height; | ||
| 36 | + | ||
| 37 | + @Schema(description = "图片宽度") | ||
| 38 | + @NotNull(message = "图片宽度不能为空") | ||
| 39 | + private Integer width; | ||
| 40 | + | ||
| 41 | + // ========== 各平台绘画的拓展参数 ========== | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 绘制参数,不同 platform 的不同参数 | ||
| 45 | + * | ||
| 46 | + * 1. {@link OpenAiImageOptions} | ||
| 47 | + * 2. {@link StabilityAiImageOptions} | ||
| 48 | + */ | ||
| 49 | + @Schema(description = "绘制参数") | ||
| 50 | + private Map<String, String> options; | ||
| 51 | + | ||
| 52 | +} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImageMidjourneyOperateReqVO.java deleted
| 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 Long 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/AiImageRespVO.java
| @@ -5,63 +5,44 @@ import lombok.Data; | @@ -5,63 +5,44 @@ import lombok.Data; | ||
| 5 | 5 | ||
| 6 | import java.util.Map; | 6 | import java.util.Map; |
| 7 | 7 | ||
| 8 | -// TODO @芋艿:完善 swagger 注解 | 8 | +@Schema(description = "管理后台 - 绘画 Response VO") |
| 9 | @Data | 9 | @Data |
| 10 | public class AiImageRespVO { | 10 | public class AiImageRespVO { |
| 11 | 11 | ||
| 12 | - @Schema(description = "id编号", example = "1") | 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 13 | private Long id; | 13 | private Long id; |
| 14 | 14 | ||
| 15 | - @Schema(description = "用户id", example = "1") | 15 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 16 | private Long userId; | 16 | private Long userId; |
| 17 | 17 | ||
| 18 | - @Schema(description = "提示词", example = "南极的小企鹅") | ||
| 19 | - private String prompt; | ||
| 20 | - | ||
| 21 | - @Schema(description = "平台", example = "openai") | ||
| 22 | - private String platform; | 18 | + @Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI") |
| 19 | + private String platform; // 参见 AiPlatformEnum 枚举 | ||
| 23 | 20 | ||
| 24 | - @Schema(description = "模型", example = "dall2") | 21 | + @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "stable-diffusion-v1-6") |
| 25 | private String model; | 22 | private String model; |
| 26 | 23 | ||
| 27 | - @Schema(description = "图片宽度", example = "1024") | ||
| 28 | - private String width; | 24 | + @Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "南极的小企鹅") |
| 25 | + private String prompt; | ||
| 29 | 26 | ||
| 30 | - @Schema(description = "图片高度", example = "1024") | ||
| 31 | - private String height; | 27 | + @Schema(description = "图片宽度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| 28 | + private Integer width; | ||
| 32 | 29 | ||
| 33 | - @Schema(description = "绘画状态:10 进行中、20 绘画完成、30 绘画失败", example = "10") | ||
| 34 | - private String status; | 30 | + @Schema(description = "图片高度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| 31 | + private Integer height; | ||
| 35 | 32 | ||
| 36 | - @Schema(description = "是否发布", example = "public") | ||
| 37 | - private String publicStatus; | 33 | + @Schema(description = "绘画状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
| 34 | + private Integer status; | ||
| 38 | 35 | ||
| 39 | - @Schema(description = "图片地址(自己服务器)", example = "http://") | ||
| 40 | - private String picUrl; | 36 | + @Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "public") |
| 37 | + private Boolean publicStatus; | ||
| 41 | 38 | ||
| 42 | - @Schema(description = "绘画图片地址(绘画好的服务器)", example = "http://") | ||
| 43 | - private String originalPicUrl; | 39 | + @Schema(description = "图片地址", example = "https://www.iocoder.cn/1.png") |
| 40 | + private String picUrl; | ||
| 44 | 41 | ||
| 45 | @Schema(description = "绘画错误信息", example = "图片错误信息") | 42 | @Schema(description = "绘画错误信息", example = "图片错误信息") |
| 46 | private String errorMessage; | 43 | private String errorMessage; |
| 47 | 44 | ||
| 48 | - // ============ 绘画请求参数 | ||
| 49 | - | ||
| 50 | - // todo @fan:下面的 style、mjNonceId 直接就不用注释啦,直接去看 DO 完事哈 | ||
| 51 | - | ||
| 52 | - /** | ||
| 53 | - * - style | ||
| 54 | - */ | ||
| 55 | - @Schema(description = "绘画请求参数") | ||
| 56 | - private Map<String, Object> drawRequest; | ||
| 57 | - | ||
| 58 | - /** | ||
| 59 | - * - mjNonceId | ||
| 60 | - * - mjOperationId | ||
| 61 | - * - mjOperationName | ||
| 62 | - * - mjOperations | ||
| 63 | - */ | ||
| 64 | - @Schema(description = "绘画请求响应参数") | ||
| 65 | - private Map<String, Object> drawResponse; | 45 | + @Schema(description = "绘制参数") |
| 46 | + private Map<String, String> options; | ||
| 66 | 47 | ||
| 67 | } | 48 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java
| @@ -3,14 +3,13 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.chat; | @@ -3,14 +3,13 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.chat; | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | 4 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; |
| 5 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | 5 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 6 | -import cn.iocoder.yudao.module.ai.enums.AiModelEnum; | 6 | +import cn.iocoder.yudao.module.ai.enums.model.AiModelEnum; |
| 7 | import com.baomidou.mybatisplus.annotation.KeySequence; | 7 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 8 | import com.baomidou.mybatisplus.annotation.TableId; | 8 | import com.baomidou.mybatisplus.annotation.TableId; |
| 9 | import com.baomidou.mybatisplus.annotation.TableName; | 9 | import com.baomidou.mybatisplus.annotation.TableName; |
| 10 | import lombok.*; | 10 | import lombok.*; |
| 11 | 11 | ||
| 12 | import java.time.LocalDateTime; | 12 | import java.time.LocalDateTime; |
| 13 | -import java.util.Date; | ||
| 14 | 13 | ||
| 15 | /** | 14 | /** |
| 16 | * AI Chat 对话 DO | 15 | * AI Chat 对话 DO |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java
| @@ -5,7 +5,7 @@ import org.springframework.ai.chat.messages.MessageType; | @@ -5,7 +5,7 @@ import org.springframework.ai.chat.messages.MessageType; | ||
| 5 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 5 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 6 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | 6 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; |
| 7 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | 7 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 8 | -import cn.iocoder.yudao.module.ai.enums.AiModelEnum; | 8 | +import cn.iocoder.yudao.module.ai.enums.model.AiModelEnum; |
| 9 | import com.baomidou.mybatisplus.annotation.KeySequence; | 9 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 10 | import com.baomidou.mybatisplus.annotation.TableName; | 10 | import com.baomidou.mybatisplus.annotation.TableName; |
| 11 | import lombok.*; | 11 | import lombok.*; |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java
| 1 | package cn.iocoder.yudao.module.ai.dal.dataobject.image; | 1 | package cn.iocoder.yudao.module.ai.dal.dataobject.image; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | ||
| 5 | +import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum; | ||
| 6 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 4 | import com.baomidou.mybatisplus.annotation.IdType; | 7 | import com.baomidou.mybatisplus.annotation.IdType; |
| 5 | import com.baomidou.mybatisplus.annotation.TableField; | 8 | import com.baomidou.mybatisplus.annotation.TableField; |
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 9 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | import com.baomidou.mybatisplus.annotation.TableName; | 10 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | 11 | import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; |
| 9 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 10 | import lombok.Data; | 12 | import lombok.Data; |
| 13 | +import org.springframework.ai.openai.OpenAiImageOptions; | ||
| 14 | +import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; | ||
| 11 | 15 | ||
| 12 | import java.util.Map; | 16 | import java.util.Map; |
| 13 | 17 | ||
| @@ -16,70 +20,86 @@ import java.util.Map; | @@ -16,70 +20,86 @@ import java.util.Map; | ||
| 16 | * | 20 | * |
| 17 | * @author fansili | 21 | * @author fansili |
| 18 | */ | 22 | */ |
| 19 | -@TableName("ai_image") | 23 | +@TableName(value = "ai_image", autoResultMap = true) |
| 20 | @Data | 24 | @Data |
| 21 | public class AiImageDO extends BaseDO { | 25 | public class AiImageDO extends BaseDO { |
| 22 | 26 | ||
| 23 | // TODO @fan:1)使用 java 注释哈,不要注解。2)关联、枚举字段,要关联到对应类,参考 AiChatMessageDO 的注释 | 27 | // TODO @fan:1)使用 java 注释哈,不要注解。2)关联、枚举字段,要关联到对应类,参考 AiChatMessageDO 的注释 |
| 24 | 28 | ||
| 29 | + /** | ||
| 30 | + * 编号 | ||
| 31 | + */ | ||
| 25 | @TableId(type = IdType.AUTO) | 32 | @TableId(type = IdType.AUTO) |
| 26 | private Long id; | 33 | private Long id; |
| 27 | 34 | ||
| 28 | - @Schema(description = "用户编号") | 35 | + /** |
| 36 | + * 用户编号 | ||
| 37 | + * | ||
| 38 | + * 关联 {@link AdminUserRespDTO#getId()} | ||
| 39 | + */ | ||
| 29 | private Long userId; | 40 | private Long userId; |
| 30 | 41 | ||
| 31 | - @Schema(description = "midjourney proxy 关联的 job id") | ||
| 32 | - private String jobId; | ||
| 33 | - | ||
| 34 | - @Schema(description = "提示词") | 42 | + /** |
| 43 | + * 提示词 | ||
| 44 | + */ | ||
| 35 | private String prompt; | 45 | private String prompt; |
| 36 | 46 | ||
| 37 | - @Schema(description = "平台") | 47 | + /** |
| 48 | + * 平台 | ||
| 49 | + * | ||
| 50 | + * 枚举 {@link cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum} | ||
| 51 | + */ | ||
| 38 | private String platform; | 52 | private String platform; |
| 39 | - | ||
| 40 | - @Schema(description = "模型") | 53 | + /** |
| 54 | + * 模型 | ||
| 55 | + * | ||
| 56 | + * 冗余 {@link AiChatModelDO#getModel()} | ||
| 57 | + */ | ||
| 41 | private String model; | 58 | private String model; |
| 42 | 59 | ||
| 43 | - @Schema(description = "图片宽度") | 60 | + /** |
| 61 | + * 图片宽度 | ||
| 62 | + */ | ||
| 44 | private Integer width; | 63 | private Integer width; |
| 45 | - | ||
| 46 | - @Schema(description = "图片高度") | 64 | + /** |
| 65 | + * 图片高度 | ||
| 66 | + */ | ||
| 47 | private Integer height; | 67 | private Integer height; |
| 48 | 68 | ||
| 49 | // TODO @fan:这种就注释绘画状态,然后枚举类关联下就好啦 | 69 | // TODO @fan:这种就注释绘画状态,然后枚举类关联下就好啦 |
| 50 | - @Schema(description = "绘画状态:提交、排队、绘画中、绘画完成、绘画失败") | 70 | + /** |
| 71 | + * 生成状态 | ||
| 72 | + * | ||
| 73 | + * 枚举 {@link AiImageStatusEnum} | ||
| 74 | + */ | ||
| 51 | private String status; | 75 | private String status; |
| 52 | 76 | ||
| 53 | - @Schema(description = "是否发布") | ||
| 54 | - private String publicStatus; | ||
| 55 | - | ||
| 56 | - @Schema(description = "图片地址(自己服务器)") | 77 | + /** |
| 78 | + * 图片地址 | ||
| 79 | + */ | ||
| 57 | private String picUrl; | 80 | private String picUrl; |
| 58 | - | ||
| 59 | - // TODO @芋艿:可能要删除掉 | ||
| 60 | - @Schema(description = "绘画图片地址(绘画好的服务器)") | ||
| 61 | - private String originalPicUrl; | ||
| 62 | - | ||
| 63 | - // ============ 绘画请求参数 ============ | ||
| 64 | - | ||
| 65 | /** | 81 | /** |
| 66 | - * - style | 82 | + * 是否公开 |
| 67 | */ | 83 | */ |
| 68 | - @Schema(description = "绘画请求参数") | ||
| 69 | - @TableField(typeHandler = JacksonTypeHandler.class) | ||
| 70 | - private Map<String, Object> drawRequest; | 84 | + private Boolean publicStatus; |
| 71 | 85 | ||
| 72 | /** | 86 | /** |
| 73 | - * - mjNonceId | ||
| 74 | - * - mjOperationId | ||
| 75 | - * - mjOperationName | ||
| 76 | - * - mjOperations | 87 | + * 绘制参数,不同 platform 的不同参数 |
| 88 | + * | ||
| 89 | + * 1. {@link OpenAiImageOptions} | ||
| 90 | + * 2. {@link StabilityAiImageOptions} | ||
| 77 | */ | 91 | */ |
| 78 | - @Schema(description = "绘画请求响应参数") | ||
| 79 | @TableField(typeHandler = JacksonTypeHandler.class) | 92 | @TableField(typeHandler = JacksonTypeHandler.class) |
| 80 | - private Map<String, Object> drawResponse; | 93 | + private Map<String, String> options; |
| 81 | 94 | ||
| 82 | - @Schema(description = "绘画错误信息") | 95 | + // TODO @芋艿:再瞅瞅 |
| 96 | + /** | ||
| 97 | + * midjourney proxy 关联的 job id | ||
| 98 | + */ | ||
| 99 | + private String jobId; | ||
| 100 | + /** | ||
| 101 | + * 绘画错误信息 | ||
| 102 | + */ | ||
| 83 | private String errorMessage; | 103 | private String errorMessage; |
| 84 | 104 | ||
| 85 | } | 105 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java
| @@ -25,8 +25,8 @@ import java.util.List; | @@ -25,8 +25,8 @@ import java.util.List; | ||
| 25 | 25 | ||
| 26 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 26 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 27 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 27 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 28 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_MODEL_ERROR; | ||
| 29 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | 28 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_MODEL_ERROR; |
| 29 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | ||
| 30 | 30 | ||
| 31 | /** | 31 | /** |
| 32 | * AI 聊天对话 Service 实现类 | 32 | * AI 聊天对话 Service 实现类 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
| @@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory; | @@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory; | ||
| 8 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 8 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 9 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 9 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 10 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 10 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 11 | -import cn.iocoder.yudao.module.ai.ErrorCodeConstants; | 11 | +import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; |
| 12 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; | 12 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; |
| 13 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; | 13 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; |
| 14 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; | 14 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; |
| @@ -39,8 +39,8 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | @@ -39,8 +39,8 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | ||
| 39 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; | 39 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; |
| 40 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 40 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 41 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 41 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 42 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.AI_CHAT_MESSAGE_NOT_EXIST; | ||
| 43 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | 42 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.AI_CHAT_MESSAGE_NOT_EXIST; |
| 43 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | ||
| 44 | 44 | ||
| 45 | /** | 45 | /** |
| 46 | * AI 聊天消息 Service 实现类 | 46 | * AI 聊天消息 Service 实现类 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java
| @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.ai.service.image; | @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.ai.service.image; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO; | 5 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO; |
| 6 | -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallReqVO; | 6 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO; |
| 7 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO; | 7 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO; |
| 8 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | 8 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; |
| 9 | 9 | ||
| @@ -32,12 +32,12 @@ public interface AiImageService { | @@ -32,12 +32,12 @@ public interface AiImageService { | ||
| 32 | AiImageDO getImage(Long id); | 32 | AiImageDO getImage(Long id); |
| 33 | 33 | ||
| 34 | /** | 34 | /** |
| 35 | - * ai绘画 - dall2/dall3 绘画 | 35 | + * 绘制图片 |
| 36 | * | 36 | * |
| 37 | - * @param loginUserId | ||
| 38 | - * @param req | 37 | + * @param userId 用户编号 |
| 38 | + * @param drawReqVO 绘制请求 | ||
| 39 | */ | 39 | */ |
| 40 | - Long dall(Long loginUserId, AiImageDallReqVO req); | 40 | + Long drawImage(Long userId, AiImageDrawReqVO drawReqVO); |
| 41 | 41 | ||
| 42 | /** | 42 | /** |
| 43 | * midjourney 图片生成 | 43 | * midjourney 图片生成 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
| 1 | package cn.iocoder.yudao.module.ai.service.image; | 1 | package cn.iocoder.yudao.module.ai.service.image; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.bean.BeanUtil; | ||
| 4 | import cn.hutool.core.codec.Base64; | 3 | import cn.hutool.core.codec.Base64; |
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 5 | import cn.hutool.core.util.ObjUtil; | 5 | import cn.hutool.core.util.ObjUtil; |
| 6 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 7 | import cn.hutool.extra.spring.SpringUtil; | 7 | import cn.hutool.extra.spring.SpringUtil; |
| 8 | import cn.hutool.http.HttpUtil; | 8 | import cn.hutool.http.HttpUtil; |
| 9 | import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | 9 | import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; |
| 10 | -import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageModelEnum; | ||
| 11 | -import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageStyleEnum; | ||
| 12 | import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory; | 10 | import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory; |
| 13 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 11 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 14 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 12 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 15 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 13 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 16 | -import cn.iocoder.yudao.module.ai.AiCommonConstants; | ||
| 17 | import cn.iocoder.yudao.module.ai.client.MidjourneyProxyClient; | 14 | import cn.iocoder.yudao.module.ai.client.MidjourneyProxyClient; |
| 18 | import cn.iocoder.yudao.module.ai.client.enums.MidjourneyModelEnum; | 15 | import cn.iocoder.yudao.module.ai.client.enums.MidjourneyModelEnum; |
| 19 | import cn.iocoder.yudao.module.ai.client.enums.MidjourneySubmitCodeEnum; | 16 | import cn.iocoder.yudao.module.ai.client.enums.MidjourneySubmitCodeEnum; |
| @@ -21,17 +18,18 @@ import cn.iocoder.yudao.module.ai.client.enums.MidjourneyTaskStatusEnum; | @@ -21,17 +18,18 @@ import cn.iocoder.yudao.module.ai.client.enums.MidjourneyTaskStatusEnum; | ||
| 21 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyImagineReqVO; | 18 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyImagineReqVO; |
| 22 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO; | 19 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO; |
| 23 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneySubmitRespVO; | 20 | import cn.iocoder.yudao.module.ai.client.vo.MidjourneySubmitRespVO; |
| 24 | -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallReqVO; | 21 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO; |
| 25 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO; | 22 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO; |
| 26 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | 23 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; |
| 27 | import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper; | 24 | import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper; |
| 28 | -import cn.iocoder.yudao.module.ai.enums.AiImagePublicStatusEnum; | ||
| 29 | -import cn.iocoder.yudao.module.ai.enums.AiImageStatusEnum; | 25 | +import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum; |
| 30 | import cn.iocoder.yudao.module.infra.api.file.FileApi; | 26 | import cn.iocoder.yudao.module.infra.api.file.FileApi; |
| 31 | -import com.google.common.collect.ImmutableMap; | ||
| 32 | import jakarta.annotation.Resource; | 27 | import jakarta.annotation.Resource; |
| 33 | import lombok.extern.slf4j.Slf4j; | 28 | import lombok.extern.slf4j.Slf4j; |
| 34 | -import org.springframework.ai.image.*; | 29 | +import org.springframework.ai.image.ImageClient; |
| 30 | +import org.springframework.ai.image.ImageOptions; | ||
| 31 | +import org.springframework.ai.image.ImagePrompt; | ||
| 32 | +import org.springframework.ai.image.ImageResponse; | ||
| 35 | import org.springframework.ai.openai.OpenAiImageOptions; | 33 | import org.springframework.ai.openai.OpenAiImageOptions; |
| 36 | import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; | 34 | import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; |
| 37 | import org.springframework.beans.factory.annotation.Autowired; | 35 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -41,7 +39,7 @@ import org.springframework.stereotype.Service; | @@ -41,7 +39,7 @@ import org.springframework.stereotype.Service; | ||
| 41 | import org.springframework.transaction.annotation.Transactional; | 39 | import org.springframework.transaction.annotation.Transactional; |
| 42 | 40 | ||
| 43 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 41 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 44 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.AI_IMAGE_NOT_EXISTS; | 42 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.AI_IMAGE_NOT_EXISTS; |
| 45 | 43 | ||
| 46 | /** | 44 | /** |
| 47 | * AI 绘画 Service 实现类 | 45 | * AI 绘画 Service 实现类 |
| @@ -78,22 +76,18 @@ public class AiImageServiceImpl implements AiImageService { | @@ -78,22 +76,18 @@ public class AiImageServiceImpl implements AiImageService { | ||
| 78 | } | 76 | } |
| 79 | 77 | ||
| 80 | @Override | 78 | @Override |
| 81 | - public Long dall(Long userId, AiImageDallReqVO req) { | ||
| 82 | - req.setPlatform("dall"); // TODO 芋艿:临时写死 | 79 | + public Long drawImage(Long userId, AiImageDrawReqVO drawReqVO) { |
| 83 | // 1. 保存数据库 | 80 | // 1. 保存数据库 |
| 84 | - AiImageDO image = BeanUtils.toBean(req, AiImageDO.class) | ||
| 85 | - .setUserId(userId).setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()) | ||
| 86 | - .setWidth(req.getWidth()).setHeight(req.getHeight()) | ||
| 87 | - .setDrawRequest(ImmutableMap.of(AiCommonConstants.DRAW_REQ_KEY_STYLE, req.getStyle())) | ||
| 88 | - .setPublicStatus(AiImagePublicStatusEnum.PRIVATE.getStatus()); | 81 | + AiImageDO image = BeanUtils.toBean(drawReqVO, AiImageDO.class).setUserId(userId).setPublicStatus(false) |
| 82 | + .setWidth(drawReqVO.getWidth()).setHeight(drawReqVO.getHeight()).setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()); | ||
| 89 | imageMapper.insert(image); | 83 | imageMapper.insert(image); |
| 90 | - // 2. 异步绘制,后续前端通过返回的 id 进行伦旭 | ||
| 91 | - getSelf().doDall(image, req); | 84 | + // 2. 异步绘制,后续前端通过返回的 id 进行轮询结果 |
| 85 | + getSelf().doDall(image, drawReqVO); | ||
| 92 | return image.getId(); | 86 | return image.getId(); |
| 93 | } | 87 | } |
| 94 | 88 | ||
| 95 | @Async | 89 | @Async |
| 96 | - public void doDall(AiImageDO image, AiImageDallReqVO req) { | 90 | + public void doDall(AiImageDO image, AiImageDrawReqVO req) { |
| 97 | try { | 91 | try { |
| 98 | // 1.1 构建请求 | 92 | // 1.1 构建请求 |
| 99 | ImageOptions request = buildImageOptions(req); | 93 | ImageOptions request = buildImageOptions(req); |
| @@ -106,7 +100,7 @@ public class AiImageServiceImpl implements AiImageService { | @@ -106,7 +100,7 @@ public class AiImageServiceImpl implements AiImageService { | ||
| 106 | String filePath = fileApi.createFile(fileContent); | 100 | String filePath = fileApi.createFile(fileContent); |
| 107 | 101 | ||
| 108 | // 3. 更新数据库 | 102 | // 3. 更新数据库 |
| 109 | - imageMapper.updateById(new AiImageDO().setId(image.getId()).setStatus(AiImageStatusEnum.COMPLETE.getStatus()) | 103 | + imageMapper.updateById(new AiImageDO().setId(image.getId()).setStatus(AiImageStatusEnum.SUCCESS.getStatus()) |
| 110 | .setPicUrl(filePath)); | 104 | .setPicUrl(filePath)); |
| 111 | } catch (Exception ex) { | 105 | } catch (Exception ex) { |
| 112 | log.error("[doDall][image({}) 生成异常]", image, ex); | 106 | log.error("[doDall][image({}) 生成异常]", image, ex); |
| @@ -115,30 +109,28 @@ public class AiImageServiceImpl implements AiImageService { | @@ -115,30 +109,28 @@ public class AiImageServiceImpl implements AiImageService { | ||
| 115 | } | 109 | } |
| 116 | } | 110 | } |
| 117 | 111 | ||
| 118 | - private static ImageOptions buildImageOptions(AiImageDallReqVO draw) { | ||
| 119 | - if (ObjUtil.equal(draw.getPlatform(), AiPlatformEnum.OPEN_AI_DALL.getPlatform())) { | ||
| 120 | - OpenAiImageOptions request = new OpenAiImageOptions(); | ||
| 121 | - request.setModel(OpenAiImageModelEnum.valueOfModel(draw.getModel()).getModel()); | ||
| 122 | - request.setStyle(OpenAiImageStyleEnum.valueOfStyle(draw.getStyle()).getStyle()); | ||
| 123 | - request.setSize(String.format(AiCommonConstants.DALL_SIZE_TEMPLATE, draw.getWidth(), draw.getHeight())); | ||
| 124 | - request.setResponseFormat("b64_json"); | ||
| 125 | - return request; | ||
| 126 | - } else { | ||
| 127 | - // https://platform.stability.ai/docs/api-reference#tag/Generate/paths/~1v2beta~1stable-image~1generate~1sd3/post | ||
| 128 | - return StabilityAiImageOptions.builder().withModel(draw.getModel()) | 112 | + private static ImageOptions buildImageOptions(AiImageDrawReqVO draw) { |
| 113 | + if (ObjUtil.equal(draw.getPlatform(), AiPlatformEnum.OPENAI.getPlatform())) { | ||
| 114 | + // https://platform.openai.com/docs/api-reference/images/create | ||
| 115 | + return OpenAiImageOptions.builder().withModel(draw.getModel()) | ||
| 129 | .withHeight(draw.getHeight()).withWidth(draw.getWidth()) | 116 | .withHeight(draw.getHeight()).withWidth(draw.getWidth()) |
| 117 | + .withStyle(MapUtil.getStr(draw.getOptions(), "style")) // 风格 | ||
| 118 | + .withResponseFormat("b64_json") | ||
| 119 | + .build(); | ||
| 120 | + } else if (ObjUtil.equal(draw.getPlatform(), AiPlatformEnum.STABLE_DIFFUSION.getPlatform())) { | ||
| 121 | + // https://platform.stability.ai/docs/api-reference#tag/Text-to-Image/operation/textToImage | ||
| 122 | + return StabilityAiImageOptions.builder().withModel(draw.getModel()) | ||
| 123 | + .withHeight(draw.getHeight()).withWidth(draw.getWidth()) // TODO @芋艿:各种参数 | ||
| 130 | .build(); | 124 | .build(); |
| 131 | } | 125 | } |
| 132 | -// return null; | 126 | + throw new IllegalArgumentException("不支持的 AI 平台:" + draw.getPlatform()); |
| 133 | } | 127 | } |
| 134 | 128 | ||
| 135 | @Override | 129 | @Override |
| 136 | @Transactional(rollbackFor = Exception.class) | 130 | @Transactional(rollbackFor = Exception.class) |
| 137 | public Long midjourneyImagine(Long loginUserId, AiImageMidjourneyImagineReqVO req) { | 131 | public Long midjourneyImagine(Long loginUserId, AiImageMidjourneyImagineReqVO req) { |
| 138 | - | ||
| 139 | // 1、构建 AiImageDO | 132 | // 1、构建 AiImageDO |
| 140 | AiImageDO aiImageDO = new AiImageDO(); | 133 | AiImageDO aiImageDO = new AiImageDO(); |
| 141 | - aiImageDO.setId(null); | ||
| 142 | aiImageDO.setUserId(loginUserId); | 134 | aiImageDO.setUserId(loginUserId); |
| 143 | aiImageDO.setPrompt(req.getPrompt()); | 135 | aiImageDO.setPrompt(req.getPrompt()); |
| 144 | aiImageDO.setPlatform(AiPlatformEnum.MIDJOURNEY.getPlatform()); | 136 | aiImageDO.setPlatform(AiPlatformEnum.MIDJOURNEY.getPlatform()); |
| @@ -147,12 +139,6 @@ public class AiImageServiceImpl implements AiImageService { | @@ -147,12 +139,6 @@ public class AiImageServiceImpl implements AiImageService { | ||
| 147 | aiImageDO.setWidth(null); | 139 | aiImageDO.setWidth(null); |
| 148 | aiImageDO.setHeight(null); | 140 | aiImageDO.setHeight(null); |
| 149 | aiImageDO.setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()); | 141 | aiImageDO.setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()); |
| 150 | - aiImageDO.setPublicStatus(AiImagePublicStatusEnum.PRIVATE.getStatus()); | ||
| 151 | - aiImageDO.setPicUrl(null); | ||
| 152 | - aiImageDO.setOriginalPicUrl(null); | ||
| 153 | - aiImageDO.setDrawRequest(null); | ||
| 154 | - aiImageDO.setDrawResponse(null); | ||
| 155 | - aiImageDO.setErrorMessage(null); | ||
| 156 | 142 | ||
| 157 | // 2、保存 image | 143 | // 2、保存 image |
| 158 | imageMapper.insert(aiImageDO); | 144 | imageMapper.insert(aiImageDO); |
| @@ -211,7 +197,7 @@ public class AiImageServiceImpl implements AiImageService { | @@ -211,7 +197,7 @@ public class AiImageServiceImpl implements AiImageService { | ||
| 211 | // | 197 | // |
| 212 | String imageStatus = null; | 198 | String imageStatus = null; |
| 213 | if (MidjourneyTaskStatusEnum.SUCCESS == notifyReqVO.getStatus()) { | 199 | if (MidjourneyTaskStatusEnum.SUCCESS == notifyReqVO.getStatus()) { |
| 214 | - imageStatus = AiImageStatusEnum.COMPLETE.getStatus(); | 200 | + imageStatus = AiImageStatusEnum.SUCCESS.getStatus(); |
| 215 | } else if (MidjourneyTaskStatusEnum.FAILURE == notifyReqVO.getStatus()) { | 201 | } else if (MidjourneyTaskStatusEnum.FAILURE == notifyReqVO.getStatus()) { |
| 216 | imageStatus = AiImageStatusEnum.FAIL.getStatus(); | 202 | imageStatus = AiImageStatusEnum.FAIL.getStatus(); |
| 217 | } | 203 | } |
| @@ -226,8 +212,7 @@ public class AiImageServiceImpl implements AiImageService { | @@ -226,8 +212,7 @@ public class AiImageServiceImpl implements AiImageService { | ||
| 226 | .setId(image.getId()) | 212 | .setId(image.getId()) |
| 227 | .setStatus(imageStatus) | 213 | .setStatus(imageStatus) |
| 228 | .setPicUrl(filePath) | 214 | .setPicUrl(filePath) |
| 229 | - .setOriginalPicUrl(notifyReqVO.getImageUrl()) | ||
| 230 | - .setDrawResponse(BeanUtil.beanToMap(notifyReqVO)) | 215 | +// .setOriginalPicUrl(notifyReqVO.getImageUrl()) TODO @fan:就不存原始的图片地址啦 |
| 231 | ); | 216 | ); |
| 232 | return true; | 217 | return true; |
| 233 | } | 218 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/midjourneyHandler/YuDaoMidjourneyMessageHandler.java
| @@ -5,7 +5,7 @@ import cn.hutool.core.util.StrUtil; | @@ -5,7 +5,7 @@ import cn.hutool.core.util.StrUtil; | ||
| 5 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyOperationsVO; | 5 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyOperationsVO; |
| 6 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; | 6 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; |
| 7 | import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper; | 7 | import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper; |
| 8 | -import cn.iocoder.yudao.module.ai.enums.AiImageStatusEnum; | 8 | +import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum; |
| 9 | import com.alibaba.fastjson.JSON; | 9 | import com.alibaba.fastjson.JSON; |
| 10 | import lombok.AllArgsConstructor; | 10 | import lombok.AllArgsConstructor; |
| 11 | import lombok.extern.slf4j.Slf4j; | 11 | import lombok.extern.slf4j.Slf4j; |
| @@ -89,7 +89,7 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler { | @@ -89,7 +89,7 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler { | ||
| 89 | AiImageStatusEnum drawingStatusEnum = null; | 89 | AiImageStatusEnum drawingStatusEnum = null; |
| 90 | String generateStatus = midjourneyMessage.getGenerateStatus(); | 90 | String generateStatus = midjourneyMessage.getGenerateStatus(); |
| 91 | if (MidjourneyGennerateStatusEnum.COMPLETED.getStatus().equals(generateStatus)) { | 91 | if (MidjourneyGennerateStatusEnum.COMPLETED.getStatus().equals(generateStatus)) { |
| 92 | - drawingStatusEnum = AiImageStatusEnum.COMPLETE; | 92 | + drawingStatusEnum = AiImageStatusEnum.SUCCESS; |
| 93 | } else if (MidjourneyGennerateStatusEnum.IN_PROGRESS.getStatus().equals(generateStatus)) { | 93 | } else if (MidjourneyGennerateStatusEnum.IN_PROGRESS.getStatus().equals(generateStatus)) { |
| 94 | drawingStatusEnum = AiImageStatusEnum.IN_PROGRESS; | 94 | drawingStatusEnum = AiImageStatusEnum.IN_PROGRESS; |
| 95 | } | 95 | } |
| @@ -101,7 +101,6 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler { | @@ -101,7 +101,6 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler { | ||
| 101 | // 更新数据库 | 101 | // 更新数据库 |
| 102 | aiImageMapper.updateByMjNonce(nonceId, | 102 | aiImageMapper.updateByMjNonce(nonceId, |
| 103 | new AiImageDO() | 103 | new AiImageDO() |
| 104 | - .setOriginalPicUrl(imageUrl) | ||
| 105 | .setStatus(drawingStatusEnum == null ? null : drawingStatusEnum.getStatus()) | 104 | .setStatus(drawingStatusEnum == null ? null : drawingStatusEnum.getStatus()) |
| 106 | // .setMjNonceId(midjourneyMessage.getId()) | 105 | // .setMjNonceId(midjourneyMessage.getId()) |
| 107 | // .setMjOperations(JsonUtils.toJsonString(midjourneyOperations)) | 106 | // .setMjOperations(JsonUtils.toJsonString(midjourneyOperations)) |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/midjourneyHandler/vo/AiChatModalChatConfigVO.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.service.image.midjourneyHandler.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 | - * chat config | ||
| 10 | - * | ||
| 11 | - * @author fansili | ||
| 12 | - * @time 2024/5/6 15:06 | ||
| 13 | - * @since 1.0 | ||
| 14 | - */ | ||
| 15 | -@Data | ||
| 16 | -@Accessors(chain = true) | ||
| 17 | -public class AiChatModalChatConfigVO extends AiChatModalConfigVO { | ||
| 18 | - | ||
| 19 | - @NotNull | ||
| 20 | - @Schema(description = "在生成消息时采用的Top-K采样大小") | ||
| 21 | - private Double topK; | ||
| 22 | - | ||
| 23 | - @NotNull | ||
| 24 | - @Schema(description = "Top-P核采样方法的概率阈值") | ||
| 25 | - private Double topP; | ||
| 26 | - | ||
| 27 | - @NotNull | ||
| 28 | - @Schema(description = "温度参数,用于调整生成回复的随机性和多样性程度") | ||
| 29 | - private Double temperature; | ||
| 30 | - | ||
| 31 | - @NotNull | ||
| 32 | - @Schema(description = "最大 tokens") | ||
| 33 | - private Integer maxTokens; | ||
| 34 | - | ||
| 35 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/midjourneyHandler/vo/AiChatModalConfigVO.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.service.image.midjourneyHandler.vo; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | ||
| 4 | -import lombok.Data; | ||
| 5 | -import lombok.experimental.Accessors; | ||
| 6 | -import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel; | ||
| 7 | -import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel; | ||
| 8 | - | ||
| 9 | -/** | ||
| 10 | - * modal config | ||
| 11 | - * | ||
| 12 | - * @author fansili | ||
| 13 | - * @time 2024/5/6 15:06 | ||
| 14 | - * @since 1.0 | ||
| 15 | - */ | ||
| 16 | -@Data | ||
| 17 | -@Accessors(chain = true) | ||
| 18 | -public class AiChatModalConfigVO { | ||
| 19 | - | ||
| 20 | - /** | ||
| 21 | - * 模型平台 (冗余,方便类型转换) | ||
| 22 | - * 参考:{@link AiPlatformEnum} | ||
| 23 | - */ | ||
| 24 | - private String platform; | ||
| 25 | - /** | ||
| 26 | - * 模型类型(冗余,方便类型转换) | ||
| 27 | - * {@link YiYanChatModel} | ||
| 28 | - * {@link XingHuoChatModel} | ||
| 29 | - */ | ||
| 30 | - private String type; | ||
| 31 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/midjourneyHandler/vo/AiChatModalDallConfigVO.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.service.image.midjourneyHandler.vo; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageStyleEnum; | ||
| 4 | -import lombok.Data; | ||
| 5 | -import lombok.experimental.Accessors; | ||
| 6 | - | ||
| 7 | -/** | ||
| 8 | - * dall | ||
| 9 | - * | ||
| 10 | - * @author fansili | ||
| 11 | - * @time 2024/5/6 15:06 | ||
| 12 | - * @since 1.0 | ||
| 13 | - */ | ||
| 14 | -@Data | ||
| 15 | -@Accessors(chain = true) | ||
| 16 | -public class AiChatModalDallConfigVO extends AiChatModalConfigVO { | ||
| 17 | - // 可选字段,默认为1 | ||
| 18 | - // 生成图像的数量,必须在1到10之间。对于dall-e-3模型,目前仅支持n=1。 | ||
| 19 | - private Integer n = 1; | ||
| 20 | - | ||
| 21 | - // 可选字段,默认为standard | ||
| 22 | - // 设置生成图像的质量。hd质量将创建细节更丰富、图像整体一致性更高的图片。该参数仅对dall-e-3模型有效。 | ||
| 23 | - private String quality = "standard"; | ||
| 24 | - | ||
| 25 | - // 可选字段,默认为url | ||
| 26 | - // 返回生成图像的格式。必须是url或b64_json中的一种。URL链接的有效期是从生成图像后开始计算的60分钟内有效。 | ||
| 27 | - private String responseFormat = "url"; | ||
| 28 | - | ||
| 29 | - // 可选字段,默认为1024x1024 | ||
| 30 | - // 生成图像的尺寸大小。对于dall-e-2模型,尺寸可为256x256, 512x512, 或 1024x1024。对于dall-e-3模型,尺寸可为1024x1024, 1792x1024, 或 1024x1792。 | ||
| 31 | - private String size = "1024x1024"; | ||
| 32 | - | ||
| 33 | - // 可选字段,默认为vivid | ||
| 34 | - // 图像生成的风格。可为vivid(生动)或natural(自然)。vivid会使模型偏向生成超现实和戏剧性的图像,而natural则会让模型产出更自然、不那么超现实的图像。该参数仅对dall-e-3模型有效。 | ||
| 35 | - private OpenAiImageStyleEnum style = OpenAiImageStyleEnum.VIVID; | ||
| 36 | - | ||
| 37 | - // 可选字段 | ||
| 38 | - // 代表您的终端用户的唯一标识符,有助于OpenAI监控并检测滥用行为。了解更多信息请参考官方文档。 | ||
| 39 | - private String endUserId = "UID123456"; | ||
| 40 | - | ||
| 41 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/midjourneyHandler/vo/AiChatModalMidjourneyConfigVO.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.service.image.midjourneyHandler.vo; | ||
| 2 | - | ||
| 3 | -import lombok.Data; | ||
| 4 | -import lombok.experimental.Accessors; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * Midjourney Config | ||
| 8 | - * | ||
| 9 | - * @author fansili | ||
| 10 | - * @time 2024/5/6 15:07 | ||
| 11 | - * @since 1.0 | ||
| 12 | - */ | ||
| 13 | -@Data | ||
| 14 | -@Accessors(chain = true) | ||
| 15 | -public class AiChatModalMidjourneyConfigVO extends AiChatModalConfigVO { | ||
| 16 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java
| @@ -17,7 +17,7 @@ import org.springframework.validation.annotation.Validated; | @@ -17,7 +17,7 @@ import org.springframework.validation.annotation.Validated; | ||
| 17 | import java.util.List; | 17 | import java.util.List; |
| 18 | 18 | ||
| 19 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 19 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 20 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.*; | 20 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | * AI API 密钥 Service 实现类 | 23 | * AI API 密钥 Service 实现类 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java
| @@ -16,7 +16,7 @@ import java.util.Collection; | @@ -16,7 +16,7 @@ import java.util.Collection; | ||
| 16 | import java.util.List; | 16 | import java.util.List; |
| 17 | 17 | ||
| 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 19 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.*; | 19 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; |
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * AI 聊天模型 Service 实现类 | 22 | * AI 聊天模型 Service 实现类 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java
| @@ -21,7 +21,7 @@ import java.util.List; | @@ -21,7 +21,7 @@ import java.util.List; | ||
| 21 | 21 | ||
| 22 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 22 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 23 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 23 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 24 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.*; | 24 | +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; |
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | * AI 聊天角色 Service 实现类 | 27 | * AI 聊天角色 Service 实现类 |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java
| @@ -3,10 +3,9 @@ package cn.iocoder.yudao.framework.ai.config; | @@ -3,10 +3,9 @@ package cn.iocoder.yudao.framework.ai.config; | ||
| 3 | import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | 3 | import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; |
| 4 | import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel; | 4 | import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel; |
| 5 | import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel; | 5 | import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel; |
| 6 | -import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageModelEnum; | ||
| 7 | -import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageStyleEnum; | ||
| 8 | import lombok.Data; | 6 | import lombok.Data; |
| 9 | import lombok.experimental.Accessors; | 7 | import lombok.experimental.Accessors; |
| 8 | +import org.springframework.ai.autoconfigure.openai.OpenAiImageProperties; | ||
| 10 | import org.springframework.boot.context.properties.ConfigurationProperties; | 9 | import org.springframework.boot.context.properties.ConfigurationProperties; |
| 11 | 10 | ||
| 12 | /** | 11 | /** |
| @@ -94,27 +93,6 @@ public class YudaoAiProperties { | @@ -94,27 +93,6 @@ public class YudaoAiProperties { | ||
| 94 | 93 | ||
| 95 | @Data | 94 | @Data |
| 96 | @Accessors(chain = true) | 95 | @Accessors(chain = true) |
| 97 | - public static class OpenAiImageProperties { | ||
| 98 | - | ||
| 99 | - private boolean enable = false; | ||
| 100 | - | ||
| 101 | - /** | ||
| 102 | - * api key | ||
| 103 | - */ | ||
| 104 | - private String apiKey; | ||
| 105 | - /** | ||
| 106 | - * 模型 | ||
| 107 | - */ | ||
| 108 | - private OpenAiImageModelEnum model = OpenAiImageModelEnum.DALL_E_2; | ||
| 109 | - /** | ||
| 110 | - * 风格 | ||
| 111 | - */ | ||
| 112 | - private OpenAiImageStyleEnum style = OpenAiImageStyleEnum.VIVID; | ||
| 113 | - | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - @Data | ||
| 117 | - @Accessors(chain = true) | ||
| 118 | public static class MidjourneyProperties { | 96 | public static class MidjourneyProperties { |
| 119 | private boolean enable = false; | 97 | private boolean enable = false; |
| 120 | 98 |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java
| @@ -20,7 +20,6 @@ public enum AiPlatformEnum { | @@ -20,7 +20,6 @@ public enum AiPlatformEnum { | ||
| 20 | QIAN_WEN("QianWen", "千问"), // 阿里 | 20 | QIAN_WEN("QianWen", "千问"), // 阿里 |
| 21 | GEMIR ("gemir ", "gemir "), // 谷歌 | 21 | GEMIR ("gemir ", "gemir "), // 谷歌 |
| 22 | 22 | ||
| 23 | - OPEN_AI_DALL("dall", "dall"), // TODO OpenAI 提供的绘图,接入中;TODO 要不要统一下?! | ||
| 24 | STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI | 23 | STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI |
| 25 | MIDJOURNEY("midjourney", "midjourney"), // TODO MJ 提供的绘图,接入中 | 24 | MIDJOURNEY("midjourney", "midjourney"), // TODO MJ 提供的绘图,接入中 |
| 26 | ; | 25 | ; |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/OpenAiImageModelEnum.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.core.enums; | ||
| 2 | - | ||
| 3 | -import lombok.AllArgsConstructor; | ||
| 4 | -import lombok.Getter; | ||
| 5 | - | ||
| 6 | -// TODO 芋艿:待梳理 | ||
| 7 | -/** | ||
| 8 | - * open ai | ||
| 9 | - * | ||
| 10 | - * @author fansili | ||
| 11 | - * @time 2024/4/28 14:21 | ||
| 12 | - * @since 1.0 | ||
| 13 | - */ | ||
| 14 | -@AllArgsConstructor | ||
| 15 | -@Getter | ||
| 16 | -@Deprecated | ||
| 17 | -public enum OpenAiImageModelEnum { | ||
| 18 | - | ||
| 19 | - DALL_E_2("dall-e-2", "dall-e-2"), | ||
| 20 | - | ||
| 21 | - DALL_E_3("dall-e-3", "dall-e-3") | ||
| 22 | - | ||
| 23 | - ; | ||
| 24 | - | ||
| 25 | - private String model; | ||
| 26 | - | ||
| 27 | - private String name; | ||
| 28 | - | ||
| 29 | - public static OpenAiImageModelEnum valueOfModel(String model) { | ||
| 30 | - for (OpenAiImageModelEnum itemEnum : OpenAiImageModelEnum.values()) { | ||
| 31 | - if (itemEnum.getModel().equals(model)) { | ||
| 32 | - return itemEnum; | ||
| 33 | - } | ||
| 34 | - } | ||
| 35 | - throw new IllegalArgumentException("Invalid MessageType value: " + model); | ||
| 36 | - } | ||
| 37 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/OpenAiImageStyleEnum.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.core.enums; | ||
| 2 | - | ||
| 3 | -import lombok.AllArgsConstructor; | ||
| 4 | -import lombok.Getter; | ||
| 5 | - | ||
| 6 | -// TODO 芋艿:待梳理 | ||
| 7 | -/** | ||
| 8 | - * open ai image style | ||
| 9 | - * | ||
| 10 | - * @author fansili | ||
| 11 | - * @time 2024/4/28 16:15 | ||
| 12 | - * @since 1.0 | ||
| 13 | - */ | ||
| 14 | -@AllArgsConstructor | ||
| 15 | -@Getter | ||
| 16 | -@Deprecated | ||
| 17 | -public enum OpenAiImageStyleEnum { | ||
| 18 | - | ||
| 19 | - // 图像生成的风格。可为vivid(生动)或 natural(自然)。vivid会使模型偏向生成超现实和戏剧性的图像,而natural则会让模型产出更自然、不那么超现实的图像。该参数仅对dall-e-3模型有效。 | ||
| 20 | - | ||
| 21 | - VIVID("vivid", "生动"), | ||
| 22 | - NATURAL("natural", "自然"), | ||
| 23 | - | ||
| 24 | - ; | ||
| 25 | - | ||
| 26 | - private String style; | ||
| 27 | - | ||
| 28 | - private String name; | ||
| 29 | - | ||
| 30 | - public static OpenAiImageStyleEnum valueOfStyle(String style) { | ||
| 31 | - for (OpenAiImageStyleEnum itemEnum : OpenAiImageStyleEnum.values()) { | ||
| 32 | - if (itemEnum.getStyle().equals(style)) { | ||
| 33 | - return itemEnum; | ||
| 34 | - } | ||
| 35 | - } | ||
| 36 | - throw new IllegalArgumentException("Invalid MessageType value: " + style); | ||
| 37 | - } | ||
| 38 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java
| @@ -33,6 +33,7 @@ import org.springframework.ai.openai.OpenAiChatOptions; | @@ -33,6 +33,7 @@ import org.springframework.ai.openai.OpenAiChatOptions; | ||
| 33 | import org.springframework.ai.openai.OpenAiImageClient; | 33 | import org.springframework.ai.openai.OpenAiImageClient; |
| 34 | import org.springframework.ai.openai.api.ApiUtils; | 34 | import org.springframework.ai.openai.api.ApiUtils; |
| 35 | import org.springframework.ai.openai.api.OpenAiApi; | 35 | import org.springframework.ai.openai.api.OpenAiApi; |
| 36 | +import org.springframework.ai.stabilityai.StabilityAiImageClient; | ||
| 36 | 37 | ||
| 37 | import java.util.List; | 38 | import java.util.List; |
| 38 | 39 | ||
| @@ -88,12 +89,15 @@ public class AiClientFactoryImpl implements AiClientFactory { | @@ -88,12 +89,15 @@ public class AiClientFactoryImpl implements AiClientFactory { | ||
| 88 | 89 | ||
| 89 | @Override | 90 | @Override |
| 90 | public ImageClient getDefaultImageClient(AiPlatformEnum platform) { | 91 | public ImageClient getDefaultImageClient(AiPlatformEnum platform) { |
| 92 | + //noinspection EnhancedSwitchMigration | ||
| 91 | switch (platform) { | 93 | switch (platform) { |
| 92 | - case OPEN_AI_DALL: | 94 | + case OPENAI: |
| 93 | return SpringUtil.getBean(OpenAiImageClient.class); | 95 | return SpringUtil.getBean(OpenAiImageClient.class); |
| 94 | - | 96 | + case STABLE_DIFFUSION: |
| 97 | + return SpringUtil.getBean(StabilityAiImageClient.class); | ||
| 98 | + default: | ||
| 99 | + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); | ||
| 95 | } | 100 | } |
| 96 | - return null; | ||
| 97 | } | 101 | } |
| 98 | 102 | ||
| 99 | private static String buildClientCacheKey(Class<?> clazz, Object... params) { | 103 | private static String buildClientCacheKey(Class<?> clazz, Object... params) { |