Commit c21b5f76790e9cc05bfa0dd2545be057e96e1f94
1 parent
11815842
【调整】根据接口设计调整,ai model
Showing
16 changed files
with
392 additions
and
66 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java
| ... | ... | @@ -11,24 +11,27 @@ public interface ErrorCodeConstants { |
| 11 | 11 | |
| 12 | 12 | // ========== 模块 ai 错误码区间 [1-022-000-000 ~ 1-023-000-000) ========== |
| 13 | 13 | |
| 14 | - // TODO @fansili:1)类注释不太对;2)中英文之间,有个空格;例如说 AI 模型 | |
| 15 | - ErrorCode AI_MODULE_NOT_SUPPORTED = new ErrorCode(1_022_000_000, "AI模型暂不支持!"); | |
| 14 | + // chat | |
| 16 | 15 | |
| 16 | + ErrorCode AI_MODULE_NOT_SUPPORTED = new ErrorCode(1_022_000_000, "AI 模型暂不支持!"); | |
| 17 | 17 | ErrorCode AI_CHAT_ROLE_NOT_EXISTENT = new ErrorCode(1_022_000_001, "AI Role 不存在!");; |
| 18 | + ErrorCode AI_CHAT_CONTINUE_CONVERSATION_ID_NOT_NULL = new ErrorCode(1_022_000_002, "chat 继续对话,对话 id 不能为空!");; | |
| 19 | + ErrorCode AI_CHAT_CONTINUE_NOT_EXIST = new ErrorCode(1_022_000_020, "chat 对话不存在!"); | |
| 20 | + ErrorCode AI_CHAT_CONVERSATION_NOT_YOURS = new ErrorCode(1_022_000_021, "这条 chat 对话不是你的!"); | |
| 18 | 21 | |
| 19 | - | |
| 20 | - ErrorCode AI_CHAT_CONTINUE_CONVERSATION_ID_NOT_NULL = new ErrorCode(1_022_000_002, "chat 继续对话,对话id不能为空!");; | |
| 21 | - | |
| 22 | - | |
| 23 | - | |
| 24 | - ErrorCode AI_CHAT_CONTINUE_NOT_EXIST = new ErrorCode(1_022_000_020, "chat对话不存在!"); | |
| 25 | - ErrorCode AI_CHAT_CONVERSATION_NOT_YOURS = new ErrorCode(1_022_000_021, "这条chat对话不是你的!"); | |
| 22 | + // midjourney | |
| 26 | 23 | |
| 27 | 24 | ErrorCode AI_MIDJOURNEY_IMAGINE_FAIL = new ErrorCode(1_022_000_040, "midjourney imagine 操作失败!"); |
| 28 | 25 | |
| 29 | - ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "chatRole不存在!"); | |
| 26 | + // role | |
| 27 | + | |
| 28 | + ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "chatRole 不存在!"); | |
| 30 | 29 | |
| 31 | - ErrorCode AI_MODAL_NOT_EXIST = new ErrorCode(1_022_000_080, "ai模型不存在!"); | |
| 30 | + // modal | |
| 32 | 31 | |
| 32 | + ErrorCode AI_MODAL_NOT_EXIST = new ErrorCode(1_022_000_080, "AI 模型不存在!"); | |
| 33 | + ErrorCode AI_MODAL_CONFIG_PARAMS_INCORRECT = new ErrorCode(1_022_000_081, "AI 模型 config 参数不正确! {} "); | |
| 34 | + ErrorCode AI_MODAL_NOT_SUPPORTED_MODAL = new ErrorCode(1_022_000_082, "AI 模型不支持的 modal! {} "); | |
| 35 | + ErrorCode AI_MODAL_PLATFORM_PARAMS_INCORRECT = new ErrorCode(1_022_000_083, "AI 平台参数不正确! {} "); | |
| 33 | 36 | |
| 34 | 37 | } | ... | ... |
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatModalTypeEnum.java
0 → 100644
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 { |
| 30 | 30 | |
| 31 | 31 | private final AiChatModalService aiChatModalService; |
| 32 | 32 | |
| 33 | - @Operation(summary = "ai模型 - 模型照片上传") | |
| 33 | + @Operation(summary = "ai模型 - 模型列表") | |
| 34 | 34 | @GetMapping("/modal/list") |
| 35 | 35 | public PageResult<AiChatModalListRes> list(@ModelAttribute AiChatModalListReq req) { |
| 36 | 36 | return aiChatModalService.list(req); | ... | ... |
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 { |
| 22 | 22 | */ |
| 23 | 23 | private Long id; |
| 24 | 24 | /** |
| 25 | - * 模型key | |
| 25 | + * 名字 | |
| 26 | 26 | */ |
| 27 | - private String modelKey; | |
| 27 | + private String name; | |
| 28 | 28 | /** |
| 29 | - * 模型类型 参考:{@link cn.iocoder.yudao.framework.ai.AiPlatformEnum} | |
| 30 | - */ | |
| 31 | - private String modelPlatform; | |
| 32 | - /** | |
| 33 | - * 模型类型 | |
| 29 | + * 类型 | |
| 34 | 30 | * {@link cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel} |
| 35 | 31 | * {@link cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel} |
| 36 | 32 | */ |
| 37 | - private String modelType; | |
| 33 | + private String modal; | |
| 38 | 34 | /** |
| 39 | - * 模型名字 | |
| 35 | + * 平台 参考:{@link cn.iocoder.yudao.framework.ai.AiPlatformEnum} | |
| 40 | 36 | */ |
| 41 | - private String modelName; | |
| 37 | + private String platform; | |
| 42 | 38 | /** |
| 43 | - * 模型照片 | |
| 39 | + * 图片地址 | |
| 44 | 40 | */ |
| 45 | - private String modalImage; | |
| 41 | + private String imageUrl; | |
| 46 | 42 | /** |
| 47 | 43 | * 禁用 0、正常 1、禁用 |
| 48 | 44 | */ | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalChatConfigVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.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/dal/vo/AiChatModalConfigVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.vo; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | +import lombok.experimental.Accessors; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * modal config | |
| 8 | + * | |
| 9 | + * @author fansili | |
| 10 | + * @time 2024/5/6 15:06 | |
| 11 | + * @since 1.0 | |
| 12 | + */ | |
| 13 | +@Data | |
| 14 | +@Accessors(chain = true) | |
| 15 | +public class AiChatModalConfigVO { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 模型平台 (冗余,方便类型转换) | |
| 19 | + * 参考:{@link cn.iocoder.yudao.framework.ai.AiPlatformEnum} | |
| 20 | + */ | |
| 21 | + private String platform; | |
| 22 | + /** | |
| 23 | + * 模型类型(冗余,方便类型转换) | |
| 24 | + * {@link cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel} | |
| 25 | + * {@link cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel} | |
| 26 | + */ | |
| 27 | + private String type; | |
| 28 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/vo/AiChatModalDallConfigVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.imageopenai.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/dal/vo/AiChatModalMidjourneyConfigVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.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/mapper/typeHandler/AiChatModelConfigTypeHandler.java
0 → 100644
| 1 | +//package cn.iocoder.yudao.module.ai.mapper.typeHandler; | |
| 2 | +// | |
| 3 | +//import cn.hutool.core.util.StrUtil; | |
| 4 | +//import cn.iocoder.yudao.framework.ai.AiPlatformEnum; | |
| 5 | +//import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 6 | +//import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatModalDO; | |
| 7 | +//import org.apache.ibatis.type.BaseTypeHandler; | |
| 8 | +//import org.apache.ibatis.type.JdbcType; | |
| 9 | +//import org.apache.ibatis.type.MappedTypes; | |
| 10 | +// | |
| 11 | +//import java.sql.CallableStatement; | |
| 12 | +//import java.sql.PreparedStatement; | |
| 13 | +//import java.sql.ResultSet; | |
| 14 | +//import java.sql.SQLException; | |
| 15 | +// | |
| 16 | +///** | |
| 17 | +// * chat modal config | |
| 18 | +// * | |
| 19 | +// * @author fansili | |
| 20 | +// * @time 2024/5/6 11:18 | |
| 21 | +// * @since 1.0 | |
| 22 | +// */ | |
| 23 | +//@MappedTypes(value = AiChatModalDO.Config.class) | |
| 24 | +//public class AiChatModelConfigTypeHandler extends BaseTypeHandler<AiChatModalDO.Config> { | |
| 25 | +// | |
| 26 | +// @Override | |
| 27 | +// public void setNonNullParameter(PreparedStatement ps, int i, AiChatModalDO.Config parameter, JdbcType jdbcType) throws SQLException { | |
| 28 | +// // 将 MyCustomType 转换为数据库类型并设置到 PreparedStatement 中 | |
| 29 | +// if (parameter == null) { | |
| 30 | +// ps.setString(i, ""); | |
| 31 | +// } else { | |
| 32 | +// ps.setString(i, JsonUtils.toJsonString(parameter)); | |
| 33 | +// } | |
| 34 | +// } | |
| 35 | +// | |
| 36 | +// @Override | |
| 37 | +// public AiChatModalDO.Config getNullableResult(ResultSet rs, String columnName) throws SQLException { | |
| 38 | +// // 从 ResultSet 中获取数据库类型并转换为 MyCustomType | |
| 39 | +// String str = rs.getString(columnName); | |
| 40 | +// if (StrUtil.isBlank(str)) { | |
| 41 | +// return null; | |
| 42 | +// } | |
| 43 | +// AiChatModalDO.Config config = JsonUtils.parseObject(str, AiChatModalDO.Config.class); | |
| 44 | +// // 获取平台 | |
| 45 | +// AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(config.getModelPlatform()); | |
| 46 | +// if (AiPlatformEnum.CHAT_PLATFORM_LIST.contains(platformEnum)) { | |
| 47 | +// return JsonUtils.parseObject(str, AiChatModalDO.ChatConfig.class); | |
| 48 | +// } else if (AiPlatformEnum.OPEN_AI_DALL == platformEnum) { | |
| 49 | +// return JsonUtils.parseObject(str, AiChatModalDO.OpenAiImageConfig.class); | |
| 50 | +// } else if (AiPlatformEnum.MIDJOURNEY == platformEnum) { | |
| 51 | +// return JsonUtils.parseObject(str, AiChatModalDO.MidjourneyConfig.class); | |
| 52 | +// } | |
| 53 | +// throw new IllegalArgumentException("ai模型中config不能转换! json: " + str); | |
| 54 | +// } | |
| 55 | +// | |
| 56 | +// @Override | |
| 57 | +// public AiChatModalDO.Config getNullableResult(ResultSet rs, int columnIndex) throws SQLException { | |
| 58 | +// // 从 ResultSet 中获取数据库类型并转换为 MyCustomType | |
| 59 | +// String str = rs.getString(columnIndex); | |
| 60 | +// if (StrUtil.isBlank(str)) { | |
| 61 | +// return null; | |
| 62 | +// } | |
| 63 | +// return JsonUtils.parseObject(str, AiChatModalDO.Config.class); | |
| 64 | +// } | |
| 65 | +// | |
| 66 | +// @Override | |
| 67 | +// public AiChatModalDO.Config getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { | |
| 68 | +// // 从 CallableStatement 中获取数据库类型并转换为 MyCustomType | |
| 69 | +// String str = cs.getString(columnIndex); | |
| 70 | +// if (StrUtil.isBlank(str)) { | |
| 71 | +// return null; | |
| 72 | +// } | |
| 73 | +// return JsonUtils.parseObject(str, AiChatModalDO.Config.class); | |
| 74 | +// } | |
| 75 | +//} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatModalServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.service.impl; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | +import cn.hutool.extra.validation.ValidationUtil; | |
| 5 | +import cn.iocoder.yudao.framework.ai.AiPlatformEnum; | |
| 6 | +import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatModal; | |
| 7 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel; | |
| 8 | +import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel; | |
| 4 | 9 | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| 5 | 10 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 11 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 6 | 12 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 7 | 13 | import cn.iocoder.yudao.module.ai.ErrorCodeConstants; |
| 8 | 14 | import cn.iocoder.yudao.module.ai.convert.AiChatModalConvert; |
| 9 | 15 | import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatModalDO; |
| 16 | +import cn.iocoder.yudao.module.ai.dal.vo.AiChatModalChatConfigVO; | |
| 17 | +import cn.iocoder.yudao.module.ai.dal.vo.AiChatModalConfigVO; | |
| 18 | +import cn.iocoder.yudao.module.ai.dal.vo.AiChatModalDallConfigVO; | |
| 10 | 19 | import cn.iocoder.yudao.module.ai.enums.AiChatModalDisableEnum; |
| 11 | 20 | import cn.iocoder.yudao.module.ai.mapper.AiChatModalMapper; |
| 12 | 21 | import cn.iocoder.yudao.module.ai.service.AiChatModalService; |
| 13 | 22 | import cn.iocoder.yudao.module.ai.vo.AiChatModalAddReq; |
| 14 | 23 | import cn.iocoder.yudao.module.ai.vo.AiChatModalListReq; |
| 15 | 24 | import cn.iocoder.yudao.module.ai.vo.AiChatModalListRes; |
| 25 | +import jakarta.validation.ConstraintViolation; | |
| 16 | 26 | import lombok.AllArgsConstructor; |
| 17 | 27 | import lombok.extern.slf4j.Slf4j; |
| 18 | 28 | import org.springframework.stereotype.Service; |
| 19 | 29 | |
| 20 | 30 | import java.util.List; |
| 31 | +import java.util.Set; | |
| 21 | 32 | |
| 22 | 33 | /** |
| 23 | 34 | * ai 模型 |
| ... | ... | @@ -40,7 +51,7 @@ public class AiChatModalServiceImpl implements AiChatModalService { |
| 40 | 51 | queryWrapperX.eq(AiChatModalDO::getDisable, AiChatModalDisableEnum.NO.getValue()); |
| 41 | 52 | // search |
| 42 | 53 | if (!StrUtil.isBlank(req.getSearch())) { |
| 43 | - queryWrapperX.like(AiChatModalDO::getModelName, req.getSearch().trim()); | |
| 54 | + queryWrapperX.like(AiChatModalDO::getName, req.getSearch().trim()); | |
| 44 | 55 | } |
| 45 | 56 | // 默认排序 |
| 46 | 57 | queryWrapperX.orderByDesc(AiChatModalDO::getId); |
| ... | ... | @@ -53,21 +64,38 @@ public class AiChatModalServiceImpl implements AiChatModalService { |
| 53 | 64 | |
| 54 | 65 | @Override |
| 55 | 66 | public void add(AiChatModalAddReq req) { |
| 67 | + // 校验 platform、type | |
| 68 | + validatePlatform(req.getPlatform()); | |
| 69 | + validateModal(req.getPlatform(), req.getModal()); | |
| 70 | + // 转换config | |
| 71 | + AiChatModalConfigVO aiChatModalConfigVO = convertConfig(req); | |
| 72 | + // 校验 modal config | |
| 73 | + validateModalConfig(aiChatModalConfigVO); | |
| 56 | 74 | // 转换 do |
| 57 | 75 | AiChatModalDO insertChatModalDO = AiChatModalConvert.INSTANCE.convertAiChatModalDO(req); |
| 58 | - // | |
| 76 | + // 设置默认属性 | |
| 59 | 77 | insertChatModalDO.setDisable(AiChatModalDisableEnum.NO.getValue()); |
| 78 | + insertChatModalDO.setConfig(JsonUtils.toJsonString(aiChatModalConfigVO)); | |
| 60 | 79 | // 保存数据库 |
| 61 | 80 | aiChatModalMapper.insert(insertChatModalDO); |
| 62 | 81 | } |
| 63 | 82 | |
| 64 | 83 | @Override |
| 65 | 84 | public void update(Long id, AiChatModalAddReq req) { |
| 85 | + // 校验 platform、type | |
| 86 | + validatePlatform(req.getPlatform()); | |
| 87 | + validateModal(req.getPlatform(), req.getModal()); | |
| 88 | + // 转换config | |
| 89 | + AiChatModalConfigVO aiChatModalConfigVO = convertConfig(req); | |
| 90 | + // 校验 modal config | |
| 91 | + validateModalConfig(aiChatModalConfigVO); | |
| 92 | + | |
| 66 | 93 | // 校验模型是否存在 |
| 67 | 94 | validateChatModalExists(id); |
| 68 | 95 | // 转换 updateChatModalDO |
| 69 | 96 | AiChatModalDO updateChatModalDO = AiChatModalConvert.INSTANCE.convertAiChatModalDO(req); |
| 70 | 97 | updateChatModalDO.setId(id); |
| 98 | + updateChatModalDO.setConfig(JsonUtils.toJsonString(aiChatModalConfigVO)); | |
| 71 | 99 | // 更新数据库 |
| 72 | 100 | aiChatModalMapper.updateById(updateChatModalDO); |
| 73 | 101 | } |
| ... | ... | @@ -86,4 +114,52 @@ public class AiChatModalServiceImpl implements AiChatModalService { |
| 86 | 114 | throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_NOT_EXIST); |
| 87 | 115 | } |
| 88 | 116 | } |
| 117 | + | |
| 118 | + private void validateModal(String platform, String modal) { | |
| 119 | + AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(platform); | |
| 120 | + try { | |
| 121 | + if (AiPlatformEnum.QIAN_WEN == platformEnum) { | |
| 122 | + QianWenChatModal.valueOfModel(modal); | |
| 123 | + } else if (AiPlatformEnum.XING_HUO == platformEnum) { | |
| 124 | + XingHuoChatModel.valueOfModel(modal); | |
| 125 | + } else if (AiPlatformEnum.YI_YAN == platformEnum) { | |
| 126 | + YiYanChatModel.valueOfModel(modal); | |
| 127 | + } else { | |
| 128 | + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_NOT_SUPPORTED_MODAL, platform); | |
| 129 | + } | |
| 130 | + } catch (IllegalArgumentException e) { | |
| 131 | + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_CONFIG_PARAMS_INCORRECT, e.getMessage()); | |
| 132 | + } | |
| 133 | + } | |
| 134 | + | |
| 135 | + private void validatePlatform(String platform) { | |
| 136 | + try { | |
| 137 | + AiPlatformEnum.valueOfPlatform(platform); | |
| 138 | + } catch (IllegalArgumentException e) { | |
| 139 | + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_PLATFORM_PARAMS_INCORRECT, e.getMessage()); | |
| 140 | + } | |
| 141 | + } | |
| 142 | + | |
| 143 | + private void validateModalConfig(AiChatModalConfigVO aiChatModalConfigVO) { | |
| 144 | + Set<ConstraintViolation<AiChatModalConfigVO>> validate = ValidationUtil.validate(aiChatModalConfigVO); | |
| 145 | + for (ConstraintViolation<AiChatModalConfigVO> constraintViolation : validate) { | |
| 146 | + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MODAL_CONFIG_PARAMS_INCORRECT, constraintViolation.getMessage()); | |
| 147 | + } | |
| 148 | + } | |
| 149 | + | |
| 150 | + private static AiChatModalConfigVO convertConfig(AiChatModalAddReq req) { | |
| 151 | + AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(req.getPlatform()); | |
| 152 | + AiChatModalConfigVO resVo = null; | |
| 153 | + if (AiPlatformEnum.CHAT_PLATFORM_LIST.contains(platformEnum)) { | |
| 154 | + resVo = JsonUtils.parseObject(JsonUtils.toJsonString(req.getConfig()), AiChatModalChatConfigVO.class); | |
| 155 | + } else if (AiPlatformEnum.OPEN_AI_DALL == platformEnum) { | |
| 156 | + resVo = JsonUtils.parseObject(JsonUtils.toJsonString(req.getConfig()), AiChatModalDallConfigVO.class); | |
| 157 | + } | |
| 158 | + if (resVo == null) { | |
| 159 | + throw new IllegalArgumentException("ai模型中config不能转换! json: " + req.getConfig()); | |
| 160 | + } | |
| 161 | + resVo.setType(req.getModal()); | |
| 162 | + resVo.setPlatform(req.getPlatform()); | |
| 163 | + return resVo; | |
| 164 | + } | |
| 89 | 165 | } | ... | ... |
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; |
| 5 | 5 | import cn.iocoder.yudao.framework.ai.image.ImagePrompt; |
| 6 | 6 | import cn.iocoder.yudao.framework.ai.image.ImageResponse; |
| 7 | 7 | import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageClient; |
| 8 | -import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageModelEnum; | |
| 8 | +import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum; | |
| 9 | 9 | import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions; |
| 10 | -import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageStyleEnum; | |
| 10 | +import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum; | |
| 11 | 11 | import cn.iocoder.yudao.framework.ai.midjourney.api.MidjourneyInteractionsApi; |
| 12 | 12 | import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyWebSocketStarter; |
| 13 | 13 | import cn.iocoder.yudao.framework.ai.midjourney.webSocket.WssNotify; |
| ... | ... | @@ -21,7 +21,6 @@ import cn.iocoder.yudao.module.ai.mapper.AiImageMapper; |
| 21 | 21 | import cn.iocoder.yudao.module.ai.service.AiImageService; |
| 22 | 22 | import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq; |
| 23 | 23 | import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyReq; |
| 24 | -import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyRes; | |
| 25 | 24 | import jakarta.annotation.PostConstruct; |
| 26 | 25 | import lombok.AllArgsConstructor; |
| 27 | 26 | import lombok.extern.slf4j.Slf4j; | ... | ... |
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; |
| 6 | 6 | import lombok.Data; |
| 7 | 7 | import lombok.experimental.Accessors; |
| 8 | 8 | |
| 9 | +import java.util.Map; | |
| 10 | + | |
| 9 | 11 | /** |
| 10 | 12 | * ai chat modal |
| 11 | 13 | * |
| ... | ... | @@ -19,18 +21,24 @@ public class AiChatModalAddReq { |
| 19 | 21 | |
| 20 | 22 | @NotNull |
| 21 | 23 | @Schema(description = "模型名字") |
| 22 | - @Size(max = 60, message = "模型名字最大60") | |
| 23 | - private String modelName; | |
| 24 | + @Size(max = 60, message = "模型名字最大60个字符") | |
| 25 | + private String name; | |
| 26 | + | |
| 27 | + @NotNull | |
| 28 | + @Size(max = 32, message = "模型平台最大32个字符") | |
| 29 | + @Schema(description = "模型平台 参考 AiPlatformEnum") | |
| 30 | + private String platform; | |
| 24 | 31 | |
| 25 | 32 | @NotNull |
| 26 | 33 | @Schema(description = "模型类型(qianwen、yiyan、xinghuo、openai)") |
| 27 | - @Size(max = 32, message = "模型类型最大32") | |
| 28 | - private String modelType; | |
| 34 | + @Size(max = 32, message = "模型类型最大32个字符") | |
| 35 | + private String modal; | |
| 29 | 36 | |
| 30 | 37 | @Schema(description = "模型照片") |
| 31 | - private String modalImage; | |
| 38 | + @Size(max = 256, message = "模型照片地址最大256个字符") | |
| 39 | + private String imageUrl; | |
| 32 | 40 | |
| 33 | 41 | @Schema(description = "模型配置JSON") |
| 34 | - private String modelConfig; | |
| 35 | - | |
| 42 | +// @Size(max = 1024, message = "模型配置最大1024个字符") | |
| 43 | + private Map<String, Object> config; | |
| 36 | 44 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/AiChatModalListRes.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.vo; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatModalDO; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 3 | 5 | import lombok.Data; |
| 4 | 6 | import lombok.experimental.Accessors; |
| 5 | 7 | |
| ... | ... | @@ -13,29 +15,25 @@ import lombok.experimental.Accessors; |
| 13 | 15 | @Data |
| 14 | 16 | @Accessors(chain = true) |
| 15 | 17 | public class AiChatModalListRes { |
| 16 | - /** | |
| 17 | - * 编号 | |
| 18 | - */ | |
| 18 | + | |
| 19 | + @Schema(description = "id") | |
| 19 | 20 | private Long id; |
| 20 | - /** | |
| 21 | - * 模型名字 | |
| 22 | - */ | |
| 23 | - private String modelName; | |
| 24 | - /** | |
| 25 | - * 模型类型(qianwen、yiyan、xinghuo、openai) | |
| 26 | - */ | |
| 27 | - private String modelType; | |
| 28 | - /** | |
| 29 | - * 模型照片 | |
| 30 | - */ | |
| 31 | - private String modalImage; | |
| 32 | - /** | |
| 33 | - * 模型配置JSON | |
| 34 | - */ | |
| 35 | - private String modelConfig; | |
| 36 | - /** | |
| 37 | - * 禁用 0、正常 1、禁用 | |
| 38 | - */ | |
| 21 | + | |
| 22 | + @Schema(description = "模型平台 参考 AiPlatformEnum") | |
| 23 | + private String platform; | |
| 24 | + | |
| 25 | + @Schema(description = "模型类型 参考 YiYanChatModel、XingHuoChatModel") | |
| 26 | + private String modal; | |
| 27 | + | |
| 28 | + @Schema(description = "模型名字") | |
| 29 | + private String name; | |
| 30 | + | |
| 31 | + @Schema(description = "模型照片") | |
| 32 | + private String image; | |
| 33 | + | |
| 34 | + @Schema(description = "禁用 0、正常 1、禁用") | |
| 39 | 35 | private Integer disable; |
| 40 | 36 | |
| 37 | + @Schema(description = "modal 配置") | |
| 38 | + private String config; | |
| 41 | 39 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/resources/http/chat-modal.http
| 1 | 1 | |
| 2 | - | |
| 3 | 2 | ### chat call |
| 4 | 3 | GET {{baseUrl}}/ai/chat/modal/list |
| 5 | 4 | Authorization: {{token}} |
| 6 | 5 | |
| 7 | 6 | |
| 8 | - | |
| 9 | 7 | ### chat call |
| 10 | 8 | PUT {{baseUrl}}/ai/chat/modal |
| 11 | 9 | Content-Type: application/json |
| 12 | 10 | Authorization: {{token}} |
| 13 | 11 | |
| 14 | 12 | { |
| 15 | - "modelName": "小红书Ai写作大模型", | |
| 16 | - "modelType": "yiyan", | |
| 17 | - "modalImage": "", | |
| 18 | - "modelConfig": "" | |
| 13 | + "name": "小红书Ai写作大模型-plus", | |
| 14 | + "modal": "ERNIE-3.5-8K", | |
| 15 | + "platform": "yiyan", | |
| 16 | + "imageUrl": "", | |
| 17 | + "config": { | |
| 18 | + "topK": 0.6, | |
| 19 | + "topP": 0.6, | |
| 20 | + "temperature": 0.86, | |
| 21 | + "maxTokens": 2048 | |
| 22 | + } | |
| 23 | +} | |
| 24 | + | |
| 25 | +### chat call | |
| 26 | +POST {{baseUrl}}/ai/chat/modal/7 | |
| 27 | +Content-Type: application/json | |
| 28 | +Authorization: {{token}} | |
| 29 | + | |
| 30 | +{ | |
| 31 | + "name": "小红书Ai写作大模型-plus", | |
| 32 | + "modal": "ERNIE-3.5-8K", | |
| 33 | + "platform": "yiyan", | |
| 34 | + "imageUrl": "", | |
| 35 | + "config": { | |
| 36 | + "topK": 0.6, | |
| 37 | + "topP": 0.6, | |
| 38 | + "temperature": 0.86, | |
| 39 | + "maxTokens": 2048 | |
| 40 | + } | |
| 19 | 41 | } | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/AiPlatformEnum.java
| 1 | 1 | package cn.iocoder.yudao.framework.ai; |
| 2 | 2 | |
| 3 | +import com.google.common.collect.Lists; | |
| 3 | 4 | import lombok.AllArgsConstructor; |
| 4 | 5 | import lombok.Getter; |
| 5 | 6 | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 6 | 9 | /** |
| 7 | 10 | * ai 模型平台 |
| 8 | 11 | * |
| ... | ... | @@ -17,12 +20,27 @@ public enum AiPlatformEnum { |
| 17 | 20 | YI_YAN("yiyan", "一言"), |
| 18 | 21 | QIAN_WEN("qianwen", "千问"), |
| 19 | 22 | XING_HUO("xinghuo", "星火"), |
| 23 | + OPEN_AI("openai", "openAi"), | |
| 24 | + OPEN_AI_DALL("dall", "dall"), | |
| 25 | + MIDJOURNEY("midjourney", "midjourney"), | |
| 20 | 26 | |
| 21 | 27 | ; |
| 22 | 28 | |
| 23 | 29 | private String platform; |
| 24 | 30 | private String name; |
| 25 | 31 | |
| 32 | + public static List<AiPlatformEnum> CHAT_PLATFORM_LIST = Lists.newArrayList( | |
| 33 | + AiPlatformEnum.YI_YAN, | |
| 34 | + AiPlatformEnum.QIAN_WEN, | |
| 35 | + AiPlatformEnum.XING_HUO, | |
| 36 | + AiPlatformEnum.OPEN_AI | |
| 37 | + ); | |
| 38 | + | |
| 39 | + public static List<AiPlatformEnum> IMAGE_PLATFORM_LIST = Lists.newArrayList( | |
| 40 | + AiPlatformEnum.OPEN_AI_DALL, | |
| 41 | + AiPlatformEnum.MIDJOURNEY | |
| 42 | + ); | |
| 43 | + | |
| 26 | 44 | public static AiPlatformEnum valueOfPlatform(String platform) { |
| 27 | 45 | for (AiPlatformEnum itemEnum : AiPlatformEnum.values()) { |
| 28 | 46 | if (itemEnum.getPlatform().equals(platform)) { | ... | ... |
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; |
| 3 | 3 | import cn.iocoder.yudao.framework.ai.AiPlatformEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel; |
| 5 | 5 | import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel; |
| 6 | -import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageModelEnum; | |
| 7 | -import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageStyleEnum; | |
| 6 | +import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum; | |
| 7 | +import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum; | |
| 8 | 8 | import lombok.Data; |
| 9 | 9 | import lombok.experimental.Accessors; |
| 10 | 10 | import org.springframework.boot.context.properties.ConfigurationProperties; | ... | ... |