Commit 2adb5accc4e132059d3c06c0d6bbd183a19e5bcc
1 parent
44f7c841
【优化】ai chat client自动配置和初始化。
Showing
11 changed files
with
227 additions
and
213 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiClientNameEnum.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.enums; | ||
| 2 | - | ||
| 3 | -import lombok.AllArgsConstructor; | ||
| 4 | -import lombok.Getter; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * ai client 名字 | ||
| 8 | - * | ||
| 9 | - * 这个需要根据配置文件起的来决定 | ||
| 10 | - * | ||
| 11 | - * @author fansili | ||
| 12 | - * @time 2024/4/14 16:02 | ||
| 13 | - * @since 1.0 | ||
| 14 | - */ | ||
| 15 | -@AllArgsConstructor | ||
| 16 | -@Getter | ||
| 17 | -public enum AiClientNameEnum { | ||
| 18 | - | ||
| 19 | - QIAN_WEN("qianWen", "千问模型!"), | ||
| 20 | - YI_YAN_3_5_8K("yiYan3_5_8k", "文心一言(3.5-8k)"), | ||
| 21 | - XING_HUO("xingHuo", "星火模型!"), | ||
| 22 | - | ||
| 23 | - ; | ||
| 24 | - | ||
| 25 | - private String name; | ||
| 26 | - | ||
| 27 | - private String message; | ||
| 28 | - | ||
| 29 | - public static AiClientNameEnum valueOfName(String name) { | ||
| 30 | - for (AiClientNameEnum nameEnum : AiClientNameEnum.values()) { | ||
| 31 | - if (nameEnum.getName().equals(name)) { | ||
| 32 | - return nameEnum; | ||
| 33 | - } | ||
| 34 | - } | ||
| 35 | - throw new IllegalArgumentException("Invalid MessageType value: " + name); | ||
| 36 | - } | ||
| 37 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/config/AiChatClientFactory.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.AiPlatformEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.ai.chat.ChatClient; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatClient; | ||
| 7 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatClient; | ||
| 8 | +import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatClient; | ||
| 9 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 10 | +import org.springframework.context.ApplicationContext; | ||
| 11 | +import org.springframework.stereotype.Component; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * factory | ||
| 15 | + * | ||
| 16 | + * @author fansili | ||
| 17 | + * @time 2024/4/25 17:36 | ||
| 18 | + * @since 1.0 | ||
| 19 | + */ | ||
| 20 | +@Component | ||
| 21 | +public class AiChatClientFactory { | ||
| 22 | + | ||
| 23 | + @Autowired | ||
| 24 | + private ApplicationContext applicationContext; | ||
| 25 | + | ||
| 26 | + public ChatClient getChatClient(AiPlatformEnum platformEnum) { | ||
| 27 | + if (AiPlatformEnum.QIAN_WEN == platformEnum) { | ||
| 28 | + return applicationContext.getBean(QianWenChatClient.class); | ||
| 29 | + } else if (AiPlatformEnum.YI_YAN == platformEnum) { | ||
| 30 | + return applicationContext.getBean(YiYanChatClient.class); | ||
| 31 | + } else if (AiPlatformEnum.XING_HUO == platformEnum) { | ||
| 32 | + return applicationContext.getBean(XingHuoChatClient.class); | ||
| 33 | + } | ||
| 34 | + throw new IllegalArgumentException("不支持的 chat client!"); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + // TODO yunai 要不再加一个接口,让他们拥有 ChatClient、StreamingChatClient 功能 | ||
| 38 | + public StreamingChatClient getStreamingChatClient(AiPlatformEnum platformEnum) { | ||
| 39 | + if (AiPlatformEnum.QIAN_WEN == platformEnum) { | ||
| 40 | + return applicationContext.getBean(QianWenChatClient.class); | ||
| 41 | + } else if (AiPlatformEnum.YI_YAN == platformEnum) { | ||
| 42 | + return applicationContext.getBean(YiYanChatClient.class); | ||
| 43 | + } else if (AiPlatformEnum.XING_HUO == platformEnum) { | ||
| 44 | + return applicationContext.getBean(XingHuoChatClient.class); | ||
| 45 | + } | ||
| 46 | + throw new IllegalArgumentException("不支持的 chat client!"); | ||
| 47 | + } | ||
| 48 | +} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java
| 1 | package cn.iocoder.yudao.module.ai.service.impl; | 1 | package cn.iocoder.yudao.module.ai.service.impl; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.exceptions.ExceptionUtil; | 3 | import cn.hutool.core.exceptions.ExceptionUtil; |
| 4 | +import cn.iocoder.yudao.framework.ai.AiPlatformEnum; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chat.ChatClient; | ||
| 4 | import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | 6 | import cn.iocoder.yudao.framework.ai.chat.ChatResponse; |
| 7 | +import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient; | ||
| 5 | import cn.iocoder.yudao.framework.ai.chat.messages.MessageType; | 8 | import cn.iocoder.yudao.framework.ai.chat.messages.MessageType; |
| 6 | import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | 9 | import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; |
| 7 | -import cn.iocoder.yudao.framework.ai.config.AiClient; | ||
| 8 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | 10 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 11 | +import cn.iocoder.yudao.module.ai.config.AiChatClientFactory; | ||
| 9 | import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; | 12 | import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; |
| 10 | import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatMessageDO; | 13 | import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatMessageDO; |
| 11 | -import cn.iocoder.yudao.module.ai.enums.AiClientNameEnum; | ||
| 12 | import cn.iocoder.yudao.module.ai.mapper.AiChatConversationMapper; | 14 | import cn.iocoder.yudao.module.ai.mapper.AiChatConversationMapper; |
| 13 | import cn.iocoder.yudao.module.ai.mapper.AiChatMessageMapper; | 15 | import cn.iocoder.yudao.module.ai.mapper.AiChatMessageMapper; |
| 14 | import cn.iocoder.yudao.module.ai.mapper.AiChatRoleMapper; | 16 | import cn.iocoder.yudao.module.ai.mapper.AiChatRoleMapper; |
| @@ -38,7 +40,7 @@ import java.util.function.Consumer; | @@ -38,7 +40,7 @@ import java.util.function.Consumer; | ||
| 38 | @AllArgsConstructor | 40 | @AllArgsConstructor |
| 39 | public class AiChatServiceImpl implements AiChatService { | 41 | public class AiChatServiceImpl implements AiChatService { |
| 40 | 42 | ||
| 41 | - private final AiClient aiClient; | 43 | + private final AiChatClientFactory aiChatClientFactory; |
| 42 | private final AiChatRoleMapper aiChatRoleMapper; | 44 | private final AiChatRoleMapper aiChatRoleMapper; |
| 43 | private final AiChatMessageMapper aiChatMessageMapper; | 45 | private final AiChatMessageMapper aiChatMessageMapper; |
| 44 | private final AiChatConversationMapper aiChatConversationMapper; | 46 | private final AiChatConversationMapper aiChatConversationMapper; |
| @@ -54,7 +56,7 @@ public class AiChatServiceImpl implements AiChatService { | @@ -54,7 +56,7 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 54 | public String chat(AiChatReq req) { | 56 | public String chat(AiChatReq req) { |
| 55 | Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); | 57 | Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); |
| 56 | // 获取 client 类型 | 58 | // 获取 client 类型 |
| 57 | - AiClientNameEnum clientNameEnum = AiClientNameEnum.valueOfName(req.getModal()); | 59 | + AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(req.getModal()); |
| 58 | // 获取对话信息 | 60 | // 获取对话信息 |
| 59 | AiChatConversationRes conversationRes = chatConversationService.getConversation(req.getConversationId()); | 61 | AiChatConversationRes conversationRes = chatConversationService.getConversation(req.getConversationId()); |
| 60 | // 保存 chat message | 62 | // 保存 chat message |
| @@ -67,7 +69,8 @@ public class AiChatServiceImpl implements AiChatService { | @@ -67,7 +69,8 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 67 | req.setTopP(req.getTopP()); | 69 | req.setTopP(req.getTopP()); |
| 68 | req.setTemperature(req.getTemperature()); | 70 | req.setTemperature(req.getTemperature()); |
| 69 | // 发送 call 调用 | 71 | // 发送 call 调用 |
| 70 | - ChatResponse call = aiClient.call(prompt, clientNameEnum.getName()); | 72 | + ChatClient chatClient = aiChatClientFactory.getChatClient(platformEnum); |
| 73 | + ChatResponse call = chatClient.call(prompt); | ||
| 71 | content = call.getResult().getOutput().getContent(); | 74 | content = call.getResult().getOutput().getContent(); |
| 72 | // 更新 conversation | 75 | // 更新 conversation |
| 73 | 76 | ||
| @@ -128,7 +131,7 @@ public class AiChatServiceImpl implements AiChatService { | @@ -128,7 +131,7 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 128 | public void chatStream(AiChatReq req, Utf8SseEmitter sseEmitter) { | 131 | public void chatStream(AiChatReq req, Utf8SseEmitter sseEmitter) { |
| 129 | Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); | 132 | Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); |
| 130 | // 获取 client 类型 | 133 | // 获取 client 类型 |
| 131 | - AiClientNameEnum clientNameEnum = AiClientNameEnum.valueOfName(req.getModal()); | 134 | + AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(req.getModal()); |
| 132 | // 获取对话信息 | 135 | // 获取对话信息 |
| 133 | AiChatConversationRes conversationRes = chatConversationService.getConversation(req.getConversationId()); | 136 | AiChatConversationRes conversationRes = chatConversationService.getConversation(req.getConversationId()); |
| 134 | // 创建 chat 需要的 Prompt | 137 | // 创建 chat 需要的 Prompt |
| @@ -138,7 +141,8 @@ public class AiChatServiceImpl implements AiChatService { | @@ -138,7 +141,8 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 138 | req.setTemperature(req.getTemperature()); | 141 | req.setTemperature(req.getTemperature()); |
| 139 | // 保存 chat message | 142 | // 保存 chat message |
| 140 | saveChatMessage(req, conversationRes, loginUserId); | 143 | saveChatMessage(req, conversationRes, loginUserId); |
| 141 | - Flux<ChatResponse> streamResponse = aiClient.stream(prompt, clientNameEnum.getName()); | 144 | + StreamingChatClient streamingChatClient = aiChatClientFactory.getStreamingChatClient(platformEnum); |
| 145 | + Flux<ChatResponse> streamResponse = streamingChatClient.stream(prompt); | ||
| 142 | 146 | ||
| 143 | StringBuffer contentBuffer = new StringBuffer(); | 147 | StringBuffer contentBuffer = new StringBuffer(); |
| 144 | streamResponse.subscribe( | 148 | streamResponse.subscribe( |
yudao-module-ai/yudao-module-ai-biz/src/main/resources/http/chat.http
| @@ -16,7 +16,7 @@ tenant-id: 1 | @@ -16,7 +16,7 @@ tenant-id: 1 | ||
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | ### chat call | 18 | ### chat call |
| 19 | -GET {{baseUrl}}/ai/chat?modal=qianWen&conversationId=1781604279872581644&prompt=中国好看吗? | 19 | +GET {{baseUrl}}/ai/chat?modal=qianwen&conversationId=1781604279872581644&prompt=中国好看吗? |
| 20 | Authorization: {{token}} | 20 | Authorization: {{token}} |
| 21 | 21 | ||
| 22 | 22 |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/AiPlatformEnum.java
| @@ -3,10 +3,6 @@ package cn.iocoder.yudao.framework.ai; | @@ -3,10 +3,6 @@ package cn.iocoder.yudao.framework.ai; | ||
| 3 | import lombok.AllArgsConstructor; | 3 | import lombok.AllArgsConstructor; |
| 4 | import lombok.Getter; | 4 | import lombok.Getter; |
| 5 | 5 | ||
| 6 | -import java.util.Arrays; | ||
| 7 | -import java.util.Map; | ||
| 8 | -import java.util.stream.Collectors; | ||
| 9 | - | ||
| 10 | /** | 6 | /** |
| 11 | * 讯飞星火 模型 | 7 | * 讯飞星火 模型 |
| 12 | * | 8 | * |
| @@ -24,15 +20,22 @@ import java.util.stream.Collectors; | @@ -24,15 +20,22 @@ import java.util.stream.Collectors; | ||
| 24 | public enum AiPlatformEnum { | 20 | public enum AiPlatformEnum { |
| 25 | 21 | ||
| 26 | 22 | ||
| 27 | - YI_YAN("yiyan"), | ||
| 28 | - QIAN_WEN("qianwen"), | ||
| 29 | - XING_HUO("xinghuo"), | 23 | + YI_YAN("yiyan", "一言"), |
| 24 | + QIAN_WEN("qianwen", "千问"), | ||
| 25 | + XING_HUO("xinghuo", "星火"), | ||
| 30 | 26 | ||
| 31 | ; | 27 | ; |
| 32 | 28 | ||
| 33 | - public static final Map<String, AiPlatformEnum> mapValues | ||
| 34 | - = Arrays.stream(values()).collect(Collectors.toMap(AiPlatformEnum::name, o -> o)); | ||
| 35 | - | ||
| 36 | - private String value; | 29 | + private String platform; |
| 30 | + private String name; | ||
| 31 | + | ||
| 32 | + public static AiPlatformEnum valueOfPlatform(String platform) { | ||
| 33 | + for (AiPlatformEnum itemEnum : AiPlatformEnum.values()) { | ||
| 34 | + if (itemEnum.getPlatform().equals(platform)) { | ||
| 35 | + return itemEnum; | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + throw new IllegalArgumentException("Invalid MessageType value: " + platform); | ||
| 39 | + } | ||
| 37 | 40 | ||
| 38 | } | 41 | } |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/AiClient.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.config; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | ||
| 4 | -import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | ||
| 5 | -import reactor.core.publisher.Flux; | ||
| 6 | - | ||
| 7 | -/** | ||
| 8 | - * ai client传入 | ||
| 9 | - * | ||
| 10 | - * @author fansili | ||
| 11 | - * @time 2024/4/14 10:27 | ||
| 12 | - * @since 1.0 | ||
| 13 | - */ | ||
| 14 | -public interface AiClient { | ||
| 15 | - | ||
| 16 | - ChatResponse call(Prompt prompt, String clientName); | ||
| 17 | - | ||
| 18 | - Flux<ChatResponse> stream(Prompt prompt, String clientName); | ||
| 19 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
| 1 | package cn.iocoder.yudao.framework.ai.config; | 1 | package cn.iocoder.yudao.framework.ai.config; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.bean.BeanUtil; | ||
| 4 | -import cn.iocoder.yudao.framework.ai.AiPlatformEnum; | ||
| 5 | import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatClient; | 3 | import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatClient; |
| 6 | import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenOptions; | 4 | import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenOptions; |
| 7 | import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi; | 5 | import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi; |
| @@ -11,15 +9,11 @@ import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoApi; | @@ -11,15 +9,11 @@ import cn.iocoder.yudao.framework.ai.chatxinghuo.api.XingHuoApi; | ||
| 11 | import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatClient; | 9 | import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatClient; |
| 12 | import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanOptions; | 10 | import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanOptions; |
| 13 | import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanApi; | 11 | import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanApi; |
| 14 | -import cn.iocoder.yudao.framework.ai.exception.AiException; | ||
| 15 | import org.springframework.boot.autoconfigure.AutoConfiguration; | 12 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 16 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | 13 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 17 | import org.springframework.boot.context.properties.EnableConfigurationProperties; | 14 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| 18 | import org.springframework.context.annotation.Bean; | 15 | import org.springframework.context.annotation.Bean; |
| 19 | 16 | ||
| 20 | -import java.util.HashMap; | ||
| 21 | -import java.util.Map; | ||
| 22 | - | ||
| 23 | /** | 17 | /** |
| 24 | * ai 自动配置 | 18 | * ai 自动配置 |
| 25 | * | 19 | * |
| @@ -32,86 +26,46 @@ import java.util.Map; | @@ -32,86 +26,46 @@ import java.util.Map; | ||
| 32 | public class YudaoAiAutoConfiguration { | 26 | public class YudaoAiAutoConfiguration { |
| 33 | 27 | ||
| 34 | @Bean | 28 | @Bean |
| 35 | - @ConditionalOnMissingBean(value = AiClient.class) | ||
| 36 | - public AiClient aiClient(YudaoAiProperties yudaoAiProperties) { | ||
| 37 | - Map<String, Object> chatClientMap = buildChatClientMap(yudaoAiProperties); | ||
| 38 | - return new YudaoAiClient(chatClientMap); | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - public Map<String, Object> buildChatClientMap(YudaoAiProperties yudaoAiProperties) { | ||
| 42 | - Map<String, Object> chatMap = new HashMap<>(); | ||
| 43 | - for (Map.Entry<String, Map<String, Object>> properties : yudaoAiProperties.entrySet()) { | ||
| 44 | - String beanName = properties.getKey(); | ||
| 45 | - Map<String, Object> aiPlatformMap = properties.getValue(); | ||
| 46 | - | ||
| 47 | - // 检查平台类型是否正确 | ||
| 48 | - String aiPlatform = String.valueOf(aiPlatformMap.get("aiPlatform")); | ||
| 49 | - if (!AiPlatformEnum.mapValues.containsKey(aiPlatform)) { | ||
| 50 | - throw new AiException("AI平台名称错误! 可以参考 AiPlatformEnum 类!"); | ||
| 51 | - } | ||
| 52 | - // 获取平台类型 | ||
| 53 | - AiPlatformEnum aiPlatformEnum = AiPlatformEnum.mapValues.get(aiPlatform); | ||
| 54 | - // 获取 chat properties | ||
| 55 | - YudaoAiProperties.ChatProperties chatProperties = getChatProperties(aiPlatformEnum, aiPlatformMap); | ||
| 56 | - // 创建客户端 | ||
| 57 | - Object chatClient = createChatClient(chatProperties); | ||
| 58 | - chatMap.put(beanName, chatClient); | ||
| 59 | - } | ||
| 60 | - return chatMap; | 29 | + @ConditionalOnProperty(value = "yudao.ai.xinghuo.enable", havingValue = "true") |
| 30 | + public XingHuoChatClient xingHuoChatClient(YudaoAiProperties yudaoAiProperties) { | ||
| 31 | + YudaoAiProperties.XingHuoProperties xingHuoProperties = yudaoAiProperties.getXinghuo(); | ||
| 32 | + return new XingHuoChatClient( | ||
| 33 | + new XingHuoApi( | ||
| 34 | + xingHuoProperties.getAppId(), | ||
| 35 | + xingHuoProperties.getAppKey(), | ||
| 36 | + xingHuoProperties.getSecretKey() | ||
| 37 | + ), | ||
| 38 | + new XingHuoOptions().setChatModel(xingHuoProperties.getChatModel()) | ||
| 39 | + ); | ||
| 61 | } | 40 | } |
| 62 | 41 | ||
| 63 | - private static Object createChatClient(YudaoAiProperties.ChatProperties chatProperties) { | ||
| 64 | - if (AiPlatformEnum.XING_HUO == chatProperties.getAiPlatform()) { | ||
| 65 | - YudaoAiProperties.XingHuoProperties xingHuoProperties = (YudaoAiProperties.XingHuoProperties) chatProperties; | ||
| 66 | - return new XingHuoChatClient( | ||
| 67 | - new XingHuoApi( | ||
| 68 | - xingHuoProperties.getAppId(), | ||
| 69 | - xingHuoProperties.getAppKey(), | ||
| 70 | - xingHuoProperties.getSecretKey() | ||
| 71 | - ), | ||
| 72 | - new XingHuoOptions().setChatModel(xingHuoProperties.getChatModel()) | ||
| 73 | - ); | ||
| 74 | - } else if (AiPlatformEnum.QIAN_WEN == chatProperties.getAiPlatform()) { | ||
| 75 | - YudaoAiProperties.QianWenProperties qianWenProperties = (YudaoAiProperties.QianWenProperties) chatProperties; | ||
| 76 | - return new QianWenChatClient( | ||
| 77 | - new QianWenApi( | ||
| 78 | - qianWenProperties.getAccessKeyId(), | ||
| 79 | - qianWenProperties.getAccessKeySecret(), | ||
| 80 | - qianWenProperties.getAgentKey(), | ||
| 81 | - qianWenProperties.getEndpoint() | ||
| 82 | - ), | ||
| 83 | - new QianWenOptions() | ||
| 84 | - .setAppId(qianWenProperties.getAppId()) | ||
| 85 | - ); | ||
| 86 | - } else if (AiPlatformEnum.YI_YAN == chatProperties.getAiPlatform()) { | ||
| 87 | - YudaoAiProperties.YiYanProperties yiYanProperties = (YudaoAiProperties.YiYanProperties) chatProperties; | ||
| 88 | - return new YiYanChatClient( | ||
| 89 | - new YiYanApi( | ||
| 90 | - yiYanProperties.getAppKey(), | ||
| 91 | - yiYanProperties.getSecretKey(), | ||
| 92 | - yiYanProperties.getChatModel(), | ||
| 93 | - yiYanProperties.getRefreshTokenSecondTime() | ||
| 94 | - ), | ||
| 95 | - new YiYanOptions().setMax_output_tokens(2048)); | ||
| 96 | - } | ||
| 97 | - throw new AiException("不支持的Ai类型!"); | 42 | + @Bean |
| 43 | + @ConditionalOnProperty(value = "yudao.ai.qianwen.enable", havingValue = "true") | ||
| 44 | + public QianWenChatClient qianWenChatClient(YudaoAiProperties yudaoAiProperties) { | ||
| 45 | + YudaoAiProperties.QianWenProperties qianWenProperties = yudaoAiProperties.getQianwen(); | ||
| 46 | + return new QianWenChatClient( | ||
| 47 | + new QianWenApi( | ||
| 48 | + qianWenProperties.getAccessKeyId(), | ||
| 49 | + qianWenProperties.getAccessKeySecret(), | ||
| 50 | + qianWenProperties.getAgentKey(), | ||
| 51 | + qianWenProperties.getEndpoint() | ||
| 52 | + ), | ||
| 53 | + new QianWenOptions() | ||
| 54 | + .setAppId(qianWenProperties.getAppId()) | ||
| 55 | + ); | ||
| 98 | } | 56 | } |
| 99 | 57 | ||
| 100 | - | ||
| 101 | - private static YudaoAiProperties.ChatProperties getChatProperties(AiPlatformEnum aiPlatformEnum, Map<String, Object> aiPlatformMap) { | ||
| 102 | - if (AiPlatformEnum.XING_HUO == aiPlatformEnum) { | ||
| 103 | - YudaoAiProperties.XingHuoProperties xingHuoProperties = new YudaoAiProperties.XingHuoProperties(); | ||
| 104 | - BeanUtil.fillBeanWithMap(aiPlatformMap, xingHuoProperties, true); | ||
| 105 | - return xingHuoProperties; | ||
| 106 | - } else if (AiPlatformEnum.YI_YAN == aiPlatformEnum) { | ||
| 107 | - YudaoAiProperties.YiYanProperties yiYanProperties = new YudaoAiProperties.YiYanProperties(); | ||
| 108 | - BeanUtil.fillBeanWithMap(aiPlatformMap, yiYanProperties, true); | ||
| 109 | - return yiYanProperties; | ||
| 110 | - } else if (AiPlatformEnum.QIAN_WEN == aiPlatformEnum) { | ||
| 111 | - YudaoAiProperties.QianWenProperties qianWenProperties = new YudaoAiProperties.QianWenProperties(); | ||
| 112 | - BeanUtil.fillBeanWithMap(aiPlatformMap, qianWenProperties, true); | ||
| 113 | - return qianWenProperties; | ||
| 114 | - } | ||
| 115 | - throw new AiException("不支持的Ai类型!"); | 58 | + @Bean |
| 59 | + @ConditionalOnProperty(value = "yudao.ai.yiyan.enable", havingValue = "true") | ||
| 60 | + public YiYanChatClient yiYanChatClient(YudaoAiProperties yudaoAiProperties) { | ||
| 61 | + YudaoAiProperties.YiYanProperties yiYanProperties = yudaoAiProperties.getYiyan(); | ||
| 62 | + return new YiYanChatClient( | ||
| 63 | + new YiYanApi( | ||
| 64 | + yiYanProperties.getAppKey(), | ||
| 65 | + yiYanProperties.getSecretKey(), | ||
| 66 | + yiYanProperties.getChatModel(), | ||
| 67 | + yiYanProperties.getRefreshTokenSecondTime() | ||
| 68 | + ), | ||
| 69 | + new YiYanOptions().setMax_output_tokens(2048)); | ||
| 116 | } | 70 | } |
| 117 | } | 71 | } |
| 118 | \ No newline at end of file | 72 | \ No newline at end of file |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiClient.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.config; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.ai.chat.ChatClient; | ||
| 4 | -import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | ||
| 5 | -import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient; | ||
| 6 | -import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | ||
| 7 | -import cn.iocoder.yudao.framework.ai.exception.AiException; | ||
| 8 | -import reactor.core.publisher.Flux; | ||
| 9 | - | ||
| 10 | -import java.util.Map; | ||
| 11 | - | ||
| 12 | -/** | ||
| 13 | - * yudao ai client | ||
| 14 | - * | ||
| 15 | - * @author fansili | ||
| 16 | - * @time 2024/4/14 10:27 | ||
| 17 | - * @since 1.0 | ||
| 18 | - */ | ||
| 19 | -public class YudaoAiClient implements AiClient { | ||
| 20 | - | ||
| 21 | - protected Map<String, Object> chatClientMap; | ||
| 22 | - | ||
| 23 | - public YudaoAiClient(Map<String, Object> chatClientMap) { | ||
| 24 | - this.chatClientMap = chatClientMap; | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - @Override | ||
| 28 | - public ChatResponse call(Prompt prompt, String clientName) { | ||
| 29 | - if (!chatClientMap.containsKey(clientName)) { | ||
| 30 | - throw new AiException("clientName不存在!"); | ||
| 31 | - } | ||
| 32 | - ChatClient chatClient = (ChatClient) chatClientMap.get(clientName); | ||
| 33 | - return chatClient.call(prompt); | ||
| 34 | - } | ||
| 35 | - | ||
| 36 | - @Override | ||
| 37 | - public Flux<ChatResponse> stream(Prompt prompt, String clientName) { | ||
| 38 | - if (!chatClientMap.containsKey(clientName)) { | ||
| 39 | - throw new AiException("clientName不存在!"); | ||
| 40 | - } | ||
| 41 | - StreamingChatClient streamingChatClient = (StreamingChatClient) chatClientMap.get(clientName); | ||
| 42 | - return streamingChatClient.stream(prompt); | ||
| 43 | - } | ||
| 44 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiImageProperties.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.AiPlatformEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoChatModel; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.chatxinghuo.XingHuoOptions; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.chatyiyan.YiYanChatModel; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 10 | + | ||
| 11 | +import java.util.LinkedHashMap; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * ai 自动配置 | ||
| 16 | + * | ||
| 17 | + * @author fansili | ||
| 18 | + * @time 2024/4/12 16:29 | ||
| 19 | + * @since 1.0 | ||
| 20 | + */ | ||
| 21 | + | ||
| 22 | +@Data | ||
| 23 | +@Accessors(chain = true) | ||
| 24 | +public class YudaoAiImageProperties extends LinkedHashMap<String, Map<String, Object>> { | ||
| 25 | + | ||
| 26 | + private String initType; | ||
| 27 | + private QianWenProperties qianwen; | ||
| 28 | + private XingHuoOptions xinghuo; | ||
| 29 | + private YiYanProperties yiyan; | ||
| 30 | + | ||
| 31 | + @Data | ||
| 32 | + @Accessors(chain = true) | ||
| 33 | + public static class QianWenProperties extends ChatProperties { | ||
| 34 | + /** | ||
| 35 | + * 阿里云:服务器接入点 | ||
| 36 | + */ | ||
| 37 | + private String endpoint = "bailian.cn-beijing.aliyuncs.com"; | ||
| 38 | + /** | ||
| 39 | + * 阿里云:权限 accessKeyId | ||
| 40 | + */ | ||
| 41 | + private String accessKeyId; | ||
| 42 | + /** | ||
| 43 | + * 阿里云:权限 accessKeySecret | ||
| 44 | + */ | ||
| 45 | + private String accessKeySecret; | ||
| 46 | + /** | ||
| 47 | + * 阿里云:agentKey | ||
| 48 | + */ | ||
| 49 | + private String agentKey; | ||
| 50 | + /** | ||
| 51 | + * 阿里云:agentKey(相当于应用id) | ||
| 52 | + */ | ||
| 53 | + private String appId; | ||
| 54 | + | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Data | ||
| 58 | + @Accessors(chain = true) | ||
| 59 | + public static class XingHuoProperties extends ChatProperties { | ||
| 60 | + private String appId; | ||
| 61 | + private String appKey; | ||
| 62 | + private String secretKey; | ||
| 63 | + private XingHuoChatModel chatModel; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + @Data | ||
| 67 | + @Accessors(chain = true) | ||
| 68 | + public static class YiYanProperties extends ChatProperties { | ||
| 69 | + /** | ||
| 70 | + * appKey | ||
| 71 | + */ | ||
| 72 | + private String appKey; | ||
| 73 | + /** | ||
| 74 | + * secretKey | ||
| 75 | + */ | ||
| 76 | + private String secretKey; | ||
| 77 | + /** | ||
| 78 | + * 模型 | ||
| 79 | + */ | ||
| 80 | + private YiYanChatModel chatModel = YiYanChatModel.ERNIE4_3_5_8K; | ||
| 81 | + /** | ||
| 82 | + * token 刷新时间(默认 86400 = 24小时) | ||
| 83 | + */ | ||
| 84 | + private int refreshTokenSecondTime = 86400; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + @Data | ||
| 88 | + @Accessors(chain = true) | ||
| 89 | + public static class ChatProperties { | ||
| 90 | + | ||
| 91 | + private AiPlatformEnum aiPlatform; | ||
| 92 | + | ||
| 93 | + private Float temperature; | ||
| 94 | + | ||
| 95 | + private Float topP; | ||
| 96 | + | ||
| 97 | + private Integer topK; | ||
| 98 | + } | ||
| 99 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java
| @@ -7,9 +7,6 @@ import lombok.Data; | @@ -7,9 +7,6 @@ import lombok.Data; | ||
| 7 | import lombok.experimental.Accessors; | 7 | import lombok.experimental.Accessors; |
| 8 | import org.springframework.boot.context.properties.ConfigurationProperties; | 8 | import org.springframework.boot.context.properties.ConfigurationProperties; |
| 9 | 9 | ||
| 10 | -import java.util.LinkedHashMap; | ||
| 11 | -import java.util.Map; | ||
| 12 | - | ||
| 13 | /** | 10 | /** |
| 14 | * ai 自动配置 | 11 | * ai 自动配置 |
| 15 | * | 12 | * |
| @@ -18,17 +15,21 @@ import java.util.Map; | @@ -18,17 +15,21 @@ import java.util.Map; | ||
| 18 | * @since 1.0 | 15 | * @since 1.0 |
| 19 | */ | 16 | */ |
| 20 | @Data | 17 | @Data |
| 18 | +@Accessors(chain = true) | ||
| 21 | @ConfigurationProperties(prefix = "yudao.ai") | 19 | @ConfigurationProperties(prefix = "yudao.ai") |
| 22 | -public class YudaoAiProperties extends LinkedHashMap<String, Map<String, Object>> { | 20 | +public class YudaoAiProperties { |
| 23 | 21 | ||
| 24 | -// private QianWenProperties qianWen; | ||
| 25 | -// private XingHuoProperties xingHuo; | ||
| 26 | -// private YiYanProperties yiYan; | 22 | + private String initSource; |
| 23 | + private QianWenProperties qianwen; | ||
| 24 | + private XingHuoProperties xinghuo; | ||
| 25 | + private YiYanProperties yiyan; | ||
| 27 | 26 | ||
| 28 | @Data | 27 | @Data |
| 29 | @Accessors(chain = true) | 28 | @Accessors(chain = true) |
| 30 | public static class ChatProperties { | 29 | public static class ChatProperties { |
| 31 | 30 | ||
| 31 | + private boolean enable = false; | ||
| 32 | + | ||
| 32 | private AiPlatformEnum aiPlatform; | 33 | private AiPlatformEnum aiPlatform; |
| 33 | 34 | ||
| 34 | private Float temperature; | 35 | private Float temperature; |
yudao-server/src/main/resources/application-local.yaml
| @@ -224,7 +224,9 @@ wx: | @@ -224,7 +224,9 @@ wx: | ||
| 224 | # 芋道配置项,设置当前项目所有自定义的配置 | 224 | # 芋道配置项,设置当前项目所有自定义的配置 |
| 225 | yudao: | 225 | yudao: |
| 226 | ai: | 226 | ai: |
| 227 | - qianWen: | 227 | + initSource: yaml |
| 228 | + qianwen: | ||
| 229 | + enable: true | ||
| 228 | aiPlatform: QIAN_WEN | 230 | aiPlatform: QIAN_WEN |
| 229 | temperature: 1 | 231 | temperature: 1 |
| 230 | topP: 1 | 232 | topP: 1 |
| @@ -234,7 +236,8 @@ yudao: | @@ -234,7 +236,8 @@ yudao: | ||
| 234 | accessKeySecret: ZJ0JQeyjzxxm5CfeTV6k1wNE9UsvZP | 236 | accessKeySecret: ZJ0JQeyjzxxm5CfeTV6k1wNE9UsvZP |
| 235 | agentKey: f0c1088824594f589c8f10567ccd929f_p_efm | 237 | agentKey: f0c1088824594f589c8f10567ccd929f_p_efm |
| 236 | appId: 5f14955f201a44eb8dbe0c57250a32ce | 238 | appId: 5f14955f201a44eb8dbe0c57250a32ce |
| 237 | - xingHuo: | 239 | + xinghuo: |
| 240 | + enable: true | ||
| 238 | aiPlatform: XING_HUO | 241 | aiPlatform: XING_HUO |
| 239 | temperature: 1 | 242 | temperature: 1 |
| 240 | topP: 1 | 243 | topP: 1 |
| @@ -243,7 +246,8 @@ yudao: | @@ -243,7 +246,8 @@ yudao: | ||
| 243 | appKey: cb6415c19d6162cda07b47316fcb0416 | 246 | appKey: cb6415c19d6162cda07b47316fcb0416 |
| 244 | secretKey: Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh | 247 | secretKey: Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh |
| 245 | chatModel: XING_HUO_3_5 | 248 | chatModel: XING_HUO_3_5 |
| 246 | - yiYan3_5_8k: | 249 | + yiyan: |
| 250 | + enable: true | ||
| 247 | aiPlatform: YI_YAN | 251 | aiPlatform: YI_YAN |
| 248 | temperature: 1 | 252 | temperature: 1 |
| 249 | topP: 1 | 253 | topP: 1 |
| @@ -252,6 +256,7 @@ yudao: | @@ -252,6 +256,7 @@ yudao: | ||
| 252 | secretKey: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK | 256 | secretKey: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK |
| 253 | refreshTokenSecondTime: 86400 | 257 | refreshTokenSecondTime: 86400 |
| 254 | chatModel: ERNIE4_3_5_8K | 258 | chatModel: ERNIE4_3_5_8K |
| 259 | + | ||
| 255 | captcha: | 260 | captcha: |
| 256 | enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试; | 261 | enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试; |
| 257 | security: | 262 | security: |