diff --git a/README.md b/README.md
index f8ce58b7..78ea6497 100644
--- a/README.md
+++ b/README.md
@@ -150,6 +150,13 @@
QQ技术交流群
技术讨论
+
+
+
+微信技术交流群
+技术讨论
+ |
+
diff --git a/docs/工作流模块说明.md b/docs/工作流模块说明.md
new file mode 100644
index 00000000..8d2f4396
--- /dev/null
+++ b/docs/工作流模块说明.md
@@ -0,0 +1,432 @@
+# Ruoyi-AI 工作流模块详细说明文档
+
+## 概述
+
+Ruoyi-AI 工作流模块是一个基于 LangGraph4j 的智能工作流引擎,支持可视化工作流设计、AI 模型集成、条件分支、人机交互等高级功能。该模块采用微服务架构,提供完整的 RESTful API 和流式响应支持。
+
+## 模块架构
+
+### 1. 模块结构
+
+```
+ruoyi-ai/
+├── ruoyi-modules/
+│ └── ruoyi-workflow/ # 工作流核心模块
+│ ├── pom.xml
+│ └── src/main/java/org/ruoyi/workflow/
+│ └── controller/ # 控制器层
+│ ├── WorkflowController.java
+│ ├── WorkflowRuntimeController.java
+│ └── admin/ # 管理端控制器
+│ ├── AdminWorkflowController.java
+│ └── AdminWorkflowComponentController.java
+└── ruoyi-modules-api/
+ └── ruoyi-workflow-api/ # 工作流API模块
+ ├── pom.xml
+ └── src/main/java/org/ruoyi/workflow/
+ ├── entity/ # 实体类
+ ├── dto/ # 数据传输对象
+ ├── service/ # 服务接口
+ ├── mapper/ # 数据访问层
+ ├── workflow/ # 工作流核心逻辑
+ ├── enums/ # 枚举类
+ ├── util/ # 工具类
+ └── exception/ # 异常处理
+```
+
+### 2. 核心依赖
+
+- **LangGraph4j**: 1.5.3 - 工作流图执行引擎
+- **LangChain4j**: 1.2.0 - AI 模型集成框架
+- **Spring Boot**: 3.x - 应用框架
+- **MyBatis Plus**: 数据访问层
+- **Redis**: 缓存和状态管理
+- **Swagger/OpenAPI**: API 文档
+
+## 核心功能
+
+### 1. 工作流管理
+
+#### 1.1 工作流定义
+- **创建工作流**: 支持自定义标题、描述、公开性设置
+- **编辑工作流**: 可视化节点编辑、连接线配置
+- **版本控制**: 支持工作流的版本管理和回滚
+- **权限管理**: 支持公开/私有工作流设置
+
+#### 1.2 工作流执行
+- **流式执行**: 基于 SSE 的实时流式响应
+- **状态管理**: 完整的执行状态跟踪
+- **错误处理**: 详细的错误信息和异常处理
+- **中断恢复**: 支持工作流中断和恢复执行
+
+### 2. 节点类型
+
+#### 2.1 基础节点
+- **Start**: 开始节点,定义工作流入口
+- **End**: 结束节点,定义工作流出口
+
+#### 2.2 AI 模型节点
+- **Answer**: 大语言模型问答节点
+- **Dalle3**: DALL-E 3 图像生成
+- **Tongyiwanx**: 通义万相图像生成
+- **Classifier**: 内容分类节点
+
+#### 2.3 数据处理节点
+- **DocumentExtractor**: 文档信息提取
+- **KeywordExtractor**: 关键词提取
+- **FaqExtractor**: 常见问题提取
+- **KnowledgeRetrieval**: 知识库检索
+
+#### 2.4 控制流节点
+- **Switcher**: 条件分支节点
+- **HumanFeedback**: 人机交互节点
+
+#### 2.5 外部集成节点
+- **Google**: Google 搜索集成
+- **MailSend**: 邮件发送
+- **HttpRequest**: HTTP 请求
+- **Template**: 模板转换
+
+### 3. 数据流管理
+
+#### 3.1 输入输出定义
+```java
+// 节点输入输出数据结构
+public class NodeIOData {
+ private String name; // 参数名称
+ private NodeIODataContent content; // 参数内容
+}
+
+// 支持的数据类型
+public enum WfIODataTypeEnum {
+ TEXT, // 文本
+ NUMBER, // 数字
+ BOOLEAN, // 布尔值
+ FILES, // 文件
+ OPTIONS // 选项
+}
+```
+
+#### 3.2 参数引用
+- **节点间引用**: 支持上游节点输出作为下游节点输入
+- **参数映射**: 自动处理参数名称映射
+- **类型转换**: 自动进行数据类型转换
+
+## 数据库设计
+
+### 1. 核心表结构
+
+#### 1.1 工作流定义表 (t_workflow)
+```sql
+CREATE TABLE t_workflow (
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
+ uuid VARCHAR(32) NOT NULL DEFAULT '',
+ title VARCHAR(100) NOT NULL DEFAULT '',
+ remark TEXT NOT NULL DEFAULT '',
+ user_id BIGINT NOT NULL DEFAULT 0,
+ is_public TINYINT(1) NOT NULL DEFAULT 0,
+ is_enable TINYINT(1) NOT NULL DEFAULT 1,
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ is_deleted TINYINT(1) NOT NULL DEFAULT 0
+);
+```
+
+#### 1.2 工作流节点表 (t_workflow_node)
+```sql
+CREATE TABLE t_workflow_node (
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
+ uuid VARCHAR(32) NOT NULL DEFAULT '',
+ workflow_id BIGINT NOT NULL DEFAULT 0,
+ workflow_component_id BIGINT NOT NULL DEFAULT 0,
+ user_id BIGINT NOT NULL DEFAULT 0,
+ title VARCHAR(100) NOT NULL DEFAULT '',
+ remark VARCHAR(500) NOT NULL DEFAULT '',
+ input_config JSON NOT NULL DEFAULT ('{}'),
+ node_config JSON NOT NULL DEFAULT ('{}'),
+ position_x DOUBLE NOT NULL DEFAULT 0,
+ position_y DOUBLE NOT NULL DEFAULT 0,
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ is_deleted TINYINT(1) NOT NULL DEFAULT 0
+);
+```
+
+#### 1.3 工作流边表 (t_workflow_edge)
+```sql
+CREATE TABLE t_workflow_edge (
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
+ uuid VARCHAR(32) NOT NULL DEFAULT '',
+ workflow_id BIGINT NOT NULL DEFAULT 0,
+ source_node_uuid VARCHAR(32) NOT NULL DEFAULT '',
+ source_handle VARCHAR(32) NOT NULL DEFAULT '',
+ target_node_uuid VARCHAR(32) NOT NULL DEFAULT '',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ is_deleted TINYINT(1) NOT NULL DEFAULT 0
+);
+```
+
+#### 1.4 工作流运行时表 (t_workflow_runtime)
+```sql
+CREATE TABLE t_workflow_runtime (
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
+ uuid VARCHAR(32) NOT NULL DEFAULT '',
+ user_id BIGINT NOT NULL DEFAULT 0,
+ workflow_id BIGINT NOT NULL DEFAULT 0,
+ input JSON NOT NULL DEFAULT ('{}'),
+ output JSON NOT NULL DEFAULT ('{}'),
+ status SMALLINT NOT NULL DEFAULT 1,
+ status_remark VARCHAR(250) NOT NULL DEFAULT '',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ is_deleted TINYINT(1) NOT NULL DEFAULT 0
+);
+```
+
+#### 1.5 工作流组件表 (t_workflow_component)
+```sql
+CREATE TABLE t_workflow_component (
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
+ uuid VARCHAR(32) DEFAULT '' NOT NULL,
+ name VARCHAR(32) DEFAULT '' NOT NULL,
+ title VARCHAR(100) DEFAULT '' NOT NULL,
+ remark TEXT NOT NULL,
+ display_order INT DEFAULT 0 NOT NULL,
+ is_enable TINYINT(1) DEFAULT 0 NOT NULL,
+ create_time DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ update_time DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ is_deleted TINYINT(1) DEFAULT 0 NOT NULL
+);
+```
+
+## API 接口
+
+### 1. 工作流管理接口
+
+#### 1.1 基础操作
+```http
+# 创建工作流
+POST /workflow/add
+Content-Type: application/json
+{
+ "title": "工作流标题",
+ "remark": "工作流描述",
+ "isPublic": false
+}
+
+# 更新工作流
+POST /workflow/update
+Content-Type: application/json
+{
+ "uuid": "工作流UUID",
+ "title": "新标题",
+ "remark": "新描述"
+}
+
+# 删除工作流
+POST /workflow/del/{uuid}
+
+# 启用/禁用工作流
+POST /workflow/enable/{uuid}?enable=true
+```
+
+#### 1.2 搜索和查询
+```http
+# 搜索我的工作流
+GET /workflow/mine/search?keyword=关键词&isPublic=true¤tPage=1&pageSize=10
+
+# 搜索公开工作流
+GET /workflow/public/search?keyword=关键词¤tPage=1&pageSize=10
+
+# 获取工作流组件列表
+GET /workflow/public/component/list
+```
+
+### 2. 工作流执行接口
+
+#### 2.1 流式执行
+```http
+# 流式执行工作流
+POST /workflow/run
+Content-Type: application/json
+Accept: text/event-stream
+{
+ "uuid": "工作流UUID",
+ "inputs": [
+ {
+ "name": "input",
+ "content": {
+ "type": 1,
+ "textContent": "用户输入内容"
+ }
+ }
+ ]
+}
+```
+
+#### 2.2 运行时管理
+```http
+# 恢复中断的工作流
+POST /workflow/runtime/resume/{runtimeUuid}
+Content-Type: application/json
+{
+ "feedbackContent": "用户反馈内容"
+}
+
+# 查询工作流执行历史
+GET /workflow/runtime/page?wfUuid=工作流UUID¤tPage=1&pageSize=10
+
+# 查询运行时节点详情
+GET /workflow/runtime/nodes/{runtimeUuid}
+
+# 清理运行时数据
+POST /workflow/runtime/clear?wfUuid=工作流UUID
+```
+
+### 3. 管理端接口
+
+#### 3.1 工作流管理
+```http
+# 搜索所有工作流
+POST /admin/workflow/search
+Content-Type: application/json
+{
+ "title": "搜索关键词",
+ "isPublic": true,
+ "isEnable": true
+}
+
+# 启用/禁用工作流
+POST /admin/workflow/enable?uuid=工作流UUID&isEnable=true
+```
+
+## 核心实现
+
+### 1. 工作流引擎 (WorkflowEngine)
+
+工作流引擎是整个模块的核心,负责:
+- 工作流图的构建和编译
+- 节点执行调度
+- 状态管理和持久化
+- 流式输出处理
+
+```java
+public class WorkflowEngine {
+ // 核心执行方法
+ public void run(User user, List userInputs, SseEmitter sseEmitter) {
+ // 1. 验证工作流状态
+ // 2. 创建运行时实例
+ // 3. 构建状态图
+ // 4. 执行工作流
+ // 5. 处理流式输出
+ }
+
+ // 恢复执行方法
+ public void resume(String userInput) {
+ // 1. 更新状态
+ // 2. 继续执行
+ }
+}
+```
+
+### 2. 节点工厂 (WfNodeFactory)
+
+节点工厂负责根据组件类型创建对应的节点实例:
+
+```java
+public class WfNodeFactory {
+ public static AbstractWfNode create(WorkflowComponent component,
+ WorkflowNode node,
+ WfState wfState,
+ WfNodeState nodeState) {
+ // 根据组件类型创建对应的节点实例
+ switch (component.getName()) {
+ case "Answer":
+ return new LLMAnswerNode(component, node, wfState, nodeState);
+ case "Switcher":
+ return new SwitcherNode(component, node, wfState, nodeState);
+ // ... 其他节点类型
+ }
+ }
+}
+```
+
+### 3. 图构建器 (WorkflowGraphBuilder)
+
+图构建器负责将工作流定义转换为可执行的状态图:
+
+```java
+public class WorkflowGraphBuilder {
+ public StateGraph build(WorkflowNode startNode) {
+ // 1. 构建编译节点树
+ // 2. 转换为状态图
+ // 3. 添加节点和边
+ // 4. 处理条件分支
+ // 5. 处理并行执行
+ }
+}
+```
+
+## 流式响应机制
+
+### 1. SSE 事件类型
+
+工作流执行过程中会发送多种类型的 SSE 事件:
+
+```javascript
+// 节点开始执行
+[NODE_RUN_节点UUID] - 节点执行开始事件
+
+// 节点输入数据
+[NODE_INPUT_节点UUID] - 节点输入数据事件
+
+// 节点输出数据
+[NODE_OUTPUT_节点UUID] - 节点输出数据事件
+
+// 流式内容块
+[NODE_CHUNK_节点UUID] - 流式内容块事件
+
+// 等待用户输入
+[NODE_WAIT_FEEDBACK_BY_节点UUID] - 等待用户输入事件
+```
+
+### 2. 流式处理流程
+
+1. **初始化**: 创建工作流运行时实例
+2. **节点执行**: 逐个执行工作流节点
+3. **实时输出**: 通过 SSE 实时推送执行结果
+4. **状态更新**: 实时更新节点和工作流状态
+5. **错误处理**: 捕获并处理执行过程中的错误
+
+
+## 扩展开发
+
+### 1. 自定义节点开发
+
+要开发自定义工作流节点,需要:
+
+1. **创建节点类**:继承 `AbstractWfNode`
+2. **实现处理逻辑**:重写 `onProcess()` 方法
+3. **定义配置类**:创建节点配置类
+4. **注册组件**:在组件表中注册新组件
+
+```java
+public class CustomNode extends AbstractWfNode {
+ @Override
+ protected NodeProcessResult onProcess() {
+ // 实现自定义处理逻辑
+ List outputs = new ArrayList<>();
+ // ... 处理逻辑
+ return NodeProcessResult.success(outputs);
+ }
+}
+```
+
+### 2. 自定义组件注册
+
+```sql
+-- 在 t_workflow_component 表中添加新组件
+INSERT INTO t_workflow_component (uuid, name, title, remark, is_enable)
+VALUES (REPLACE(UUID(), '-', ''), 'CustomNode', '自定义节点', '自定义节点描述', true);
+```
diff --git a/pom.xml b/pom.xml
index b164fbfb..6f282a46 100644
--- a/pom.xml
+++ b/pom.xml
@@ -270,13 +270,6 @@
${lock4j.version}
-
-
- com.xuxueli
- xxl-job-core
- ${xxl-job.version}
-
-
com.alibaba
transmittable-thread-local
@@ -373,6 +366,23 @@
langchain4j-community-neo4j
${langchain4j-neo4j.version}
+ ruoyi-aihuman
+ ${revision}
+
+
+
+
+ org.ruoyi
+ ruoyi-workflow
+ ${revision}
+
+
+
+ org.ruoyi
+ ruoyi-workflow-api
+ ${revision}
+
+
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 3cf17cc7..5aa1fba8 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -61,6 +61,14 @@
org.ruoyi
ruoyi-graph
+
+ org.ruoyi
+ ruoyi-workflow
+
+
+
+ org.ruoyi
+ ruoyi-aihuman
diff --git a/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java b/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java
index cc65b7b4..ea5d664f 100644
--- a/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java
+++ b/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java
@@ -11,7 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
*
* @author Lion Li
*/
-@SpringBootApplication
+@SpringBootApplication(scanBasePackages = {"org.ruoyi", "org.ruoyi.aihuman"})
@EnableScheduling
@EnableAsync
public class RuoYiAIApplication {
@@ -22,4 +22,4 @@ public class RuoYiAIApplication {
application.run(args);
System.out.println("(♥◠‿◠)ノ゙ RuoYiAI启动成功 ლ(´ڡ`ლ)゙");
}
-}
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index a722f88b..cb082f50 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -37,6 +37,8 @@ spring:
connectionTestQuery: SELECT 1
# 多久检查一次连接的活性
keepaliveTime: 30000
+ mail:
+ username: xx
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
@@ -102,7 +104,15 @@ pdf:
#百炼模型配置
dashscope:
key: sk-xxxx
- model: qvq-max
+
+local:
+ images: xx
+
+
+
+ files: xx
+
+
--- # Neo4j 知识图谱配置
neo4j:
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 6d5e6d2f..4c6d38a0 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -156,6 +156,8 @@ security:
# actuator 监控配置
- /actuator
- /actuator/**
+ - /workflow/**
+ - /admin/workflow/**
# 多租户配置
tenant:
# 是否开启
@@ -328,3 +330,19 @@ spring:
servers-configuration: classpath:mcp-server.json
request-timeout: 300s
+# 向量库配置
+vector-store:
+ # 向量存储类型 可选(weaviate/milvus)
+ # 如需修改向量库类型,请修改此配置值!
+ type: weaviate
+
+ # Weaviate配置
+ weaviate:
+ protocol: http
+ host: 127.0.0.1:6038
+ classname: LocalKnowledge
+ # Milvus配置
+ milvus:
+ url: http://localhost:19530
+ collectionname: LocalKnowledge
+
diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java
index f0eacdfc..ba351cf7 100644
--- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java
+++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java
@@ -26,11 +26,18 @@ public class ChatRequest {
*/
private String prompt;
+
/**
* 系统提示词
*/
private String sysPrompt;
+
+ /**
+ * 消息id
+ */
+ private Long messageId;
+
/**
* 是否开启流式对话
*/
@@ -72,6 +79,11 @@ public class ChatRequest {
*/
private Boolean hasAttachment;
+ /**
+ * 是否启用深度思考
+ */
+ private Boolean enableThinking;
+
/**
* 是否自动切换模型
*/
@@ -82,9 +94,4 @@ public class ChatRequest {
*/
private String token;
- /**
- * 消息ID(保存消息成功后设置,用于后续扣费更新)
- */
- private Long messageId;
-
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/VectorStoreProperties.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/VectorStoreProperties.java
new file mode 100644
index 00000000..b4bb135d
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/config/VectorStoreProperties.java
@@ -0,0 +1,62 @@
+package org.ruoyi.common.core.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 向量库配置属性
+ *
+ * @author ageer
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "vector-store")
+public class VectorStoreProperties {
+
+ /**
+ * 向量库类型
+ */
+ private String type;
+
+ /**
+ * Weaviate配置
+ */
+ private Weaviate weaviate = new Weaviate();
+
+ /**
+ * Milvus配置
+ */
+ private Milvus milvus = new Milvus();
+
+ @Data
+ public static class Weaviate {
+ /**
+ * 协议
+ */
+ private String protocol;
+
+ /**
+ * 主机地址
+ */
+ private String host;
+
+ /**
+ * 类名
+ */
+ private String classname;
+ }
+
+ @Data
+ public static class Milvus {
+ /**
+ * 连接URL
+ */
+ private String url;
+
+ /**
+ * 集合名称
+ */
+ private String collectionname;
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-modules-api/pom.xml b/ruoyi-modules-api/pom.xml
index a3f0ef00..2cf63600 100644
--- a/ruoyi-modules-api/pom.xml
+++ b/ruoyi-modules-api/pom.xml
@@ -17,6 +17,7 @@
ruoyi-chat-api
ruoyi-knowledge-api
ruoyi-system-api
+ ruoyi-workflow-api
diff --git a/ruoyi-modules-api/ruoyi-chat-api/pom.xml b/ruoyi-modules-api/ruoyi-chat-api/pom.xml
index c1af20a5..7e08c9af 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/pom.xml
+++ b/ruoyi-modules-api/ruoyi-chat-api/pom.xml
@@ -16,7 +16,7 @@
17
17
UTF-8
- 1.0.0
+ 1.0.0-M7
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java
index e8f0e308..34465613 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java
@@ -1,6 +1,7 @@
package org.ruoyi.domain;
+import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -81,6 +82,11 @@ public class ChatModel extends BaseEntity {
*/
private Integer priority;
+ /**
+ * 模型供应商
+ */
+ private String ProviderName;
+
/**
* 备注
*/
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/McpInfo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/McpInfo.java
new file mode 100644
index 00000000..f8392ad6
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/McpInfo.java
@@ -0,0 +1,67 @@
+package org.ruoyi.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.ruoyi.annotation.DataColumn;
+import org.ruoyi.core.domain.BaseEntity;
+
+import java.util.Date;
+
+/**
+ * MCP对象 mcp_info
+ *
+ * @author ageerle
+ * @date Sat Aug 09 16:50:58 CST 2025
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("mcp_info")
+public class McpInfo extends BaseEntity {
+
+
+ /**
+ * id
+ */
+ @TableId(value = "mcp_id", type = IdType.AUTO)
+ private Integer mcpId;
+
+ /**
+ * 服务器名称
+ */
+ private String serverName;
+
+ /**
+ * 链接方式
+ */
+
+ private String transportType;
+
+ /**
+ * Command
+ */
+ private String command;
+
+ /**
+ * Args
+ */
+ private String arguments;
+
+ private String description;
+
+ /**
+ * Env
+ */
+ private String env;
+
+ /**
+ * 是否启用
+ */
+ private Boolean status;
+
+
+
+
+}
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java
index b828515b..34ee975e 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java
@@ -1,5 +1,6 @@
package org.ruoyi.domain.bo;
+import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -85,6 +86,10 @@ public class ChatModelBo extends BaseEntity {
@NotBlank(message = "密钥不能为空", groups = { AddGroup.class, EditGroup.class })
private String apiKey;
+ /**
+ * 模型供应商
+ */
+ private String ProviderName;
/**
* 备注
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/McpInfoBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/McpInfoBo.java
new file mode 100644
index 00000000..2228fb99
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/McpInfoBo.java
@@ -0,0 +1,59 @@
+package org.ruoyi.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.ruoyi.domain.McpInfo;
+
+
+import java.io.Serializable;
+
+/**
+ * MCP业务对象 mcp_info
+ *
+ * @author ageerle
+ * @date Sat Aug 09 16:50:58 CST 2025
+ */
+@Data
+
+@AutoMapper(target = McpInfo.class, reverseConvertGenerate = false)
+public class McpInfoBo implements Serializable {
+
+ /**
+ * id
+ */
+ @NotNull(message = "id不能为空" )
+ private Integer mcpId;
+
+ /**
+ * 服务器名称
+ */
+ private String serverName;
+
+ /**
+ * 链接方式
+ */
+ private String transportType;
+
+ /**
+ * Command
+ */
+ private String command;
+
+ /**
+ * Args
+ */
+ private String arguments;
+ private String description;
+ /**
+ * Env
+ */
+ private String env;
+
+ /**
+ * 是否启用
+ */
+ private Boolean status;
+
+
+}
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java
index 0638c13a..062a378a 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java
@@ -70,6 +70,11 @@ public class ChatModelVo implements Serializable {
@ExcelProperty(value = "是否显示")
private String modelShow;
+ /**
+ * 模型维度
+ */
+ private Integer dimension;
+
/**
* 系统提示词
*/
@@ -95,6 +100,12 @@ public class ChatModelVo implements Serializable {
@ExcelProperty(value = "优先级")
private Integer priority;
+ /**
+ * 模型供应商
+ */
+ @ExcelProperty(value = "模型供应商")
+ private String ProviderName;
+
/**
* 备注
*/
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/McpInfoVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/McpInfoVo.java
new file mode 100644
index 00000000..b5cc27c1
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/McpInfoVo.java
@@ -0,0 +1,65 @@
+package org.ruoyi.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.ruoyi.common.excel.annotation.ExcelDictFormat;
+import org.ruoyi.common.excel.convert.ExcelDictConvert;
+import org.ruoyi.domain.McpInfo;
+
+import java.io.Serializable;
+
+
+/**
+ * MCP视图对象 mcp_info
+ *
+ * @author jiyi
+ * @date Sat Aug 09 16:50:58 CST 2025
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = McpInfo.class)
+public class McpInfoVo implements Serializable {
+ private Integer mcpId;
+
+ /**
+ * 服务器名称
+ */
+ @ExcelProperty(value = "服务器名称")
+ private String serverName;
+
+ /**
+ * 链接方式
+ */
+ @ExcelProperty(value = "链接方式", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "mcp_transport_type")
+ private String transportType;
+
+ /**
+ * Command
+ */
+ @ExcelProperty(value = "Command")
+ private String command;
+
+ /**
+ * Args
+ */
+ @ExcelProperty(value = "Args")
+ private String arguments;
+ @ExcelProperty(value = "Description")
+ private String description;
+ /**
+ * Env
+ */
+ @ExcelProperty(value = "Env")
+ private String env;
+
+ /**
+ * 是否启用
+ */
+ @ExcelProperty(value = "是否启用")
+ private Boolean status;
+
+
+}
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/McpInfoMapper.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/McpInfoMapper.java
new file mode 100644
index 00000000..fb26aaac
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/McpInfoMapper.java
@@ -0,0 +1,33 @@
+package org.ruoyi.mapper;
+
+
+import org.apache.ibatis.annotations.*;
+import org.ruoyi.core.mapper.BaseMapperPlus;
+import org.ruoyi.domain.McpInfo;
+import org.ruoyi.domain.vo.McpInfoVo;
+
+import java.util.List;
+
+/**
+ * MCPMapper接口
+ *
+ * @author jiuyi
+ * @date Sat Aug 09 16:50:58 CST 2025
+ */
+@Mapper
+public interface McpInfoMapper extends BaseMapperPlus {
+ @Select("SELECT * FROM mcp_info WHERE server_name = #{serverName}")
+ McpInfo selectByServerName(@Param("serverName") String serverName);
+
+ @Select("SELECT * FROM mcp_info WHERE status = 1")
+ List selectActiveServers();
+
+ @Select("SELECT server_name FROM mcp_info WHERE status = 1")
+ List selectActiveServerNames();
+
+ @Update("UPDATE mcp_info SET status = #{status} WHERE server_name = #{serverName}")
+ int updateActiveStatus(@Param("serverName") String serverName, @Param("status") Boolean status);
+
+ @Delete("DELETE FROM mcp_info WHERE server_name = #{serverName}")
+ int deleteByServerName(@Param("serverName") String serverName);
+}
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/resources/mapper/McpInfoMapper.xml b/ruoyi-modules-api/ruoyi-chat-api/src/main/resources/mapper/McpInfoMapper.xml
new file mode 100644
index 00000000..f2a28e2a
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/resources/mapper/McpInfoMapper.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml b/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
index f8082a67..fc7e01bc 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
@@ -74,6 +74,18 @@
1.19.6
+
+ io.milvus
+ milvus-sdk-java
+ 2.6.4
+
+
+
+
+ dev.langchain4j
+ langchain4j-milvus
+
+
dev.langchain4j
langchain4j-open-ai
@@ -101,11 +113,10 @@
commons-compress
-
- com.alibaba
- dashscope-sdk-java
- 2.19.0
-
+
+ org.ruoyi
+ ruoyi-chat-api
+
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java
index 627cd3c6..f892b3c1 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java
@@ -83,6 +83,11 @@ public class KnowledgeInfo extends BaseEntity {
*/
private String vectorModelName;
+ /**
+ * 向量化模型id
+ */
+ private Long embeddingModelId;
+
/**
* 向量化模型名称
*/
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoBo.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoBo.java
index 39083871..af453492 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoBo.java
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoBo.java
@@ -92,7 +92,11 @@ public class KnowledgeInfoBo extends BaseEntity {
/**
* 向量化模型名称
*/
- @NotBlank(message = "向量模型不能为空", groups = { AddGroup.class, EditGroup.class })
+ private Long embeddingModelId;
+
+ /**
+ * 向量化模型名称
+ */
private String embeddingModelName;
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/QueryVectorBo.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/QueryVectorBo.java
index ff3a26e5..0d5b2e6e 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/QueryVectorBo.java
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/QueryVectorBo.java
@@ -31,7 +31,12 @@ public class QueryVectorBo {
private String vectorModelName;
/**
- * 向量化模型名称
+ * 向量化模型ID
+ */
+ private Long embeddingModelId;
+
+ /**
+ * 向量化模型ID
*/
private String embeddingModelName;
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/StoreEmbeddingBo.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/StoreEmbeddingBo.java
index e4d8c381..eedfe4d6 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/StoreEmbeddingBo.java
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/StoreEmbeddingBo.java
@@ -32,9 +32,14 @@ public class StoreEmbeddingBo {
private List fids;
/**
- * 向量库模型名称
+ * 向量库名称
*/
- private String vectorModelName;
+ private String vectorStoreName;
+
+ /**
+ * 向量化模型id
+ */
+ private Long embeddingModelId;
/**
* 向量化模型名称
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeInfoVo.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeInfoVo.java
index 2dc73d45..c907e940 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeInfoVo.java
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeInfoVo.java
@@ -101,6 +101,11 @@ public class KnowledgeInfoVo implements Serializable {
*/
private String vectorModelName;
+ /**
+ * 向量化模型id
+ */
+ private Long embeddingModelId;
+
/**
* 向量化模型名称
*/
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/BaseEmbedModelService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/BaseEmbedModelService.java
new file mode 100644
index 00000000..9b3d0021
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/BaseEmbedModelService.java
@@ -0,0 +1,26 @@
+package org.ruoyi.embedding;
+
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import org.ruoyi.domain.vo.ChatModelVo;
+import org.ruoyi.embedding.model.ModalityType;
+
+import java.util.Set;
+
+/**
+ * BaseEmbedModelService 接口,扩展了 EmbeddingModel 接口
+ * 该接口定义了嵌入模型服务的基本配置和功能方法
+ */
+public interface BaseEmbedModelService extends EmbeddingModel {
+ /**
+ * 根据配置信息配置嵌入模型
+ * @param config 包含模型配置信息的 ChatModelVo 对象
+ */
+ void configure(ChatModelVo config);
+
+ /**
+ * 获取当前嵌入模型支持的所有模态类型
+ * @return 返回支持的模态类型集合
+ */
+ Set getSupportedModalities();
+
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/EmbeddingModelFactory.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/EmbeddingModelFactory.java
new file mode 100644
index 00000000..3acf8a91
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/EmbeddingModelFactory.java
@@ -0,0 +1,120 @@
+package org.ruoyi.embedding;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.ruoyi.domain.vo.ChatModelVo;
+import org.ruoyi.service.IChatModelService;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 嵌入模型工厂服务类
+ * 负责创建和管理各种嵌入模型实例
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class EmbeddingModelFactory {
+
+ private final ApplicationContext applicationContext;
+
+ private final IChatModelService chatModelService;
+
+ // 模型缓存,使用ConcurrentHashMap保证线程安全
+ private final Map modelCache = new ConcurrentHashMap<>();
+
+ /**
+ * 创建嵌入模型实例
+ * 如果模型已存在于缓存中,则直接返回;否则创建新的实例
+ *
+ * @param embeddingModelName 嵌入模型名称
+ * @param dimension 模型维度大小
+ */
+ public BaseEmbedModelService createModel(String embeddingModelName, Integer dimension) {
+ return modelCache.computeIfAbsent(embeddingModelName, name -> {
+ ChatModelVo modelConfig = chatModelService.selectModelByName(embeddingModelName);
+ if (modelConfig == null) {
+ throw new IllegalArgumentException("未找到模型配置,name=" + name);
+ }
+ if (modelConfig.getDimension() != null) {
+ modelConfig.setDimension(dimension);
+ }
+ return createModelInstance(modelConfig.getProviderName(), modelConfig);
+ });
+ }
+
+ /**
+ * 检查模型是否支持多模态
+ *
+ * @param embeddingModelName 嵌入模型名称
+ * @return boolean 如果模型支持多模态则返回true,否则返回false
+ */
+ public boolean isMultimodalModel(String embeddingModelName) {
+ return createModel(embeddingModelName, null) instanceof MultiModalEmbedModelService;
+ }
+
+ /**
+ * 创建多模态嵌入模型实例
+ *
+ * @param embeddingModelName 嵌入模型名称
+ * @return MultiModalEmbedModelService 多模态嵌入模型服务实例
+ * @throws IllegalArgumentException 当模型不支持多模态时抛出
+ */
+ public MultiModalEmbedModelService createMultimodalModel(String embeddingModelName) {
+ BaseEmbedModelService model = createModel(embeddingModelName, null);
+ if (model instanceof MultiModalEmbedModelService) {
+ return (MultiModalEmbedModelService) model;
+ }
+ throw new IllegalArgumentException("该模型不支持多模态");
+ }
+
+ /**
+ * 刷新模型缓存
+ * 根据给定的嵌入模型ID从缓存中移除对应的模型
+ *
+ * @param embeddingModelId 嵌入模型的唯一标识ID
+ */
+ public void refreshModel(Long embeddingModelId) {
+ // 从模型缓存中移除指定ID的模型
+ modelCache.remove(embeddingModelId);
+ }
+
+ /**
+ * 获取所有支持模型工厂的列表
+ *
+ * @return List 支持的模型工厂名称列表
+ */
+ public List getSupportedFactories() {
+ return new ArrayList<>(applicationContext.getBeansOfType(BaseEmbedModelService.class)
+ .keySet());
+ }
+
+ /**
+ * 创建具体的模型实例
+ * 根据提供的工厂名称和配置信息创建并配置模型实例
+ *
+ * @param factory 工厂名称,用于标识模型类型
+ * @param config 模型配置信息
+ * @return BaseEmbedModelService 配置好的模型实例
+ * @throws IllegalArgumentException 当无法获取指定的模型实例时抛出
+ */
+ private BaseEmbedModelService createModelInstance(String factory, ChatModelVo config) {
+ try {
+ // 从Spring上下文中获取模型实例
+ BaseEmbedModelService model = applicationContext.getBean(factory, BaseEmbedModelService.class);
+ // 配置模型参数
+ model.configure(config);
+ log.info("成功创建嵌入模型: factory={}, modelId={}", config.getProviderName(), config.getId());
+
+ return model;
+ } catch (NoSuchBeanDefinitionException e) {
+ throw new IllegalArgumentException("获取不到嵌入模型: " + factory, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/MultiModalEmbedModelService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/MultiModalEmbedModelService.java
new file mode 100644
index 00000000..062ff00f
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/MultiModalEmbedModelService.java
@@ -0,0 +1,35 @@
+package org.ruoyi.embedding;
+
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.model.output.Response;
+import org.ruoyi.embedding.model.MultiModalInput;
+
+
+/**
+ * 多模态嵌入模型服务接口,继承自基础嵌入模型服务
+ * 该接口提供了处理图像、视频以及多模态数据并转换为嵌入向量的功能
+ */
+public interface MultiModalEmbedModelService extends BaseEmbedModelService {
+ /**
+ * 将图像数据转换为嵌入向量
+ * @param imageDataUrl 图像的地址,必须是公开可访问的URL
+ * @return 包含嵌入向量的响应对象,可能包含状态信息和嵌入结果
+ */
+ Response embedImage(String imageDataUrl);
+
+ /**
+ * 将视频数据转换为嵌入向量
+ * @param videoDataUrl 视频的地址,必须是公开可访问的URL
+ * @return 包含嵌入向量的响应对象,可能包含状态信息和嵌入结果
+ */
+ Response embedVideo(String videoDataUrl);
+
+
+ /**
+ * 处理多模态输入并返回嵌入向量的方法
+ *
+ * @param input 包含多种模态信息(如图像、文本等)的输入对象
+ * @return Response 包含嵌入向量的响应对象,Embedding通常表示输入数据的向量表示
+ */
+ Response embedMultiModal(MultiModalInput input);
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianBaseEmbedProvider.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianBaseEmbedProvider.java
new file mode 100644
index 00000000..1511a0fe
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianBaseEmbedProvider.java
@@ -0,0 +1,14 @@
+package org.ruoyi.embedding.impl;
+
+
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author: Robust_H
+ * @Date: 2025-09-30-下午3:00
+ * @Description: 阿里百炼基础嵌入模型(兼容openai)
+ */
+@Component("alibailian")
+public class AliBaiLianBaseEmbedProvider extends OpenAiEmbeddingProvider{
+
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianMultiEmbeddingProvider.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianMultiEmbeddingProvider.java
new file mode 100644
index 00000000..ad3e8374
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/embedding/impl/AliBaiLianMultiEmbeddingProvider.java
@@ -0,0 +1,281 @@
+package org.ruoyi.embedding.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.model.output.Response;
+import dev.langchain4j.model.output.TokenUsage;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.ruoyi.domain.vo.ChatModelVo;
+import org.ruoyi.embedding.MultiModalEmbedModelService;
+import org.ruoyi.embedding.model.AliyunMultiModalEmbedRequest;
+import org.ruoyi.embedding.model.AliyunMultiModalEmbedResponse;
+import org.ruoyi.embedding.model.ModalityType;
+import org.ruoyi.embedding.model.MultiModalInput;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 阿里云百炼多模态嵌入模型服务实现类
+ * 实现了MultiModalEmbedModelService接口,提供文本、图像和视频的嵌入向量生成服务
+ */
+@Component("bailianMultiModel")
+@Slf4j
+public class AliBaiLianMultiEmbeddingProvider implements MultiModalEmbedModelService {
+ private ChatModelVo chatModelVo;
+
+ private final OkHttpClient okHttpClient;
+
+ /**
+ * 构造函数,初始化HTTP客户端
+ * 设置连接超时、读取超时和写入超时时间
+ */
+ public AliBaiLianMultiEmbeddingProvider() {
+ this.okHttpClient = new OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(60, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .build();
+ }
+
+ /**
+ * 图像嵌入向量生成
+ * @param imageDataUrl 图像数据的URL
+ * @return 包含图像嵌入向量的Response对象
+ */
+ @Override
+ public Response embedImage(String imageDataUrl) {
+ return embedSingleModality("image", imageDataUrl);
+ }
+
+ /**
+ * 视频嵌入向量生成
+ * @param videoDataUrl 视频数据的URL
+ * @return 包含视频嵌入向量的Response对象
+ */
+ @Override
+ public Response embedVideo(String videoDataUrl) {
+ return embedSingleModality("video", videoDataUrl);
+ }
+
+ /**
+ * 多模态嵌入向量生成
+ * 支持同时处理文本、图像和视频等多种模态的数据
+ * @param input 包含多种模态输入的对象
+ * @return 包含多模态嵌入向量的Response对象
+ */
+ @Override
+ public Response embedMultiModal(MultiModalInput input) {
+ try {
+ // 构建请求内容
+ List