Commit 6d10f136a037ddc5afaaa131cf54f002eeacd3aa

Authored by 芋道源码
Committed by GitHub
2 parents ba8f8b36 2208396e

Merge pull request #981 from gezipppp-ux/master-jdk17

支持 GROK
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
@@ -40,6 +40,7 @@ public enum AiPlatformEnum implements ArrayValuable<String> { @@ -40,6 +40,7 @@ public enum AiPlatformEnum implements ArrayValuable<String> {
40 STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI 40 STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI
41 MIDJOURNEY("Midjourney", "Midjourney"), // Midjourney 41 MIDJOURNEY("Midjourney", "Midjourney"), // Midjourney
42 SUNO("Suno", "Suno"), // Suno AI 42 SUNO("Suno", "Suno"), // Suno AI
  43 + GROK("Grok","Grok"), // Grok
43 44
44 ; 45 ;
45 46
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactoryImpl; @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactoryImpl;
7 import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel; 7 import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
8 import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel; 8 import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
9 import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel; 9 import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
  10 +import cn.iocoder.yudao.module.ai.framework.ai.core.model.grok.GrokChatModel;
10 import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel; 11 import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
11 import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi; 12 import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
12 import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; 13 import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
@@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient; @@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient;
17 import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha.AiBoChaWebSearchClient; 18 import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha.AiBoChaWebSearchClient;
18 import cn.iocoder.yudao.module.ai.tool.method.PersonService; 19 import cn.iocoder.yudao.module.ai.tool.method.PersonService;
19 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.ai.chat.model.ChatModel;
20 import org.springframework.ai.deepseek.DeepSeekChatModel; 22 import org.springframework.ai.deepseek.DeepSeekChatModel;
21 import org.springframework.ai.deepseek.DeepSeekChatOptions; 23 import org.springframework.ai.deepseek.DeepSeekChatOptions;
22 import org.springframework.ai.deepseek.api.DeepSeekApi; 24 import org.springframework.ai.deepseek.api.DeepSeekApi;
@@ -40,6 +42,7 @@ import org.springframework.context.annotation.Bean; @@ -40,6 +42,7 @@ import org.springframework.context.annotation.Bean;
40 import org.springframework.context.annotation.Configuration; 42 import org.springframework.context.annotation.Configuration;
41 43
42 import java.util.List; 44 import java.util.List;
  45 +import java.util.Optional;
43 46
44 /** 47 /**
45 * 芋道 AI 自动配置 48 * 芋道 AI 自动配置
@@ -286,4 +289,25 @@ public class AiAutoConfiguration { @@ -286,4 +289,25 @@ public class AiAutoConfiguration {
286 return List.of(ToolCallbacks.from(personService)); 289 return List.of(ToolCallbacks.from(personService));
287 } 290 }
288 291
  292 + public ChatModel buildGrokChatClient(YudaoAiProperties.Grok properties) {
  293 + if (StrUtil.isEmpty(properties.getModel())) {
  294 + properties.setModel(GrokChatModel.MODEL_DEFAULT);
  295 + }
  296 + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
  297 + .openAiApi(OpenAiApi.builder()
  298 + .baseUrl(Optional.ofNullable(properties.getBaseUrl())
  299 + .orElse(GrokChatModel.BASE_URL))
  300 + .completionsPath(GrokChatModel.COMPLETE_PATH)
  301 + .apiKey(properties.getApiKey())
  302 + .build())
  303 + .defaultOptions(OpenAiChatOptions.builder()
  304 + .model(properties.getModel())
  305 + .temperature(properties.getTemperature())
  306 + .maxTokens(properties.getMaxTokens())
  307 + .topP(properties.getTopP())
  308 + .build())
  309 + .toolCallingManager(getToolCallingManager())
  310 + .build();
  311 + return new DouBaoChatModel(openAiChatModel);
  312 + }
289 } 313 }
290 \ No newline at end of file 314 \ No newline at end of file
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
@@ -161,6 +161,20 @@ public class YudaoAiProperties { @@ -161,6 +161,20 @@ public class YudaoAiProperties {
161 } 161 }
162 162
163 @Data 163 @Data
  164 + public static class Grok {
  165 +
  166 + private String enable;
  167 + private String apiKey;
  168 + private String baseUrl;
  169 +
  170 + private String model;
  171 + private Double temperature;
  172 + private Integer maxTokens;
  173 + private Double topP;
  174 +
  175 + }
  176 +
  177 + @Data
164 public static class WebSearch { 178 public static class WebSearch {
165 179
166 private boolean enable; 180 private boolean enable;
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
@@ -178,6 +178,8 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -178,6 +178,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
178 return buildGeminiChatModel(apiKey); 178 return buildGeminiChatModel(apiKey);
179 case OLLAMA: 179 case OLLAMA:
180 return buildOllamaChatModel(url); 180 return buildOllamaChatModel(url);
  181 + case GROK:
  182 + return buildGrokChatModel(apiKey,url);
181 default: 183 default:
182 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); 184 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
183 } 185 }
@@ -405,6 +407,12 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -405,6 +407,12 @@ public class AiModelFactoryImpl implements AiModelFactory {
405 .build(); 407 .build();
406 } 408 }
407 409
  410 + private ChatModel buildGrokChatModel(String apiKey,String url) {
  411 + YudaoAiProperties.Grok properties = new YudaoAiProperties.Grok()
  412 + .setBaseUrl(url)
  413 + .setApiKey(apiKey);
  414 + return new AiAutoConfiguration().buildGrokChatClient(properties);
  415 + }
408 /** 416 /**
409 * 可参考 {@link AiAutoConfiguration#douBaoChatClient(YudaoAiProperties)} 417 * 可参考 {@link AiAutoConfiguration#douBaoChatClient(YudaoAiProperties)}
410 */ 418 */
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.framework.ai.core.model.grok;
  2 +
  3 +import lombok.RequiredArgsConstructor;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.ai.chat.model.ChatModel;
  6 +import org.springframework.ai.chat.model.ChatResponse;
  7 +import org.springframework.ai.chat.prompt.ChatOptions;
  8 +import org.springframework.ai.chat.prompt.Prompt;
  9 +import reactor.core.publisher.Flux;
  10 +
  11 +/**
  12 + * Grok {@link ChatModel} 实现类
  13 + *
  14 + *
  15 + */
  16 +@Slf4j
  17 +@RequiredArgsConstructor
  18 +public class GrokChatModel implements ChatModel {
  19 +
  20 + public static final String BASE_URL = "https://api.x.ai";
  21 + public static final String COMPLETE_PATH = "/v1/chat/completions";
  22 + public static final String MODEL_DEFAULT = "grok-4-fast-reasoning";
  23 +
  24 + /**
  25 + * 兼容 OpenAI 接口,进行复用
  26 + */
  27 + private final ChatModel openAiChatModel;
  28 +
  29 + @Override
  30 + public ChatResponse call(Prompt prompt) {
  31 + return openAiChatModel.call(prompt);
  32 + }
  33 +
  34 + @Override
  35 + public Flux<ChatResponse> stream(Prompt prompt) {
  36 + return openAiChatModel.stream(prompt);
  37 + }
  38 +
  39 + @Override
  40 + public ChatOptions getDefaultOptions() {
  41 + return openAiChatModel.getDefaultOptions();
  42 + }
  43 +
  44 +}
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
@@ -79,6 +79,9 @@ public class AiUtils { @@ -79,6 +79,9 @@ public class AiUtils {
79 case OLLAMA: 79 case OLLAMA:
80 return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens) 80 return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
81 .toolCallbacks(toolCallbacks).toolContext(toolContext).build(); 81 .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
  82 + case GROK:
  83 + return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
  84 + .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
82 default: 85 default:
83 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); 86 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
84 } 87 }