refactor: 重命名 ruoyi 目录和文件为 hzhub
This commit is contained in:
336
hzhub-ai/hzhub-modules/hzhub-chat/docs/mcp-api-spec.md
Normal file
336
hzhub-ai/hzhub-modules/hzhub-chat/docs/mcp-api-spec.md
Normal file
@@ -0,0 +1,336 @@
|
||||
# MCP工具管理模块 - API接口文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了MCP工具管理模块的REST API接口,供前端开发人员参考。
|
||||
|
||||
## 基础信息
|
||||
|
||||
- **Base URL**: `/api/mcp`
|
||||
- **认证方式**: Bearer Token (SaToken)
|
||||
- **响应格式**: JSON
|
||||
|
||||
---
|
||||
|
||||
## 1. MCP工具管理
|
||||
|
||||
### 1.1 查询工具列表(分页)
|
||||
|
||||
**接口**: `GET /tool/list`
|
||||
|
||||
**权限**: `mcp:tool:list`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| name | String | 否 | 工具名称(模糊查询) |
|
||||
| description | String | 否 | 工具描述(模糊查询) |
|
||||
| type | String | 否 | 工具类型:LOCAL/REMOTE/BUILTIN |
|
||||
| status | String | 否 | 状态:0-启用, 1-禁用 |
|
||||
| pageNum | Integer | 是 | 页码,默认1 |
|
||||
| pageSize | Integer | 是 | 每页数量,默认10 |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"rows": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "ReadFileTool",
|
||||
"description": "读取文件内容工具",
|
||||
"type": "BUILTIN",
|
||||
"status": "0",
|
||||
"configJson": null,
|
||||
"createTime": "2026-03-08 10:00:00",
|
||||
"updateTime": "2026-03-08 10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 查询工具列表(不分页)
|
||||
|
||||
**接口**: `GET /tool/all`
|
||||
|
||||
**权限**: `mcp:tool:list`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| keyword | String | 否 | 关键词 |
|
||||
| type | String | 否 | 工具类型 |
|
||||
| status | String | 否 | 状态 |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "ReadFileTool",
|
||||
"description": "读取文件内容工具",
|
||||
"type": "BUILTIN",
|
||||
"status": "0"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 获取工具详情
|
||||
|
||||
**接口**: `GET /tool/{id}`
|
||||
|
||||
**权限**: `mcp:tool:query`
|
||||
|
||||
**路径参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | Long | 是 | 工具ID |
|
||||
|
||||
### 1.4 新增工具
|
||||
|
||||
**接口**: `POST /tool`
|
||||
|
||||
**权限**: `mcp:tool:add`
|
||||
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"name": "MyMcpTool",
|
||||
"description": "我的MCP工具",
|
||||
"type": "REMOTE",
|
||||
"status": "0",
|
||||
"configJson": "{\"baseUrl\": \"http://localhost:8080/mcp\"}"
|
||||
}
|
||||
```
|
||||
|
||||
### 1.5 修改工具
|
||||
|
||||
**接口**: `PUT /tool`
|
||||
|
||||
**权限**: `mcp:tool:edit`
|
||||
|
||||
**请求体**: 同新增工具
|
||||
|
||||
### 1.6 删除工具
|
||||
|
||||
**接口**: `DELETE /tool/{ids}`
|
||||
|
||||
**权限**: `mcp:tool:remove`
|
||||
|
||||
**路径参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| ids | String | 是 | 工具ID,多个用逗号分隔 |
|
||||
|
||||
### 1.7 更新工具状态
|
||||
|
||||
**接口**: `PUT /tool/{id}/status`
|
||||
|
||||
**权限**: `mcp:tool:edit`
|
||||
|
||||
**路径参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | Long | 是 | 工具ID |
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| status | String | 是 | 状态:0-启用, 1-禁用 |
|
||||
|
||||
### 1.8 测试工具连接
|
||||
|
||||
**接口**: `POST /tool/{id}/test`
|
||||
|
||||
**权限**: `mcp:tool:query`
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "连接测试成功",
|
||||
"toolCount": 5,
|
||||
"tools": ["tool1", "tool2", "tool3", "tool4", "tool5"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. MCP市场管理
|
||||
|
||||
### 2.1 查询市场列表
|
||||
|
||||
**接口**: `GET /market/list`
|
||||
|
||||
**权限**: `mcp:market:list`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| name | String | 否 | 市场名称 |
|
||||
| description | String | 否 | 市场描述 |
|
||||
| status | String | 否 | 状态 |
|
||||
| pageNum | Integer | 是 | 页码 |
|
||||
| pageSize | Integer | 是 | 每页数量 |
|
||||
|
||||
### 2.2 获取市场工具列表
|
||||
|
||||
**接口**: `GET /market/{marketId}/tools`
|
||||
|
||||
**权限**: `mcp:market:query`
|
||||
|
||||
**路径参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| marketId | Long | 是 | 市场ID |
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| page | Integer | 否 | 页码,默认1 |
|
||||
| size | Integer | 否 | 每页数量,默认10 |
|
||||
|
||||
### 2.3 刷新市场工具
|
||||
|
||||
**接口**: `POST /market/{marketId}/refresh`
|
||||
|
||||
**权限**: `mcp:market:edit`
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "刷新成功",
|
||||
"addedCount": 3,
|
||||
"updatedCount": 5
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 加载工具到本地
|
||||
|
||||
**接口**: `POST /market/tool/{toolId}/load`
|
||||
|
||||
**权限**: `mcp:market:edit`
|
||||
|
||||
**路径参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| toolId | Long | 是 | 市场工具ID |
|
||||
|
||||
### 2.5 批量加载工具
|
||||
|
||||
**接口**: `POST /market/tools/batchLoad`
|
||||
|
||||
**权限**: `mcp:market:edit`
|
||||
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"toolIds": [1, 2, 3]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 工具调用日志
|
||||
|
||||
### 3.1 查询调用日志
|
||||
|
||||
**接口**: `GET /tool/callLog`
|
||||
|
||||
**权限**: `mcp:tool:query`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| toolId | Long | 否 | 工具ID |
|
||||
| sessionId | Long | 否 | 会话ID |
|
||||
| startDate | Date | 否 | 开始日期 |
|
||||
| endDate | Date | 否 | 结束日期 |
|
||||
| pageNum | Integer | 是 | 页码 |
|
||||
| pageSize | Integer | 是 | 每页数量 |
|
||||
|
||||
### 3.2 获取工具统计
|
||||
|
||||
**接口**: `GET /tool/{toolId}/metrics`
|
||||
|
||||
**权限**: `mcp:tool:query`
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"toolId": 1,
|
||||
"toolName": "ReadFileTool",
|
||||
"today": {
|
||||
"callCount": 100,
|
||||
"successCount": 95,
|
||||
"failureCount": 5,
|
||||
"avgDurationMs": 150,
|
||||
"successRate": 95.0
|
||||
},
|
||||
"week": {
|
||||
"callCount": 500,
|
||||
"successCount": 475,
|
||||
"failureCount": 25,
|
||||
"avgDurationMs": 160,
|
||||
"successRate": 95.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| 200 | 请求成功 |
|
||||
| 401 | 未认证 |
|
||||
| 403 | 无权限 |
|
||||
| 404 | 资源不存在 |
|
||||
| 500 | 服务器错误 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 前端页面需求
|
||||
|
||||
### 5.1 MCP工具管理页面 (`/mcp/tool`)
|
||||
|
||||
**功能**:
|
||||
- 工具列表展示(分页)
|
||||
- 工具搜索和筛选
|
||||
- 新增/编辑/删除工具
|
||||
- 工具状态切换
|
||||
- 工具连接测试
|
||||
|
||||
**表格列**:
|
||||
- 工具名称
|
||||
- 工具描述
|
||||
- 工具类型(标签显示)
|
||||
- 状态(开关)
|
||||
- 创建时间
|
||||
- 操作(编辑、删除、测试)
|
||||
|
||||
### 5.2 MCP市场管理页面 (`/mcp/market`)
|
||||
|
||||
**功能**:
|
||||
- 市场列表展示
|
||||
- 市场工具浏览
|
||||
- 刷新市场工具
|
||||
- 加载工具到本地
|
||||
|
||||
### 5.3 工具调用日志页面 (`/mcp/log`)
|
||||
|
||||
**功能**:
|
||||
- 调用日志列表
|
||||
- 按工具/日期筛选
|
||||
- 成功率统计
|
||||
- 响应时间统计
|
||||
|
||||
**图表**:
|
||||
- 每日调用次数趋势图
|
||||
- 工具调用成功率饼图
|
||||
- 平均响应时间柱状图
|
||||
152
hzhub-ai/hzhub-modules/hzhub-chat/docs/数据库智能体实现总结.md
Normal file
152
hzhub-ai/hzhub-modules/hzhub-chat/docs/数据库智能体实现总结.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# 数据库操作智能体实现总结
|
||||
|
||||
## 概述
|
||||
基于 LangChain4j 的 **Pure agentic AI** 模式,完成了一个智能数据库查询系统。该系统能够根据用户的自然语言问题,自动分析数据库结构、生成查询计划并执行相应的数据库操作。
|
||||
|
||||
## 架构设计
|
||||
|
||||
### 1. 整体框架
|
||||
```
|
||||
用户请求 → SupervisorAgent(协调器) → SqlAgent(数据库专家) → 数据库工具 → 数据库
|
||||
↓
|
||||
结果处理与响应
|
||||
```
|
||||
|
||||
### 2. 核心组件
|
||||
|
||||
#### A. SqlAgent (数据库查询专家)
|
||||
- **文件**: `org.hzhub.agent.SqlAgent`
|
||||
- **职责**: 根据用户的自然语言问题,调用相应的工具查询数据库
|
||||
- **使用的工具**:
|
||||
- `QueryAllTablesTool`: 查询所有表名和注释
|
||||
- `QueryTableSchemaTool`: 查询表的DDL(CREATE TABLE语句)
|
||||
- `ExecuteSqlQueryTool`: 执行SELECT查询
|
||||
|
||||
```java
|
||||
public interface SqlAgent {
|
||||
@SystemMessage("...") // 详细的系统提示
|
||||
@UserMessage("请回答以下问题:{{query}}")
|
||||
@Agent("一个智能数据库查询助手...")
|
||||
String getData(@V("query") String query);
|
||||
}
|
||||
```
|
||||
|
||||
#### B. SupervisorAgent (总体协调器)
|
||||
- 在 `OpenAIServiceImpl.doAgent()` 中创建
|
||||
- 作用:协调 SqlAgent 的执行,管理任务流程
|
||||
- 响应策略:`SUMMARY` - 返回所有操作的摘要
|
||||
|
||||
```java
|
||||
SupervisorAgent supervisor = AgenticServices
|
||||
.supervisorBuilder()
|
||||
.chatModel(PLANNER_MODEL)
|
||||
.subAgents(sqlAgent)
|
||||
.responseStrategy(SupervisorResponseStrategy.SUMMARY)
|
||||
.build();
|
||||
```
|
||||
|
||||
#### C. 数据库工具 (Tools)
|
||||
|
||||
##### 1. QueryAllTablesTool
|
||||
```java
|
||||
@Tool("Query all tables in the database and return table names and basic information")
|
||||
public String queryAllTables()
|
||||
```
|
||||
- 返回数据库中所有表的名称和注释
|
||||
- 使用注入的 `agentDataSource` DataSource
|
||||
|
||||
##### 2. QueryTableSchemaTool
|
||||
```java
|
||||
@Tool("Query the CREATE TABLE statement (DDL) for a specific table by table name")
|
||||
public String queryTableSchema(String tableName)
|
||||
```
|
||||
- 返回指定表的建表SQL语句
|
||||
- 包含SQL注入防护(表名有效性验证)
|
||||
|
||||
##### 3. ExecuteSqlQueryTool
|
||||
```java
|
||||
@Tool("Execute a SELECT SQL query and return the results. Example: SELECT * FROM sys_user")
|
||||
public String executeSql(String sql)
|
||||
```
|
||||
- 执行SELECT查询(安全性考虑,不允许执行其他操作)
|
||||
- 格式化查询结果,最多显示前20行
|
||||
|
||||
### 3. 配置体系
|
||||
|
||||
#### AgentMysqlProperties
|
||||
配置文件前缀:`agent.mysql`
|
||||
```yaml
|
||||
agent:
|
||||
mysql:
|
||||
enabled: true
|
||||
url: jdbc:mysql://localhost:3306/your_database
|
||||
username: your_username
|
||||
password: your_password
|
||||
max-pool-size: 10
|
||||
min-idle: 2
|
||||
```
|
||||
|
||||
#### AgentMysqlConfig
|
||||
- 创建独立的 DataSource Bean (`agentDataSource`)
|
||||
- 使用 HikariCP 连接池管理
|
||||
- 与项目主数据源隔离
|
||||
|
||||
#### TableSchemaManager
|
||||
- 在应用启动时初始化表结构缓存
|
||||
- 使用 `ConcurrentHashMap` 存储结构信息
|
||||
- 支持按需刷新单个表的结构
|
||||
|
||||
## 工作流程示例
|
||||
|
||||
### 用户查询: "数据库有哪些表?"
|
||||
|
||||
```
|
||||
1. SupervisorAgent 接收请求
|
||||
↓
|
||||
2. SupervisorAgent 分析请求,决定调用 SqlAgent
|
||||
↓
|
||||
3. SqlAgent 理解需求,调用 QueryAllTablesTool
|
||||
↓
|
||||
4. QueryAllTablesTool 连接数据库,获取所有表
|
||||
↓
|
||||
5. 结果返回给 SqlAgent
|
||||
↓
|
||||
6. SqlAgent 格式化结果
|
||||
↓
|
||||
7. SupervisorAgent 生成最终摘要
|
||||
↓
|
||||
8. 结果通过流式处理器返回给用户
|
||||
```
|
||||
|
||||
### 用户查询: "查询 sys_user 表中有多少条记录"
|
||||
|
||||
```
|
||||
1. SqlAgent 接收请求
|
||||
↓
|
||||
2. SqlAgent 分析需求,可能先调用 QueryTableSchemaTool 了解表结构
|
||||
↓
|
||||
3. 然后调用 ExecuteSqlQueryTool 执行 "SELECT COUNT(*) FROM sys_user"
|
||||
↓
|
||||
4. 获取查询结果并返回
|
||||
```
|
||||
|
||||
## Agentic AI 特性
|
||||
|
||||
### 自适应决策
|
||||
- Agent 能根据上下文和之前的结果决定下一步操作
|
||||
- 不是预定义的固定流程,而是动态适应
|
||||
|
||||
### 例子
|
||||
当询问"查询部门表的字段信息时":
|
||||
- SqlAgent 可能先调用 `QueryTableSchemaTool` 获取建表SQL
|
||||
- 如果发现需要具体的数据示例,会继续调用 `ExecuteSqlQueryTool`
|
||||
- 整个决策过程由 LLM 驱动,非硬编码
|
||||
|
||||
## 安全考虑
|
||||
|
||||
1. **数据源隔离**: Agent 使用独立的数据源(agentDataSource),与主应用隔离
|
||||
2. **SQL验证**: 只允许执行 SELECT 查询
|
||||
3. **表名验证**: 表名必须通过正则表达式验证(防止SQL注入)
|
||||
4. **权限限制**: 可通过 AGENT_ALLOWED_TABLES 环境变量限制可访问的表
|
||||
5. **凭证管理**: 数据库凭证通过配置文件管理,不硬编码
|
||||
|
||||
151
hzhub-ai/hzhub-modules/hzhub-chat/pom.xml
Normal file
151
hzhub-ai/hzhub-modules/hzhub-chat/pom.xml
Normal file
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-modules</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ruoyi-chat</artifactId>
|
||||
<description>
|
||||
聊天模块 - API定义和服务实现
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-common-chat</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-common-sse</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-common-sensitive</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-open-ai</artifactId>
|
||||
<version>${langchain4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-ollama</artifactId>
|
||||
<version>${langchain4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-agentic</artifactId>
|
||||
<version>${langchain4j.community.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-community-dashscope</artifactId>
|
||||
<version>${langchain4j.community.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-community-zhipu-ai</artifactId>
|
||||
<version>${langchain4j.community.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--文档解析-->
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-document-parser-apache-tika</artifactId>
|
||||
<version>${langchain4j.community.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- LangChain4j Milvus Embedding Store -->
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-milvus</artifactId>
|
||||
<version>${langchain4j.community.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-weaviate</artifactId>
|
||||
<version>${langchain4j.community.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-mcp</artifactId>
|
||||
<version>${langchain4j.community.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>weaviate</artifactId>
|
||||
<version>${weaviate.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-common-idempotent</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-common-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hzhub</groupId>
|
||||
<artifactId>hzhub-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.neo4j.driver</groupId>
|
||||
<artifactId>neo4j-java-driver</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.imfangs</groupId>
|
||||
<artifactId>dify-java-client</artifactId>
|
||||
<version>${dify.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- HikariCP 数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL JDBC 驱动 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.hzhub.agent;
|
||||
|
||||
import dev.langchain4j.agentic.Agent;
|
||||
import dev.langchain4j.service.SystemMessage;
|
||||
import dev.langchain4j.service.UserMessage;
|
||||
import dev.langchain4j.service.V;
|
||||
|
||||
|
||||
public interface ChartGenerationAgent extends Agent {
|
||||
|
||||
@SystemMessage("""
|
||||
You are a chart generation specialist. Your only task is to generate Apache ECharts
|
||||
chart configurations. Respond with ONLY the ECharts configuration in ```echarts markdown
|
||||
code block format. Do not include any explanations, descriptions, or other content.
|
||||
""")
|
||||
@UserMessage("""
|
||||
Generate an Apache ECharts chart configuration for: {{query}}
|
||||
Response format: ```echarts
|
||||
{valid JSON ECharts configuration}
|
||||
```
|
||||
""")
|
||||
@Agent("Generate Apache ECharts chart configurations only.")
|
||||
String generateChart(@V("query") String query);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.hzhub.agent;
|
||||
|
||||
import dev.langchain4j.agentic.Agent;
|
||||
import dev.langchain4j.service.SystemMessage;
|
||||
import dev.langchain4j.service.UserMessage;
|
||||
import dev.langchain4j.service.V;
|
||||
|
||||
/**
|
||||
* Text2SQL and Echarts Chart Generation Agent
|
||||
* An intelligent assistant that converts natural language queries into SQL,
|
||||
* executes database queries, and generates Echarts visualizations.
|
||||
*/
|
||||
public interface EchartsAgent {
|
||||
|
||||
@SystemMessage("""
|
||||
You are a data visualization assistant that generates Echarts chart configurations.
|
||||
|
||||
CRITICAL OUTPUT REQUIREMENTS:
|
||||
- Return Echarts JSON wrapped in markdown code block
|
||||
- Use this exact format: ```json\n{...}\n```
|
||||
- The JSON inside must be valid Echarts configuration
|
||||
- Frontend expects markdown format for proper parsing
|
||||
|
||||
Your workflow:
|
||||
1. Use MCP tools to query the database and get data
|
||||
2. The MCP tool returns data in this structure:
|
||||
{"data": [{"dict_type": "value1", "count": 10}, {"dict_type": "value2", "count": 20}, ...]}
|
||||
3. Transform this data into Echarts configuration
|
||||
4. Return ONLY the Echarts JSON
|
||||
|
||||
Data transformation rules:
|
||||
- Extract array elements into xAxis categories and series data
|
||||
- For the example above: xAxis.data = ["value1", "value2"], series.data = [10, 20]
|
||||
- Choose chart type based on request: bar (default), line, pie, etc.
|
||||
|
||||
Expected output format (bar chart example):
|
||||
```json
|
||||
{
|
||||
"title": {
|
||||
"text": "Dict Type Distribution",
|
||||
"left": "center"
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": "axis"
|
||||
},
|
||||
"xAxis": {
|
||||
"type": "category",
|
||||
"data": ["type1", "type2", "type3"]
|
||||
},
|
||||
"yAxis": {
|
||||
"type": "value"
|
||||
},
|
||||
"series": [
|
||||
{
|
||||
"name": "数量",
|
||||
"type": "bar",
|
||||
"data": [10, 20, 15]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
For pie charts:
|
||||
{
|
||||
"title": {"text": "Chart Title", "left": "center"},
|
||||
"tooltip": {"trigger": "item"},
|
||||
"series": [{
|
||||
"type": "pie",
|
||||
"radius": "50%",
|
||||
"data": [
|
||||
{"value": 10, "name": "Category1"},
|
||||
{"value": 20, "name": "Category2"}
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
REMEMBER:
|
||||
- Always wrap JSON in ```json and ``` markers
|
||||
- Use proper formatting with indentation
|
||||
- This is the expected format for frontend parsing
|
||||
""")
|
||||
@UserMessage("""
|
||||
Generate an Echarts chart for: {{query}}
|
||||
|
||||
IMPORTANT: Return the Echarts configuration JSON wrapped in markdown code block (```json...```).
|
||||
""")
|
||||
@Agent("Data visualization assistant that returns Echarts JSON configurations for frontend rendering")
|
||||
String search(@V("query") String query);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.hzhub.agent;
|
||||
|
||||
import dev.langchain4j.agentic.Agent;
|
||||
import dev.langchain4j.service.SystemMessage;
|
||||
import dev.langchain4j.service.UserMessage;
|
||||
import dev.langchain4j.service.V;
|
||||
|
||||
/**
|
||||
* SQL Database Agent
|
||||
* A database query assistant that answers natural language questions by querying the database
|
||||
* and returning relevant data and analysis results.
|
||||
*
|
||||
*/
|
||||
public interface SqlAgent extends Agent {
|
||||
|
||||
@SystemMessage("""
|
||||
This agent is designed for MySQL 5.7
|
||||
You are an intelligent database query assistant. Your responsibility is to:
|
||||
1. Query all tables in the database to understand the database structure
|
||||
2. Understand the user's natural language question
|
||||
3. Query the database to get the information needed
|
||||
4. Provide accurate and helpful answers
|
||||
|
||||
Available tools:
|
||||
- queryAllTables: Query all tables in the database
|
||||
- queryTableSchema: Query the table structure and CREATE SQL for a specified table
|
||||
- executeSql: Execute a SELECT SQL query and return results
|
||||
|
||||
CRITICAL REQUIREMENT - MUST FOLLOW:
|
||||
- You MUST ALWAYS use queryAllTables first to query all tables in the database before executing any SQL queries
|
||||
- Only after understanding the database schema can you construct and execute appropriate SQL queries
|
||||
- This is mandatory and applies to all queries without exception
|
||||
""")
|
||||
@UserMessage("""
|
||||
Answer the following question: {{query}}
|
||||
""")
|
||||
@Agent("Intelligent database query assistant that MUST check database tables first, then query table structures and execute SQL queries")
|
||||
String getData(@V("query") String query);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.hzhub.agent;
|
||||
|
||||
import dev.langchain4j.agentic.Agent;
|
||||
import dev.langchain4j.service.SystemMessage;
|
||||
import dev.langchain4j.service.UserMessage;
|
||||
import dev.langchain4j.service.V;
|
||||
|
||||
/**
|
||||
* Web Search Agent
|
||||
* A web search assistant that answers natural language questions by searching the internet
|
||||
* and returning relevant information from web pages.
|
||||
*/
|
||||
public interface WebSearchAgent extends Agent {
|
||||
|
||||
@SystemMessage("""
|
||||
You are a web search assistant. Answer questions by searching and retrieving web content.
|
||||
|
||||
Available tools:
|
||||
1. bing_search: Search the internet with keywords
|
||||
- query (required): search keywords
|
||||
- count (optional): number of results, default 10, max 50
|
||||
- offset (optional): pagination offset, default 0
|
||||
Returns: title, link, and summary for each result
|
||||
|
||||
2. crawl_webpage: Extract text content from a web page
|
||||
- url (required): web page URL
|
||||
Returns: cleaned page title and main content
|
||||
|
||||
Instructions:
|
||||
- Always cite sources in your answers
|
||||
- Only use the two tools listed above
|
||||
""")
|
||||
@UserMessage("""
|
||||
Answer the following question by searching the web: {{query}}
|
||||
""")
|
||||
@Agent("Web search assistant using Bing search and web scraping to find and retrieve information")
|
||||
String search(@V("query") String query);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// package org.hzhub.agent.config;
|
||||
|
||||
// import com.zaxxer.hikari.HikariConfig;
|
||||
// import com.zaxxer.hikari.HikariDataSource;
|
||||
// import javax.sql.DataSource;
|
||||
// import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
// import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
// import org.springframework.context.annotation.Bean;
|
||||
// import org.springframework.context.annotation.Configuration;
|
||||
|
||||
// /**
|
||||
// * Agent MySQL 数据源配置
|
||||
// * 为 Agent 配置独立的 MySQL 数据库连接池(HikariCP)
|
||||
// *
|
||||
// * 仅在 agent.mysql.enabled=true 时启用
|
||||
// */
|
||||
// @Configuration
|
||||
// @EnableConfigurationProperties(AgentMysqlProperties.class)
|
||||
// @ConditionalOnProperty(name = "agent.mysql.enabled", havingValue = "true")
|
||||
// public class AgentMysqlConfig {
|
||||
|
||||
// /**
|
||||
// * 创建 Agent 专用的数据源
|
||||
// * 与项目主数据源隔离,独立管理
|
||||
// *
|
||||
// * @param properties Agent MySQL 配置属性
|
||||
// * @return HikariCP 数据源
|
||||
// */
|
||||
// @Bean("agentDataSource")
|
||||
// public DataSource agentDataSource(AgentMysqlProperties properties) {
|
||||
// HikariConfig config = new HikariConfig();
|
||||
// config.setJdbcUrl(properties.getUrl());
|
||||
// config.setUsername(properties.getUsername());
|
||||
// config.setPassword(properties.getPassword());
|
||||
// config.setDriverClassName("com.mysql.cj.jdbc.Driver");
|
||||
// config.setMaximumPoolSize(properties.getMaxPoolSize());
|
||||
// config.setMinimumIdle(properties.getMinIdle());
|
||||
// config.setConnectionTimeout(30000);
|
||||
// config.setIdleTimeout(600000);
|
||||
// config.setMaxLifetime(1800000);
|
||||
|
||||
// return new HikariDataSource(config);
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.hzhub.agent.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Agent MySQL 配置属性
|
||||
* 前缀:agent.mysql
|
||||
*
|
||||
* 配置示例:
|
||||
* agent:
|
||||
* mysql:
|
||||
* enabled: true
|
||||
* url: jdbc:mysql://localhost:3306/database
|
||||
* username: user
|
||||
* password: password
|
||||
* max-pool-size: 10
|
||||
* min-idle: 2
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "agent.mysql")
|
||||
public class AgentMysqlProperties {
|
||||
|
||||
/**
|
||||
* 是否启用 Agent MySQL 查询功能
|
||||
*/
|
||||
private Boolean enabled = false;
|
||||
|
||||
/**
|
||||
* 数据库 URL (jdbc:mysql://host:port/database)
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 数据库用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 数据库密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 数据库连接池最大连接数
|
||||
*/
|
||||
private Integer maxPoolSize = 10;
|
||||
|
||||
/**
|
||||
* 数据库连接池最小空闲连接数
|
||||
*/
|
||||
private Integer minIdle = 2;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.hzhub.agent.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 数据库列(字段)信息
|
||||
* 描述表中单个列的详细信息
|
||||
*/
|
||||
@Data
|
||||
public class ColumnInfo {
|
||||
|
||||
/**
|
||||
* 列名
|
||||
*/
|
||||
private String columnName;
|
||||
|
||||
/**
|
||||
* 列数据类型
|
||||
* 示例:VARCHAR(100), INT, DECIMAL(10,2), DATE 等
|
||||
*/
|
||||
private String columnType;
|
||||
|
||||
/**
|
||||
* 是否可为空
|
||||
*/
|
||||
private boolean nullable = true;
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
private String defaultValue;
|
||||
|
||||
/**
|
||||
* 列注释/说明
|
||||
*/
|
||||
private String columnComment;
|
||||
|
||||
/**
|
||||
* 是否是主键
|
||||
*/
|
||||
private boolean primaryKey = false;
|
||||
|
||||
/**
|
||||
* 是否自增
|
||||
*/
|
||||
private boolean autoIncrement = false;
|
||||
|
||||
/**
|
||||
* 是否有索引
|
||||
*/
|
||||
private boolean indexed = false;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.hzhub.agent.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 单个查询条件
|
||||
* 用于 WHERE 子句中的条件
|
||||
*
|
||||
* 示例:
|
||||
* Condition c = new Condition();
|
||||
* c.setField("order_date");
|
||||
* c.setOperator(">=");
|
||||
* c.setValue("2024-01-01");
|
||||
*/
|
||||
@Data
|
||||
public class Condition {
|
||||
|
||||
/**
|
||||
* 字段名
|
||||
* 仅允许:字母、数字、下划线
|
||||
*/
|
||||
private String field;
|
||||
|
||||
/**
|
||||
* 操作符
|
||||
* 支持:=, !=, <, >, <=, >=, LIKE, IN, BETWEEN, IS NULL, IS NOT NULL
|
||||
*/
|
||||
private String operator;
|
||||
|
||||
/**
|
||||
* 条件值
|
||||
* 类型可以是:String, Number, Boolean 等
|
||||
* 会自动转义防止 SQL 注入
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
public Condition() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 带参数的构造函数
|
||||
*/
|
||||
public Condition(String field, String operator, Object value) {
|
||||
this.field = field;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.hzhub.agent.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库查询对象
|
||||
* 用于构建 SELECT 查询条件
|
||||
*/
|
||||
@Data
|
||||
public class Query {
|
||||
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
private String table;
|
||||
|
||||
/**
|
||||
* 选择的字段列表
|
||||
* 可以使用 "*" 表示所有字段
|
||||
*/
|
||||
private List<String> select;
|
||||
|
||||
/**
|
||||
* WHERE 条件列表
|
||||
* 多个条件之间用 AND 连接
|
||||
*/
|
||||
private List<Condition> where;
|
||||
|
||||
/**
|
||||
* 返回结果数量限制
|
||||
* 默认 100,最大 1000
|
||||
*/
|
||||
private Integer limit = 100;
|
||||
|
||||
/**
|
||||
* 获取安全的 LIMIT 值
|
||||
* @return 限制数量,最多 1000
|
||||
*/
|
||||
public Integer getLimit() {
|
||||
if (limit == null) {
|
||||
limit = 100;
|
||||
}
|
||||
return Math.min(limit, 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.hzhub.agent.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据库查询结果
|
||||
* 返回 SELECT 查询的结果
|
||||
*/
|
||||
@Data
|
||||
public class Result {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 错误消息或成功消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 查询结果数据
|
||||
* 每个 Map 代表一行,key 是字段名,value 是字段值
|
||||
*/
|
||||
private List<Map<String, Object>> data;
|
||||
|
||||
/**
|
||||
* 创建成功结果
|
||||
* @param data 查询数据
|
||||
* @return Result 对象
|
||||
*/
|
||||
public static Result success(List<Map<String, Object>> data) {
|
||||
Result result = new Result();
|
||||
result.success = true;
|
||||
result.data = data;
|
||||
result.message = "Query successful";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败结果
|
||||
* @param message 错误消息
|
||||
* @return Result 对象
|
||||
*/
|
||||
public static Result error(String message) {
|
||||
Result result = new Result();
|
||||
result.success = false;
|
||||
result.message = message;
|
||||
result.data = new ArrayList<>();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.hzhub.agent.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表结构查询结果
|
||||
* 返回数据库的表结构信息
|
||||
*/
|
||||
@Data
|
||||
public class SchemaResult {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 错误消息或成功消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 表结构列表
|
||||
*/
|
||||
private List<TableStructure> tables;
|
||||
|
||||
/**
|
||||
* 创建成功结果
|
||||
* @param tables 表结构列表
|
||||
* @return SchemaResult 对象
|
||||
*/
|
||||
public static SchemaResult success(List<TableStructure> tables) {
|
||||
SchemaResult result = new SchemaResult();
|
||||
result.success = true;
|
||||
result.tables = tables != null ? tables : new ArrayList<>();
|
||||
result.message = "Schema retrieved successfully";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败结果
|
||||
* @param message 错误消息
|
||||
* @return SchemaResult 对象
|
||||
*/
|
||||
public static SchemaResult error(String message) {
|
||||
SchemaResult result = new SchemaResult();
|
||||
result.success = false;
|
||||
result.message = message;
|
||||
result.tables = new ArrayList<>();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.hzhub.agent.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表列表查询结果
|
||||
* 返回允许查询的表的名称列表
|
||||
*/
|
||||
@Data
|
||||
public class TableListResult {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 错误消息或成功消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 表名列表
|
||||
*/
|
||||
private List<String> tables;
|
||||
|
||||
/**
|
||||
* 创建成功结果
|
||||
* @param tables 表名列表
|
||||
* @return TableListResult 对象
|
||||
*/
|
||||
public static TableListResult success(List<String> tables) {
|
||||
TableListResult result = new TableListResult();
|
||||
result.success = true;
|
||||
result.tables = tables != null ? tables : new ArrayList<>();
|
||||
result.message = "Tables listed successfully";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败结果
|
||||
* @param message 错误消息
|
||||
* @return TableListResult 对象
|
||||
*/
|
||||
public static TableListResult error(String message) {
|
||||
TableListResult result = new TableListResult();
|
||||
result.success = false;
|
||||
result.message = message;
|
||||
result.tables = new ArrayList<>();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.hzhub.agent.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库表结构信息
|
||||
* 包含表的所有字段、类型、约束等信息
|
||||
* Agent 使用此信息来理解数据库架构
|
||||
*/
|
||||
@Data
|
||||
public class TableStructure {
|
||||
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
private String tableName;
|
||||
|
||||
private String tableType; // 添加此字段:BASE TABLE 或 VIEW
|
||||
/**
|
||||
* 表注释/说明
|
||||
*/
|
||||
private String tableComment;
|
||||
|
||||
/**
|
||||
* 字段列表
|
||||
*/
|
||||
private List<ColumnInfo> columns = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 主键字段名
|
||||
*/
|
||||
private String primaryKey;
|
||||
|
||||
/**
|
||||
* 获取字段总数
|
||||
* @return 字段数量
|
||||
*/
|
||||
public int getColumnCount() {
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取格式化的表结构描述
|
||||
* 用于 Agent 理解表结构
|
||||
*
|
||||
* @return 格式化的表结构描述
|
||||
*/
|
||||
public String getFormattedDescription() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("表: ").append(tableName);
|
||||
if (tableComment != null && !tableComment.isEmpty()) {
|
||||
sb.append("(").append(tableComment).append(")");
|
||||
}
|
||||
sb.append("\n字段:\n");
|
||||
for (ColumnInfo col : columns) {
|
||||
sb.append(" - ").append(col.getColumnName())
|
||||
.append(" (").append(col.getColumnType()).append(")");
|
||||
if (!col.isNullable()) {
|
||||
sb.append(" NOT NULL");
|
||||
}
|
||||
if (col.getColumnComment() != null && !col.getColumnComment().isEmpty()) {
|
||||
sb.append(" // ").append(col.getColumnComment());
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.hzhub.agent.manager;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 架构初始化器
|
||||
* 在应用启动完成后自动初始化表结构缓存
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
// @ConditionalOnProperty(name = "agent.mysql.enabled", havingValue = "true")
|
||||
public class TableSchemaInitializer {
|
||||
|
||||
@Autowired(required = false)
|
||||
private TableSchemaManager tableSchemaManager;
|
||||
|
||||
/**
|
||||
* 应用启动完成后初始化
|
||||
*/
|
||||
@EventListener(ContextRefreshedEvent.class)
|
||||
public void initializeOnStartup() {
|
||||
if (tableSchemaManager != null) {
|
||||
tableSchemaManager.initializeSchema();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
package org.hzhub.agent.manager;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hzhub.agent.domain.ColumnInfo;
|
||||
import org.hzhub.agent.domain.TableStructure;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 表结构管理器
|
||||
* 负责获取和缓存数据库表结构信息
|
||||
*
|
||||
* 特点:
|
||||
* - 应用启动时自动初始化所有表结构
|
||||
* - 使用内存缓存 (ConcurrentHashMap) 确保高性能
|
||||
* - 支持按需刷新单个表的结构
|
||||
* - 延迟初始化:失败时在首次查询时重试
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@DS("agent")
|
||||
public class TableSchemaManager {
|
||||
|
||||
@Autowired(required = false)
|
||||
private DataSource agentDataSource;
|
||||
|
||||
@Value("${AGENT_ALLOWED_TABLES}")
|
||||
private String allowedTables;
|
||||
|
||||
/**
|
||||
* 表结构缓存 (表名 -> 表结构)
|
||||
* 使用 ConcurrentHashMap 支持高并发访问
|
||||
*/
|
||||
private final Map<String, TableStructure> schemaCache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 缓存初始化标志
|
||||
*/
|
||||
private volatile boolean initialized = false;
|
||||
|
||||
/**
|
||||
* 初始化表结构缓存
|
||||
* Spring 会自动在 Bean 创建后调用此方法
|
||||
*/
|
||||
public void initializeSchema() {
|
||||
if (agentDataSource == null) {
|
||||
log.warn("Agent datasource not configured, schema initialization skipped");
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
log.info("Initializing database schema cache...");
|
||||
loadAllowedTableSchemas();
|
||||
initialized = true;
|
||||
log.info("Schema cache initialized with {} tables", schemaCache.size());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to initialize schema cache", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载所有允许的表的结构信息
|
||||
*/
|
||||
private void loadAllowedTableSchemas() {
|
||||
List<String> allowedTables = getAllowedTableNames();
|
||||
for (String tableName : allowedTables) {
|
||||
try {
|
||||
TableStructure schema = loadTableSchema(tableName);
|
||||
if (schema != null) {
|
||||
schemaCache.put(tableName, schema);
|
||||
log.debug("Loaded schema for table: {}", tableName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to load schema for table: {}", tableName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数据库加载指定表的结构信息
|
||||
*/
|
||||
private TableStructure loadTableSchema(String tableName) throws SQLException {
|
||||
if (!isValidIdentifier(tableName) || !isTableAllowed(tableName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TableStructure table = new TableStructure();
|
||||
table.setTableName(tableName);
|
||||
|
||||
try (Connection conn = agentDataSource.getConnection()) {
|
||||
DatabaseMetaData metaData = conn.getMetaData();
|
||||
|
||||
// 获取表注释
|
||||
try (ResultSet tableRs = metaData.getTables(conn.getCatalog(), null, tableName, new String[]{"TABLE"})) {
|
||||
if (tableRs.next()) {
|
||||
table.setTableComment(tableRs.getString("REMARKS"));
|
||||
table.setTableType(tableRs.getString("TABLE_TYPE"));
|
||||
}
|
||||
}
|
||||
|
||||
// 获取列信息
|
||||
List<ColumnInfo> columns = new ArrayList<>();
|
||||
try (ResultSet colRs = metaData.getColumns(conn.getCatalog(), null, tableName, null)) {
|
||||
while (colRs.next()) {
|
||||
ColumnInfo col = new ColumnInfo();
|
||||
col.setColumnName(colRs.getString("COLUMN_NAME"));
|
||||
col.setColumnType(colRs.getString("TYPE_NAME"));
|
||||
|
||||
int columnSize = colRs.getInt("COLUMN_SIZE");
|
||||
if (columnSize > 0 && !isNumericType(col.getColumnType())) {
|
||||
col.setColumnType(col.getColumnType() + "(" + columnSize + ")");
|
||||
}
|
||||
|
||||
col.setNullable("YES".equalsIgnoreCase(colRs.getString("IS_NULLABLE")));
|
||||
col.setDefaultValue(colRs.getString("COLUMN_DEF"));
|
||||
col.setColumnComment(colRs.getString("REMARKS"));
|
||||
col.setAutoIncrement("YES".equalsIgnoreCase(colRs.getString("IS_AUTOINCREMENT")));
|
||||
|
||||
columns.add(col);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取主键信息
|
||||
try (ResultSet pkRs = metaData.getPrimaryKeys(conn.getCatalog(), null, tableName)) {
|
||||
if (pkRs.next()) {
|
||||
String pkName = pkRs.getString("COLUMN_NAME");
|
||||
table.setPrimaryKey(pkName);
|
||||
for (ColumnInfo col : columns) {
|
||||
if (col.getColumnName().equals(pkName)) {
|
||||
col.setPrimaryKey(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取索引信息
|
||||
try (ResultSet indexRs = metaData.getIndexInfo(conn.getCatalog(), null, tableName, false, false)) {
|
||||
Set<String> indexedColumns = new HashSet<>();
|
||||
while (indexRs.next()) {
|
||||
String colName = indexRs.getString("COLUMN_NAME");
|
||||
if (colName != null) {
|
||||
indexedColumns.add(colName);
|
||||
}
|
||||
}
|
||||
for (ColumnInfo col : columns) {
|
||||
if (indexedColumns.contains(col.getColumnName())) {
|
||||
col.setIndexed(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table.setColumns(columns);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有允许的表的结构信息
|
||||
*/
|
||||
public List<TableStructure> getAllowedTableSchemas() {
|
||||
if (!initialized) {
|
||||
initializeSchema();
|
||||
}
|
||||
|
||||
List<String> allowedTables = getAllowedTableNames();
|
||||
return allowedTables.stream().map(schemaCache::get).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有允许的表名
|
||||
*/
|
||||
public List<String> getAllowedTableNames() {
|
||||
if (allowedTables == null || allowedTables.trim().isEmpty()) {
|
||||
log.warn("AGENT_ALLOWED_TABLES not configured");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return Arrays.stream(allowedTables.split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新指定表的结构信息
|
||||
*/
|
||||
public TableStructure refreshTableSchema(String tableName) throws SQLException {
|
||||
if (!isValidIdentifier(tableName) || !isTableAllowed(tableName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TableStructure schema = loadTableSchema(tableName);
|
||||
if (schema != null) {
|
||||
schemaCache.put(tableName, schema);
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否为有效的 SQL 标识符
|
||||
*/
|
||||
private boolean isValidIdentifier(String identifier) {
|
||||
if (identifier == null || identifier.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return identifier.matches("^[a-zA-Z0-9_\\.]+$");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查表是否在允许列表中
|
||||
*/
|
||||
private boolean isTableAllowed(String tableName) {
|
||||
// String allowedTables = System.getenv("AGENT_ALLOWED_TABLES");
|
||||
if (allowedTables == null || allowedTables.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Set<String> tables = new HashSet<>(Arrays.asList(allowedTables.split(",")));
|
||||
return tables.contains(tableName.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为数值类型
|
||||
*/
|
||||
private boolean isNumericType(String typeName) {
|
||||
String upper = typeName.toUpperCase();
|
||||
return upper.contains("INT") || upper.contains("FLOAT") ||
|
||||
upper.contains("DOUBLE") || upper.contains("DECIMAL");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package org.hzhub.agent.tool;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hzhub.common.core.utils.SpringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
|
||||
|
||||
import dev.langchain4j.agent.tool.Tool;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hzhub.mcp.service.core.BuiltinToolProvider;
|
||||
|
||||
/**
|
||||
* 执行 SQL 查询的 Tool
|
||||
* 执行指定的 SELECT SQL 查询并返回结果
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ExecuteSqlQueryTool implements BuiltinToolProvider {
|
||||
|
||||
// 使用延迟初始化,避免在构造函数中调用 SpringUtils.getBean()
|
||||
private DataSource getDataSource() {
|
||||
return SpringUtils.getBean(DataSource.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 SELECT SQL 查询
|
||||
* 只允许执行 SELECT 查询,防止恶意的数据修改操作
|
||||
*
|
||||
* @param sql 要执行的 SELECT SQL 语句,例如:SELECT * FROM sys_user
|
||||
* @return 包含查询结果的字符串
|
||||
*/
|
||||
@Tool("Execute a SELECT SQL query and return the results. Example: SELECT * FROM sys_user")
|
||||
public String executeSql(String sql) {
|
||||
// 2. 手动推入数据源上下文
|
||||
DynamicDataSourceContextHolder.push("agent");
|
||||
if (sql == null || sql.trim().isEmpty()) {
|
||||
return "Error: SQL query cannot be empty";
|
||||
}
|
||||
|
||||
// 只允许执行 SELECT 查询,防止恶意操作
|
||||
String upperSql = sql.trim().toUpperCase();
|
||||
if (!upperSql.startsWith("SELECT")) {
|
||||
return "Error: Only SELECT queries are allowed for security reasons";
|
||||
}
|
||||
|
||||
try {
|
||||
DataSource dataSource = getDataSource();
|
||||
if (dataSource == null) {
|
||||
return "Error: Database datasource not configured";
|
||||
}
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sql);
|
||||
ResultSet resultSet = preparedStatement.executeQuery()) {
|
||||
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
|
||||
List<Map<String, Object>> results = new ArrayList<>();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
|
||||
// 获取列名
|
||||
List<String> columnNames = new ArrayList<>();
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
columnNames.add(metaData.getColumnName(i));
|
||||
}
|
||||
|
||||
// 获取数据行,限制最多1000行以防止内存溢出
|
||||
int maxRows = 1000;
|
||||
while (resultSet.next() && results.size() < maxRows) {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
row.put(columnNames.get(i - 1), resultSet.getObject(i));
|
||||
}
|
||||
results.add(row);
|
||||
}
|
||||
|
||||
return formatResults(results, columnNames);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error executing SQL: {}", sql, e);
|
||||
// 3. 必须在 finally 中清除上下文,防止污染其他请求
|
||||
DynamicDataSourceContextHolder.clear();
|
||||
return "Error: " + e.getMessage();
|
||||
} finally {
|
||||
// 3. 必须在 finally 中清除上下文,防止污染其他请求
|
||||
DynamicDataSourceContextHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化查询结果
|
||||
* 返回清晰的表格格式,展示关键数据
|
||||
*/
|
||||
private String formatResults(List<Map<String, Object>> results, List<String> columnNames) {
|
||||
if (results.isEmpty()) {
|
||||
return "Query executed successfully, but no results returned";
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
// 限制显示的列数和行数,避免输出过大
|
||||
int displayCols = Math.min(columnNames.size(), 8); // 最多显示8列
|
||||
int displayRows = Math.min(results.size(), 10); // 最多显示10行
|
||||
|
||||
List<String> displayColumns = columnNames.subList(0, displayCols);
|
||||
|
||||
// 构建表头
|
||||
result.append("| ");
|
||||
for (String col : displayColumns) {
|
||||
result.append(formatColumnName(col)).append(" | ");
|
||||
}
|
||||
result.append("\n");
|
||||
|
||||
// 构建分隔线
|
||||
result.append("|");
|
||||
for (int i = 0; i < displayCols; i++) {
|
||||
result.append(" --- |");
|
||||
}
|
||||
result.append("\n");
|
||||
|
||||
// 构建数据行
|
||||
for (int i = 0; i < displayRows; i++) {
|
||||
result.append("| ");
|
||||
Map<String, Object> row = results.get(i);
|
||||
for (String column : displayColumns) {
|
||||
Object value = row.get(column);
|
||||
String displayValue = formatValue(value);
|
||||
result.append(displayValue).append(" | ");
|
||||
}
|
||||
result.append("\n");
|
||||
}
|
||||
|
||||
// 统计信息
|
||||
result.append("\n").append("Total: ").append(results.size()).append(" rows");
|
||||
if (displayRows < results.size()) {
|
||||
result.append(" (displayed ").append(displayRows).append(" rows)");
|
||||
}
|
||||
if (displayCols < columnNames.size()) {
|
||||
result.append("\nColumns: ").append(displayCols).append(" / ").append(columnNames.size());
|
||||
}
|
||||
|
||||
log.info("Successfully executed SQL query, returned {} rows", results.size());
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化列名,使其更易读
|
||||
*/
|
||||
private String formatColumnName(String columnName) {
|
||||
// 将下划线替换为空格,首字母大写
|
||||
String formatted = columnName.replace("_", " ");
|
||||
if (formatted.length() > 15) {
|
||||
return formatted.substring(0, 12) + "...";
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单个值,适合表格显示
|
||||
*/
|
||||
private String formatValue(Object value) {
|
||||
if (value == null) {
|
||||
return "-";
|
||||
}
|
||||
String str = value.toString();
|
||||
// 限制列宽以保持表格整洁,长文本截断
|
||||
if (str.length() > 20) {
|
||||
return str.substring(0, 17) + "...";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolName() {
|
||||
return "execute_sql_query";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "执行SQL查询";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Execute a SELECT SQL query and return the results. Example: SELECT * FROM sys_user";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.hzhub.agent.tool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hzhub.agent.domain.TableStructure;
|
||||
import org.hzhub.agent.manager.TableSchemaManager;
|
||||
import org.hzhub.common.core.utils.SpringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import dev.langchain4j.agent.tool.Tool;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hzhub.mcp.service.core.BuiltinToolProvider;
|
||||
|
||||
/**
|
||||
* 查询数据库所有表的 Tool
|
||||
* 获取指定数据库中所有表的列表
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class QueryAllTablesTool implements BuiltinToolProvider {
|
||||
|
||||
// 使用延迟初始化,避免在构造函数中调用 SpringUtils.getBean()
|
||||
private TableSchemaManager getTableSchemaManager() {
|
||||
return SpringUtils.getBean(TableSchemaManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据库中所有表
|
||||
* 返回数据库中存在的所有表的列表
|
||||
*
|
||||
* @return 包含所有表信息的结果
|
||||
*/
|
||||
@Tool("Query all tables in the database and return table names and basic information")
|
||||
public String queryAllTables() {
|
||||
try {
|
||||
// 1. 从管理器获取所有允许的表结构信息(内部已包含初始化/缓存逻辑)
|
||||
List<TableStructure> tableSchemas = getTableSchemaManager().getAllowedTableSchemas();
|
||||
|
||||
if (tableSchemas == null || tableSchemas.isEmpty()) {
|
||||
return "No tables found in database or cache is empty.";
|
||||
}
|
||||
|
||||
// 2. 格式化结果
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("Found ").append(tableSchemas.size()).append(" tables in cache:\n");
|
||||
|
||||
for (TableStructure schema : tableSchemas) {
|
||||
String tableName = schema.getTableName();
|
||||
String tableType = schema.getTableType() != null ? schema.getTableType() : "TABLE";
|
||||
String tableComment = schema.getTableComment();
|
||||
|
||||
result.append(String.format("- %s (%s) - %s\n",
|
||||
tableName,
|
||||
tableType,
|
||||
tableComment != null ? tableComment : "No comment"));
|
||||
}
|
||||
|
||||
log.info("Successfully retrieved {} tables from schema cache", tableSchemas.size());
|
||||
return result.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Error retrieving tables from cache", e);
|
||||
return "Error: " + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolName() {
|
||||
return "query_all_tables";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "查询所有表";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Query all tables in the database and return table names and basic information";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.hzhub.agent.tool;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hzhub.common.core.utils.SpringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
|
||||
|
||||
import dev.langchain4j.agent.tool.Tool;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hzhub.mcp.service.core.BuiltinToolProvider;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class QueryTableSchemaTool implements BuiltinToolProvider {
|
||||
|
||||
// 使用延迟初始化,避免在构造函数中调用 SpringUtils.getBean()
|
||||
private DataSource getDataSource() {
|
||||
return SpringUtils.getBean(DataSource.class);
|
||||
}
|
||||
|
||||
@Tool("Query the CREATE TABLE statement (DDL) for a specific table by table name")
|
||||
public String queryTableSchema(String tableName) {
|
||||
// 2. 手动推入数据源上下文
|
||||
DynamicDataSourceContextHolder.push("agent");
|
||||
if (tableName == null || tableName.trim().isEmpty()) {
|
||||
return "Error: Table name cannot be empty";
|
||||
}
|
||||
|
||||
if (!tableName.matches("^[a-zA-Z0-9_]+$")) {
|
||||
return "Error: Invalid table name format";
|
||||
}
|
||||
|
||||
String sql = "SHOW CREATE TABLE `" + tableName + "`";
|
||||
|
||||
try (Connection connection = getDataSource().getConnection();
|
||||
PreparedStatement ps = connection.prepareStatement(sql);
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
|
||||
if (rs.next()) {
|
||||
return rs.getString("Create Table");
|
||||
}
|
||||
return "Table not found: " + tableName;
|
||||
|
||||
} catch (Exception e) {
|
||||
// 3. 必须在 finally 中清除上下文,防止污染其他请求
|
||||
DynamicDataSourceContextHolder.clear();
|
||||
log.error("Error querying table schema: {}", tableName, e);
|
||||
return "Error: " + e.getMessage();
|
||||
} finally {
|
||||
// 3. 必须在 finally 中清除上下文,防止污染其他请求
|
||||
DynamicDataSourceContextHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolName() {
|
||||
return "query_table_schema";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "查询表结构";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Query the CREATE TABLE statement (DDL) for a specific table by table name";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.hzhub.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "mcp.sse")
|
||||
public class McpSseConfig {
|
||||
|
||||
/**
|
||||
* mcp对外暴露的端点地址
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
private boolean enabled;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.hzhub.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package org.hzhub.config.mcp;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hzhub.domain.entity.mcp.McpTool;
|
||||
import org.hzhub.enums.McpToolStatus;
|
||||
import org.hzhub.mapper.mcp.McpToolMapper;
|
||||
import org.hzhub.mcp.service.core.BuiltinToolDefinition;
|
||||
import org.hzhub.mcp.service.core.BuiltinToolRegistry;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 系统工具初始化器
|
||||
* 在应用启动时,将系统内置工具同步到数据库
|
||||
* 这样可以统一管理所有工具,支持动态启用/禁用
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Order(999) // 确保在其他初始化器之后执行
|
||||
@RequiredArgsConstructor
|
||||
public class SystemToolInitializer implements ApplicationRunner {
|
||||
|
||||
private final McpToolMapper mcpToolMapper;
|
||||
private final BuiltinToolRegistry builtinToolRegistry;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void run(ApplicationArguments args) {
|
||||
log.info("开始同步系统内置工具到数据库...");
|
||||
|
||||
int addedCount = 0;
|
||||
int existingCount = 0;
|
||||
|
||||
for (BuiltinToolDefinition tool : builtinToolRegistry.getAllBuiltinTools()) {
|
||||
try {
|
||||
boolean added = syncBuiltinTool(tool);
|
||||
if (added) {
|
||||
addedCount++;
|
||||
} else {
|
||||
existingCount++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("同步内置工具失败: {}", tool.name(), e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("系统内置工具同步完成: 新增 {} 个, 已存在 {} 个", addedCount, existingCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步单个内置工具到数据库
|
||||
*
|
||||
* @param tool 工具定义
|
||||
* @return 是否新增(true=新增, false=已存在)
|
||||
*/
|
||||
private boolean syncBuiltinTool(BuiltinToolDefinition tool) {
|
||||
// 检查是否已存在
|
||||
LambdaQueryWrapper<McpTool> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(McpTool::getName, tool.name())
|
||||
.eq(McpTool::getType, BuiltinToolRegistry.TYPE_BUILTIN);
|
||||
|
||||
McpTool existing = mcpToolMapper.selectOne(wrapper);
|
||||
|
||||
if (existing != null) {
|
||||
// 已存在,更新描述信息(保留状态不变)
|
||||
if (!tool.description().equals(existing.getDescription())) {
|
||||
existing.setDescription(tool.description());
|
||||
mcpToolMapper.updateById(existing);
|
||||
log.debug("更新内置工具描述: {}", tool.name());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 新增
|
||||
McpTool newTool = new McpTool();
|
||||
newTool.setName(tool.name());
|
||||
newTool.setDescription(tool.description());
|
||||
newTool.setType(BuiltinToolRegistry.TYPE_BUILTIN);
|
||||
newTool.setStatus(McpToolStatus.ENABLED.getValue()); // 默认启用
|
||||
newTool.setConfigJson(null); // 内置工具不需要配置
|
||||
mcpToolMapper.insert(newTool);
|
||||
|
||||
log.info("新增内置工具: {} ({})", tool.name(), tool.displayName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.hzhub.constant;
|
||||
|
||||
public class FileTypeConstants {
|
||||
public static final String TXT = "txt";
|
||||
public static final String CSV = "csv";
|
||||
public static final String MD = "md";
|
||||
public static final String DOC = "doc";
|
||||
public static final String DOCX = "docx";
|
||||
public static final String PDF = "pdf";
|
||||
public static final String XLS = "xls";
|
||||
public static final String XLSX = "xlsx";
|
||||
|
||||
public static final String LOG = "log";
|
||||
public static final String XML = "xml";
|
||||
|
||||
public static final String JAVA = "java";
|
||||
public static final String HTML = "html";
|
||||
public static final String HTM = "htm";
|
||||
public static final String CSS = "css";
|
||||
public static final String JS = "js";
|
||||
public static final String PY = "py";
|
||||
public static final String CPP = "cpp";
|
||||
public static final String SQL = "sql";
|
||||
public static final String PHP = "php";
|
||||
public static final String RUBY = "ruby";
|
||||
public static final String C = "c";
|
||||
public static final String H = "h";
|
||||
public static final String HPP = "hpp";
|
||||
public static final String SWIFT = "swift";
|
||||
public static final String TS = "ts";
|
||||
public static final String RUST = "rs";
|
||||
public static final String PERL = "perl";
|
||||
public static final String SHELL = "shell";
|
||||
public static final String BAT = "bat";
|
||||
public static final String CMD = "cmd";
|
||||
|
||||
public static final String PROPERTIES = "properties";
|
||||
public static final String INI = "ini";
|
||||
public static final String YAML = "yaml";
|
||||
public static final String YML = "yml";
|
||||
|
||||
public static boolean isTextFile(String type) {
|
||||
if (type.equalsIgnoreCase(TXT) || type.equalsIgnoreCase(CSV) || type.equalsIgnoreCase(PROPERTIES)
|
||||
|| type.equalsIgnoreCase(INI) || type.equalsIgnoreCase(YAML) || type.equalsIgnoreCase(YML)
|
||||
|| type.equalsIgnoreCase(LOG) || type.equalsIgnoreCase(XML)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCodeFile(String type) {
|
||||
if (type.equalsIgnoreCase(JAVA) || type.equalsIgnoreCase(HTML) || type.equalsIgnoreCase(HTM) || type.equalsIgnoreCase(JS) || type.equalsIgnoreCase(PY)
|
||||
|| type.equalsIgnoreCase(CPP) || type.equalsIgnoreCase(SQL) || type.equalsIgnoreCase(PHP) || type.equalsIgnoreCase(RUBY)
|
||||
|| type.equalsIgnoreCase(C) || type.equalsIgnoreCase(H) || type.equalsIgnoreCase(HPP) || type.equalsIgnoreCase(SWIFT)
|
||||
|| type.equalsIgnoreCase(TS) || type.equalsIgnoreCase(RUST) || type.equalsIgnoreCase(PERL) || type.equalsIgnoreCase(SHELL)
|
||||
|| type.equalsIgnoreCase(BAT) || type.equalsIgnoreCase(CMD) || type.equalsIgnoreCase(CSS)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isMdFile(String type) {
|
||||
if (type.equalsIgnoreCase(MD)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWord(String type) {
|
||||
if (type.equalsIgnoreCase(DOC) || type.equalsIgnoreCase(DOCX)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPdf(String type) {
|
||||
if (type.equalsIgnoreCase(PDF)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isExcel(String type) {
|
||||
if (type.equalsIgnoreCase(XLS) || type.equalsIgnoreCase(XLSX)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.hzhub.controller.chat;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hzhub.common.chat.domain.dto.request.ChatRequest;
|
||||
import org.hzhub.service.chat.impl.ChatServiceFacade;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
|
||||
/**
|
||||
* 聊天管理
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* @date 2023-03-01
|
||||
*/
|
||||
@Controller
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/chat")
|
||||
public class ChatController {
|
||||
|
||||
private final ChatServiceFacade chatService;
|
||||
|
||||
/**
|
||||
* 聊天接口
|
||||
*/
|
||||
@PostMapping("/send")
|
||||
@ResponseBody
|
||||
public SseEmitter sseChat(@RequestBody @Valid ChatRequest chatRequest) {
|
||||
return chatService.sseChat(chatRequest);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.hzhub.controller.chat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.hzhub.common.chat.domain.bo.chat.ChatMessageBo;
|
||||
import org.hzhub.common.chat.domain.vo.chat.ChatMessageVo;
|
||||
import org.hzhub.service.chat.IChatMessageService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 聊天消息
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/message")
|
||||
public class ChatMessageController extends BaseController {
|
||||
|
||||
private final IChatMessageService chatMessageService;
|
||||
|
||||
/**
|
||||
* 查询聊天消息列表
|
||||
*/
|
||||
@SaCheckPermission("system:message:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ChatMessageVo> list(ChatMessageBo bo, PageQuery pageQuery) {
|
||||
return chatMessageService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出聊天消息列表
|
||||
*/
|
||||
@SaCheckPermission("system:message:export")
|
||||
@Log(title = "聊天消息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ChatMessageBo bo, HttpServletResponse response) {
|
||||
List<ChatMessageVo> list = chatMessageService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "聊天消息", ChatMessageVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聊天消息详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("system:message:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<ChatMessageVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(chatMessageService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增聊天消息
|
||||
*/
|
||||
@SaCheckPermission("system:message:add")
|
||||
@Log(title = "聊天消息", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ChatMessageBo bo) {
|
||||
return toAjax(chatMessageService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改聊天消息
|
||||
*/
|
||||
@SaCheckPermission("system:message:edit")
|
||||
@Log(title = "聊天消息", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ChatMessageBo bo) {
|
||||
return toAjax(chatMessageService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除聊天消息
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("system:message:remove")
|
||||
@Log(title = "聊天消息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(chatMessageService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.hzhub.controller.chat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.hzhub.common.chat.service.chat.IChatModelService;
|
||||
import org.hzhub.common.chat.domain.bo.chat.ChatModelBo;
|
||||
import org.hzhub.common.chat.domain.vo.chat.ChatModelVo;
|
||||
import org.hzhub.enums.ModelType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 模型管理
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/model")
|
||||
public class ChatModelController extends BaseController {
|
||||
|
||||
private final IChatModelService chatModelService;
|
||||
|
||||
/**
|
||||
* 查询模型管理列表
|
||||
*/
|
||||
@SaCheckPermission("system:model:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ChatModelVo> list(ChatModelBo bo, PageQuery pageQuery) {
|
||||
return chatModelService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户聊天模型列表
|
||||
*/
|
||||
@GetMapping("/modelList")
|
||||
public R<List<ChatModelVo>> modelList(ChatModelBo bo) {
|
||||
bo.setCategory(ModelType.CHAT.getKey());
|
||||
return R.ok(chatModelService.queryList(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出模型管理列表
|
||||
*/
|
||||
@SaCheckPermission("system:model:export")
|
||||
@Log(title = "模型管理", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ChatModelBo bo, HttpServletResponse response) {
|
||||
List<ChatModelVo> list = chatModelService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "模型管理", ChatModelVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型管理详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("system:model:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<ChatModelVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(chatModelService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增模型管理
|
||||
*/
|
||||
@SaCheckPermission("system:model:add")
|
||||
@Log(title = "模型管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ChatModelBo bo) {
|
||||
return toAjax(chatModelService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改模型管理
|
||||
*/
|
||||
@SaCheckPermission("system:model:edit")
|
||||
@Log(title = "模型管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ChatModelBo bo) {
|
||||
return toAjax(chatModelService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除模型管理
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("system:model:remove")
|
||||
@Log(title = "模型管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(chatModelService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.hzhub.controller.chat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.hzhub.service.chat.IChatProviderService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.domain.vo.chat.ChatProviderVo;
|
||||
import org.hzhub.domain.bo.chat.ChatProviderBo;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 厂商管理
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/provider")
|
||||
public class ChatProviderController extends BaseController {
|
||||
|
||||
private final IChatProviderService chatProviderService;
|
||||
|
||||
/**
|
||||
* 查询厂商管理列表
|
||||
*/
|
||||
@SaCheckPermission("system:provider:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ChatProviderVo> list(ChatProviderBo bo, PageQuery pageQuery) {
|
||||
return chatProviderService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出厂商管理列表
|
||||
*/
|
||||
@SaCheckPermission("system:provider:export")
|
||||
@Log(title = "厂商管理", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ChatProviderBo bo, HttpServletResponse response) {
|
||||
List<ChatProviderVo> list = chatProviderService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "厂商管理", ChatProviderVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取厂商管理详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("system:provider:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<ChatProviderVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(chatProviderService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增厂商管理
|
||||
*/
|
||||
@SaCheckPermission("system:provider:add")
|
||||
@Log(title = "厂商管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ChatProviderBo bo) {
|
||||
return toAjax(chatProviderService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改厂商管理
|
||||
*/
|
||||
@SaCheckPermission("system:provider:edit")
|
||||
@Log(title = "厂商管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ChatProviderBo bo) {
|
||||
return toAjax(chatProviderService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除厂商管理
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("system:provider:remove")
|
||||
@Log(title = "厂商管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(chatProviderService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.hzhub.controller.chat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.hzhub.common.satoken.utils.LoginHelper;
|
||||
import org.hzhub.service.chat.IChatSessionService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.domain.vo.chat.ChatSessionVo;
|
||||
import org.hzhub.domain.bo.chat.ChatSessionBo;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 会话管理
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-30
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/session")
|
||||
public class ChatSessionController extends BaseController {
|
||||
|
||||
private final IChatSessionService chatSessionService;
|
||||
|
||||
/**
|
||||
* 查询会话管理列表
|
||||
*/
|
||||
@SaCheckPermission("system:session:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ChatSessionVo> list(ChatSessionBo bo, PageQuery pageQuery) {
|
||||
if(!LoginHelper.isLogin()){
|
||||
// 如果用户没有登录,返回空会话列表
|
||||
return TableDataInfo.build();
|
||||
}
|
||||
// 默认查询当前用户会话
|
||||
bo.setUserId(LoginHelper.getUserId());
|
||||
return chatSessionService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出会话管理列表
|
||||
*/
|
||||
@SaCheckPermission("system:session:export")
|
||||
@Log(title = "会话管理", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ChatSessionBo bo, HttpServletResponse response) {
|
||||
List<ChatSessionVo> list = chatSessionService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "会话管理", ChatSessionVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话管理详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("system:session:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<ChatSessionVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(chatSessionService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增会话管理
|
||||
*/
|
||||
@SaCheckPermission("system:session:add")
|
||||
@Log(title = "会话管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Long> add(@Validated(AddGroup.class) @RequestBody ChatSessionBo bo) {
|
||||
bo.setUserId(LoginHelper.getUserId());
|
||||
chatSessionService.insertByBo(bo);
|
||||
// 返回会话id
|
||||
return R.ok(bo.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改会话管理
|
||||
*/
|
||||
@SaCheckPermission("system:session:edit")
|
||||
@Log(title = "会话管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ChatSessionBo bo) {
|
||||
return toAjax(chatSessionService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会话管理
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("system:session:remove")
|
||||
@Log(title = "会话管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(chatSessionService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.hzhub.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.hzhub.domain.bo.knowledge.KnowledgeAttachBo;
|
||||
import org.hzhub.domain.bo.knowledge.KnowledgeInfoUploadBo;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeAttachVo;
|
||||
import org.hzhub.service.knowledge.IKnowledgeAttachService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 知识库附件
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/attach")
|
||||
public class KnowledgeAttachController extends BaseController {
|
||||
|
||||
private final IKnowledgeAttachService knowledgeAttachService;
|
||||
|
||||
/**
|
||||
* 查询知识库附件列表
|
||||
*/
|
||||
@SaCheckPermission("system:attach:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<KnowledgeAttachVo> list(KnowledgeAttachBo bo, PageQuery pageQuery) {
|
||||
return knowledgeAttachService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出知识库附件列表
|
||||
*/
|
||||
@SaCheckPermission("system:attach:export")
|
||||
@Log(title = "知识库附件", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(KnowledgeAttachBo bo, HttpServletResponse response) {
|
||||
List<KnowledgeAttachVo> list = knowledgeAttachService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "知识库附件", KnowledgeAttachVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取知识库附件详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("system:attach:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<KnowledgeAttachVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(knowledgeAttachService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增知识库附件
|
||||
*/
|
||||
@SaCheckPermission("system:attach:add")
|
||||
@Log(title = "知识库附件", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody KnowledgeAttachBo bo) {
|
||||
return toAjax(knowledgeAttachService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改知识库附件
|
||||
*/
|
||||
@SaCheckPermission("system:attach:edit")
|
||||
@Log(title = "知识库附件", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody KnowledgeAttachBo bo) {
|
||||
return toAjax(knowledgeAttachService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库附件
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("system:attach:remove")
|
||||
@Log(title = "知识库附件", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(knowledgeAttachService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传知识库附件
|
||||
*/
|
||||
@PostMapping(value = "/upload")
|
||||
public R<String> upload(KnowledgeInfoUploadBo bo){
|
||||
knowledgeAttachService.upload(bo);
|
||||
return R.ok("上传知识库附件成功!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.hzhub.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.hzhub.domain.bo.knowledge.KnowledgeFragmentBo;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeFragmentVo;
|
||||
import org.hzhub.service.knowledge.IKnowledgeFragmentService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 知识片段
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/fragment")
|
||||
public class KnowledgeFragmentController extends BaseController {
|
||||
|
||||
private final IKnowledgeFragmentService knowledgeFragmentService;
|
||||
|
||||
/**
|
||||
* 查询知识片段列表
|
||||
*/
|
||||
@SaCheckPermission("system:fragment:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<KnowledgeFragmentVo> list(KnowledgeFragmentBo bo, PageQuery pageQuery) {
|
||||
return knowledgeFragmentService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出知识片段列表
|
||||
*/
|
||||
@SaCheckPermission("system:fragment:export")
|
||||
@Log(title = "知识片段", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(KnowledgeFragmentBo bo, HttpServletResponse response) {
|
||||
List<KnowledgeFragmentVo> list = knowledgeFragmentService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "知识片段", KnowledgeFragmentVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取知识片段详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("system:fragment:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<KnowledgeFragmentVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(knowledgeFragmentService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增知识片段
|
||||
*/
|
||||
@SaCheckPermission("system:fragment:add")
|
||||
@Log(title = "知识片段", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody KnowledgeFragmentBo bo) {
|
||||
return toAjax(knowledgeFragmentService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改知识片段
|
||||
*/
|
||||
@SaCheckPermission("system:fragment:edit")
|
||||
@Log(title = "知识片段", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody KnowledgeFragmentBo bo) {
|
||||
return toAjax(knowledgeFragmentService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识片段
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("system:fragment:remove")
|
||||
@Log(title = "知识片段", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(knowledgeFragmentService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.hzhub.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.hzhub.domain.bo.knowledge.KnowledgeGraphInstanceBo;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeGraphInstanceVo;
|
||||
import org.hzhub.service.knowledge.IKnowledgeGraphInstanceService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.hzhub.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.hzhub.domain.bo.knowledge.KnowledgeGraphSegmentBo;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeGraphSegmentVo;
|
||||
import org.hzhub.service.knowledge.IKnowledgeGraphSegmentService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.hzhub.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.hzhub.common.satoken.utils.LoginHelper;
|
||||
import org.hzhub.domain.bo.knowledge.KnowledgeInfoBo;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeInfoVo;
|
||||
import org.hzhub.service.knowledge.IKnowledgeInfoService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 知识库
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/info")
|
||||
public class KnowledgeInfoController extends BaseController {
|
||||
|
||||
private final IKnowledgeInfoService knowledgeInfoService;
|
||||
|
||||
/**
|
||||
* 查询知识库列表
|
||||
*/
|
||||
@SaCheckPermission("system:info:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<KnowledgeInfoVo> list(KnowledgeInfoBo bo, PageQuery pageQuery) {
|
||||
return knowledgeInfoService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出知识库列表
|
||||
*/
|
||||
@SaCheckPermission("system:info:export")
|
||||
@Log(title = "知识库", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(KnowledgeInfoBo bo, HttpServletResponse response) {
|
||||
List<KnowledgeInfoVo> list = knowledgeInfoService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "知识库", KnowledgeInfoVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取知识库详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("system:info:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<KnowledgeInfoVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(knowledgeInfoService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增知识库
|
||||
*/
|
||||
@SaCheckPermission("system:info:add")
|
||||
@Log(title = "知识库", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody KnowledgeInfoBo bo) {
|
||||
bo.setUserId(LoginHelper.getUserId());
|
||||
return toAjax(knowledgeInfoService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改知识库
|
||||
*/
|
||||
@SaCheckPermission("system:info:edit")
|
||||
@Log(title = "知识库", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody KnowledgeInfoBo bo) {
|
||||
return toAjax(knowledgeInfoService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除知识库
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("system:info:remove")
|
||||
@Log(title = "知识库", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(knowledgeInfoService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package org.hzhub.controller.mcp;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.domain.bo.mcp.McpMarketBo;
|
||||
import org.hzhub.domain.dto.mcp.McpMarketListResult;
|
||||
import org.hzhub.domain.dto.mcp.McpMarketRefreshResult;
|
||||
import org.hzhub.domain.dto.mcp.McpMarketToolListResult;
|
||||
import org.hzhub.domain.vo.mcp.McpMarketVo;
|
||||
import org.hzhub.service.mcp.IMcpMarketService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MCP 市场管理 Controller
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/mcp/market")
|
||||
public class McpMarketController extends BaseController {
|
||||
|
||||
private final IMcpMarketService mcpMarketService;
|
||||
|
||||
/**
|
||||
* 查询市场列表
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<McpMarketVo> list(McpMarketBo bo, PageQuery pageQuery) {
|
||||
return mcpMarketService.selectPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询市场列表(不分页)
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:list")
|
||||
@GetMapping("/all")
|
||||
public McpMarketListResult listAll(
|
||||
@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false) String status) {
|
||||
return mcpMarketService.listMarkets(keyword, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出 MCP 市场列表
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:export")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(McpMarketBo bo, HttpServletResponse response) {
|
||||
List<McpMarketVo> list = mcpMarketService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "MCP市场", McpMarketVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据市场ID获取详细信息
|
||||
*
|
||||
* @param id 市场ID
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<McpMarketVo> getInfo(@PathVariable Long id) {
|
||||
return R.ok(mcpMarketService.selectById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增市场
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:add")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody McpMarketBo bo) {
|
||||
mcpMarketService.insert(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改市场
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:edit")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody McpMarketBo bo) {
|
||||
mcpMarketService.update(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除市场
|
||||
*
|
||||
* @param ids 市场ID串
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:remove")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@PathVariable Long[] ids) {
|
||||
mcpMarketService.deleteByIds(List.of(ids));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新市场状态
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:edit")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{id}/status")
|
||||
public R<Void> updateStatus(@PathVariable Long id, @RequestParam String status) {
|
||||
mcpMarketService.updateStatus(id, status);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取市场工具列表(分页)
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:query")
|
||||
@GetMapping("/{marketId}/tools")
|
||||
public McpMarketToolListResult getMarketTools(
|
||||
@PathVariable Long marketId,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
return mcpMarketService.getMarketTools(marketId, page, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新市场工具列表
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:edit")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/{marketId}/refresh")
|
||||
public R<McpMarketRefreshResult> refreshMarketTools(@PathVariable Long marketId) {
|
||||
return R.ok(mcpMarketService.refreshMarketTools(marketId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载单个工具到本地
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:add")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/tools/{toolId}/load")
|
||||
public R<Void> loadToolToLocal(@PathVariable Long toolId) {
|
||||
mcpMarketService.loadToolToLocal(toolId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量加载工具到本地
|
||||
*/
|
||||
@SaCheckPermission("mcp:market:add")
|
||||
@Log(title = "MCP市场管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/tools/batch-load")
|
||||
public R<Map<String, Object>> batchLoadTools(@RequestBody List<Long> toolIds) {
|
||||
int successCount = mcpMarketService.batchLoadTools(toolIds);
|
||||
return R.ok(Map.of("successCount", successCount));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.hzhub.controller.mcp;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.hzhub.common.core.domain.R;
|
||||
import org.hzhub.common.excel.utils.ExcelUtil;
|
||||
import org.hzhub.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.hzhub.common.log.annotation.Log;
|
||||
import org.hzhub.common.log.enums.BusinessType;
|
||||
import org.hzhub.common.mybatis.core.page.PageQuery;
|
||||
import org.hzhub.common.mybatis.core.page.TableDataInfo;
|
||||
import org.hzhub.common.web.core.BaseController;
|
||||
import org.hzhub.domain.bo.mcp.McpToolBo;
|
||||
import org.hzhub.domain.dto.mcp.McpToolListResult;
|
||||
import org.hzhub.domain.dto.mcp.McpToolTestResult;
|
||||
import org.hzhub.domain.vo.mcp.McpToolVo;
|
||||
import org.hzhub.service.mcp.IMcpToolService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MCP 工具管理 Controller
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/mcp/tool")
|
||||
public class McpToolController extends BaseController {
|
||||
|
||||
private final IMcpToolService mcpToolService;
|
||||
|
||||
/**
|
||||
* 查询 MCP 工具列表
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<McpToolVo> list(McpToolBo bo, PageQuery pageQuery) {
|
||||
return mcpToolService.selectPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询 MCP 工具列表(不分页)
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:list")
|
||||
@GetMapping("/all")
|
||||
public McpToolListResult listAll(
|
||||
@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false) String type,
|
||||
@RequestParam(required = false) String status) {
|
||||
return mcpToolService.listTools(keyword, type, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出 MCP 工具列表
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:export")
|
||||
@Log(title = "MCP工具管理", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(McpToolBo bo, HttpServletResponse response) {
|
||||
List<McpToolVo> list = mcpToolService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "MCP工具", McpToolVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据工具ID获取详细信息
|
||||
*
|
||||
* @param id 工具ID
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<McpToolVo> getInfo(@PathVariable Long id) {
|
||||
return R.ok(mcpToolService.selectById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增 MCP 工具
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:add")
|
||||
@Log(title = "MCP工具管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody McpToolBo bo) {
|
||||
mcpToolService.insert(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改 MCP 工具
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:edit")
|
||||
@Log(title = "MCP工具管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody McpToolBo bo) {
|
||||
mcpToolService.update(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 MCP 工具
|
||||
*
|
||||
* @param ids 工具ID串
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:remove")
|
||||
@Log(title = "MCP工具管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@PathVariable Long[] ids) {
|
||||
mcpToolService.deleteByIds(List.of(ids));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新工具状态
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:edit")
|
||||
@Log(title = "MCP工具管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{id}/status")
|
||||
public R<Void> updateStatus(@PathVariable Long id, @RequestParam String status) {
|
||||
mcpToolService.updateStatus(id, status);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试工具连接
|
||||
*/
|
||||
@SaCheckPermission("mcp:tool:query")
|
||||
@PostMapping("/{id}/test")
|
||||
public R<McpToolTestResult> testTool(@PathVariable Long id) {
|
||||
return R.ok(mcpToolService.testTool(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.hzhub.domain.bo.chat;
|
||||
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.domain.entity.chat.ChatProvider;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 厂商管理业务对象 chat_provider
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = ChatProvider.class, reverseConvertGenerate = false)
|
||||
public class ChatProviderBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 厂商名称
|
||||
*/
|
||||
@NotBlank(message = "厂商名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String providerName;
|
||||
|
||||
/**
|
||||
* 厂商编码
|
||||
*/
|
||||
@NotBlank(message = "厂商编码不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String providerCode;
|
||||
|
||||
/**
|
||||
* 厂商图标
|
||||
*/
|
||||
private String providerIcon;
|
||||
|
||||
/**
|
||||
* 厂商描述
|
||||
*/
|
||||
private String providerDesc;
|
||||
|
||||
/**
|
||||
* API地址
|
||||
*/
|
||||
private String apiHost;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Long sortOrder;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 更新IP
|
||||
*/
|
||||
private String updateIp;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.hzhub.domain.bo.chat;
|
||||
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.domain.entity.chat.ChatSession;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 会话管理业务对象 chat_session
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-30
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = ChatSession.class, reverseConvertGenerate = false)
|
||||
public class ChatSessionBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 会话标题
|
||||
*/
|
||||
private String sessionTitle;
|
||||
|
||||
/**
|
||||
* 会话内容
|
||||
*/
|
||||
private String sessionContent;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 会话ID
|
||||
*/
|
||||
private String conversationId;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.hzhub.domain.bo.knowledge;
|
||||
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeAttach;
|
||||
|
||||
/**
|
||||
* 知识库附件业务对象 knowledge_attach
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = KnowledgeAttach.class, reverseConvertGenerate = false)
|
||||
public class KnowledgeAttachBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 知识库ID
|
||||
*/
|
||||
@NotBlank(message = "知识库ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long knowledgeId;
|
||||
|
||||
|
||||
/**
|
||||
* 文档ID-用于关联文本块信息
|
||||
*/
|
||||
private String docId;
|
||||
|
||||
/**
|
||||
* 附件名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 附件类型
|
||||
*/
|
||||
@NotBlank(message = "附件类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 对象存储ID
|
||||
*/
|
||||
private Long ossId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.hzhub.domain.bo.knowledge;
|
||||
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeFragment;
|
||||
|
||||
/**
|
||||
* 知识片段业务对象 knowledge_fragment
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = KnowledgeFragment.class, reverseConvertGenerate = false)
|
||||
public class KnowledgeFragmentBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 文档ID-用于关联文本块信息
|
||||
*/
|
||||
private String docId;
|
||||
|
||||
|
||||
/**
|
||||
* 片段索引下标
|
||||
*/
|
||||
@NotNull(message = "片段索引下标不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer idx;
|
||||
|
||||
/**
|
||||
* 文档内容
|
||||
*/
|
||||
@NotBlank(message = "文档内容不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package org.hzhub.domain.bo.knowledge;
|
||||
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeGraphInstance;
|
||||
|
||||
/**
|
||||
* 知识图谱实例业务对象 knowledge_graph_instance
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = KnowledgeGraphInstance.class, reverseConvertGenerate = false)
|
||||
public class KnowledgeGraphInstanceBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图谱UUID
|
||||
*/
|
||||
@NotBlank(message = "图谱UUID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String graphUuid;
|
||||
|
||||
/**
|
||||
* 关联knowledge_info.kid
|
||||
*/
|
||||
@NotBlank(message = "关联knowledge_info.kid不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String knowledgeId;
|
||||
|
||||
/**
|
||||
* 图谱名称
|
||||
*/
|
||||
@NotBlank(message = "图谱名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String graphName;
|
||||
|
||||
/**
|
||||
* 构建状态:10构建中、20已完成、30失败
|
||||
*/
|
||||
private Long graphStatus;
|
||||
|
||||
/**
|
||||
* 节点数量
|
||||
*/
|
||||
private Long nodeCount;
|
||||
|
||||
/**
|
||||
* 关系数量
|
||||
*/
|
||||
private Long relationshipCount;
|
||||
|
||||
/**
|
||||
* 图谱配置(JSON格式)
|
||||
*/
|
||||
private String config;
|
||||
|
||||
/**
|
||||
* LLM模型名称
|
||||
*/
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* 实体类型(逗号分隔)
|
||||
*/
|
||||
private String entityTypes;
|
||||
|
||||
/**
|
||||
* 关系类型(逗号分隔)
|
||||
*/
|
||||
private String relationTypes;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.hzhub.domain.bo.knowledge;
|
||||
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeGraphSegment;
|
||||
|
||||
/**
|
||||
* 知识图谱片段业务对象 knowledge_graph_segment
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = KnowledgeGraphSegment.class, reverseConvertGenerate = false)
|
||||
public class KnowledgeGraphSegmentBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 片段UUID
|
||||
*/
|
||||
@NotBlank(message = "片段UUID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String uuid;
|
||||
|
||||
/**
|
||||
* 知识库UUID
|
||||
*/
|
||||
@NotBlank(message = "知识库UUID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String kbUuid;
|
||||
|
||||
/**
|
||||
* 知识库条目UUID
|
||||
*/
|
||||
private String kbItemUuid;
|
||||
|
||||
/**
|
||||
* 文档UUID
|
||||
*/
|
||||
private String docUuid;
|
||||
|
||||
/**
|
||||
* 片段文本内容
|
||||
*/
|
||||
private String segmentText;
|
||||
|
||||
/**
|
||||
* 片段索引(第几个片段)
|
||||
*/
|
||||
private Long chunkIndex;
|
||||
|
||||
/**
|
||||
* 总片段数
|
||||
*/
|
||||
private Long totalChunks;
|
||||
|
||||
/**
|
||||
* 抽取状态:0-待处理 1-处理中 2-已完成 3-失败
|
||||
*/
|
||||
private Long extractionStatus;
|
||||
|
||||
/**
|
||||
* 抽取的实体数量
|
||||
*/
|
||||
private Long entityCount;
|
||||
|
||||
/**
|
||||
* 抽取的关系数量
|
||||
*/
|
||||
private Long relationCount;
|
||||
|
||||
/**
|
||||
* 消耗的token数
|
||||
*/
|
||||
private Long tokenUsed;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.hzhub.domain.bo.knowledge;
|
||||
|
||||
import org.hzhub.common.core.validate.AddGroup;
|
||||
import org.hzhub.common.core.validate.EditGroup;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeInfo;
|
||||
|
||||
/**
|
||||
* 知识库业务对象 knowledge_info
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = KnowledgeInfo.class, reverseConvertGenerate = false)
|
||||
public class KnowledgeInfoBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
@NotBlank(message = "知识库名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 是否公开知识库(0 否 1是)
|
||||
*/
|
||||
private Long share;
|
||||
|
||||
/**
|
||||
* 知识库描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 知识分隔符
|
||||
*/
|
||||
private String separator;
|
||||
|
||||
/**
|
||||
* 重叠字符数
|
||||
*/
|
||||
private Long overlapChar;
|
||||
|
||||
/**
|
||||
* 知识库中检索的条数
|
||||
*/
|
||||
private Long retrieveLimit;
|
||||
|
||||
/**
|
||||
* 文本块大小
|
||||
*/
|
||||
private Long textBlockSize;
|
||||
|
||||
/**
|
||||
* 向量库
|
||||
*/
|
||||
private String vectorModel;
|
||||
|
||||
/**
|
||||
* 向量模型
|
||||
*/
|
||||
private String embeddingModel;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.hzhub.domain.bo.knowledge;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 附件上传请求
|
||||
*/
|
||||
@Data
|
||||
public class KnowledgeInfoUploadBo {
|
||||
|
||||
private Long knowledgeId;
|
||||
|
||||
private MultipartFile file;
|
||||
|
||||
/**
|
||||
* 生效时间, 为空则立即生效
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date effectiveTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.hzhub.domain.bo.mcp;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import org.hzhub.domain.entity.mcp.McpMarket;
|
||||
|
||||
/**
|
||||
* MCP 市场业务对象
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = McpMarket.class, reverseConvertGenerate = false)
|
||||
public class McpMarketBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 市场ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 市场名称
|
||||
*/
|
||||
@NotBlank(message = "市场名称不能为空")
|
||||
@Size(min = 0, max = 200, message = "市场名称不能超过{max}个字符")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 市场 URL
|
||||
*/
|
||||
@NotBlank(message = "市场URL不能为空")
|
||||
@Size(min = 0, max = 500, message = "市场URL不能超过{max}个字符")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 市场描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 认证配置(JSON格式)
|
||||
*/
|
||||
private String authConfig;
|
||||
|
||||
/**
|
||||
* 状态:ENABLED-启用, DISABLED-禁用
|
||||
*/
|
||||
private String status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.hzhub.domain.bo.mcp;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
import org.hzhub.domain.entity.mcp.McpTool;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* MCP 工具业务对象
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = McpTool.class, reverseConvertGenerate = false)
|
||||
public class McpToolBo extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 工具ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 工具名称
|
||||
*/
|
||||
@NotBlank(message = "工具名称不能为空")
|
||||
@Size(min = 0, max = 200, message = "工具名称不能超过{max}个字符")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 工具描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 工具类型:LOCAL-本地, REMOTE-远程, BUILTIN-内置
|
||||
*/
|
||||
@NotBlank(message = "工具类型不能为空")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 状态:ENABLED-启用, DISABLED-禁用
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 配置信息(JSON格式)
|
||||
*/
|
||||
private String configJson;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.hzhub.domain.bo.vector;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 查询向量所需参数
|
||||
*
|
||||
* @author ageer
|
||||
*/
|
||||
@Data
|
||||
public class QueryVectorBo {
|
||||
|
||||
/**
|
||||
* 查询内容
|
||||
*/
|
||||
private String query;
|
||||
|
||||
/**
|
||||
* 知识库kid
|
||||
*/
|
||||
private String kid;
|
||||
|
||||
/**
|
||||
* 查询向量返回条数
|
||||
*/
|
||||
private Integer maxResults;
|
||||
|
||||
/**
|
||||
* 向量库模型名称
|
||||
*/
|
||||
private String vectorModelName;
|
||||
|
||||
/**
|
||||
* 向量化模型ID
|
||||
*/
|
||||
private Long embeddingModelId;
|
||||
|
||||
/**
|
||||
* 向量化模型ID
|
||||
*/
|
||||
private String embeddingModelName;
|
||||
|
||||
/**
|
||||
* 请求key
|
||||
*/
|
||||
private String apiKey;
|
||||
|
||||
/**
|
||||
* 请求地址
|
||||
*/
|
||||
private String baseUrl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.hzhub.domain.bo.vector;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 保存向量所需参数
|
||||
*
|
||||
* @author ageer
|
||||
*/
|
||||
@Data
|
||||
public class StoreEmbeddingBo {
|
||||
|
||||
/**
|
||||
* 切分文本块列表
|
||||
*/
|
||||
private List<String> chunkList;
|
||||
|
||||
/**
|
||||
* 知识库kid
|
||||
*/
|
||||
private String kid;
|
||||
|
||||
/**
|
||||
* 文档id
|
||||
*/
|
||||
private String docId;
|
||||
|
||||
/**
|
||||
* 知识块id列表
|
||||
*/
|
||||
private List<String> fids;
|
||||
|
||||
/**
|
||||
* 向量库名称
|
||||
*/
|
||||
private String vectorStoreName;
|
||||
|
||||
/**
|
||||
* 向量化模型id
|
||||
*/
|
||||
private Long embeddingModelId;
|
||||
|
||||
/**
|
||||
* 向量化模型名称
|
||||
*/
|
||||
private String embeddingModelName;
|
||||
|
||||
/**
|
||||
* 请求key
|
||||
*/
|
||||
private String apiKey;
|
||||
|
||||
/**
|
||||
* 请求地址
|
||||
*/
|
||||
private String baseUrl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.hzhub.domain.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 抽取的实体
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-09-30
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ExtractedEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 实体名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 实体类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 实体描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 置信度(0.0-1.0)
|
||||
*/
|
||||
private Double confidence;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.hzhub.domain.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 抽取的关系
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-09-30
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ExtractedRelation implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 源实体名称
|
||||
*/
|
||||
private String sourceEntity;
|
||||
|
||||
/**
|
||||
* 目标实体名称
|
||||
*/
|
||||
private String targetEntity;
|
||||
|
||||
/**
|
||||
* 关系描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 关系强度(0-10)
|
||||
*/
|
||||
private Integer strength;
|
||||
|
||||
/**
|
||||
* 置信度(0.0-1.0)
|
||||
*/
|
||||
private Double confidence;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.hzhub.domain.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 图谱抽取结果
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-09-30
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GraphExtractionResult implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 抽取的实体列表
|
||||
*/
|
||||
private List<ExtractedEntity> entities;
|
||||
|
||||
/**
|
||||
* 抽取的关系列表
|
||||
*/
|
||||
private List<ExtractedRelation> relations;
|
||||
|
||||
/**
|
||||
* 原始LLM响应
|
||||
*/
|
||||
private String rawResponse;
|
||||
|
||||
/**
|
||||
* 消耗的token数
|
||||
*/
|
||||
private Integer tokenUsed;
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private Boolean success;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.hzhub.domain.dto;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: Robust_H
|
||||
* @Date: 2025-09-30-下午2:13
|
||||
* @Description: 多模态输入
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class MultiModalInput {
|
||||
private String text;
|
||||
private byte[] imageData;
|
||||
private byte[] videoData;
|
||||
private String imageMimeType;
|
||||
private String videoMimeType;
|
||||
private String[] multiImageUrls;
|
||||
private String imageUrl;
|
||||
private String videoUrl;
|
||||
|
||||
/**
|
||||
* 检查是否有文本内容
|
||||
*/
|
||||
public boolean hasText() {
|
||||
return StrUtil.isNotBlank(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有图片内容
|
||||
*/
|
||||
public boolean hasImage() {
|
||||
return ArrayUtil.isNotEmpty(imageData) || StrUtil.isNotBlank(imageUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有视频内容
|
||||
*/
|
||||
public boolean hasVideo() {
|
||||
return ArrayUtil.isNotEmpty(videoData) || StrUtil.isNotBlank(videoUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有多图片
|
||||
*/
|
||||
public boolean hasMultiImages() {
|
||||
return ArrayUtil.isNotEmpty(multiImageUrls);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有任何内容
|
||||
*/
|
||||
public boolean hasAnyContent() {
|
||||
return hasText() || hasImage() || hasVideo() || hasMultiImages();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容的数量
|
||||
*/
|
||||
public int getContentCount() {
|
||||
int count = 0;
|
||||
if (hasText()) count++;
|
||||
if (hasImage()) count++;
|
||||
if (hasVideo()) count++;
|
||||
if (hasMultiImages()) count++;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.hzhub.domain.dto.mcp;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hzhub.domain.entity.mcp.McpMarket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MCP 市场列表返回结果
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class McpMarketListResult {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 市场列表
|
||||
*/
|
||||
private List<McpMarket> data;
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
private int total;
|
||||
|
||||
public static McpMarketListResult of(List<McpMarket> data) {
|
||||
return McpMarketListResult.builder()
|
||||
.success(true)
|
||||
.data(data)
|
||||
.total(data != null ? data.size() : 0)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.hzhub.domain.dto.mcp;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* MCP 市场工具刷新结果
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class McpMarketRefreshResult {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 新增工具数量
|
||||
*/
|
||||
private int addedCount;
|
||||
|
||||
/**
|
||||
* 更新工具数量
|
||||
*/
|
||||
private int updatedCount;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.hzhub.domain.dto.mcp;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hzhub.domain.entity.mcp.McpMarketTool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MCP 市场工具列表返回结果(分页)
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class McpMarketToolListResult {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 工具列表
|
||||
*/
|
||||
private List<McpMarketTool> data;
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
private long total;
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
private int page;
|
||||
|
||||
/**
|
||||
* 每页大小
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* 总页数
|
||||
*/
|
||||
private long pages;
|
||||
|
||||
public static McpMarketToolListResult of(List<McpMarketTool> data, long total, int page, int size) {
|
||||
long pages = (total + size - 1) / size;
|
||||
return McpMarketToolListResult.builder()
|
||||
.success(true)
|
||||
.data(data)
|
||||
.total(total)
|
||||
.page(page)
|
||||
.size(size)
|
||||
.pages(pages)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.hzhub.domain.dto.mcp;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hzhub.domain.entity.mcp.McpTool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MCP 工具列表返回结果
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class McpToolListResult {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 工具列表
|
||||
*/
|
||||
private List<McpTool> data;
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
private int total;
|
||||
|
||||
public static McpToolListResult of(List<McpTool> data) {
|
||||
return McpToolListResult.builder()
|
||||
.success(true)
|
||||
.data(data)
|
||||
.total(data != null ? data.size() : 0)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.hzhub.domain.dto.mcp;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MCP 工具测试结果
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class McpToolTestResult {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 发现的工具数量
|
||||
*/
|
||||
private Integer toolCount;
|
||||
|
||||
/**
|
||||
* 工具名称列表
|
||||
*/
|
||||
private List<String> tools;
|
||||
|
||||
public static McpToolTestResult success(String message, int toolCount, List<String> tools) {
|
||||
return McpToolTestResult.builder()
|
||||
.success(true)
|
||||
.message(message)
|
||||
.toolCount(toolCount)
|
||||
.tools(tools)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpToolTestResult fail(String message) {
|
||||
return McpToolTestResult.builder()
|
||||
.success(false)
|
||||
.message(message)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.hzhub.domain.dto.request;
|
||||
|
||||
import lombok.Data;
|
||||
import org.hzhub.common.json.utils.JsonUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: Robust_H
|
||||
* @Date: 2025-10-1-上午10:00
|
||||
* @Description: 阿里云多模态嵌入请求
|
||||
*/
|
||||
@Data
|
||||
public class AliyunMultiModalEmbedRequest {
|
||||
private String model;
|
||||
private Input input;
|
||||
|
||||
/**
|
||||
* 创建请求对象
|
||||
*/
|
||||
public static AliyunMultiModalEmbedRequest create(String modelName, List<Map<String, Object>> contents) {
|
||||
AliyunMultiModalEmbedRequest request = new AliyunMultiModalEmbedRequest();
|
||||
request.setModel(modelName);
|
||||
Input input = new Input(contents);
|
||||
request.setInput(input);
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为JSON字符串
|
||||
*/
|
||||
public String toJson() {
|
||||
return JsonUtils.toJsonString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示输入数据的记录类(Record)
|
||||
* 该类用于封装一个包含多个映射关系列表的输入数据结构
|
||||
*
|
||||
* @param contents 包含多个Map的列表,每个Map中存储String类型的键和Object类型的值
|
||||
*/
|
||||
public record Input(List<Map<String, Object>> contents) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.hzhub.domain.dto.response;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 阿里云多模态嵌入 API 响应数据模型
|
||||
*/
|
||||
public record AliyunMultiModalEmbedResponse(
|
||||
Output output, // 输出结果对象
|
||||
String request_id, // 请求唯一标识
|
||||
String code, // 错误码
|
||||
String message, // 错误消息
|
||||
Usage usage // 用量信息
|
||||
) {
|
||||
|
||||
/**
|
||||
* 输出对象,包含嵌入向量结果
|
||||
*/
|
||||
public record Output(
|
||||
List<EmbeddingItem> embeddings // 嵌入向量列表
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个嵌入向量条目
|
||||
*/
|
||||
public record EmbeddingItem(
|
||||
int index, // 输入内容的索引
|
||||
List<Double> embedding, // 生成的 1024 维向量
|
||||
String type // 输入的类型 (text/image/video/multi_images)
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 用量统计信息
|
||||
*/
|
||||
public record Usage(
|
||||
int input_tokens, // 本次请求输入的 Token 数量
|
||||
int image_tokens, // 本次请求输入的图像 Token 数量
|
||||
int image_count, // 本次请求输入的图像数量
|
||||
int duration // 本次请求输入的视频时长(秒)
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package org.hzhub.domain.entity.chat;
|
||||
|
||||
import org.hzhub.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 厂商管理对象 chat_provider
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("chat_provider")
|
||||
public class ChatProvider extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 厂商名称
|
||||
*/
|
||||
private String providerName;
|
||||
|
||||
/**
|
||||
* 厂商编码
|
||||
*/
|
||||
private String providerCode;
|
||||
|
||||
/**
|
||||
* 厂商图标
|
||||
*/
|
||||
private String providerIcon;
|
||||
|
||||
/**
|
||||
* 厂商描述
|
||||
*/
|
||||
private String providerDesc;
|
||||
|
||||
/**
|
||||
* API地址
|
||||
*/
|
||||
private String apiHost;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Long sortOrder;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
@Version
|
||||
private Long version;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 更新IP
|
||||
*/
|
||||
private String updateIp;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.hzhub.domain.entity.chat;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 会话管理对象 chat_session
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-30
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("chat_session")
|
||||
public class ChatSession extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 会话标题
|
||||
*/
|
||||
private String sessionTitle;
|
||||
|
||||
/**
|
||||
* 会话内容
|
||||
*/
|
||||
private String sessionContent;
|
||||
|
||||
/**
|
||||
* 会话ID
|
||||
*/
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.hzhub.domain.entity.knowledge;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 知识库附件对象 knowledge_attach
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("knowledge_attach")
|
||||
public class KnowledgeAttach extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 知识库ID
|
||||
*/
|
||||
private Long knowledgeId;
|
||||
|
||||
/**
|
||||
* 文档ID-用于关联文本块信息
|
||||
*/
|
||||
private String docId;
|
||||
|
||||
/**
|
||||
* 附件名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 附件类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 对象存储ID
|
||||
*/
|
||||
private Long ossId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.hzhub.domain.entity.knowledge;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 知识片段对象 knowledge_fragment
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("knowledge_fragment")
|
||||
public class KnowledgeFragment extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 文档ID-用于关联文本块信息
|
||||
*/
|
||||
private String docId;
|
||||
|
||||
/**
|
||||
* 片段索引下标
|
||||
*/
|
||||
private Integer idx;
|
||||
|
||||
/**
|
||||
* 文档内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.hzhub.domain.entity.knowledge;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 知识图谱实例对象 knowledge_graph_instance
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("knowledge_graph_instance")
|
||||
public class KnowledgeGraphInstance extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图谱UUID
|
||||
*/
|
||||
private String graphUuid;
|
||||
|
||||
/**
|
||||
* 关联knowledge_info.kid
|
||||
*/
|
||||
private String knowledgeId;
|
||||
|
||||
/**
|
||||
* 图谱名称
|
||||
*/
|
||||
private String graphName;
|
||||
|
||||
/**
|
||||
* 构建状态:10构建中、20已完成、30失败
|
||||
*/
|
||||
private Long graphStatus;
|
||||
|
||||
/**
|
||||
* 节点数量
|
||||
*/
|
||||
private Long nodeCount;
|
||||
|
||||
/**
|
||||
* 关系数量
|
||||
*/
|
||||
private Long relationshipCount;
|
||||
|
||||
/**
|
||||
* 图谱配置(JSON格式)
|
||||
*/
|
||||
private String config;
|
||||
|
||||
/**
|
||||
* LLM模型名称
|
||||
*/
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* 实体类型(逗号分隔)
|
||||
*/
|
||||
private String entityTypes;
|
||||
|
||||
/**
|
||||
* 关系类型(逗号分隔)
|
||||
*/
|
||||
private String relationTypes;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package org.hzhub.domain.entity.knowledge;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 知识图谱片段对象 knowledge_graph_segment
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("knowledge_graph_segment")
|
||||
public class KnowledgeGraphSegment extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 片段UUID
|
||||
*/
|
||||
private String uuid;
|
||||
|
||||
/**
|
||||
* 知识库UUID
|
||||
*/
|
||||
private String kbUuid;
|
||||
|
||||
/**
|
||||
* 知识库条目UUID
|
||||
*/
|
||||
private String kbItemUuid;
|
||||
|
||||
/**
|
||||
* 文档UUID
|
||||
*/
|
||||
private String docUuid;
|
||||
|
||||
/**
|
||||
* 片段文本内容
|
||||
*/
|
||||
private String segmentText;
|
||||
|
||||
/**
|
||||
* 片段索引(第几个片段)
|
||||
*/
|
||||
private Long chunkIndex;
|
||||
|
||||
/**
|
||||
* 总片段数
|
||||
*/
|
||||
private Long totalChunks;
|
||||
|
||||
/**
|
||||
* 抽取状态:0-待处理 1-处理中 2-已完成 3-失败
|
||||
*/
|
||||
private Long extractionStatus;
|
||||
|
||||
/**
|
||||
* 抽取的实体数量
|
||||
*/
|
||||
private Long entityCount;
|
||||
|
||||
/**
|
||||
* 抽取的关系数量
|
||||
*/
|
||||
private Long relationCount;
|
||||
|
||||
/**
|
||||
* 消耗的token数
|
||||
*/
|
||||
private Long tokenUsed;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.hzhub.domain.entity.knowledge;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 知识库对象 knowledge_info
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("knowledge_info")
|
||||
public class KnowledgeInfo extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 是否公开知识库(0 否 1是)
|
||||
*/
|
||||
private Long share;
|
||||
|
||||
/**
|
||||
* 知识库描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 知识分隔符
|
||||
*/
|
||||
@TableField(value = "`separator`")
|
||||
private String separator;
|
||||
|
||||
/**
|
||||
* 重叠字符数
|
||||
*/
|
||||
private Long overlapChar;
|
||||
|
||||
/**
|
||||
* 知识库中检索的条数
|
||||
*/
|
||||
private Long retrieveLimit;
|
||||
|
||||
/**
|
||||
* 文本块大小
|
||||
*/
|
||||
private Long textBlockSize;
|
||||
|
||||
/**
|
||||
* 向量库
|
||||
*/
|
||||
private String vectorModel;
|
||||
|
||||
/**
|
||||
* 向量模型
|
||||
*/
|
||||
private String embeddingModel;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.hzhub.domain.entity.mcp;
|
||||
|
||||
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.hzhub.common.tenant.core.TenantEntity;
|
||||
|
||||
/**
|
||||
* MCP 市场信息实体
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("mcp_market_info")
|
||||
public class McpMarket extends TenantEntity {
|
||||
|
||||
/**
|
||||
* 市场ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 市场名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 市场 URL
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 市场描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 认证配置(JSON格式)
|
||||
*/
|
||||
private String authConfig;
|
||||
|
||||
/**
|
||||
* 状态:ENABLED-启用, DISABLED-禁用
|
||||
*/
|
||||
private String status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.hzhub.domain.entity.mcp;
|
||||
|
||||
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.hzhub.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* MCP 市场工具关联实体
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("mcp_market_tool")
|
||||
public class McpMarketTool extends BaseEntity {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 市场 ID
|
||||
*/
|
||||
private Long marketId;
|
||||
|
||||
/**
|
||||
* 工具名称
|
||||
*/
|
||||
private String toolName;
|
||||
|
||||
/**
|
||||
* 工具描述
|
||||
*/
|
||||
private String toolDescription;
|
||||
|
||||
/**
|
||||
* 工具版本
|
||||
*/
|
||||
private String toolVersion;
|
||||
|
||||
/**
|
||||
* 工具元数据(JSON格式)
|
||||
*/
|
||||
private String toolMetadata;
|
||||
|
||||
/**
|
||||
* 是否已加载到本地
|
||||
*/
|
||||
private Boolean isLoaded;
|
||||
|
||||
/**
|
||||
* 关联的本地工具 ID
|
||||
*/
|
||||
private Long localToolId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.hzhub.domain.entity.mcp;
|
||||
|
||||
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.hzhub.common.tenant.core.TenantEntity;
|
||||
|
||||
|
||||
/**
|
||||
* MCP 工具信息实体
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("mcp_tool_info")
|
||||
public class McpTool extends TenantEntity {
|
||||
|
||||
/**
|
||||
* 工具ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 工具名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 工具描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 工具类型:LOCAL-本地, REMOTE-远程, BUILTIN-内置
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 状态:ENABLED-启用, DISABLED-禁用
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 配置信息(JSON格式)
|
||||
* LOCAL: {"command": "npx", "args": ["-y", "@example/mcp-server"], "env": {...}}
|
||||
* REMOTE: {"baseUrl": "http://localhost:8080/mcp"}
|
||||
* BUILTIN: null
|
||||
*/
|
||||
private String configJson;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.hzhub.domain.vo.chat;
|
||||
|
||||
import org.hzhub.domain.entity.chat.ChatProvider;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.hzhub.common.excel.annotation.ExcelDictFormat;
|
||||
import org.hzhub.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 厂商管理视图对象 chat_provider
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = ChatProvider.class)
|
||||
public class ChatProviderVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 厂商名称
|
||||
*/
|
||||
@ExcelProperty(value = "厂商名称")
|
||||
private String providerName;
|
||||
|
||||
/**
|
||||
* 厂商编码
|
||||
*/
|
||||
@ExcelProperty(value = "厂商编码")
|
||||
private String providerCode;
|
||||
|
||||
/**
|
||||
* 厂商图标
|
||||
*/
|
||||
@ExcelProperty(value = "厂商图标")
|
||||
private String providerIcon;
|
||||
|
||||
/**
|
||||
* 厂商描述
|
||||
*/
|
||||
@ExcelProperty(value = "厂商描述")
|
||||
private String providerDesc;
|
||||
|
||||
/**
|
||||
* API地址
|
||||
*/
|
||||
@ExcelProperty(value = "API地址")
|
||||
private String apiHost;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=正常,1=停用")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
@ExcelProperty(value = "排序")
|
||||
private Long sortOrder;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 更新IP
|
||||
*/
|
||||
@ExcelProperty(value = "更新IP")
|
||||
private String updateIp;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.hzhub.domain.vo.chat;
|
||||
|
||||
import org.hzhub.domain.entity.chat.ChatSession;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* 会话管理视图对象 chat_session
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-30
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = ChatSession.class)
|
||||
public class ChatSessionVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
@ExcelProperty(value = "用户id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 会话标题
|
||||
*/
|
||||
@ExcelProperty(value = "会话标题")
|
||||
private String sessionTitle;
|
||||
|
||||
/**
|
||||
* 会话内容
|
||||
*/
|
||||
@ExcelProperty(value = "会话内容")
|
||||
private String sessionContent;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 会话ID
|
||||
*/
|
||||
@ExcelProperty(value = "会话ID")
|
||||
private String conversationId;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.hzhub.domain.vo.knowledge;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeAttach;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 知识库附件视图对象 knowledge_attach
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = KnowledgeAttach.class)
|
||||
public class KnowledgeAttachVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 知识库ID
|
||||
*/
|
||||
@ExcelProperty(value = "知识库ID")
|
||||
private Long knowledgeId;
|
||||
|
||||
/**
|
||||
* 文档ID-用于关联文本块信息
|
||||
*/
|
||||
@ExcelProperty(value = "文档ID")
|
||||
private String docId;
|
||||
|
||||
/**
|
||||
* 附件名称
|
||||
*/
|
||||
@ExcelProperty(value = "附件名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 附件类型
|
||||
*/
|
||||
@ExcelProperty(value = "附件类型")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 对象存储ID
|
||||
*/
|
||||
@ExcelProperty(value = "对象存储ID")
|
||||
private Long ossId;
|
||||
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.hzhub.domain.vo.knowledge;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeFragment;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* 知识片段视图对象 knowledge_fragment
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = KnowledgeFragment.class)
|
||||
public class KnowledgeFragmentVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 文档ID-用于关联文本块信息
|
||||
*/
|
||||
private String docId;
|
||||
|
||||
/**
|
||||
* 片段索引下标
|
||||
*/
|
||||
@ExcelProperty(value = "片段索引下标")
|
||||
private Long idx;
|
||||
|
||||
/**
|
||||
* 文档内容
|
||||
*/
|
||||
@ExcelProperty(value = "文档内容")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.hzhub.domain.vo.knowledge;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.hzhub.common.excel.annotation.ExcelDictFormat;
|
||||
import org.hzhub.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeGraphInstance;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 知识图谱实例视图对象 knowledge_graph_instance
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = KnowledgeGraphInstance.class)
|
||||
public class KnowledgeGraphInstanceVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图谱UUID
|
||||
*/
|
||||
@ExcelProperty(value = "图谱UUID")
|
||||
private String graphUuid;
|
||||
|
||||
/**
|
||||
* 关联knowledge_info.kid
|
||||
*/
|
||||
@ExcelProperty(value = "关联knowledge_info.kid")
|
||||
private String knowledgeId;
|
||||
|
||||
/**
|
||||
* 图谱名称
|
||||
*/
|
||||
@ExcelProperty(value = "图谱名称")
|
||||
private String graphName;
|
||||
|
||||
/**
|
||||
* 构建状态:10构建中、20已完成、30失败
|
||||
*/
|
||||
@ExcelProperty(value = "构建状态:10构建中、20已完成、30失败")
|
||||
private Long graphStatus;
|
||||
|
||||
/**
|
||||
* 节点数量
|
||||
*/
|
||||
@ExcelProperty(value = "节点数量")
|
||||
private Long nodeCount;
|
||||
|
||||
/**
|
||||
* 关系数量
|
||||
*/
|
||||
@ExcelProperty(value = "关系数量")
|
||||
private Long relationshipCount;
|
||||
|
||||
/**
|
||||
* 图谱配置(JSON格式)
|
||||
*/
|
||||
@ExcelProperty(value = "图谱配置(JSON格式)")
|
||||
private String config;
|
||||
|
||||
/**
|
||||
* LLM模型名称
|
||||
*/
|
||||
@ExcelProperty(value = "LLM模型名称")
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* 实体类型(逗号分隔)
|
||||
*/
|
||||
@ExcelProperty(value = "实体类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "逗=号分隔")
|
||||
private String entityTypes;
|
||||
|
||||
/**
|
||||
* 关系类型(逗号分隔)
|
||||
*/
|
||||
@ExcelProperty(value = "关系类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "逗=号分隔")
|
||||
private String relationTypes;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
@ExcelProperty(value = "错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package org.hzhub.domain.vo.knowledge;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.hzhub.common.excel.annotation.ExcelDictFormat;
|
||||
import org.hzhub.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeGraphSegment;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 知识图谱片段视图对象 knowledge_graph_segment
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = KnowledgeGraphSegment.class)
|
||||
public class KnowledgeGraphSegmentVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 片段UUID
|
||||
*/
|
||||
@ExcelProperty(value = "片段UUID")
|
||||
private String uuid;
|
||||
|
||||
/**
|
||||
* 知识库UUID
|
||||
*/
|
||||
@ExcelProperty(value = "知识库UUID")
|
||||
private String kbUuid;
|
||||
|
||||
/**
|
||||
* 知识库条目UUID
|
||||
*/
|
||||
@ExcelProperty(value = "知识库条目UUID")
|
||||
private String kbItemUuid;
|
||||
|
||||
/**
|
||||
* 文档UUID
|
||||
*/
|
||||
@ExcelProperty(value = "文档UUID")
|
||||
private String docUuid;
|
||||
|
||||
/**
|
||||
* 片段文本内容
|
||||
*/
|
||||
@ExcelProperty(value = "片段文本内容")
|
||||
private String segmentText;
|
||||
|
||||
/**
|
||||
* 片段索引(第几个片段)
|
||||
*/
|
||||
@ExcelProperty(value = "片段索引", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "第=几个片段")
|
||||
private Long chunkIndex;
|
||||
|
||||
/**
|
||||
* 总片段数
|
||||
*/
|
||||
@ExcelProperty(value = "总片段数")
|
||||
private Long totalChunks;
|
||||
|
||||
/**
|
||||
* 抽取状态:0-待处理 1-处理中 2-已完成 3-失败
|
||||
*/
|
||||
@ExcelProperty(value = "抽取状态:0-待处理 1-处理中 2-已完成 3-失败")
|
||||
private Long extractionStatus;
|
||||
|
||||
/**
|
||||
* 抽取的实体数量
|
||||
*/
|
||||
@ExcelProperty(value = "抽取的实体数量")
|
||||
private Long entityCount;
|
||||
|
||||
/**
|
||||
* 抽取的关系数量
|
||||
*/
|
||||
@ExcelProperty(value = "抽取的关系数量")
|
||||
private Long relationCount;
|
||||
|
||||
/**
|
||||
* 消耗的token数
|
||||
*/
|
||||
@ExcelProperty(value = "消耗的token数")
|
||||
private Long tokenUsed;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
@ExcelProperty(value = "错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package org.hzhub.domain.vo.knowledge;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.hzhub.common.excel.annotation.ExcelDictFormat;
|
||||
import org.hzhub.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeInfo;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 知识库视图对象 knowledge_info
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = KnowledgeInfo.class)
|
||||
public class KnowledgeInfoVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
@ExcelProperty(value = "知识库名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 是否公开知识库(0 否 1是)
|
||||
*/
|
||||
@ExcelProperty(value = "是否公开知识库", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=,否=,1=是")
|
||||
private Long share;
|
||||
|
||||
/**
|
||||
* 知识库描述
|
||||
*/
|
||||
@ExcelProperty(value = "知识库描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 知识分隔符
|
||||
*/
|
||||
@ExcelProperty(value = "知识分隔符")
|
||||
private String separator;
|
||||
|
||||
/**
|
||||
* 重叠字符数
|
||||
*/
|
||||
@ExcelProperty(value = "重叠字符数")
|
||||
private Long overlapChar;
|
||||
|
||||
/**
|
||||
* 知识库中检索的条数
|
||||
*/
|
||||
@ExcelProperty(value = "知识库中检索的条数")
|
||||
private Integer retrieveLimit;
|
||||
|
||||
/**
|
||||
* 文本块大小
|
||||
*/
|
||||
@ExcelProperty(value = "文本块大小")
|
||||
private Long textBlockSize;
|
||||
|
||||
/**
|
||||
* 向量库
|
||||
*/
|
||||
@ExcelProperty(value = "向量库")
|
||||
private String vectorModel;
|
||||
|
||||
/**
|
||||
* 向量模型
|
||||
*/
|
||||
@ExcelProperty(value = "向量模型")
|
||||
private String embeddingModel;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package org.hzhub.domain.vo.mcp;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.hzhub.domain.entity.mcp.McpMarket;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* MCP 市场视图对象
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = McpMarket.class)
|
||||
public class McpMarketVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 市场ID
|
||||
*/
|
||||
@ExcelProperty(value = "市场ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 市场名称
|
||||
*/
|
||||
@ExcelProperty(value = "市场名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 市场 URL
|
||||
*/
|
||||
@ExcelProperty(value = "市场URL")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 市场描述
|
||||
*/
|
||||
@ExcelProperty(value = "市场描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 认证配置
|
||||
*/
|
||||
@ExcelProperty(value = "认证配置")
|
||||
private String authConfig;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@ExcelProperty(value = "状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.hzhub.domain.vo.mcp;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.hzhub.domain.entity.mcp.McpTool;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* MCP 工具视图对象
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = McpTool.class)
|
||||
public class McpToolVo implements Serializable {
|
||||
|
||||
/**
|
||||
* 工具ID
|
||||
*/
|
||||
@ExcelProperty(value = "工具ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 工具名称
|
||||
*/
|
||||
@ExcelProperty(value = "工具名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 工具描述
|
||||
*/
|
||||
@ExcelProperty(value = "工具描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 工具类型
|
||||
*/
|
||||
@ExcelProperty(value = "工具类型")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@ExcelProperty(value = "状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
*/
|
||||
@ExcelProperty(value = "配置信息")
|
||||
private String configJson;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 计费类型枚举
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BillingType {
|
||||
|
||||
TOKEN("1", "token计费"),
|
||||
COUNT("2", "次数计费"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 模型分类
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Getter
|
||||
public enum ChatModeType {
|
||||
OLLAMA("ollama", "ollama本地部署模型"),
|
||||
ZHI_PU("zhipu", "智谱清言"),
|
||||
DEEP_SEEK("deepseek", "深度求索"),
|
||||
QIAN_WEN("qianwen", "通义千问"),
|
||||
OPEN_AI("openai", "openai"),
|
||||
PPIO("ppio", "ppio");
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
ChatModeType(String code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 是否显示
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
@Getter
|
||||
public enum DisplayType {
|
||||
HIDDEN("1", "不显示"),
|
||||
VISIBLE("0", "显示");
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
DisplayType(String code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 文生图模型分类
|
||||
*
|
||||
* @author Zengxb
|
||||
* @date 2026-02-14
|
||||
*/
|
||||
@Getter
|
||||
public enum ImageModeType {
|
||||
|
||||
TONGYI_WANX("Tongyiwanx", "万相");
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
ImageModeType(String code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* MCP 工具状态枚举
|
||||
*
|
||||
* @author ruoyi team
|
||||
*/
|
||||
@Getter
|
||||
public enum McpToolStatus {
|
||||
|
||||
/**
|
||||
* 启用状态
|
||||
*/
|
||||
ENABLED("ENABLED", "启用"),
|
||||
|
||||
/**
|
||||
* 禁用状态
|
||||
*/
|
||||
DISABLED("DISABLED", "禁用");
|
||||
|
||||
/**
|
||||
* 状态值(存储到数据库)
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 状态描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
McpToolStatus(String value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为启用状态
|
||||
*
|
||||
* @param value 状态值
|
||||
* @return 是否启用
|
||||
*/
|
||||
public static boolean isEnabled(String value) {
|
||||
return ENABLED.value.equals(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
/**
|
||||
* 模态类型
|
||||
*/
|
||||
public enum ModalityType {
|
||||
TEXT, IMAGE, AUDIO, VIDEO, MULTI
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 模型分类枚举
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* @date 2025-12-30
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ModelType {
|
||||
|
||||
/**
|
||||
* 聊天模型
|
||||
*/
|
||||
CHAT(0, "chat", "聊天模型"),
|
||||
|
||||
/**
|
||||
* 图片识别模型
|
||||
*/
|
||||
IMAGE(1, "image", "图片识别模型"),
|
||||
|
||||
/**
|
||||
* 知识库向量模型
|
||||
*/
|
||||
VECTOR(3, "vector", "知识库向量模型"),
|
||||
|
||||
/**
|
||||
* 知识库内容重新排序模型
|
||||
*/
|
||||
RERANKER(4, "reranker", "知识库内容重新排序模型"),
|
||||
|
||||
/**
|
||||
* 语音生成模型
|
||||
*/
|
||||
AUDIO(5, "audio", "语音生成模型"),
|
||||
|
||||
/**
|
||||
* 语音转文本模型
|
||||
*/
|
||||
TEXT(6, "text", "语音转文本模型"),
|
||||
|
||||
/**
|
||||
* 文生视频模型
|
||||
*/
|
||||
VIDEO(7, "video", "文生视频模型"),
|
||||
|
||||
/**
|
||||
* 文生PPT模型
|
||||
*/
|
||||
PPT(8, "ppt", "文生PPT模型"),
|
||||
|
||||
/**
|
||||
* 文生音乐模型
|
||||
*/
|
||||
MUSIC(9, "music", "文生音乐模型"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final Integer code;
|
||||
|
||||
/**
|
||||
* 标识
|
||||
*/
|
||||
private final String key;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 构建任务状态枚举
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-09-30
|
||||
*/
|
||||
@Getter
|
||||
public enum TaskStatusEnum {
|
||||
|
||||
/**
|
||||
* 待执行
|
||||
*/
|
||||
PENDING(1, "待执行"),
|
||||
|
||||
/**
|
||||
* 执行中
|
||||
*/
|
||||
RUNNING(2, "执行中"),
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
SUCCESS(3, "成功"),
|
||||
|
||||
/**
|
||||
* 失败
|
||||
*/
|
||||
FAILED(4, "失败");
|
||||
|
||||
private final Integer code;
|
||||
private final String description;
|
||||
|
||||
TaskStatusEnum(Integer code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据code获取枚举
|
||||
*/
|
||||
public static TaskStatusEnum getByCode(Integer code) {
|
||||
for (TaskStatusEnum status : values()) {
|
||||
if (status.getCode().equals(code)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.hzhub.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 构建任务类型枚举
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-09-30
|
||||
*/
|
||||
@Getter
|
||||
public enum TaskTypeEnum {
|
||||
|
||||
/**
|
||||
* 全量构建
|
||||
*/
|
||||
FULL_BUILD(1, "全量构建"),
|
||||
|
||||
/**
|
||||
* 增量更新
|
||||
*/
|
||||
INCREMENTAL_UPDATE(2, "增量更新"),
|
||||
|
||||
/**
|
||||
* 重建
|
||||
*/
|
||||
REBUILD(3, "重建");
|
||||
|
||||
private final Integer code;
|
||||
private final String description;
|
||||
|
||||
TaskTypeEnum(Integer code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据code获取枚举
|
||||
*/
|
||||
public static TaskTypeEnum getByCode(Integer code) {
|
||||
for (TaskTypeEnum type : values()) {
|
||||
if (type.getCode().equals(code)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.hzhub.factory;
|
||||
|
||||
import org.hzhub.common.chat.service.chat.IChatService;
|
||||
import org.hzhub.service.chat.AbstractChatService;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 聊天服务工厂类
|
||||
*
|
||||
* @author ageerle@163.com
|
||||
* @date 2025-12-13
|
||||
*/
|
||||
@Component
|
||||
public class ChatServiceFactory implements ApplicationContextAware {
|
||||
|
||||
private final Map<String, AbstractChatService> chatServiceMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
// 初始化时收集所有IChatService的实现
|
||||
Map<String, AbstractChatService> serviceMap = applicationContext.getBeansOfType(AbstractChatService.class);
|
||||
for (AbstractChatService service : serviceMap.values()) {
|
||||
if (service != null ) {
|
||||
chatServiceMap.put(service.getProviderName(), service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取原始服务(不包装代理)
|
||||
*/
|
||||
public AbstractChatService getOriginalService(String category) {
|
||||
AbstractChatService service = chatServiceMap.get(category);
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("不支持的模型类别: " + category);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.hzhub.factory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hzhub.common.chat.service.chat.IChatModelService;
|
||||
import org.hzhub.common.chat.domain.vo.chat.ChatModelVo;
|
||||
import org.hzhub.service.embed.BaseEmbedModelService;
|
||||
import org.hzhub.service.embed.MultiModalEmbedModelService;
|
||||
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<String, BaseEmbedModelService> modelCache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 创建嵌入模型实例
|
||||
* 如果模型已存在于缓存中,则直接返回;否则创建新的实例
|
||||
*
|
||||
* @param embeddingModelName 嵌入模型名称
|
||||
*/
|
||||
public BaseEmbedModelService createModel(String embeddingModelName) {
|
||||
return modelCache.computeIfAbsent(embeddingModelName, name -> {
|
||||
ChatModelVo modelConfig = chatModelService.selectModelByName(embeddingModelName);
|
||||
|
||||
if (modelConfig == null) {
|
||||
throw new IllegalArgumentException("未找到模型配置,name=" + name);
|
||||
}
|
||||
return createModelInstance(modelConfig.getProviderCode(), modelConfig);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查模型是否支持多模态
|
||||
*
|
||||
* @param embeddingModelName 嵌入模型名称
|
||||
* @return boolean 如果模型支持多模态则返回true,否则返回false
|
||||
*/
|
||||
public boolean isMultimodalModel(String embeddingModelName) {
|
||||
return createModel(embeddingModelName) instanceof MultiModalEmbedModelService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建多模态嵌入模型实例
|
||||
*
|
||||
* @param embeddingModelName 嵌入模型名称
|
||||
* @return MultiModalEmbedModelService 多模态嵌入模型服务实例
|
||||
* @throws IllegalArgumentException 当模型不支持多模态时抛出
|
||||
*/
|
||||
public MultiModalEmbedModelService createMultimodalModel(String embeddingModelName) {
|
||||
BaseEmbedModelService model = createModel(embeddingModelName);
|
||||
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<String> 支持的模型工厂名称列表
|
||||
*/
|
||||
public List<String> 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.getProviderCode(), config.getId());
|
||||
return model;
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
throw new IllegalArgumentException("获取不到嵌入模型: " + factory, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.hzhub.factory;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hzhub.constant.FileTypeConstants;
|
||||
import org.hzhub.service.knowledge.ResourceLoader;
|
||||
import org.hzhub.service.knowledge.impl.loader.*;
|
||||
import org.hzhub.service.knowledge.impl.split.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Component
|
||||
public class ResourceLoaderFactory {
|
||||
private final CharacterTextSplitter characterTextSplitter;
|
||||
private final CodeTextSplitter codeTextSplitter;
|
||||
private final MarkdownTextSplitter markdownTextSplitter;
|
||||
private final ExcelTextSplitter excelTextSplitter;
|
||||
|
||||
public ResourceLoader getLoaderByFileType(String fileType) {
|
||||
fileType = StringUtils.removeStart(fileType, ".");
|
||||
if (FileTypeConstants.isTextFile(fileType)) {
|
||||
return new TextFileLoader(characterTextSplitter);
|
||||
} else if (FileTypeConstants.isWord(fileType)) {
|
||||
return new WordLoader(characterTextSplitter);
|
||||
} else if (FileTypeConstants.isPdf(fileType)) {
|
||||
return new PdfFileLoader(characterTextSplitter);
|
||||
} else if (FileTypeConstants.isMdFile(fileType)) {
|
||||
return new MarkDownFileLoader(markdownTextSplitter);
|
||||
} else if (FileTypeConstants.isCodeFile(fileType)) {
|
||||
return new CodeFileLoader(codeTextSplitter);
|
||||
} else if (FileTypeConstants.isExcel(fileType)) {
|
||||
return new ExcelFileLoader(excelTextSplitter);
|
||||
} else {
|
||||
return new TextFileLoader(characterTextSplitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.hzhub.factory;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.hzhub.config.VectorStoreProperties;
|
||||
import org.hzhub.service.vector.VectorStoreService;
|
||||
import org.hzhub.service.vector.impl.MilvusVectorStoreStrategy;
|
||||
import org.hzhub.service.vector.impl.WeaviateVectorStoreStrategy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 向量库策略工厂
|
||||
* 根据配置动态选择向量库实现
|
||||
*
|
||||
* @author Yzm
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class VectorStoreStrategyFactory {
|
||||
|
||||
private final VectorStoreProperties vectorStoreProperties;
|
||||
private final WeaviateVectorStoreStrategy weaviateStrategy;
|
||||
private final MilvusVectorStoreStrategy milvusStrategy;
|
||||
|
||||
private Map<String, VectorStoreService> strategies;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
strategies = new HashMap<>();
|
||||
strategies.put("weaviate", weaviateStrategy);
|
||||
strategies.put("milvus", milvusStrategy);
|
||||
log.info("向量库策略工厂初始化完成,支持的策略: {}", strategies.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前配置的向量库策略
|
||||
*/
|
||||
public VectorStoreService getStrategy() {
|
||||
String vectorStoreType = vectorStoreProperties.getType();
|
||||
if (vectorStoreType == null || vectorStoreType.trim().isEmpty()) {
|
||||
vectorStoreType = "weaviate"; // 默认使用weaviate
|
||||
}
|
||||
VectorStoreService strategy = strategies.get(vectorStoreType.toLowerCase());
|
||||
if (strategy == null) {
|
||||
log.warn("未找到向量库策略: {}, 使用默认策略: weaviate", vectorStoreType);
|
||||
strategy = strategies.get("weaviate");
|
||||
}
|
||||
log.debug("使用向量库策略: {}", vectorStoreType);
|
||||
return strategy;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.chat;
|
||||
|
||||
import org.hzhub.common.chat.domain.vo.chat.ChatMessageVo;
|
||||
import org.hzhub.common.chat.entity.chat.ChatMessage;
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 聊天消息Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
public interface ChatMessageMapper extends BaseMapperPlus<ChatMessage, ChatMessageVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.chat;
|
||||
|
||||
import org.hzhub.common.chat.entity.chat.ChatModel;
|
||||
import org.hzhub.common.chat.domain.vo.chat.ChatModelVo;
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 模型管理Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
public interface ChatModelMapper extends BaseMapperPlus<ChatModel, ChatModelVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.chat;
|
||||
|
||||
import org.hzhub.domain.entity.chat.ChatProvider;
|
||||
import org.hzhub.domain.vo.chat.ChatProviderVo;
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 厂商管理Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-14
|
||||
*/
|
||||
public interface ChatProviderMapper extends BaseMapperPlus<ChatProvider, ChatProviderVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.chat;
|
||||
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.hzhub.domain.entity.chat.ChatSession;
|
||||
import org.hzhub.domain.vo.chat.ChatSessionVo;
|
||||
|
||||
/**
|
||||
* 会话管理Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-30
|
||||
*/
|
||||
public interface ChatSessionMapper extends BaseMapperPlus<ChatSession, ChatSessionVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.knowledge;
|
||||
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeAttach;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeAttachVo;
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 知识库附件Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
public interface KnowledgeAttachMapper extends BaseMapperPlus<KnowledgeAttach, KnowledgeAttachVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.knowledge;
|
||||
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeFragment;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeFragmentVo;
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 知识片段Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
public interface KnowledgeFragmentMapper extends BaseMapperPlus<KnowledgeFragment, KnowledgeFragmentVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.knowledge;
|
||||
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeGraphInstance;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeGraphInstanceVo;
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 知识图谱实例Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
public interface KnowledgeGraphInstanceMapper extends BaseMapperPlus<KnowledgeGraphInstance, KnowledgeGraphInstanceVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.hzhub.mapper.knowledge;
|
||||
|
||||
import org.hzhub.domain.entity.knowledge.KnowledgeGraphSegment;
|
||||
import org.hzhub.domain.vo.knowledge.KnowledgeGraphSegmentVo;
|
||||
import org.hzhub.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 知识图谱片段Mapper接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-12-17
|
||||
*/
|
||||
public interface KnowledgeGraphSegmentMapper extends BaseMapperPlus<KnowledgeGraphSegment, KnowledgeGraphSegmentVo> {
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user