Browse Source

【调整】根据接口设计调整,ai model

cherishsince 1 year ago
parent
commit
c21b5f7679
16 changed files with 392 additions and 66 deletions
  1. 14 11
      yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java
  2. 11 0
      yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatModalTypeEnum.java
  3. 1 1
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/AiChatModalController.java
  4. 8 12
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/AiChatModalDO.java
  5. 35 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalChatConfigVO.java
  6. 28 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalConfigVO.java
  7. 41 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalDallConfigVO.java
  8. 16 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalMidjourneyConfigVO.java
  9. 75 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/mapper/typeHandler/AiChatModelConfigTypeHandler.java
  10. 78 2
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatModalServiceImpl.java
  11. 2 3
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiImageServiceImpl.java
  12. 15 7
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/AiChatModalAddReq.java
  13. 20 22
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/AiChatModalListRes.java
  14. 28 6
      yudao-module-ai/yudao-module-ai-biz/src/main/resources/http/chat-modal.http
  15. 18 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/AiPlatformEnum.java
  16. 2 2
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java

+ 14 - 11
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java

@@ -11,24 +11,27 @@ public interface ErrorCodeConstants {
 
     // ========== 模块 ai 错误码区间 [1-022-000-000 ~ 1-023-000-000) ==========
 
-    // TODO @fansili:1)类注释不太对;2)中英文之间,有个空格;例如说 AI 模型
-    ErrorCode AI_MODULE_NOT_SUPPORTED = new ErrorCode(1_022_000_000, "AI模型暂不支持!");
+    // chat
 
+    ErrorCode AI_MODULE_NOT_SUPPORTED = new ErrorCode(1_022_000_000, "AI 模型暂不支持!");
     ErrorCode AI_CHAT_ROLE_NOT_EXISTENT = new ErrorCode(1_022_000_001, "AI Role 不存在!");;
+    ErrorCode AI_CHAT_CONTINUE_CONVERSATION_ID_NOT_NULL = new ErrorCode(1_022_000_002, "chat 继续对话,对话 id 不能为空!");;
+    ErrorCode AI_CHAT_CONTINUE_NOT_EXIST = new ErrorCode(1_022_000_020, "chat 对话不存在!");
+    ErrorCode AI_CHAT_CONVERSATION_NOT_YOURS = new ErrorCode(1_022_000_021, "这条 chat 对话不是你的!");
 
-
-    ErrorCode AI_CHAT_CONTINUE_CONVERSATION_ID_NOT_NULL = new ErrorCode(1_022_000_002, "chat 继续对话,对话id不能为空!");;
-
-
-
-    ErrorCode AI_CHAT_CONTINUE_NOT_EXIST = new ErrorCode(1_022_000_020, "chat对话不存在!");
-    ErrorCode AI_CHAT_CONVERSATION_NOT_YOURS = new ErrorCode(1_022_000_021, "这条chat对话不是你的!");
+    // midjourney
 
     ErrorCode AI_MIDJOURNEY_IMAGINE_FAIL = new ErrorCode(1_022_000_040, "midjourney imagine 操作失败!");
 
-    ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "chatRole不存在!");
+    // role
+
+    ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "chatRole 不存在!");
 
-    ErrorCode AI_MODAL_NOT_EXIST = new ErrorCode(1_022_000_080, "ai模型不存在!");
+    // modal
 
+    ErrorCode AI_MODAL_NOT_EXIST = new ErrorCode(1_022_000_080, "AI 模型不存在!");
+    ErrorCode AI_MODAL_CONFIG_PARAMS_INCORRECT = new ErrorCode(1_022_000_081, "AI 模型 config 参数不正确! {} ");
+    ErrorCode AI_MODAL_NOT_SUPPORTED_MODAL = new ErrorCode(1_022_000_082, "AI 模型不支持的 modal! {} ");
+    ErrorCode AI_MODAL_PLATFORM_PARAMS_INCORRECT = new ErrorCode(1_022_000_083, "AI 平台参数不正确! {} ");
 
 }

+ 11 - 0
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatModalTypeEnum.java

@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.ai.enums;
+
+/**
+ * 枚举
+ *
+ * @author fansili
+ * @time 2024/5/6 11:48
+ * @since 1.0
+ */
+public enum AiChatModalTypeEnum {
+}

+ 1 - 1
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/AiChatModalController.java

@@ -30,7 +30,7 @@ public class AiChatModalController {
 
     private final AiChatModalService aiChatModalService;
 
-    @Operation(summary = "ai模型 - 模型照片上传")
+    @Operation(summary = "ai模型 - 模型列表")
     @GetMapping("/modal/list")
     public PageResult<AiChatModalListRes> list(@ModelAttribute AiChatModalListReq req) {
         return aiChatModalService.list(req);

+ 8 - 12
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/AiChatModalDO.java

@@ -22,27 +22,23 @@ public class AiChatModalDO extends BaseDO {
      */
     private Long id;
     /**
-     * 模型key
+     * 名字
      */
-    private String modelKey;
+    private String name;
     /**
-     * 模型类型 参考:{@link cn.iocoder.yudao.framework.ai.AiPlatformEnum}
-     */
-    private String modelPlatform;
-    /**
-     * 模型类型
+     * 类型
      * {@link cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel}
      * {@link cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel}
      */
-    private String modelType;
+    private String modal;
     /**
-     * 模型名字
+     * 平台 参考:{@link cn.iocoder.yudao.framework.ai.AiPlatformEnum}
      */
-    private String modelName;
+    private String platform;
     /**
-     * 模型照片
+     * 图片地址
      */
-    private String modalImage;
+    private String imageUrl;
     /**
      * 禁用 0、正常 1、禁用
      */

+ 35 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalChatConfigVO.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.ai.dal.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * chat config
+ *
+ * @author fansili
+ * @time 2024/5/6 15:06
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class AiChatModalChatConfigVO extends AiChatModalConfigVO {
+
+    @NotNull
+    @Schema(description = "在生成消息时采用的Top-K采样大小")
+    private Double topK;
+
+    @NotNull
+    @Schema(description = "Top-P核采样方法的概率阈值")
+    private Double topP;
+
+    @NotNull
+    @Schema(description = "温度参数,用于调整生成回复的随机性和多样性程度")
+    private Double temperature;
+
+    @NotNull
+    @Schema(description = "最大 tokens")
+    private Integer maxTokens;
+
+}

+ 28 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalConfigVO.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.ai.dal.vo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * modal config
+ *
+ * @author fansili
+ * @time 2024/5/6 15:06
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class AiChatModalConfigVO {
+
+    /**
+     * 模型平台 (冗余,方便类型转换)
+     * 参考:{@link cn.iocoder.yudao.framework.ai.AiPlatformEnum}
+     */
+    private String platform;
+    /**
+     * 模型类型(冗余,方便类型转换)
+     * {@link cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel}
+     * {@link cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel}
+     */
+    private String type;
+}

+ 41 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalDallConfigVO.java

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.ai.dal.vo;
+
+import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * dall
+ *
+ * @author fansili
+ * @time 2024/5/6 15:06
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class AiChatModalDallConfigVO extends AiChatModalConfigVO {
+    // 可选字段,默认为1
+    // 生成图像的数量,必须在1到10之间。对于dall-e-3模型,目前仅支持n=1。
+    private Integer n = 1;
+
+    // 可选字段,默认为standard
+    // 设置生成图像的质量。hd质量将创建细节更丰富、图像整体一致性更高的图片。该参数仅对dall-e-3模型有效。
+    private String quality = "standard";
+
+    // 可选字段,默认为url
+    // 返回生成图像的格式。必须是url或b64_json中的一种。URL链接的有效期是从生成图像后开始计算的60分钟内有效。
+    private String responseFormat = "url";
+
+    // 可选字段,默认为1024x1024
+    // 生成图像的尺寸大小。对于dall-e-2模型,尺寸可为256x256, 512x512, 或 1024x1024。对于dall-e-3模型,尺寸可为1024x1024, 1792x1024, 或 1024x1792。
+    private String size = "1024x1024";
+
+    // 可选字段,默认为vivid
+    // 图像生成的风格。可为vivid(生动)或natural(自然)。vivid会使模型偏向生成超现实和戏剧性的图像,而natural则会让模型产出更自然、不那么超现实的图像。该参数仅对dall-e-3模型有效。
+    private OpenAiImageStyleEnum style = OpenAiImageStyleEnum.VIVID;
+
+    // 可选字段
+    // 代表您的终端用户的唯一标识符,有助于OpenAI监控并检测滥用行为。了解更多信息请参考官方文档。
+    private String endUserId = "UID123456";
+
+}

+ 16 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalMidjourneyConfigVO.java

@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.ai.dal.vo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * Midjourney Config
+ *
+ * @author fansili
+ * @time 2024/5/6 15:07
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class AiChatModalMidjourneyConfigVO extends AiChatModalConfigVO {
+}

+ 75 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/mapper/typeHandler/AiChatModelConfigTypeHandler.java

@@ -0,0 +1,75 @@
+//package cn.iocoder.yudao.module.ai.mapper.typeHandler;
+//
+//import cn.hutool.core.util.StrUtil;
+//import cn.iocoder.yudao.framework.ai.AiPlatformEnum;
+//import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+//import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatModalDO;
+//import org.apache.ibatis.type.BaseTypeHandler;
+//import org.apache.ibatis.type.JdbcType;
+//import org.apache.ibatis.type.MappedTypes;
+//
+//import java.sql.CallableStatement;
+//import java.sql.PreparedStatement;
+//import java.sql.ResultSet;
+//import java.sql.SQLException;
+//
+///**
+// * chat modal config
+// *
+// * @author fansili
+// * @time 2024/5/6 11:18
+// * @since 1.0
+// */
+//@MappedTypes(value = AiChatModalDO.Config.class)
+//public class AiChatModelConfigTypeHandler extends BaseTypeHandler<AiChatModalDO.Config> {
+//
+//    @Override
+//    public void setNonNullParameter(PreparedStatement ps, int i, AiChatModalDO.Config parameter, JdbcType jdbcType) throws SQLException {
+//        // 将 MyCustomType 转换为数据库类型并设置到 PreparedStatement 中
+//        if (parameter == null) {
+//            ps.setString(i, "");
+//        } else {
+//            ps.setString(i, JsonUtils.toJsonString(parameter));
+//        }
+//    }
+//
+//    @Override
+//    public AiChatModalDO.Config getNullableResult(ResultSet rs, String columnName) throws SQLException {
+//        // 从 ResultSet 中获取数据库类型并转换为 MyCustomType
+//        String str = rs.getString(columnName);
+//        if (StrUtil.isBlank(str)) {
+//            return null;
+//        }
+//        AiChatModalDO.Config config = JsonUtils.parseObject(str, AiChatModalDO.Config.class);
+//        // 获取平台
+//        AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(config.getModelPlatform());
+//        if (AiPlatformEnum.CHAT_PLATFORM_LIST.contains(platformEnum)) {
+//            return JsonUtils.parseObject(str, AiChatModalDO.ChatConfig.class);
+//        } else if (AiPlatformEnum.OPEN_AI_DALL == platformEnum) {
+//            return JsonUtils.parseObject(str, AiChatModalDO.OpenAiImageConfig.class);
+//        } else if (AiPlatformEnum.MIDJOURNEY == platformEnum) {
+//            return JsonUtils.parseObject(str, AiChatModalDO.MidjourneyConfig.class);
+//        }
+//        throw new IllegalArgumentException("ai模型中config不能转换! json: " + str);
+//    }
+//
+//    @Override
+//    public AiChatModalDO.Config getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+//        // 从 ResultSet 中获取数据库类型并转换为 MyCustomType
+//        String str = rs.getString(columnIndex);
+//        if (StrUtil.isBlank(str)) {
+//            return null;
+//        }
+//        return JsonUtils.parseObject(str, AiChatModalDO.Config.class);
+//    }
+//
+//    @Override
+//    public AiChatModalDO.Config getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+//        // 从 CallableStatement 中获取数据库类型并转换为 MyCustomType
+//        String str = cs.getString(columnIndex);
+//        if (StrUtil.isBlank(str)) {
+//            return null;
+//        }
+//        return JsonUtils.parseObject(str, AiChatModalDO.Config.class);
+//    }
+//}

+ 78 - 2
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatModalServiceImpl.java

@@ -1,23 +1,34 @@
 package cn.iocoder.yudao.module.ai.service.impl;
 
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.validation.ValidationUtil;
+import cn.iocoder.yudao.framework.ai.AiPlatformEnum;
+import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatModal;
+import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel;
+import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel;
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
 import cn.iocoder.yudao.module.ai.convert.AiChatModalConvert;
 import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatModalDO;
+import cn.iocoder.yudao.module.ai.dal.vo.AiChatModalChatConfigVO;
+import cn.iocoder.yudao.module.ai.dal.vo.AiChatModalConfigVO;
+import cn.iocoder.yudao.module.ai.dal.vo.AiChatModalDallConfigVO;
 import cn.iocoder.yudao.module.ai.enums.AiChatModalDisableEnum;
 import cn.iocoder.yudao.module.ai.mapper.AiChatModalMapper;
 import cn.iocoder.yudao.module.ai.service.AiChatModalService;
 import cn.iocoder.yudao.module.ai.vo.AiChatModalAddReq;
 import cn.iocoder.yudao.module.ai.vo.AiChatModalListReq;
 import cn.iocoder.yudao.module.ai.vo.AiChatModalListRes;
+import jakarta.validation.ConstraintViolation;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * ai 模型
@@ -40,7 +51,7 @@ public class AiChatModalServiceImpl implements AiChatModalService {
         queryWrapperX.eq(AiChatModalDO::getDisable, AiChatModalDisableEnum.NO.getValue());
         // search
         if (!StrUtil.isBlank(req.getSearch())) {
-            queryWrapperX.like(AiChatModalDO::getModelName, req.getSearch().trim());
+            queryWrapperX.like(AiChatModalDO::getName, req.getSearch().trim());
         }
         // 默认排序
         queryWrapperX.orderByDesc(AiChatModalDO::getId);
@@ -53,21 +64,38 @@ public class AiChatModalServiceImpl implements AiChatModalService {
 
     @Override
     public void add(AiChatModalAddReq req) {
+        // 校验 platform、type
+        validatePlatform(req.getPlatform());
+        validateModal(req.getPlatform(), req.getModal());
+        // 转换config
+        AiChatModalConfigVO aiChatModalConfigVO = convertConfig(req);
+        // 校验 modal config
+        validateModalConfig(aiChatModalConfigVO);
         // 转换 do
         AiChatModalDO insertChatModalDO = AiChatModalConvert.INSTANCE.convertAiChatModalDO(req);
-        //
+        // 设置默认属性
         insertChatModalDO.setDisable(AiChatModalDisableEnum.NO.getValue());
+        insertChatModalDO.setConfig(JsonUtils.toJsonString(aiChatModalConfigVO));
         // 保存数据库
         aiChatModalMapper.insert(insertChatModalDO);
     }
 
     @Override
     public void update(Long id, AiChatModalAddReq req) {
+        // 校验 platform、type
+        validatePlatform(req.getPlatform());
+        validateModal(req.getPlatform(), req.getModal());
+        // 转换config
+        AiChatModalConfigVO aiChatModalConfigVO = convertConfig(req);
+        // 校验 modal config
+        validateModalConfig(aiChatModalConfigVO);
+
         // 校验模型是否存在
         validateChatModalExists(id);
         // 转换 updateChatModalDO
         AiChatModalDO updateChatModalDO = AiChatModalConvert.INSTANCE.convertAiChatModalDO(req);
         updateChatModalDO.setId(id);
+        updateChatModalDO.setConfig(JsonUtils.toJsonString(aiChatModalConfigVO));
         // 更新数据库
         aiChatModalMapper.updateById(updateChatModalDO);
     }
@@ -86,4 +114,52 @@ public class AiChatModalServiceImpl implements AiChatModalService {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_NOT_EXIST);
         }
     }
+
+    private void validateModal(String platform, String modal) {
+        AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(platform);
+        try {
+            if (AiPlatformEnum.QIAN_WEN == platformEnum) {
+                QianWenChatModal.valueOfModel(modal);
+            } else if (AiPlatformEnum.XING_HUO == platformEnum) {
+                XingHuoChatModel.valueOfModel(modal);
+            } else if (AiPlatformEnum.YI_YAN == platformEnum) {
+                YiYanChatModel.valueOfModel(modal);
+            } else {
+                throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_NOT_SUPPORTED_MODAL, platform);
+            }
+        } catch (IllegalArgumentException e) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_CONFIG_PARAMS_INCORRECT, e.getMessage());
+        }
+    }
+
+    private void validatePlatform(String platform) {
+        try {
+            AiPlatformEnum.valueOfPlatform(platform);
+        } catch (IllegalArgumentException e) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_PLATFORM_PARAMS_INCORRECT, e.getMessage());
+        }
+    }
+
+    private void validateModalConfig(AiChatModalConfigVO aiChatModalConfigVO) {
+        Set<ConstraintViolation<AiChatModalConfigVO>> validate = ValidationUtil.validate(aiChatModalConfigVO);
+        for (ConstraintViolation<AiChatModalConfigVO> constraintViolation : validate) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_CONFIG_PARAMS_INCORRECT, constraintViolation.getMessage());
+        }
+    }
+
+    private static AiChatModalConfigVO convertConfig(AiChatModalAddReq req) {
+        AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(req.getPlatform());
+        AiChatModalConfigVO resVo = null;
+        if (AiPlatformEnum.CHAT_PLATFORM_LIST.contains(platformEnum)) {
+            resVo = JsonUtils.parseObject(JsonUtils.toJsonString(req.getConfig()), AiChatModalChatConfigVO.class);
+        } else if (AiPlatformEnum.OPEN_AI_DALL == platformEnum) {
+            resVo = JsonUtils.parseObject(JsonUtils.toJsonString(req.getConfig()), AiChatModalDallConfigVO.class);
+        }
+        if (resVo == null) {
+            throw new IllegalArgumentException("ai模型中config不能转换! json: " + req.getConfig());
+        }
+        resVo.setType(req.getModal());
+        resVo.setPlatform(req.getPlatform());
+        return resVo;
+    }
 }

+ 2 - 3
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiImageServiceImpl.java

@@ -5,9 +5,9 @@ import cn.iocoder.yudao.framework.ai.image.ImageGeneration;
 import cn.iocoder.yudao.framework.ai.image.ImagePrompt;
 import cn.iocoder.yudao.framework.ai.image.ImageResponse;
 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageClient;
-import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageModelEnum;
+import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum;
 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions;
-import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageStyleEnum;
+import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum;
 import cn.iocoder.yudao.framework.ai.midjourney.api.MidjourneyInteractionsApi;
 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyWebSocketStarter;
 import cn.iocoder.yudao.framework.ai.midjourney.webSocket.WssNotify;
@@ -21,7 +21,6 @@ import cn.iocoder.yudao.module.ai.mapper.AiImageMapper;
 import cn.iocoder.yudao.module.ai.service.AiImageService;
 import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq;
 import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyReq;
-import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyRes;
 import jakarta.annotation.PostConstruct;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;

+ 15 - 7
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/AiChatModalAddReq.java

@@ -6,6 +6,8 @@ import jakarta.validation.constraints.Size;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
+import java.util.Map;
+
 /**
  * ai chat modal
  *
@@ -19,18 +21,24 @@ public class AiChatModalAddReq {
 
     @NotNull
     @Schema(description = "模型名字")
-    @Size(max = 60, message = "模型名字最大60")
-    private String modelName;
+    @Size(max = 60, message = "模型名字最大60个字符")
+    private String name;
+
+    @NotNull
+    @Size(max = 32, message = "模型平台最大32个字符")
+    @Schema(description = "模型平台 参考 AiPlatformEnum")
+    private String platform;
 
     @NotNull
     @Schema(description = "模型类型(qianwen、yiyan、xinghuo、openai)")
-    @Size(max = 32, message = "模型类型最大32")
-    private String modelType;
+    @Size(max = 32, message = "模型类型最大32个字符")
+    private String modal;
 
     @Schema(description = "模型照片")
-    private String modalImage;
+    @Size(max = 256, message = "模型照片地址最大256个字符")
+    private String imageUrl;
 
     @Schema(description = "模型配置JSON")
-    private String modelConfig;
-
+//    @Size(max = 1024, message = "模型配置最大1024个字符")
+    private Map<String, Object> config;
 }

+ 20 - 22
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/AiChatModalListRes.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.ai.vo;
 
+import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatModalDO;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
@@ -13,29 +15,25 @@ import lombok.experimental.Accessors;
 @Data
 @Accessors(chain = true)
 public class AiChatModalListRes {
-    /**
-     * 编号
-     */
+
+    @Schema(description = "id")
     private Long id;
-    /**
-     * 模型名字
-     */
-    private String modelName;
-    /**
-     * 模型类型(qianwen、yiyan、xinghuo、openai)
-     */
-    private String modelType;
-    /**
-     * 模型照片
-     */
-    private String modalImage;
-    /**
-     * 模型配置JSON
-     */
-    private String modelConfig;
-    /**
-     * 禁用 0、正常 1、禁用
-     */
+
+    @Schema(description = "模型平台 参考 AiPlatformEnum")
+    private String platform;
+
+    @Schema(description = "模型类型 参考 YiYanChatModel、XingHuoChatModel")
+    private String modal;
+
+    @Schema(description = "模型名字")
+    private String name;
+
+    @Schema(description = "模型照片")
+    private String image;
+
+    @Schema(description = "禁用 0、正常 1、禁用")
     private Integer disable;
 
+    @Schema(description = "modal 配置")
+    private String config;
 }

+ 28 - 6
yudao-module-ai/yudao-module-ai-biz/src/main/resources/http/chat-modal.http

@@ -1,19 +1,41 @@
 
-
 ### chat call
 GET {{baseUrl}}/ai/chat/modal/list
 Authorization: {{token}}
 
 
-
 ### chat call
 PUT {{baseUrl}}/ai/chat/modal
 Content-Type: application/json
 Authorization: {{token}}
 
 {
-  "modelName": "小红书Ai写作大模型",
-  "modelType": "yiyan",
-  "modalImage": "",
-  "modelConfig": ""
+  "name": "小红书Ai写作大模型-plus",
+  "modal": "ERNIE-3.5-8K",
+  "platform": "yiyan",
+  "imageUrl": "",
+  "config": {
+    "topK": 0.6,
+    "topP": 0.6,
+    "temperature": 0.86,
+    "maxTokens": 2048
+  }
+}
+
+### chat call
+POST {{baseUrl}}/ai/chat/modal/7
+Content-Type: application/json
+Authorization: {{token}}
+
+{
+  "name": "小红书Ai写作大模型-plus",
+  "modal": "ERNIE-3.5-8K",
+  "platform": "yiyan",
+  "imageUrl": "",
+  "config": {
+    "topK": 0.6,
+    "topP": 0.6,
+    "temperature": 0.86,
+    "maxTokens": 2048
+  }
 }

+ 18 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/AiPlatformEnum.java

@@ -1,8 +1,11 @@
 package cn.iocoder.yudao.framework.ai;
 
+import com.google.common.collect.Lists;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
+import java.util.List;
+
 /**
  * ai 模型平台
  *
@@ -17,12 +20,27 @@ public enum AiPlatformEnum {
     YI_YAN("yiyan", "一言"),
     QIAN_WEN("qianwen", "千问"),
     XING_HUO("xinghuo", "星火"),
+    OPEN_AI("openai", "openAi"),
+    OPEN_AI_DALL("dall", "dall"),
+    MIDJOURNEY("midjourney", "midjourney"),
 
     ;
 
     private String platform;
     private String name;
 
+    public static List<AiPlatformEnum> CHAT_PLATFORM_LIST = Lists.newArrayList(
+            AiPlatformEnum.YI_YAN,
+            AiPlatformEnum.QIAN_WEN,
+            AiPlatformEnum.XING_HUO,
+            AiPlatformEnum.OPEN_AI
+    );
+
+    public static List<AiPlatformEnum> IMAGE_PLATFORM_LIST = Lists.newArrayList(
+            AiPlatformEnum.OPEN_AI_DALL,
+            AiPlatformEnum.MIDJOURNEY
+    );
+
     public static AiPlatformEnum valueOfPlatform(String platform) {
         for (AiPlatformEnum itemEnum : AiPlatformEnum.values()) {
             if (itemEnum.getPlatform().equals(platform)) {

+ 2 - 2
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java

@@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.ai.config;
 import cn.iocoder.yudao.framework.ai.AiPlatformEnum;
 import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel;
 import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel;
-import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageModelEnum;
-import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageStyleEnum;
+import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum;
+import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum;
 import lombok.Data;
 import lombok.experimental.Accessors;
 import org.springframework.boot.context.properties.ConfigurationProperties;