Merge branch 'master-jdk25' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk25

# Conflicts:
#	yudao-module-ai/pom.xml
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java
#	yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java
#	yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
#	yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
This commit is contained in:
YunaiV
2026-06-29 17:35:10 -07:00
8 changed files with 744 additions and 410 deletions
+1 -1
View File
@@ -36,7 +36,7 @@
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
<revision>2026.05-jdk25-SNAPSHOT</revision>
<revision>2026.06-jdk25-SNAPSHOT</revision>
<!-- Maven 相关 -->
<java.version>25</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -14,7 +14,7 @@
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
<revision>2026.05-jdk25-SNAPSHOT</revision>
<revision>2026.06-jdk25-SNAPSHOT</revision>
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
<!-- 统一依赖管理 -->
<spring.boot.version>4.1.0</spring.boot.version>
@@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.stepfun;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import reactor.core.publisher.Flux;
/**
* 阶跃星辰 {@link ChatModel} 实现类
*
* @author 芋道源码
*/
@Slf4j
@RequiredArgsConstructor
public class StepFunChatModel implements ChatModel {
public static final String BASE_URL = "https://api.stepfun.com";
public static final String COMPLETE_PATH = "/v1/chat/completions";
public static final String MODEL_DEFAULT = "step-3.7-flash";
/**
* 兼容 OpenAI 接口,复用 DeepSeek 客户端
*/
private final DeepSeekChatModel deepSeekChatModel;
@Override
public ChatResponse call(Prompt prompt) {
return deepSeekChatModel.call(prompt);
}
@Override
public Flux<ChatResponse> stream(Prompt prompt) {
return deepSeekChatModel.stream(prompt);
}
@Override
public ChatOptions getOptions() {
return deepSeekChatModel.getOptions();
}
@Override
@Deprecated(forRemoval = true)
@SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
return getOptions();
}
}
@@ -0,0 +1,80 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import cn.hutool.system.SystemUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* Azure OpenAI 集成测试
*
* @author 芋道源码
*/
public class AzureOpenAIChatModelTests {
private static final String BASE_URL = SystemUtil.get("AZURE_OPENAI_BASE_URL",
"https://xxx.openai.azure.com");
private static final String API_KEY = SystemUtil.get("AZURE_OPENAI_API_KEY",
"sk-xxxx"); // 按需改成你的 Azure OpenAI API Key
private static final String DEPLOYMENT_NAME = SystemUtil.get("AZURE_OPENAI_DEPLOYMENT_NAME",
"gpt-5.4"); // Azure 上创建的模型部署名称
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
.options(OpenAiChatOptions.builder()
.baseUrl(BASE_URL)
.apiKey(API_KEY)
.model(DEPLOYMENT_NAME)
.microsoftFoundry(true)
.deploymentName(DEPLOYMENT_NAME)
.temperature(0.7)
.build())
.build();
@Test
@Disabled
public void testCall() {
validateApiKey(API_KEY);
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
validateApiKey(API_KEY);
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
}
@@ -0,0 +1,77 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.grok.GrokChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link GrokChatModel} 集成测试
*
* @author 芋道源码
*/
public class GrokChatModelTests {
private static final String API_KEY = SystemUtil.get("GROK_API_KEY",
"sk-xxxx");
private static final String MODEL = SystemUtil.get("GROK_MODEL",
GrokChatModel.MODEL_DEFAULT);
private final GrokChatModel chatModel = new GrokChatModel(OpenAiChatModel.builder()
.options(OpenAiChatOptions.builder()
.baseUrl(GrokChatModel.BASE_URL)
.apiKey(API_KEY)
.model(MODEL)
.temperature(0.7)
.build())
.build());
@Test
@Disabled
public void testCall() {
validateApiKey(API_KEY);
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
validateApiKey(API_KEY);
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
}
@@ -0,0 +1,82 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.stepfun.StepFunChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link StepFunChatModel} 集成测试
*
* @author 芋道源码
*/
public class StepFunChatModelTests {
private static final String API_KEY = SystemUtil.get("STEPFUN_API_KEY",
"sk-xxxx");
private static final String MODEL = SystemUtil.get("STEPFUN_MODEL",
StepFunChatModel.MODEL_DEFAULT);
private final StepFunChatModel chatModel = new StepFunChatModel(DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(StepFunChatModel.BASE_URL)
.completionsPath(StepFunChatModel.COMPLETE_PATH)
.apiKey(API_KEY)
.build())
.options(DeepSeekChatOptions.builder()
.model(MODEL)
.temperature(0.7)
.build())
.build());
@Test
@Disabled
public void testCall() {
validateApiKey(API_KEY);
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
validateApiKey(API_KEY);
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
// System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
System.out.println(response.getResult() != null ? response.getResult().getOutput() : null);
}).then().block();
}
}
@@ -154,13 +154,11 @@ spring:
host: 127.0.0.1
port: 19530
openai: # OpenAI 官方
api-key: sk-aN6nWn3fILjrgLFT0fC4Aa60B72e4253826c77B29dC94f17
base-url: https://api.gptsapi.net
azure: # OpenAI 微软
openai:
endpoint: https://eastusprejade.openai.azure.com
base-url: ${OPENAI_BASE_URL}
api-key: ${OPENAI_API_KEY}
anthropic: # Anthropic Claude
api-key: sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942
base-url: ${ANTHROPIC_BASE_URL}
api-key: ${ANTHROPIC_API_KEY}
ollama:
base-url: http://127.0.0.1:11434
chat:
@@ -168,12 +166,17 @@ spring:
stabilityai:
api-key: sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx
dashscope: # 通义千问
api-key: sk-47aa124781be4bfb95244cc62f6xxxx
api-key: ${DASHSCOPE_API_KEY}
deepseek: # DeepSeek
api-key: sk-e94db327cc7d457d99a8de8810fc6b12
api-key: ${DEEPSEEK_API_KEY}
chat:
options:
model: deepseek-chat
model: deepseek-v4-flash
google:
genai: # 谷歌 Gemini
api-key: ${GEMINI_API_KEY}
chat:
model: gemini-2.5-flash
model:
rerank: false # 是否开启“通义千问”的 Rerank 模型,填写 dashscope 开启
mcp:
@@ -196,47 +199,50 @@ spring:
yudao:
ai:
gemini: # 谷歌 Gemini
enable: true
api-key: AIzaSyAVoBxgoFvvte820vEQMma2LKBnC98bqMQ
model: gemini-2.5-flash
doubao: # 字节豆包
enable: true
api-key: 5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272
model: doubao-1-5-lite-32k-250115
api-key: ${DOUBAO_API_KEY}
model: doubao-seed-2-1-turbo-260628
hunyuan: # 腾讯混元
enable: true
api-key: sk-abc
model: hunyuan-turbo
api-key: ${HUNYUAN_API_KEY}
model: hy3-preview
siliconflow: # 硅基流动
enable: true
api-key: sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz
model: deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
api-key: ${SILICONFLOW_API_KEY}
model: deepseek-ai/DeepSeek-V4-Pro
xinghuo: # 讯飞星火
enable: true
appKey: 75b161ed2aef4719b275d6e7f2a4d4cd
secretKey: YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz
model: x1
api-key: ${XINGHUO_API_KEY}
model: x2-flash
baichuan: # 百川智能
enable: true
api-key: sk-abc
model: Baichuan4-Turbo
api-key: ${BAICHUAN_API_KEY}
model: Baichuan-M3
yiyan: # 文心一言
enable: false
api-key: bce-v3/xxxx
model: ernie-4.0-8k-latest
api-key: ${YIYAN_API_KEY}
model: ernie-5.1
zhipu: # 智谱 AI(GLM)
enable: false
api-key: sk-abc
api-key: ${ZHIPU_API_KEY}
model: glm-5.2
minimax: # MiniMax
enable: false
api-key: xxxx
api-key: ${MINIMAX_API_KEY}
model: MiniMax-M3
moonshot: # 月之暗面(KIMI)
enable: false
api-key: sk-abc
api-key: ${MOONSHOT_API_KEY}
model: kimi-k2.6
stepfun: # 阶跃星辰
enable: false
api-key: ${STEPFUN_API_KEY}
model: step-3.7-flash
grok: # Grok
enable: false
api-key: ${GROK_API_KEY}
model: grok-4.3
midjourney:
enable: true
# base-url: https://api.holdai.top/mj-relax/mj