mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-04-27 18:46:41 +00:00
Compare commits
5 Commits
c4f7c1f5d0
...
081da6d18d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
081da6d18d | ||
|
|
74eb5b2530 | ||
|
|
b0328fe0ef | ||
|
|
2ee0aae57e | ||
|
|
d9c3de660a |
@@ -31,8 +31,8 @@
|
|||||||
|
|
||||||
| 模块 | 现有能力
|
| 模块 | 现有能力
|
||||||
|:----------:|---
|
|:----------:|---
|
||||||
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱)、多模态理解、Coze/DIFY/FastGPT平台集成
|
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱/MiniMax)、多模态理解、Coze/DIFY/FastGPT平台集成
|
||||||
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
|
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
|
||||||
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
|
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
|
||||||
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
|
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
|
||||||
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型
|
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
| Module | Current Capabilities |
|
| Module | Current Capabilities |
|
||||||
|:---:|---|
|
|:---:|---|
|
||||||
| **Model Management** | Multi-model integration (OpenAI/DeepSeek/Tongyi/Zhipu), multi-modal understanding, Coze/DIFY/FastGPT platform integration |
|
| **Model Management** | Multi-model integration (OpenAI/DeepSeek/Tongyi/Zhipu/MiniMax), multi-modal understanding, Coze/DIFY/FastGPT platform integration |
|
||||||
| **Knowledge Base** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
|
| **Knowledge Base** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
|
||||||
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
|
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
|
||||||
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review nodes |
|
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review nodes |
|
||||||
|
|||||||
23
docs/script/sql/minimax_provider.sql
Normal file
23
docs/script/sql/minimax_provider.sql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Add MiniMax provider
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `chat_provider` (`id`, `provider_name`, `provider_code`, `provider_icon`, `provider_desc`, `api_host`, `status`, `sort_order`, `create_dept`, `create_time`, `create_by`, `update_by`, `update_time`, `remark`, `version`, `del_flag`, `update_ip`, `tenant_id`)
|
||||||
|
VALUES (2010000000000000001, 'MiniMax', 'minimax', NULL, 'MiniMax大模型服务,支持M2.7、M2.5等模型', 'https://api.minimax.io/v1', '0', 6, NULL, NOW(), '1', '1', NOW(), 'MiniMax厂商', NULL, '0', NULL, 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Add MiniMax chat models
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
|
||||||
|
VALUES (2010000000000000002, 'chat', 'MiniMax-M2.7', 'minimax', 'MiniMax-M2.7', NULL, 'Y', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax最新旗舰模型M2.7,支持1M上下文窗口', 0);
|
||||||
|
|
||||||
|
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
|
||||||
|
VALUES (2010000000000000003, 'chat', 'MiniMax-M2.5', 'minimax', 'MiniMax-M2.5', NULL, 'Y', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax M2.5模型,204K上下文窗口', 0);
|
||||||
|
|
||||||
|
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
|
||||||
|
VALUES (2010000000000000004, 'chat', 'MiniMax-M2.5-highspeed', 'minimax', 'MiniMax-M2.5-highspeed', NULL, 'Y', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax M2.5高速版,204K上下文窗口,更低延迟', 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Add MiniMax embedding model
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `chat_model` (`id`, `category`, `model_name`, `provider_code`, `model_describe`, `model_dimension`, `model_show`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `tenant_id`)
|
||||||
|
VALUES (2010000000000000005, 'vector', 'embo-01', 'minimax', 'embo-01', 1536, 'N', 'https://api.minimax.io/v1', '', NULL, 1, NOW(), 1, NOW(), 'MiniMax embo-01嵌入模型,1536维度', 0);
|
||||||
@@ -173,6 +173,21 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
|||||||
import org.ruoyi.common.chat.service.chat.IChatModelService;
|
import org.ruoyi.common.chat.service.chat.IChatModelService;
|
||||||
import org.ruoyi.common.chat.domain.bo.chat.ChatModelBo;
|
import org.ruoyi.common.chat.domain.bo.chat.ChatModelBo;
|
||||||
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
|
import org.ruoyi.enums.ChatModeType;
|
||||||
import org.ruoyi.enums.ModelType;
|
import org.ruoyi.enums.ModelType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
@@ -23,6 +24,8 @@ import org.ruoyi.common.log.enums.BusinessType;
|
|||||||
import org.ruoyi.common.excel.utils.ExcelUtil;
|
import org.ruoyi.common.excel.utils.ExcelUtil;
|
||||||
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模型管理
|
* 模型管理
|
||||||
*
|
*
|
||||||
@@ -55,6 +58,21 @@ public class ChatModelController extends BaseController {
|
|||||||
return R.ok(chatModelService.queryList(bo));
|
return R.ok(chatModelService.queryList(bo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模型供应商枚举
|
||||||
|
*/
|
||||||
|
@GetMapping("/providerOptions")
|
||||||
|
public R<List<LinkedHashMap<String, String>>> providerOptions() {
|
||||||
|
List<LinkedHashMap<String, String>> options = new java.util.ArrayList<>();
|
||||||
|
for (ChatModeType type : ChatModeType.values()) {
|
||||||
|
LinkedHashMap<String, String> item = new LinkedHashMap<>();
|
||||||
|
item.put("label", type.getDescription());
|
||||||
|
item.put("value", type.getCode());
|
||||||
|
options.add(item);
|
||||||
|
}
|
||||||
|
return R.ok(options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出模型管理列表
|
* 导出模型管理列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
package org.ruoyi.controller.knowledge;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
||||||
import org.ruoyi.domain.bo.knowledge.KnowledgeGraphInstanceBo;
|
|
||||||
import org.ruoyi.domain.vo.knowledge.KnowledgeGraphInstanceVo;
|
|
||||||
import org.ruoyi.service.knowledge.IKnowledgeGraphInstanceService;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.ruoyi.common.idempotent.annotation.RepeatSubmit;
|
|
||||||
import org.ruoyi.common.log.annotation.Log;
|
|
||||||
import org.ruoyi.common.web.core.BaseController;
|
|
||||||
import org.ruoyi.common.mybatis.core.page.PageQuery;
|
|
||||||
import org.ruoyi.common.core.domain.R;
|
|
||||||
import org.ruoyi.common.core.validate.AddGroup;
|
|
||||||
import org.ruoyi.common.core.validate.EditGroup;
|
|
||||||
import org.ruoyi.common.log.enums.BusinessType;
|
|
||||||
import org.ruoyi.common.excel.utils.ExcelUtil;
|
|
||||||
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 知识图谱实例
|
|
||||||
*
|
|
||||||
* @author ageerle
|
|
||||||
* @date 2025-12-17
|
|
||||||
*/
|
|
||||||
@Validated
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/system/graphInstance")
|
|
||||||
public class KnowledgeGraphInstanceController extends BaseController {
|
|
||||||
|
|
||||||
private final IKnowledgeGraphInstanceService knowledgeGraphInstanceService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询知识图谱实例列表
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphInstance:list")
|
|
||||||
@GetMapping("/list")
|
|
||||||
public TableDataInfo<KnowledgeGraphInstanceVo> list(KnowledgeGraphInstanceBo bo, PageQuery pageQuery) {
|
|
||||||
return knowledgeGraphInstanceService.queryPageList(bo, pageQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出知识图谱实例列表
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphInstance:export")
|
|
||||||
@Log(title = "知识图谱实例", businessType = BusinessType.EXPORT)
|
|
||||||
@PostMapping("/export")
|
|
||||||
public void export(KnowledgeGraphInstanceBo bo, HttpServletResponse response) {
|
|
||||||
List<KnowledgeGraphInstanceVo> list = knowledgeGraphInstanceService.queryList(bo);
|
|
||||||
ExcelUtil.exportExcel(list, "知识图谱实例", KnowledgeGraphInstanceVo.class, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取知识图谱实例详细信息
|
|
||||||
*
|
|
||||||
* @param id 主键
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphInstance:query")
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
public R<KnowledgeGraphInstanceVo> getInfo(@NotNull(message = "主键不能为空")
|
|
||||||
@PathVariable Long id) {
|
|
||||||
return R.ok(knowledgeGraphInstanceService.queryById(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增知识图谱实例
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphInstance:add")
|
|
||||||
@Log(title = "知识图谱实例", businessType = BusinessType.INSERT)
|
|
||||||
@RepeatSubmit()
|
|
||||||
@PostMapping()
|
|
||||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody KnowledgeGraphInstanceBo bo) {
|
|
||||||
return toAjax(knowledgeGraphInstanceService.insertByBo(bo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改知识图谱实例
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphInstance:edit")
|
|
||||||
@Log(title = "知识图谱实例", businessType = BusinessType.UPDATE)
|
|
||||||
@RepeatSubmit()
|
|
||||||
@PutMapping()
|
|
||||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody KnowledgeGraphInstanceBo bo) {
|
|
||||||
return toAjax(knowledgeGraphInstanceService.updateByBo(bo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除知识图谱实例
|
|
||||||
*
|
|
||||||
* @param ids 主键串
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphInstance:remove")
|
|
||||||
@Log(title = "知识图谱实例", businessType = BusinessType.DELETE)
|
|
||||||
@DeleteMapping("/{ids}")
|
|
||||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
|
||||||
@PathVariable Long[] ids) {
|
|
||||||
return toAjax(knowledgeGraphInstanceService.deleteWithValidByIds(List.of(ids), true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
package org.ruoyi.controller.knowledge;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
||||||
import org.ruoyi.domain.bo.knowledge.KnowledgeGraphSegmentBo;
|
|
||||||
import org.ruoyi.domain.vo.knowledge.KnowledgeGraphSegmentVo;
|
|
||||||
import org.ruoyi.service.knowledge.IKnowledgeGraphSegmentService;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.ruoyi.common.idempotent.annotation.RepeatSubmit;
|
|
||||||
import org.ruoyi.common.log.annotation.Log;
|
|
||||||
import org.ruoyi.common.web.core.BaseController;
|
|
||||||
import org.ruoyi.common.mybatis.core.page.PageQuery;
|
|
||||||
import org.ruoyi.common.core.domain.R;
|
|
||||||
import org.ruoyi.common.core.validate.AddGroup;
|
|
||||||
import org.ruoyi.common.core.validate.EditGroup;
|
|
||||||
import org.ruoyi.common.log.enums.BusinessType;
|
|
||||||
import org.ruoyi.common.excel.utils.ExcelUtil;
|
|
||||||
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 知识图谱片段
|
|
||||||
*
|
|
||||||
* @author ageerle
|
|
||||||
* @date 2025-12-17
|
|
||||||
*/
|
|
||||||
@Validated
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/system/graphSegment")
|
|
||||||
public class KnowledgeGraphSegmentController extends BaseController {
|
|
||||||
|
|
||||||
private final IKnowledgeGraphSegmentService knowledgeGraphSegmentService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询知识图谱片段列表
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphSegment:list")
|
|
||||||
@GetMapping("/list")
|
|
||||||
public TableDataInfo<KnowledgeGraphSegmentVo> list(KnowledgeGraphSegmentBo bo, PageQuery pageQuery) {
|
|
||||||
return knowledgeGraphSegmentService.queryPageList(bo, pageQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出知识图谱片段列表
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphSegment:export")
|
|
||||||
@Log(title = "知识图谱片段", businessType = BusinessType.EXPORT)
|
|
||||||
@PostMapping("/export")
|
|
||||||
public void export(KnowledgeGraphSegmentBo bo, HttpServletResponse response) {
|
|
||||||
List<KnowledgeGraphSegmentVo> list = knowledgeGraphSegmentService.queryList(bo);
|
|
||||||
ExcelUtil.exportExcel(list, "知识图谱片段", KnowledgeGraphSegmentVo.class, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取知识图谱片段详细信息
|
|
||||||
*
|
|
||||||
* @param id 主键
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphSegment:query")
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
public R<KnowledgeGraphSegmentVo> getInfo(@NotNull(message = "主键不能为空")
|
|
||||||
@PathVariable Long id) {
|
|
||||||
return R.ok(knowledgeGraphSegmentService.queryById(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增知识图谱片段
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphSegment:add")
|
|
||||||
@Log(title = "知识图谱片段", businessType = BusinessType.INSERT)
|
|
||||||
@RepeatSubmit()
|
|
||||||
@PostMapping()
|
|
||||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody KnowledgeGraphSegmentBo bo) {
|
|
||||||
return toAjax(knowledgeGraphSegmentService.insertByBo(bo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改知识图谱片段
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphSegment:edit")
|
|
||||||
@Log(title = "知识图谱片段", businessType = BusinessType.UPDATE)
|
|
||||||
@RepeatSubmit()
|
|
||||||
@PutMapping()
|
|
||||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody KnowledgeGraphSegmentBo bo) {
|
|
||||||
return toAjax(knowledgeGraphSegmentService.updateByBo(bo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除知识图谱片段
|
|
||||||
*
|
|
||||||
* @param ids 主键串
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:graphSegment:remove")
|
|
||||||
@Log(title = "知识图谱片段", businessType = BusinessType.DELETE)
|
|
||||||
@DeleteMapping("/{ids}")
|
|
||||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
|
||||||
@PathVariable Long[] ids) {
|
|
||||||
return toAjax(knowledgeGraphSegmentService.deleteWithValidByIds(List.of(ids), true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,9 @@ public enum ChatModeType {
|
|||||||
DEEP_SEEK("deepseek", "深度求索"),
|
DEEP_SEEK("deepseek", "深度求索"),
|
||||||
QIAN_WEN("qianwen", "通义千问"),
|
QIAN_WEN("qianwen", "通义千问"),
|
||||||
OPEN_AI("openai", "openai"),
|
OPEN_AI("openai", "openai"),
|
||||||
PPIO("ppio", "ppio");
|
PPIO("ppio", "ppio"),
|
||||||
|
CUSTOM_API("custom_api", "自定义API"),
|
||||||
|
MINIMAX("minimax", "MiniMax");
|
||||||
private final String code;
|
private final String code;
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package org.ruoyi.service.chat;
|
package org.ruoyi.service.chat;
|
||||||
|
|
||||||
|
import dev.langchain4j.model.chat.ChatModel;
|
||||||
import dev.langchain4j.model.chat.StreamingChatModel;
|
import dev.langchain4j.model.chat.StreamingChatModel;
|
||||||
|
import dev.langchain4j.model.openai.OpenAiChatModel;
|
||||||
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
|
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
|
||||||
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天消息Service接口
|
* 聊天消息Service接口
|
||||||
*
|
*
|
||||||
@@ -21,6 +25,23 @@ public interface AbstractChatService {
|
|||||||
*/
|
*/
|
||||||
StreamingChatModel buildStreamingChatModel(ChatModelVo chatModelVo, ChatRequest chatRequest);
|
StreamingChatModel buildStreamingChatModel(ChatModelVo chatModelVo, ChatRequest chatRequest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建同步聊天模型(供 Agent/SupervisorAgent 使用)
|
||||||
|
* 默认实现使用 OpenAI 兼容协议,适用于 OpenAI、DeepSeek、PPIO 等兼容接口的 provider。
|
||||||
|
* ZhiPu、QianWen、Ollama 等需覆盖此方法使用各自 SDK。
|
||||||
|
*
|
||||||
|
* @param chatModelVo 模型配置
|
||||||
|
* @return 同步聊天模型实例
|
||||||
|
*/
|
||||||
|
default ChatModel buildChatModel(ChatModelVo chatModelVo) {
|
||||||
|
return OpenAiChatModel.builder()
|
||||||
|
.baseUrl(chatModelVo.getApiHost())
|
||||||
|
.apiKey(chatModelVo.getApiKey())
|
||||||
|
.modelName(chatModelVo.getModelName())
|
||||||
|
.timeout(Duration.ofSeconds(120))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取服务提供商名称
|
* 获取服务提供商名称
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package org.ruoyi.service.chat.impl.provider;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import dev.langchain4j.model.chat.ChatModel;
|
||||||
|
import dev.langchain4j.model.chat.StreamingChatModel;
|
||||||
|
import dev.langchain4j.model.openai.OpenAiChatModel;
|
||||||
|
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
|
||||||
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
|
import org.ruoyi.enums.ChatModeType;
|
||||||
|
import org.ruoyi.observability.MyChatModelListener;
|
||||||
|
import org.ruoyi.service.chat.AbstractChatService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义 API 服务调用
|
||||||
|
*
|
||||||
|
* 适用于 OpenAI 兼容接口或仅通过通用 HTTP 协议接入的第三方大模型服务。
|
||||||
|
* 通过模型配置中的 apiHost / apiKey / modelName 即可复用,不需要再写死具体供应商。
|
||||||
|
*
|
||||||
|
* @author better
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomApiServiceImpl implements AbstractChatService {
|
||||||
|
|
||||||
|
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(180);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamingChatModel buildStreamingChatModel(ChatModelVo chatModelVo, ChatRequest chatRequest) {
|
||||||
|
return OpenAiStreamingChatModel.builder()
|
||||||
|
.baseUrl(normalizeBaseUrl(chatModelVo.getApiHost()))
|
||||||
|
.apiKey(defaultIfBlank(chatModelVo.getApiKey(), "EMPTY"))
|
||||||
|
.modelName(chatModelVo.getModelName())
|
||||||
|
.timeout(DEFAULT_TIMEOUT)
|
||||||
|
.listeners(List.of(new MyChatModelListener()))
|
||||||
|
.returnThinking(chatRequest.getEnableThinking())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChatModel buildChatModel(ChatModelVo chatModelVo) {
|
||||||
|
return OpenAiChatModel.builder()
|
||||||
|
.baseUrl(normalizeBaseUrl(chatModelVo.getApiHost()))
|
||||||
|
.apiKey(defaultIfBlank(chatModelVo.getApiKey(), "EMPTY"))
|
||||||
|
.modelName(chatModelVo.getModelName())
|
||||||
|
.timeout(DEFAULT_TIMEOUT)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProviderName() {
|
||||||
|
return ChatModeType.CUSTOM_API.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeBaseUrl(String baseUrl) {
|
||||||
|
if (StrUtil.isBlank(baseUrl)) {
|
||||||
|
throw new IllegalArgumentException("自定义API的请求地址(apiHost)不能为空");
|
||||||
|
}
|
||||||
|
return baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String defaultIfBlank(String value, String defaultValue) {
|
||||||
|
return StrUtil.isBlank(value) ? defaultValue : value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package org.ruoyi.service.chat.impl.provider;
|
||||||
|
|
||||||
|
import dev.langchain4j.model.chat.StreamingChatModel;
|
||||||
|
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
|
||||||
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
|
import org.ruoyi.enums.ChatModeType;
|
||||||
|
import org.ruoyi.observability.MyChatModelListener;
|
||||||
|
import org.ruoyi.service.chat.AbstractChatService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MiniMax服务调用
|
||||||
|
* <p>
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.ruoyi.service.chat.impl.provider;
|
package org.ruoyi.service.chat.impl.provider;
|
||||||
|
|
||||||
|
|
||||||
|
import dev.langchain4j.model.chat.ChatModel;
|
||||||
import dev.langchain4j.model.chat.StreamingChatModel;
|
import dev.langchain4j.model.chat.StreamingChatModel;
|
||||||
|
import dev.langchain4j.model.ollama.OllamaChatModel;
|
||||||
import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
|
import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -37,6 +39,14 @@ public class OllamaServiceImpl implements AbstractChatService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChatModel buildChatModel(ChatModelVo chatModelVo) {
|
||||||
|
return OllamaChatModel.builder()
|
||||||
|
.baseUrl(chatModelVo.getApiHost())
|
||||||
|
.modelName(chatModelVo.getModelName())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getProviderName() {
|
public String getProviderName() {
|
||||||
return ChatModeType.OLLAMA.getCode();
|
return ChatModeType.OLLAMA.getCode();
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.ruoyi.service.chat.impl.provider;
|
package org.ruoyi.service.chat.impl.provider;
|
||||||
|
|
||||||
|
|
||||||
|
import dev.langchain4j.community.model.dashscope.QwenChatModel;
|
||||||
import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel;
|
import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel;
|
||||||
|
import dev.langchain4j.model.chat.ChatModel;
|
||||||
import dev.langchain4j.model.chat.StreamingChatModel;
|
import dev.langchain4j.model.chat.StreamingChatModel;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -38,6 +40,14 @@ public class QianWenChatServiceImpl implements AbstractChatService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChatModel buildChatModel(ChatModelVo chatModelVo) {
|
||||||
|
return QwenChatModel.builder()
|
||||||
|
.apiKey(chatModelVo.getApiKey())
|
||||||
|
.modelName(chatModelVo.getModelName())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getProviderName() {
|
public String getProviderName() {
|
||||||
return ChatModeType.QIAN_WEN.getCode();
|
return ChatModeType.QIAN_WEN.getCode();
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.ruoyi.service.chat.impl.provider;
|
package org.ruoyi.service.chat.impl.provider;
|
||||||
|
|
||||||
|
|
||||||
|
import dev.langchain4j.community.model.zhipu.ZhipuAiChatModel;
|
||||||
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
||||||
|
import dev.langchain4j.model.chat.ChatModel;
|
||||||
import dev.langchain4j.model.chat.StreamingChatModel;
|
import dev.langchain4j.model.chat.StreamingChatModel;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -35,6 +37,14 @@ public class ZhiPuChatServiceImpl implements AbstractChatService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChatModel buildChatModel(ChatModelVo chatModelVo) {
|
||||||
|
return ZhipuAiChatModel.builder()
|
||||||
|
.apiKey(chatModelVo.getApiKey())
|
||||||
|
.model(chatModelVo.getModelName())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getProviderName() {
|
public String getProviderName() {
|
||||||
return ChatModeType.ZHI_PU.getCode();
|
return ChatModeType.ZHI_PU.getCode();
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.ruoyi.service.embed.impl;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MiniMax嵌入模型(兼容OpenAI接口)
|
||||||
|
* <p>
|
||||||
|
* 支持embo-01模型,1536维度向量。
|
||||||
|
* API地址:https://api.minimax.io/v1
|
||||||
|
*
|
||||||
|
* @author octopus
|
||||||
|
* @date 2026/3/21
|
||||||
|
*/
|
||||||
|
@Component("minimax")
|
||||||
|
public class MinimaxEmbeddingProvider extends OpenAiEmbeddingProvider {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package org.ruoyi.service.embed.impl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import dev.langchain4j.community.model.zhipu.ZhipuAiEmbeddingModel;
|
||||||
|
import dev.langchain4j.data.embedding.Embedding;
|
||||||
|
import dev.langchain4j.data.segment.TextSegment;
|
||||||
|
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||||
|
import dev.langchain4j.model.output.Response;
|
||||||
|
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||||
|
import org.ruoyi.enums.ModalityType;
|
||||||
|
import org.ruoyi.service.embed.BaseEmbedModelService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:yang
|
||||||
|
* @Date:
|
||||||
|
* @Description: 智谱AI嵌入模型
|
||||||
|
*/
|
||||||
|
@Component("zhipu")
|
||||||
|
public class ZhipuAiEmbeddingProvider implements BaseEmbedModelService {
|
||||||
|
protected ChatModelVo chatModelVo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(ChatModelVo config) {
|
||||||
|
this.chatModelVo = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<ModalityType> getSupportedModalities() {
|
||||||
|
return Set.of(ModalityType.TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<List<Embedding>> embedAll(List<TextSegment> textSegments) {
|
||||||
|
EmbeddingModel model = ZhipuAiEmbeddingModel.builder()
|
||||||
|
.baseUrl(chatModelVo.getApiHost())
|
||||||
|
.apiKey(chatModelVo.getApiKey())
|
||||||
|
.model(chatModelVo.getModelName())
|
||||||
|
.dimensions(chatModelVo.getModelDimension())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return model.embedAll(textSegments);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<ModalityType> modalities = provider.getSupportedModalities();
|
||||||
|
assertNotNull(modalities);
|
||||||
|
assertTrue(modalities.contains(ModalityType.TEXT));
|
||||||
|
assertEquals(1, modalities.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void configure_setsModelConfig() {
|
||||||
|
ChatModelVo config = new ChatModelVo();
|
||||||
|
config.setApiHost("https://api.minimax.io/v1");
|
||||||
|
config.setApiKey("test-api-key");
|
||||||
|
config.setModelName("embo-01");
|
||||||
|
config.setModelDimension(1536);
|
||||||
|
|
||||||
|
provider.configure(config);
|
||||||
|
// configure sets internal state; verify no exception thrown
|
||||||
|
assertNotNull(provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user