Commit 6856f5f192d4c726a67ef3b45c9e744a49c735ae

Authored by YunaiV
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
  1 +/**
  2 + * 占位,没有特别的作用
  3 + */
  4 +package cn.iocoder.yudao.module.ai.api;
0 5 \ No newline at end of file
... ...
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
1   -package cn.iocoder.yudao.module.ai;
  1 +package cn.iocoder.yudao.module.ai.enums;
2 2  
3 3 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4  
... ...
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 3 import lombok.AllArgsConstructor;
4 4 import lombok.Getter;
... ... @@ -13,7 +13,7 @@ import lombok.Getter;
13 13 public enum AiImageStatusEnum {
14 14  
15 15 IN_PROGRESS("10", "进行中"),
16   - COMPLETE("20", "完成"),
  16 + SUCCESS("20", "完成"),
17 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
1   -package cn.iocoder.yudao.module.ai.enums;
  1 +package cn.iocoder.yudao.module.ai.enums.model;
2 2  
3 3 import lombok.AllArgsConstructor;
4 4 import lombok.Getter;
... ...
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 4 Content-Type: application/json
6 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 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 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8 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 10 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO;
11 11 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageRespVO;
12 12 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
... ... @@ -48,13 +48,10 @@ public class AiImageController {
48 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 57 @Operation(summary = "删除【我的】绘画记录")
... ... @@ -73,11 +70,11 @@ public class AiImageController {
73 70 return success(imageService.midjourneyImagine(getLoginUserId(), req));
74 71 }
75 72  
76   - // TODO @fan:可以考虑,复用 AiImageDallRespVO,统一成 AIImageRespVO
  73 + // TODO @芋艿:不拦截
77 74 @Operation(summary = "midjourney proxy - 回调通知")
78 75 @RequestMapping("/midjourney-notify")
79 76 public CommonResult<Boolean> midjourneyNotify(MidjourneyNotifyReqVO notifyReqVO) {
80 77 return success(imageService.midjourneyNotify(getLoginUserId(), notifyReqVO));
81 78 }
82 79  
83 80 -}
  81 +}
84 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 5  
6 6 import java.util.Map;
7 7  
8   -// TODO @芋艿:完善 swagger 注解
  8 +@Schema(description = "管理后台 - 绘画 Response VO")
9 9 @Data
10 10 public class AiImageRespVO {
11 11  
12   - @Schema(description = "id编号", example = "1")
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
13 13 private Long id;
14 14  
15   - @Schema(description = "用户id", example = "1")
  15 + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 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 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 42 @Schema(description = "绘画错误信息", example = "图片错误信息")
46 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 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
5 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 7 import com.baomidou.mybatisplus.annotation.KeySequence;
8 8 import com.baomidou.mybatisplus.annotation.TableId;
9 9 import com.baomidou.mybatisplus.annotation.TableName;
10 10 import lombok.*;
11 11  
12 12 import java.time.LocalDateTime;
13   -import java.util.Date;
14 13  
15 14 /**
16 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 5 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
6 6 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
7 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 9 import com.baomidou.mybatisplus.annotation.KeySequence;
10 10 import com.baomidou.mybatisplus.annotation.TableName;
11 11 import lombok.*;
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java
1 1 package cn.iocoder.yudao.module.ai.dal.dataobject.image;
2 2  
3 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 7 import com.baomidou.mybatisplus.annotation.IdType;
5 8 import com.baomidou.mybatisplus.annotation.TableField;
6 9 import com.baomidou.mybatisplus.annotation.TableId;
7 10 import com.baomidou.mybatisplus.annotation.TableName;
8 11 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
9   -import io.swagger.v3.oas.annotations.media.Schema;
10 12 import lombok.Data;
  13 +import org.springframework.ai.openai.OpenAiImageOptions;
  14 +import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
11 15  
12 16 import java.util.Map;
13 17  
... ... @@ -16,70 +20,86 @@ import java.util.Map;
16 20 *
17 21 * @author fansili
18 22 */
19   -@TableName("ai_image")
  23 +@TableName(value = "ai_image", autoResultMap = true)
20 24 @Data
21 25 public class AiImageDO extends BaseDO {
22 26  
23 27 // TODO @fan:1)使用 java 注释哈,不要注解。2)关联、枚举字段,要关联到对应类,参考 AiChatMessageDO 的注释
24 28  
  29 + /**
  30 + * 编号
  31 + */
25 32 @TableId(type = IdType.AUTO)
26 33 private Long id;
27 34  
28   - @Schema(description = "用户编号")
  35 + /**
  36 + * 用户编号
  37 + *
  38 + * 关联 {@link AdminUserRespDTO#getId()}
  39 + */
29 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 45 private String prompt;
36 46  
37   - @Schema(description = "平台")
  47 + /**
  48 + * 平台
  49 + *
  50 + * 枚举 {@link cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum}
  51 + */
38 52 private String platform;
39   -
40   - @Schema(description = "模型")
  53 + /**
  54 + * 模型
  55 + *
  56 + * 冗余 {@link AiChatModelDO#getModel()}
  57 + */
41 58 private String model;
42 59  
43   - @Schema(description = "图片宽度")
  60 + /**
  61 + * 图片宽度
  62 + */
44 63 private Integer width;
45   -
46   - @Schema(description = "图片高度")
  64 + /**
  65 + * 图片高度
  66 + */
47 67 private Integer height;
48 68  
49 69 // TODO @fan:这种就注释绘画状态,然后枚举类关联下就好啦
50   - @Schema(description = "绘画状态:提交、排队、绘画中、绘画完成、绘画失败")
  70 + /**
  71 + * 生成状态
  72 + *
  73 + * 枚举 {@link AiImageStatusEnum}
  74 + */
51 75 private String status;
52 76  
53   - @Schema(description = "是否发布")
54   - private String publicStatus;
55   -
56   - @Schema(description = "图片地址(自己服务器)")
  77 + /**
  78 + * 图片地址
  79 + */
57 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 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 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 25  
26 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
27 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 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 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
9 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 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 12 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
13 13 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
14 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 39 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
40 40 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
41 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 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 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 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 7 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO;
8 8 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
9 9  
... ... @@ -32,12 +32,12 @@ public interface AiImageService {
32 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 43 * midjourney 图片生成
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
1 1 package cn.iocoder.yudao.module.ai.service.image;
2 2  
3   -import cn.hutool.core.bean.BeanUtil;
4 3 import cn.hutool.core.codec.Base64;
  4 +import cn.hutool.core.map.MapUtil;
5 5 import cn.hutool.core.util.ObjUtil;
6 6 import cn.hutool.core.util.StrUtil;
7 7 import cn.hutool.extra.spring.SpringUtil;
8 8 import cn.hutool.http.HttpUtil;
9 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 10 import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory;
13 11 import cn.iocoder.yudao.framework.common.pojo.PageParam;
14 12 import cn.iocoder.yudao.framework.common.pojo.PageResult;
15 13 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
16   -import cn.iocoder.yudao.module.ai.AiCommonConstants;
17 14 import cn.iocoder.yudao.module.ai.client.MidjourneyProxyClient;
18 15 import cn.iocoder.yudao.module.ai.client.enums.MidjourneyModelEnum;
19 16 import cn.iocoder.yudao.module.ai.client.enums.MidjourneySubmitCodeEnum;
... ... @@ -21,17 +18,18 @@ import cn.iocoder.yudao.module.ai.client.enums.MidjourneyTaskStatusEnum;
21 18 import cn.iocoder.yudao.module.ai.client.vo.MidjourneyImagineReqVO;
22 19 import cn.iocoder.yudao.module.ai.client.vo.MidjourneyNotifyReqVO;
23 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 22 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyImagineReqVO;
26 23 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
27 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 26 import cn.iocoder.yudao.module.infra.api.file.FileApi;
31   -import com.google.common.collect.ImmutableMap;
32 27 import jakarta.annotation.Resource;
33 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 33 import org.springframework.ai.openai.OpenAiImageOptions;
36 34 import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
37 35 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -41,7 +39,7 @@ import org.springframework.stereotype.Service;
41 39 import org.springframework.transaction.annotation.Transactional;
42 40  
43 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 45 * AI 绘画 Service 实现类
... ... @@ -78,22 +76,18 @@ public class AiImageServiceImpl implements AiImageService {
78 76 }
79 77  
80 78 @Override
81   - public Long dall(Long userId, AiImageDallReqVO req) {
82   - req.setPlatform("dall"); // TODO 芋艿:临时写死
  79 + public Long drawImage(Long userId, AiImageDrawReqVO drawReqVO) {
83 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 83 imageMapper.insert(image);
90   - // 2. 异步绘制,后续前端通过返回的 id 进行伦旭
91   - getSelf().doDall(image, req);
  84 + // 2. 异步绘制,后续前端通过返回的 id 进行轮询结果
  85 + getSelf().doDall(image, drawReqVO);
92 86 return image.getId();
93 87 }
94 88  
95 89 @Async
96   - public void doDall(AiImageDO image, AiImageDallReqVO req) {
  90 + public void doDall(AiImageDO image, AiImageDrawReqVO req) {
97 91 try {
98 92 // 1.1 构建请求
99 93 ImageOptions request = buildImageOptions(req);
... ... @@ -106,7 +100,7 @@ public class AiImageServiceImpl implements AiImageService {
106 100 String filePath = fileApi.createFile(fileContent);
107 101  
108 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 104 .setPicUrl(filePath));
111 105 } catch (Exception ex) {
112 106 log.error("[doDall][image({}) 生成异常]", image, ex);
... ... @@ -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 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 124 .build();
131 125 }
132   -// return null;
  126 + throw new IllegalArgumentException("不支持的 AI 平台:" + draw.getPlatform());
133 127 }
134 128  
135 129 @Override
136 130 @Transactional(rollbackFor = Exception.class)
137 131 public Long midjourneyImagine(Long loginUserId, AiImageMidjourneyImagineReqVO req) {
138   -
139 132 // 1、构建 AiImageDO
140 133 AiImageDO aiImageDO = new AiImageDO();
141   - aiImageDO.setId(null);
142 134 aiImageDO.setUserId(loginUserId);
143 135 aiImageDO.setPrompt(req.getPrompt());
144 136 aiImageDO.setPlatform(AiPlatformEnum.MIDJOURNEY.getPlatform());
... ... @@ -147,12 +139,6 @@ public class AiImageServiceImpl implements AiImageService {
147 139 aiImageDO.setWidth(null);
148 140 aiImageDO.setHeight(null);
149 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 143 // 2、保存 image
158 144 imageMapper.insert(aiImageDO);
... ... @@ -211,7 +197,7 @@ public class AiImageServiceImpl implements AiImageService {
211 197 //
212 198 String imageStatus = null;
213 199 if (MidjourneyTaskStatusEnum.SUCCESS == notifyReqVO.getStatus()) {
214   - imageStatus = AiImageStatusEnum.COMPLETE.getStatus();
  200 + imageStatus = AiImageStatusEnum.SUCCESS.getStatus();
215 201 } else if (MidjourneyTaskStatusEnum.FAILURE == notifyReqVO.getStatus()) {
216 202 imageStatus = AiImageStatusEnum.FAIL.getStatus();
217 203 }
... ... @@ -226,8 +212,7 @@ public class AiImageServiceImpl implements AiImageService {
226 212 .setId(image.getId())
227 213 .setStatus(imageStatus)
228 214 .setPicUrl(filePath)
229   - .setOriginalPicUrl(notifyReqVO.getImageUrl())
230   - .setDrawResponse(BeanUtil.beanToMap(notifyReqVO))
  215 +// .setOriginalPicUrl(notifyReqVO.getImageUrl()) TODO @fan:就不存原始的图片地址啦
231 216 );
232 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 5 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyOperationsVO;
6 6 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
7 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 9 import com.alibaba.fastjson.JSON;
10 10 import lombok.AllArgsConstructor;
11 11 import lombok.extern.slf4j.Slf4j;
... ... @@ -89,7 +89,7 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler {
89 89 AiImageStatusEnum drawingStatusEnum = null;
90 90 String generateStatus = midjourneyMessage.getGenerateStatus();
91 91 if (MidjourneyGennerateStatusEnum.COMPLETED.getStatus().equals(generateStatus)) {
92   - drawingStatusEnum = AiImageStatusEnum.COMPLETE;
  92 + drawingStatusEnum = AiImageStatusEnum.SUCCESS;
93 93 } else if (MidjourneyGennerateStatusEnum.IN_PROGRESS.getStatus().equals(generateStatus)) {
94 94 drawingStatusEnum = AiImageStatusEnum.IN_PROGRESS;
95 95 }
... ... @@ -101,7 +101,6 @@ public class YuDaoMidjourneyMessageHandler implements MidjourneyMessageHandler {
101 101 // 更新数据库
102 102 aiImageMapper.updateByMjNonce(nonceId,
103 103 new AiImageDO()
104   - .setOriginalPicUrl(imageUrl)
105 104 .setStatus(drawingStatusEnum == null ? null : drawingStatusEnum.getStatus())
106 105 // .setMjNonceId(midjourneyMessage.getId())
107 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 17 import java.util.List;
18 18  
19 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 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 16 import java.util.List;
17 17  
18 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 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 21  
22 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
23 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 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 3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 4 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
5 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 6 import lombok.Data;
9 7 import lombok.experimental.Accessors;
  8 +import org.springframework.ai.autoconfigure.openai.OpenAiImageProperties;
10 9 import org.springframework.boot.context.properties.ConfigurationProperties;
11 10  
12 11 /**
... ... @@ -94,27 +93,6 @@ public class YudaoAiProperties {
94 93  
95 94 @Data
96 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 96 public static class MidjourneyProperties {
119 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 20 QIAN_WEN("QianWen", "千问"), // 阿里
21 21 GEMIR ("gemir ", "gemir "), // 谷歌
22 22  
23   - OPEN_AI_DALL("dall", "dall"), // TODO OpenAI 提供的绘图,接入中;TODO 要不要统一下?!
24 23 STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI
25 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 33 import org.springframework.ai.openai.OpenAiImageClient;
34 34 import org.springframework.ai.openai.api.ApiUtils;
35 35 import org.springframework.ai.openai.api.OpenAiApi;
  36 +import org.springframework.ai.stabilityai.StabilityAiImageClient;
36 37  
37 38 import java.util.List;
38 39  
... ... @@ -88,12 +89,15 @@ public class AiClientFactoryImpl implements AiClientFactory {
88 89  
89 90 @Override
90 91 public ImageClient getDefaultImageClient(AiPlatformEnum platform) {
  92 + //noinspection EnhancedSwitchMigration
91 93 switch (platform) {
92   - case OPEN_AI_DALL:
  94 + case OPENAI:
93 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 103 private static String buildClientCacheKey(Class<?> clazz, Object... params) {
... ...