+ * MiniMax提供OpenAI兼容的API接口,支持MiniMax-M2.7、MiniMax-M2.5等模型。 + * API地址:https://api.minimax.io/v1 + * + * @author octopus + * @date 2026/3/21 + */ +@Service +@Slf4j +public class MinimaxServiceImpl implements AbstractChatService { + + @Override + public StreamingChatModel buildStreamingChatModel(ChatModelVo chatModelVo, ChatRequest chatRequest) { + return OpenAiStreamingChatModel.builder() + .baseUrl(chatModelVo.getApiHost()) + .apiKey(chatModelVo.getApiKey()) + .modelName(chatModelVo.getModelName()) + .listeners(List.of(new MyChatModelListener())) + .returnThinking(chatRequest.getEnableThinking()) + .build(); + } + + @Override + public String getProviderName() { + return ChatModeType.MINIMAX.getCode(); + } + +} diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/embed/impl/MinimaxEmbeddingProvider.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/embed/impl/MinimaxEmbeddingProvider.java new file mode 100644 index 00000000..4d2dbec5 --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/embed/impl/MinimaxEmbeddingProvider.java @@ -0,0 +1,17 @@ +package org.ruoyi.service.embed.impl; + +import org.springframework.stereotype.Component; + +/** + * MiniMax嵌入模型(兼容OpenAI接口) + *
+ * 支持embo-01模型,1536维度向量。
+ * API地址:https://api.minimax.io/v1
+ *
+ * @author octopus
+ * @date 2026/3/21
+ */
+@Component("minimax")
+public class MinimaxEmbeddingProvider extends OpenAiEmbeddingProvider {
+
+}
diff --git a/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/enums/ChatModeTypeTest.java b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/enums/ChatModeTypeTest.java
new file mode 100644
index 00000000..9733af8b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/enums/ChatModeTypeTest.java
@@ -0,0 +1,42 @@
+package org.ruoyi.enums;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for ChatModeType enum
+ */
+class ChatModeTypeTest {
+
+ @Test
+ void minimaxEnumExists() {
+ ChatModeType minimax = ChatModeType.MINIMAX;
+ assertNotNull(minimax);
+ }
+
+ @Test
+ void minimaxCode_isMinimax() {
+ assertEquals("minimax", ChatModeType.MINIMAX.getCode());
+ }
+
+ @Test
+ void minimaxDescription_isMiniMax() {
+ assertEquals("MiniMax", ChatModeType.MINIMAX.getDescription());
+ }
+
+ @Test
+ void allProviders_haveUniqueCode() {
+ ChatModeType[] values = ChatModeType.values();
+ long uniqueCodes = java.util.Arrays.stream(values)
+ .map(ChatModeType::getCode)
+ .distinct()
+ .count();
+ assertEquals(values.length, uniqueCodes, "All providers must have unique codes");
+ }
+
+ @Test
+ void valueOf_minimax() {
+ assertEquals(ChatModeType.MINIMAX, ChatModeType.valueOf("MINIMAX"));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/integration/MinimaxIntegrationTest.java b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/integration/MinimaxIntegrationTest.java
new file mode 100644
index 00000000..7e052e6d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/integration/MinimaxIntegrationTest.java
@@ -0,0 +1,70 @@
+package org.ruoyi.integration;
+
+import dev.langchain4j.model.chat.StreamingChatModel;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
+import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
+import org.ruoyi.service.chat.impl.provider.MinimaxServiceImpl;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Integration tests for MiniMax provider.
+ * These tests require a valid MINIMAX_API_KEY environment variable.
+ */
+@EnabledIfEnvironmentVariable(named = "MINIMAX_API_KEY", matches = ".+")
+class MinimaxIntegrationTest {
+
+ private MinimaxServiceImpl minimaxService;
+ private String apiKey;
+
+ @BeforeEach
+ void setUp() {
+ minimaxService = new MinimaxServiceImpl();
+ apiKey = System.getenv("MINIMAX_API_KEY");
+ }
+
+ @Test
+ void buildStreamingChatModel_withRealApiKey_M27() {
+ ChatModelVo modelVo = new ChatModelVo();
+ modelVo.setApiHost("https://api.minimax.io/v1");
+ modelVo.setApiKey(apiKey);
+ modelVo.setModelName("MiniMax-M2.7");
+
+ ChatRequest request = new ChatRequest();
+ request.setEnableThinking(false);
+
+ StreamingChatModel model = minimaxService.buildStreamingChatModel(modelVo, request);
+ assertNotNull(model, "Should create streaming model with real API key");
+ }
+
+ @Test
+ void buildStreamingChatModel_withRealApiKey_M25() {
+ ChatModelVo modelVo = new ChatModelVo();
+ modelVo.setApiHost("https://api.minimax.io/v1");
+ modelVo.setApiKey(apiKey);
+ modelVo.setModelName("MiniMax-M2.5");
+
+ ChatRequest request = new ChatRequest();
+ request.setEnableThinking(false);
+
+ StreamingChatModel model = minimaxService.buildStreamingChatModel(modelVo, request);
+ assertNotNull(model, "Should create streaming model with M2.5");
+ }
+
+ @Test
+ void buildStreamingChatModel_withRealApiKey_M25Highspeed() {
+ ChatModelVo modelVo = new ChatModelVo();
+ modelVo.setApiHost("https://api.minimax.io/v1");
+ modelVo.setApiKey(apiKey);
+ modelVo.setModelName("MiniMax-M2.5-highspeed");
+
+ ChatRequest request = new ChatRequest();
+ request.setEnableThinking(false);
+
+ StreamingChatModel model = minimaxService.buildStreamingChatModel(modelVo, request);
+ assertNotNull(model, "Should create streaming model with M2.5-highspeed");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/service/chat/impl/provider/MinimaxServiceImplTest.java b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/service/chat/impl/provider/MinimaxServiceImplTest.java
new file mode 100644
index 00000000..697f52e2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/service/chat/impl/provider/MinimaxServiceImplTest.java
@@ -0,0 +1,76 @@
+package org.ruoyi.service.chat.impl.provider;
+
+import dev.langchain4j.model.chat.StreamingChatModel;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
+import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
+import org.ruoyi.enums.ChatModeType;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for MinimaxServiceImpl
+ */
+class MinimaxServiceImplTest {
+
+ private MinimaxServiceImpl minimaxService;
+
+ @BeforeEach
+ void setUp() {
+ minimaxService = new MinimaxServiceImpl();
+ }
+
+ @Test
+ void getProviderName_returnsMinimaxCode() {
+ assertEquals("minimax", minimaxService.getProviderName());
+ assertEquals(ChatModeType.MINIMAX.getCode(), minimaxService.getProviderName());
+ }
+
+ @Test
+ void buildStreamingChatModel_returnsNonNull() {
+ ChatModelVo modelVo = new ChatModelVo();
+ modelVo.setApiHost("https://api.minimax.io/v1");
+ modelVo.setApiKey("test-api-key");
+ modelVo.setModelName("MiniMax-M2.7");
+
+ ChatRequest request = new ChatRequest();
+ request.setEnableThinking(false);
+
+ StreamingChatModel model = minimaxService.buildStreamingChatModel(modelVo, request);
+ assertNotNull(model);
+ }
+
+ @Test
+ void buildStreamingChatModel_withThinkingEnabled() {
+ ChatModelVo modelVo = new ChatModelVo();
+ modelVo.setApiHost("https://api.minimax.io/v1");
+ modelVo.setApiKey("test-api-key");
+ modelVo.setModelName("MiniMax-M2.5");
+
+ ChatRequest request = new ChatRequest();
+ request.setEnableThinking(true);
+
+ StreamingChatModel model = minimaxService.buildStreamingChatModel(modelVo, request);
+ assertNotNull(model);
+ }
+
+ @Test
+ void buildStreamingChatModel_withHighspeedModel() {
+ ChatModelVo modelVo = new ChatModelVo();
+ modelVo.setApiHost("https://api.minimax.io/v1");
+ modelVo.setApiKey("test-api-key");
+ modelVo.setModelName("MiniMax-M2.5-highspeed");
+
+ ChatRequest request = new ChatRequest();
+ request.setEnableThinking(false);
+
+ StreamingChatModel model = minimaxService.buildStreamingChatModel(modelVo, request);
+ assertNotNull(model);
+ }
+
+ @Test
+ void implementsAbstractChatService() {
+ assertInstanceOf(org.ruoyi.service.chat.AbstractChatService.class, minimaxService);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/service/embed/impl/MinimaxEmbeddingProviderTest.java b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/service/embed/impl/MinimaxEmbeddingProviderTest.java
new file mode 100644
index 00000000..e089aae1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-chat/src/test/java/org/ruoyi/service/embed/impl/MinimaxEmbeddingProviderTest.java
@@ -0,0 +1,55 @@
+package org.ruoyi.service.embed.impl;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
+import org.ruoyi.enums.ModalityType;
+import org.ruoyi.service.embed.BaseEmbedModelService;
+
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for MinimaxEmbeddingProvider
+ */
+class MinimaxEmbeddingProviderTest {
+
+ private MinimaxEmbeddingProvider provider;
+
+ @BeforeEach
+ void setUp() {
+ provider = new MinimaxEmbeddingProvider();
+ }
+
+ @Test
+ void implementsBaseEmbedModelService() {
+ assertInstanceOf(BaseEmbedModelService.class, provider);
+ }
+
+ @Test
+ void extendsOpenAiEmbeddingProvider() {
+ assertInstanceOf(OpenAiEmbeddingProvider.class, provider);
+ }
+
+ @Test
+ void getSupportedModalities_returnsText() {
+ Set