2 Commits

Author SHA1 Message Date
ageerle
003c066361 chore(sql): 更新数据库脚本,移除chat_config表
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:57:55 +08:00
ageerle
a5e7c59fd4 refactor: 重构项目架构,优化向量服务
- 移除 Graph 知识图谱相关模块(Neo4j、GraphRAG等)
- 移除 demo、job、wechat 示例模块,简化项目结构
- 修复向量维度获取方式,改为从数据库配置读取
- 添加 gRPC BOM 依赖管理,解决 Milvus SDK 版本冲突
- 新增 PPIO 服务和 Embedding 提供者支持
- 清理冗余代码和未使用的依赖

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:39:30 +08:00
157 changed files with 164 additions and 11931 deletions

View File

@@ -31,14 +31,13 @@
## ✨ 核心亮点
| 模块 | 现有能力 | 扩展方向 |
|:---:|---|---|
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱)、多模态理解、Coze/DIFY/FastGPT平台集成 | 自动模式、容错机制 |
| **知识** | 本地RAG + 向量库(Milvus/Weaviate) + 知识图谱 + 文档解析 +重排序 | 音频视频解析、知识出处 |
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态 | 工具插件市场、toolAgent自动加载工具 |
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点 | 更多节点类型 |
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型 | 智能体可配置 |
| **AI编程** | 智能代码分析、项目脚手架生成、Copilot助手 | 代码生成优化 |
| 模块 | 现有能力 | 扩展方向 |
|:----------:|---|------------------------|
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱)、多模态理解、Coze/DIFY/FastGPT平台集成 | 自动模式、容错机制、计费管理 |
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate) + 文档解析 | 多模态、知识出处、知识图谱、重排序 |
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态 | 工具插件市场、 |
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点 | 更多节点类型 |
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型 | 智能体可配置 |
## 🚀 快速体验

View File

@@ -11,42 +11,12 @@
Target Server Version : 80045 (8.0.45)
File Encoding : 65001
Date: 14/03/2026 14:15:08
Date: 15/03/2026 23:56:19
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for chat_config
-- ----------------------------
DROP TABLE IF EXISTS `chat_config`;
CREATE TABLE `chat_config` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置类型',
`config_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置名称',
`config_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置值',
`config_dict` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '说明',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`version` int NULL DEFAULT NULL COMMENT '版本',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '删除标志0代表存在 1代表删除',
`update_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新IP',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `unique_category_key`(`category` ASC, `config_name` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2030620372623781891 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '配置信息表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of chat_config
-- ----------------------------
INSERT INTO `chat_config` VALUES (2030620372556673026, 'wechat', 'appid', 'xx', 'appid', 103, '2026-03-08 20:23:19', '1', '1', '2026-03-08 20:23:19', NULL, NULL, '0', NULL, 0);
INSERT INTO `chat_config` VALUES (2030620372623781890, 'wechat', 'secret', 'xx', 'secret', 103, '2026-03-08 20:23:19', '1', '1', '2026-03-08 20:23:19', NULL, NULL, '0', NULL, 0);
-- ----------------------------
-- Table structure for chat_message
-- ----------------------------
@@ -57,10 +27,8 @@ CREATE TABLE `chat_message` (
`user_id` bigint NOT NULL COMMENT '用户id',
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '消息内容',
`role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '对话角色',
`deduct_cost` double(20, 2) NULL DEFAULT 0.00 COMMENT '扣除金额',
`total_tokens` int NULL DEFAULT 0 COMMENT '累计 Tokens',
`model_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型名称',
`billing_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '计费类型1-token计费2-次数计费)',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` bigint NULL DEFAULT NULL COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
@@ -85,11 +53,8 @@ CREATE TABLE `chat_model` (
`model_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型名称',
`provider_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型供应商',
`model_describe` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型描述',
`model_price` double NULL DEFAULT NULL COMMENT '模型价格',
`model_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '计费类型',
`model_dimension` int NULL DEFAULT NULL COMMENT '模型维度',
`model_show` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '是否显示',
`model_free` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '是否免费',
`priority` int NULL DEFAULT 1 COMMENT '模型优先级(值越大优先级越高)',
`api_host` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求地址',
`api_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密钥',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
@@ -105,8 +70,8 @@ CREATE TABLE `chat_model` (
-- ----------------------------
-- Records of chat_model
-- ----------------------------
INSERT INTO `chat_model` VALUES (2000585866022060033, 'chat', 'deepseek/deepseek-v3.2', 'ppio', 'deepseek', 1, '1', 'Y', 'Y', 1, 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2025-12-15 23:16:54', 1, '2026-02-25 21:46:08', 'DeepSeek-V3.2 是一款在高效推理、复杂推理能力与智能体场景中表现突出的领先模型。其基于 DeepSeek Sparse AttentionDSA稀疏注意力机制在显著降低计算开销的同时优化长上下文性能通过可扩展强化学习框架整体能力达到 GPT-5 同级,高算力版本 V3.2-Speciale 更在推理表现上接近 Gemini-3.0-Pro同时模型依托大型智能体任务合成管线具备更强的工具调用与多步骤决策能力并在 2025 年 IMO 与 IOI 中取得金牌级表现。作为 MaaS 平台,我们已对 DeepSeek-V3.2 完成深度适配,通过动态调度、批处理加速、低延迟推理与企业级 SLA 保障,进一步增强其在企业生产环境中的稳定性、性价比与可控性,适用于搜索、问答、智能体、代码、数据处理等多类高价值场景。', 0);
INSERT INTO `chat_model` VALUES (2007528268536287233, 'vector', 'baai/bge-m3', 'ppio', 'bge-m3', 0, '1', 'N', 'Y', 1, 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2026-01-04 03:03:32', 1, '2026-02-25 21:15:14', 'bge-large-zh-v1.5', 0);
INSERT INTO `chat_model` VALUES (2000585866022060033, 'chat', 'deepseek/deepseek-v3.2', 'ppio', 'deepseek', NULL, 'Y', 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2025-12-15 23:16:54', 1, '2026-03-15 19:18:48', 'DeepSeek-V3.2 是一款在高效推理、复杂推理能力与智能体场景中表现突出的领先模型。其基于 DeepSeek Sparse AttentionDSA稀疏注意力机制在显著降低计算开销的同时优化长上下文性能通过可扩展强化学习框架整体能力达到 GPT-5 同级,高算力版本 V3.2-Speciale 更在推理表现上接近 Gemini-3.0-Pro同时模型依托大型智能体任务合成管线具备更强的工具调用与多步骤决策能力并在 2025 年 IMO 与 IOI 中取得金牌级表现。作为 MaaS 平台,我们已对 DeepSeek-V3.2 完成深度适配,通过动态调度、批处理加速、低延迟推理与企业级 SLA 保障,进一步增强其在企业生产环境中的稳定性、性价比与可控性,适用于搜索、问答、智能体、代码、数据处理等多类高价值场景。', 0);
INSERT INTO `chat_model` VALUES (2007528268536287233, 'vector', 'baai/bge-m3', 'ppio', 'bge-m3', 1024, 'N', 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2026-01-04 03:03:32', 1, '2026-03-15 19:18:51', 'BGE-M3 是一款具备多维度能力的文本嵌入模型可同时实现密集检索、多向量检索和稀疏检索三大核心功能。该模型设计上兼容超过100种语言并支持从短句到长达8192词元的长文本等多种输入形式。在跨语言检索任务中BGE-M3展现出显著优势其性能在MIRACL、MKQA等国际基准测试中位居前列。此外针对长文档检索场景该模型在MLDR、NarritiveQA等数据集上的表现同样达到行业领先水平。', 0);
-- ----------------------------
-- Table structure for chat_provider
@@ -1101,171 +1066,6 @@ INSERT INTO `gen_table_column` VALUES (2018961776721399811, 2018961776515878913,
INSERT INTO `gen_table_column` VALUES (2018961776721399812, 2018961776515878913, 'open_id', '微信用户标识', 'varchar(100)', 'String', 'openId', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'input', '', 22, 103, 1, '2026-02-04 16:16:13', 1, '2026-02-04 16:20:23');
INSERT INTO `gen_table_column` VALUES (2018961776721399813, 2018961776515878913, 'user_balance', '账户余额', 'double(20,2)', 'Long', 'userBalance', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'input', '', 23, 103, 1, '2026-02-04 16:16:13', 1, '2026-02-04 16:20:23');
-- ----------------------------
-- Table structure for graph_build_task
-- ----------------------------
DROP TABLE IF EXISTS `graph_build_task`;
CREATE TABLE `graph_build_task` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`task_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务UUID',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱UUID',
`knowledge_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '知识库ID',
`doc_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文档ID可选null表示全量构建',
`task_type` tinyint NULL DEFAULT 1 COMMENT '任务类型1全量构建、2增量更新、3重建',
`task_status` tinyint NULL DEFAULT 1 COMMENT '任务状态1待执行、2执行中、3成功、4失败',
`progress` int NULL DEFAULT 0 COMMENT '进度百分比0-100',
`total_docs` int NULL DEFAULT 0 COMMENT '总文档数',
`processed_docs` int NULL DEFAULT 0 COMMENT '已处理文档数',
`extracted_entities` int NULL DEFAULT 0 COMMENT '提取的实体数',
`extracted_relations` int NULL DEFAULT 0 COMMENT '提取的关系数',
`error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '错误信息',
`result_summary` json NULL COMMENT '结果摘要(JSON格式)',
`start_time` datetime NULL DEFAULT NULL COMMENT '开始时间',
`end_time` datetime NULL DEFAULT NULL COMMENT '结束时间',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_task_uuid`(`task_uuid` ASC) USING BTREE,
INDEX `idx_graph_uuid`(`graph_uuid` ASC) USING BTREE,
INDEX `idx_knowledge_id`(`knowledge_id` ASC) USING BTREE,
INDEX `idx_task_status`(`task_status` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱构建任务表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_build_task
-- ----------------------------
-- ----------------------------
-- Table structure for graph_entity_type
-- ----------------------------
DROP TABLE IF EXISTS `graph_entity_type`;
CREATE TABLE `graph_entity_type` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`type_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '实体类型名称',
`type_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '类型编码',
`description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
`color` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '#1890ff' COMMENT '可视化颜色',
`icon` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图标',
`sort` int NULL DEFAULT 0 COMMENT '显示顺序',
`is_enable` tinyint(1) NULL DEFAULT 1 COMMENT '是否启用0否 1是',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_type_code`(`type_code` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱实体类型定义表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_entity_type
-- ----------------------------
INSERT INTO `graph_entity_type` VALUES (1, '人物', 'PERSON', '人物实体,包括真实人物和虚拟角色', '#1890ff', 'user', 1, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (2, '机构', 'ORGANIZATION', '组织机构,包括公司、政府机构等', '#52c41a', 'bank', 2, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (3, '地点', 'LOCATION', '地理位置,包括国家、城市、地址等', '#fa8c16', 'environment', 3, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (4, '概念', 'CONCEPT', '抽象概念,包括理论、方法等', '#722ed1', 'bulb', 4, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (5, '事件', 'EVENT', '事件记录,包括历史事件、活动等', '#eb2f96', 'calendar', 5, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (6, '产品', 'PRODUCT', '产品或服务', '#13c2c2', 'shopping', 6, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (7, '技术', 'TECHNOLOGY', '技术或工具', '#2f54eb', 'tool', 7, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (8, '文档', 'DOCUMENT', '文档或资料', '#faad14', 'file-text', 8, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
-- ----------------------------
-- Table structure for graph_query_history
-- ----------------------------
DROP TABLE IF EXISTS `graph_query_history`;
CREATE TABLE `graph_query_history` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`query_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '查询UUID',
`user_id` bigint NOT NULL COMMENT '用户ID',
`knowledge_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '知识库ID',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图谱UUID',
`query_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '查询文本',
`query_type` tinyint NULL DEFAULT 1 COMMENT '查询类型1实体查询、2关系查询、3路径查询、4混合查询',
`cypher_query` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '生成的Cypher查询',
`result_count` int NULL DEFAULT 0 COMMENT '结果数量',
`response_time` int NULL DEFAULT 0 COMMENT '响应时间(ms)',
`is_success` tinyint(1) NULL DEFAULT 1 COMMENT '是否成功0否 1是',
`error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '错误信息',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_query_uuid`(`query_uuid` ASC) USING BTREE,
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
INDEX `idx_knowledge_id`(`knowledge_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱查询历史表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_query_history
-- ----------------------------
-- ----------------------------
-- Table structure for graph_relation_type
-- ----------------------------
DROP TABLE IF EXISTS `graph_relation_type`;
CREATE TABLE `graph_relation_type` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`relation_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关系名称',
`relation_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关系编码',
`description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
`direction` tinyint(1) NULL DEFAULT 1 COMMENT '关系方向0双向、1单向',
`style` json NULL COMMENT '可视化样式(JSON格式)',
`sort` int NULL DEFAULT 0 COMMENT '显示顺序',
`is_enable` tinyint(1) NULL DEFAULT 1 COMMENT '是否启用0否 1是',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_relation_code`(`relation_code` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱关系类型定义表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_relation_type
-- ----------------------------
INSERT INTO `graph_relation_type` VALUES (1, '属于', 'BELONGS_TO', '隶属关系,表示从属或归属', 1, NULL, 1, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (2, '位于', 'LOCATED_IN', '地理位置关系', 1, NULL, 2, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (3, '相关', 'RELATED_TO', '一般关联关系', 0, NULL, 3, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (4, '导致', 'CAUSES', '因果关系', 1, NULL, 4, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (5, '包含', 'CONTAINS', '包含关系', 1, NULL, 5, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (6, '提及', 'MENTIONS', '文档提及实体的关系', 1, NULL, 6, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (7, '部分', 'PART_OF', '部分关系', 1, NULL, 7, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (8, '实例', 'INSTANCE_OF', '实例关系', 1, NULL, 8, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (9, '相似', 'SIMILAR_TO', '相似关系', 0, NULL, 9, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (10, '前序', 'PRECEDES', '时序关系', 1, NULL, 10, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (11, '工作于', 'WORKS_AT', '人物与机构的工作关系', 1, NULL, 11, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (12, '创建', 'CREATED_BY', '创建关系', 1, NULL, 12, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (13, '使用', 'USES', '使用关系', 1, NULL, 13, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
-- ----------------------------
-- Table structure for graph_statistics
-- ----------------------------
DROP TABLE IF EXISTS `graph_statistics`;
CREATE TABLE `graph_statistics` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱UUID',
`stat_date` date NOT NULL COMMENT '统计日期',
`total_nodes` int NULL DEFAULT 0 COMMENT '总节点数',
`total_relationships` int NULL DEFAULT 0 COMMENT '总关系数',
`node_type_distribution` json NULL COMMENT '节点类型分布(JSON格式)',
`relation_type_distribution` json NULL COMMENT '关系类型分布(JSON格式)',
`query_count` int NULL DEFAULT 0 COMMENT '查询次数',
`avg_query_time` int NULL DEFAULT 0 COMMENT '平均查询时间(ms)',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_graph_date`(`graph_uuid` ASC, `stat_date` ASC) USING BTREE,
INDEX `idx_stat_date`(`stat_date` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱统计信息表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_statistics
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_attach
-- ----------------------------
@@ -1286,7 +1086,7 @@ CREATE TABLE `knowledge_attach` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `idx_kname`(`knowledge_id` ASC, `name` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2016797369199366146 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库附件' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 2033199209203183619 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库附件' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_attach
@@ -1309,81 +1109,12 @@ CREATE TABLE `knowledge_fragment` (
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2016797369027399683 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识片段' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 2033199209131880451 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识片段' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_fragment
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_graph_instance
-- ----------------------------
DROP TABLE IF EXISTS `knowledge_graph_instance`;
CREATE TABLE `knowledge_graph_instance` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱UUID',
`knowledge_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关联knowledge_info.kid',
`graph_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱名称',
`graph_status` tinyint NULL DEFAULT 10 COMMENT '构建状态10构建中、20已完成、30失败',
`node_count` int NULL DEFAULT 0 COMMENT '节点数量',
`relationship_count` int NULL DEFAULT 0 COMMENT '关系数量',
`config` json NULL COMMENT '图谱配置(JSON格式)',
`model_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'LLM模型名称',
`entity_types` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '实体类型(逗号分隔)',
`relation_types` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '关系类型(逗号分隔)',
`error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '错误信息',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '删除标志0代表存在 1代表删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_graph_uuid`(`graph_uuid` ASC) USING BTREE,
INDEX `idx_knowledge_id`(`knowledge_id` ASC) USING BTREE,
INDEX `idx_graph_status`(`graph_status` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识图谱实例表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_graph_instance
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_graph_segment
-- ----------------------------
DROP TABLE IF EXISTS `knowledge_graph_segment`;
CREATE TABLE `knowledge_graph_segment` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '片段UUID',
`kb_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '知识库UUID',
`kb_item_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '知识库条目UUID',
`doc_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文档UUID',
`segment_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '片段文本内容',
`chunk_index` int NULL DEFAULT 0 COMMENT '片段索引(第几个片段)',
`total_chunks` int NULL DEFAULT 1 COMMENT '总片段数',
`extraction_status` tinyint NULL DEFAULT 0 COMMENT '抽取状态0-待处理 1-处理中 2-已完成 3-失败',
`entity_count` int NULL DEFAULT 0 COMMENT '抽取的实体数量',
`relation_count` int NULL DEFAULT 0 COMMENT '抽取的关系数量',
`token_used` int NULL DEFAULT 0 COMMENT '消耗的token数',
`error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '错误信息',
`user_id` bigint NULL DEFAULT NULL COMMENT '用户ID',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_uuid`(`uuid` ASC) USING BTREE,
INDEX `idx_kb_uuid`(`kb_uuid` ASC) USING BTREE,
INDEX `idx_kb_item_uuid`(`kb_item_uuid` ASC) USING BTREE,
INDEX `idx_doc_uuid`(`doc_uuid` ASC) USING BTREE,
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识图谱片段表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_graph_segment
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_info
-- ----------------------------
@@ -1408,7 +1139,7 @@ CREATE TABLE `knowledge_info` (
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2018245281372573699 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 2033198818050781187 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_info
@@ -2639,6 +2370,21 @@ INSERT INTO `sys_logininfor` VALUES (2026654082020204546, '000000', 'admin', 'pc
INSERT INTO `sys_logininfor` VALUES (2026654455514587138, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-02-25 21:44:10');
INSERT INTO `sys_logininfor` VALUES (2027260957187186689, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-02-27 13:54:12');
INSERT INTO `sys_logininfor` VALUES (2030617171346399233, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-08 20:10:35');
INSERT INTO `sys_logininfor` VALUES (2033083137191841794, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 15:29:27');
INSERT INTO `sys_logininfor` VALUES (2033102367094214657, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 16:45:52');
INSERT INTO `sys_logininfor` VALUES (2033116897354551298, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 17:43:36');
INSERT INTO `sys_logininfor` VALUES (2033133175565836289, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 18:48:17');
INSERT INTO `sys_logininfor` VALUES (2033167392953675778, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:04:16');
INSERT INTO `sys_logininfor` VALUES (2033168637663719425, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:09:12');
INSERT INTO `sys_logininfor` VALUES (2033170263812157441, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2026-03-15 21:15:40');
INSERT INTO `sys_logininfor` VALUES (2033170654197002242, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:17:13');
INSERT INTO `sys_logininfor` VALUES (2033170805703651330, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2026-03-15 21:17:49');
INSERT INTO `sys_logininfor` VALUES (2033170821767835650, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:17:53');
INSERT INTO `sys_logininfor` VALUES (2033170964009267201, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:18:27');
INSERT INTO `sys_logininfor` VALUES (2033197762549985282, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 23:04:56');
INSERT INTO `sys_logininfor` VALUES (2033200372921217025, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '密码输入错误1次', '2026-03-15 23:15:19');
INSERT INTO `sys_logininfor` VALUES (2033200386498179073, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 23:15:22');
INSERT INTO `sys_logininfor` VALUES (2033210457315696642, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 23:55:23');
-- ----------------------------
-- Table structure for sys_menu
@@ -2831,31 +2577,19 @@ INSERT INTO `sys_menu` VALUES (2000210913846157316, '模型管理新增', 200021
INSERT INTO `sys_menu` VALUES (2000210913846157317, '模型管理修改', 2000210913846157314, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:model:edit', '#', 103, 1, '2025-12-14 22:27:59', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210913846157318, '模型管理删除', 2000210913846157314, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:model:remove', '#', 103, 1, '2025-12-14 22:27:59', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210913846157319, '模型管理导出', 2000210913846157314, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:model:export', '#', 103, 1, '2025-12-14 22:28:00', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142145, '聊天配置', 2000209300188356609, 1, 'config', 'chat/config/index', NULL, 1, 0, 'C', '0', '0', 'system:config:list', 'tdesign:task-setting', 103, 1, '2025-12-14 22:27:46', 1, '2025-12-15 00:59:48', '配置信息菜单');
INSERT INTO `sys_menu` VALUES (2000210914299142146, '配置信息查询', 2000210914299142145, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:query', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142147, '配置信息新增', 2000210914299142145, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:add', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142148, '配置信息修改', 2000210914299142145, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:edit', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142149, '配置信息删除', 2000210914299142145, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:remove', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142150, '配置信息导出', 2000210914299142145, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:export', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823809, '聊天消息', 2000209300188356609, 1, 'message', 'chat/message/index', NULL, 1, 0, 'C', '0', '0', 'system:message:list', 'system-uicons:message', 103, 1, '2025-12-14 22:27:54', 1, '2025-12-15 00:53:47', '聊天消息菜单');
INSERT INTO `sys_menu` VALUES (2000210914680823810, '聊天消息查询', 2000210914680823809, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:query', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823811, '聊天消息新增', 2000210914680823809, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:add', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823812, '聊天消息修改', 2000210914680823809, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:edit', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823813, '聊天消息删除', 2000210914680823809, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:remove', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823814, '聊天消息导出', 2000210914680823809, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:export', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813441, '知识', 2006683336984580098, 1, 'info', 'knowledge/info/index', NULL, 1, 0, 'C', '0', '0', 'knowledge:info:list', 'solar:book-line-duotone', 103, 1, '2026-01-01 18:59:05', 1, '2026-01-01 19:08:03', '知识库菜单');
INSERT INTO `sys_menu` VALUES (2006681261898813441, '知识管理', 2000209300188356609, 1, 'info', 'knowledge/info/index', NULL, 1, 0, 'C', '0', '0', 'knowledge:info:list', 'solar:book-line-duotone', 103, 1, '2026-01-01 18:59:05', 1, '2026-03-15 21:07:50', '知识库菜单');
INSERT INTO `sys_menu` VALUES (2006681261898813442, '知识库查询', 2006681261898813441, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:query', '#', 103, 1, '2026-01-01 18:59:05', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813443, '知识库新增', 2006681261898813441, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:add', '#', 103, 1, '2026-01-01 18:59:05', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813444, '知识库修改', 2006681261898813441, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:edit', '#', 103, 1, '2026-01-01 18:59:05', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813445, '知识库删除', 2006681261898813441, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:remove', '#', 103, 1, '2026-01-01 18:59:06', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813446, '知识库导出', 2006681261898813441, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:export', '#', 103, 1, '2026-01-01 18:59:06', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006683336984580098, '知识管理', 0, 2, 'knowledge', '', NULL, 1, 0, 'M', '0', '0', NULL, 'bx:book', 103, 1, '2026-01-01 19:06:05', 1, '2026-01-01 19:06:05', '');
INSERT INTO `sys_menu` VALUES (2019464280262905857, '图谱实例', 2019464531388469250, 1, 'graphInstance', 'graph/graphInstance/index', NULL, 1, 0, 'C', '0', '0', 'operator:graph:list', 'ant-design:node-index-outlined', 103, 1, '2026-02-06 01:32:59', 1, '2026-02-06 01:40:06', '');
INSERT INTO `sys_menu` VALUES (2019464531388469250, '知识图谱', 2006683336984580098, 15, 'graph', '', NULL, 1, 0, 'M', '0', '0', NULL, 'carbon:chart-relationship', 103, 1, '2026-02-06 01:33:59', 1, '2026-02-06 01:33:59', '');
INSERT INTO `sys_menu` VALUES (2019464779217309697, '图谱可视化', 2019464531388469250, 2, 'graphVisualization', 'graph/graphVisualization/index', NULL, 1, 0, 'C', '0', '0', 'operator:graph:view', 'carbon:chart-network', 103, 1, '2026-02-06 01:34:58', 1, '2026-02-06 01:40:14', '');
INSERT INTO `sys_menu` VALUES (2019464917407043585, '图谱检索', 2019464531388469250, 3, 'graphRAG', 'graph/graphRAG/index', NULL, 1, 0, 'C', '0', '0', 'operator:graph:retrieve', 'carbon:search-advanced', 103, 1, '2026-02-06 01:35:31', 1, '2026-02-06 01:40:19', '');
INSERT INTO `sys_menu` VALUES (2031360871412346881, '流程编排', 0, 2, 'aiflow', '', NULL, 1, 0, 'M', '0', '0', NULL, 'fluent:flow-dot-16-filled', 103, 1, '2026-03-10 21:25:47', 1, '2026-03-10 21:25:47', '');
INSERT INTO `sys_menu` VALUES (2031361596464902145, '编排管理', 2031360871412346881, 1, 'aiflow', 'aiflow/index', NULL, 1, 0, 'C', '0', '0', NULL, 'carbon:flow', 103, 1, '2026-03-10 21:28:40', 1, '2026-03-10 21:29:40', '');
INSERT INTO `sys_menu` VALUES (2031361596464902145, '编排管理', 2000209300188356609, 1, 'aiflow', 'aiflow/index', NULL, 1, 0, 'C', '0', '0', NULL, 'carbon:flow', 103, 1, '2026-03-10 21:28:40', 1, '2026-03-15 21:06:01', '');
-- ----------------------------
-- Table structure for sys_notice
@@ -2946,6 +2680,12 @@ INSERT INTO `sys_oss` VALUES (2026640515967557633, '000000', '2026/02/25/afecabe
INSERT INTO `sys_oss` VALUES (2026640548213366785, '000000', '2026/02/25/e16429a462e54e14a1d36673146b9e3c.png', 'ppio-color.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/02/25/e16429a462e54e14a1d36673146b9e3c.png', '{\"fileSize\":\"7382\",\"contentType\":\"image/png\"}', 103, '2026-02-25 20:48:55', 1, '2026-02-25 20:48:55', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2026640572443860993, '000000', '2026/02/25/049bb6a507174f73bba4b8d8b9e55b8a.png', 'ppio-color.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/02/25/049bb6a507174f73bba4b8d8b9e55b8a.png', '{\"fileSize\":\"7382\",\"contentType\":\"image/png\"}', 103, '2026-02-25 20:49:00', 1, '2026-02-25 20:49:00', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2026640621945036802, '000000', '2026/02/25/de2aa7e649de44f3ba5c6380ac6acd04.png', 'bailian-color.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/02/25/de2aa7e649de44f3ba5c6380ac6acd04.png', '{\"fileSize\":\"5901\",\"contentType\":\"image/png\"}', 103, '2026-02-25 20:49:12', 1, '2026-02-25 20:49:12', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033120065673043969, '000000', '2026/03/15/68c4d853814e444982c2517ffabac0f3.jpg', '9b75e600b2df6160261a507055eabfdf.jpg', '.jpg', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/68c4d853814e444982c2517ffabac0f3.jpg', '{\"fileSize\":\"28027\",\"contentType\":\"image/jpeg\"}', 103, '2026-03-15 17:56:12', 1, '2026-03-15 17:56:12', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033169884118593537, '000000', '2026/03/15/4b7e93a72bf04805ae59985cc0845ef1.png', 'logo.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/4b7e93a72bf04805ae59985cc0845ef1.png', '{\"fileSize\":\"61537\",\"contentType\":\"image/png\"}', 103, '2026-03-15 21:14:10', 1, '2026-03-15 21:14:10', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033198191581147137, '000000', '2026/03/15/66d9e6d216c74652bb466a13d24f4440.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/66d9e6d216c74652bb466a13d24f4440.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:06:39', 1, '2026-03-15 23:06:39', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033198447232364546, '000000', '2026/03/15/ae1b1e0d363e4bc1b3321d696453fdbf.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/ae1b1e0d363e4bc1b3321d696453fdbf.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:07:39', 1, '2026-03-15 23:07:39', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033198841211727874, '000000', '2026/03/15/83564059b4f643b69a1e0ea727d17364.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/83564059b4f643b69a1e0ea727d17364.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:09:13', 1, '2026-03-15 23:09:13', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033199209064771586, '000000', '2026/03/15/695360eb380d43d6af34e8a308c09696.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/695360eb380d43d6af34e8a308c09696.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:10:41', 1, '2026-03-15 23:10:41', 1, 'qcloud');
-- ----------------------------
-- Table structure for sys_oss_config
@@ -2981,7 +2721,7 @@ CREATE TABLE `sys_oss_config` (
INSERT INTO `sys_oss_config` VALUES (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-25 15:44:13', NULL);
INSERT INTO `sys_oss_config` VALUES (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-03 05:14:52', NULL);
INSERT INTO `sys_oss_config` VALUES (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-03 05:14:52', NULL);
INSERT INTO `sys_oss_config` VALUES (4, '000000', 'qcloud', 'xx', 'xx', 'ruoyiai-1254149996', '', 'cos.ap-guangzhou.myqcloud.com', '', 'Y', 'ap-guangzhou', '1', '0', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-25 16:51:41', '');
INSERT INTO `sys_oss_config` VALUES (4, '000000', 'qcloud', 'xx', 'xx', 'ruoyiai-1254149996', '', 'cos.ap-guangzhou.myqcloud.com', '', 'Y', 'ap-guangzhou', '1', '0', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-03-15 17:56:06', '');
INSERT INTO `sys_oss_config` VALUES (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:53', 1, '2026-02-03 05:14:53', NULL);
-- ----------------------------
@@ -3428,7 +3168,7 @@ CREATE TABLE `sys_user` (
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '000000', 103, 'admin', 'admin', 'sys_user', 'ageerle@163.com', '15888888888', '1', NULL, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-03-08 20:10:35', 103, 1, '2026-02-05 09:22:12', -1, '2026-03-08 20:10:35', '管理员', NULL, 0.00);
INSERT INTO `sys_user` VALUES (1, '000000', 103, 'admin', 'admin', 'sys_user', 'ageerle@163.com', '15888888888', '1', NULL, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-03-15 23:55:23', 103, 1, '2026-02-05 09:22:12', -1, '2026-03-15 23:55:23', '管理员', NULL, 0.00);
INSERT INTO `sys_user` VALUES (3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', NULL, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', '2026-02-05 09:22:12', 103, 1, '2026-02-05 09:22:12', 3, '2026-02-05 09:22:12', NULL, NULL, 0.00);
INSERT INTO `sys_user` VALUES (4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', NULL, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', '2026-02-05 09:22:12', 103, 1, '2026-02-05 09:22:12', 4, '2026-02-05 09:22:12', NULL, NULL, 0.00);

37
pom.xml
View File

@@ -59,6 +59,8 @@
<langgraph4j.version>1.5.3</langgraph4j.version>
<weaviate.version>1.19.6</weaviate.version>
<dify.version>1.0.7</dify.version>
<!-- gRPC 版本 - 解决 Milvus SDK 依赖冲突 -->
<grpc.version>1.62.2</grpc.version>
<!-- Apache Commons Compress - 用于POI处理ZIP格式 -->
<commons-compress.version>1.27.1</commons-compress.version>
@@ -129,6 +131,15 @@
<scope>import</scope>
</dependency>
<!-- gRPC BOM - 解决 Milvus SDK 依赖冲突,强制统一版本 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-bom</artifactId>
<version>${grpc.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置-->
<dependency>
<groupId>cn.hutool</groupId>
@@ -352,24 +363,12 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-job</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat</artifactId>
@@ -383,13 +382,6 @@
<version>${revision}</version>
</dependency>
<!-- 微信模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-wechat</artifactId>
<version>${revision}</version>
</dependency>
<!-- AI流程编排模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
@@ -397,13 +389,6 @@
<version>${revision}</version>
</dependency>
<!-- 企业微信SDK -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
<version>${weixin-java-cp.version}</version>
</dependency>
<!-- Jackson XML -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>

View File

@@ -70,23 +70,12 @@
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat</artifactId>
@@ -98,12 +87,6 @@
<artifactId>ruoyi-workflow</artifactId>
</dependency>
<!-- 微信模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-wechat</artifactId>
</dependency>
<!-- AI流程编排模块 -->
<dependency>
<groupId>org.ruoyi</groupId>

View File

@@ -125,9 +125,6 @@ security:
- /*/api-docs/**
- /warm-flow-ui/config
- /workflow/run
- /user/qrcode
- /user/login/qrcode
- /weixin/check
# 多租户配置
tenant:
# 是否开启
@@ -206,6 +203,7 @@ springdoc:
name: ageerle
email: ageerle@163.com
url: https://gitee.com/ageerle/ruoyi-ai
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.演示模块
@@ -247,12 +245,6 @@ management:
show-details: ALWAYS
logfile:
external-file: ./logs/sys-console.log
health:
# ⚠️ 禁用 Neo4j 健康检查
# Spring Boot Actuator 会自动为 Neo4j 创建健康检查器
# 这会导致应用在启动时尝试连接到 Neo4j
neo4j:
enabled: false
--- # 默认/推荐使用sse推送
sse:
@@ -285,7 +277,7 @@ warm-flow:
vector-store:
# 向量存储类型 可选(weaviate/milvus)
# 如需修改向量库类型,请修改此配置值!
type: weaviate
type: milvus
# Weaviate配置
weaviate:
protocol: http
@@ -295,81 +287,3 @@ vector-store:
milvus:
url: http://localhost:19530
collectionname: LocalKnowledge
chat:
memory:
enabled: true
maxMessages: 20
persistenceEnabled: true
# 企业微信应用
wechat:
cp:
corpId:
appConfigs:
- agentId:
secret: ''
token: ''
aesKey: ''
--- # Neo4j 知识图谱配置
neo4j:
uri: bolt://117.72.192.162:7687
username: neo4j
password: MySecurePass123!
database: neo4j
max-connection-pool-size: 50
connection-timeout-seconds: 30
# 知识图谱配置
knowledge:
graph:
# 是否启用知识图谱功能
enabled: false
# 图数据库类型: neo4j 或 apache-age
database-type: neo4j
# 是否自动创建索引
auto-create-index: true
# 批量处理大小
batch-size: 1000
# 最大重试次数
max-retry-count: 3
# 实体抽取配置
extraction:
# 置信度阈值(低于此值的实体将被过滤)
confidence-threshold: 0.7
# 最大实体数量(每个文档)
max-entities-per-doc: 100
# 最大关系数量(每个文档)
max-relations-per-doc: 200
# 文本分片大小(用于长文档)
chunk-size: 2000
# 分片重叠大小
chunk-overlap: 200
# 查询配置
query:
# 默认查询限制数量
default-limit: 100
# 最大查询限制数量
max-limit: 1000
# 路径查询最大深度
max-path-depth: 5
# 查询超时时间(秒)
timeout-seconds: 30
# 是否启用查询缓存
cache-enabled: true
# 缓存过期时间(分钟)
cache-expire-minutes: 60
--- # MCP 模块配置
app:
mcp:
client:
# 请求超时时间(秒)
request-timeout: 30
# 连接超时时间(秒)
connection-timeout: 10
# 最大重试次数
max-retries: 3

View File

@@ -48,11 +48,6 @@ public class ChatMessageBo extends BaseEntity {
*/
private String role;
/**
* 扣除金额
*/
private Long deductCost;
/**
* 累计 Tokens
*/
@@ -63,11 +58,6 @@ public class ChatMessageBo extends BaseEntity {
*/
private String modelName;
/**
* 计费类型1-token计费2-次数计费)
*/
private String billingType;
/**
* 备注
*/

View File

@@ -45,30 +45,15 @@ public class ChatModelBo extends BaseEntity {
*/
private String modelDescribe;
/**
* 模型价格
*/
private Long modelPrice;
/**
* 计费类型
*/
private String modelType;
/**
* 是否显示
*/
private String modelShow;
/**
* 是否免费
* 向量维度
*/
private String modelFree;
/**
* 模型优先级(值越大优先级越高)
*/
private Long priority;
private Integer modelDimension;
/**
* 请求地址

View File

@@ -56,12 +56,6 @@ public class ChatMessageVo implements Serializable {
@ExcelProperty(value = "对话角色")
private String role;
/**
* 扣除金额
*/
@ExcelProperty(value = "扣除金额")
private Long deductCost;
/**
* 累计 Tokens
*/
@@ -74,12 +68,6 @@ public class ChatMessageVo implements Serializable {
@ExcelProperty(value = "模型名称")
private String modelName;
/**
* 计费类型1-token计费2-次数计费)
*/
@ExcelProperty(value = "计费类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "1=-token计费2-次数计费")
private String billingType;
/**
* 备注

View File

@@ -54,17 +54,6 @@ public class ChatModelVo implements Serializable {
@ExcelProperty(value = "模型描述")
private String modelDescribe;
/**
* 模型价格
*/
@ExcelProperty(value = "模型价格")
private Long modelPrice;
/**
* 计费类型
*/
@ExcelProperty(value = "计费类型")
private String modelType;
/**
* 是否显示
@@ -73,16 +62,10 @@ public class ChatModelVo implements Serializable {
private String modelShow;
/**
* 是否免费
* 向量维度
*/
@ExcelProperty(value = "是否免费")
private String modelFree;
/**
* 模型优先级(值越大优先级越高)
*/
@ExcelProperty(value = "模型优先级(值越大优先级越高)")
private Long priority;
@ExcelProperty(value = "向量维度")
private Integer modelDimension;
/**
* 请求地址
@@ -102,11 +85,5 @@ public class ChatModelVo implements Serializable {
@ExcelProperty(value = "备注")
private String remark;
/**
* 模型维度
*/
private Integer dimension;
}

View File

@@ -48,10 +48,6 @@ public class ChatMessage extends TenantEntity {
*/
private String role;
/**
* 扣除金额
*/
private Long deductCost;
/**
* 累计 Tokens
@@ -63,11 +59,6 @@ public class ChatMessage extends TenantEntity {
*/
private String modelName;
/**
* 计费类型1-token计费2-次数计费)
*/
private String billingType;
/**
* 备注
*/

View File

@@ -48,15 +48,6 @@ public class ChatModel extends TenantEntity {
*/
private String modelDescribe;
/**
* 模型价格
*/
private Long modelPrice;
/**
* 计费类型
*/
private String modelType;
/**
* 是否显示
@@ -64,14 +55,9 @@ public class ChatModel extends TenantEntity {
private String modelShow;
/**
* 是否免费
* 向量维度
*/
private String modelFree;
/**
* 模型优先级(值越大优先级越高)
*/
private Long priority;
private Integer modelDimension;
/**
* 请求地址

View File

@@ -41,7 +41,6 @@ public abstract class AbstractChatMessageService {
messageBO.setContent(content);
messageBO.setRole(role);
messageBO.setModelName(chatRequest.getModel());
messageBO.setBillingType(chatModelVo.getModelType());
messageBO.setRemark(null);
chatMessageService.insertByBo(messageBO);

View File

@@ -12,11 +12,8 @@
<modules>
<module>ruoyi-aiflow</module>
<module>ruoyi-chat</module>
<module>ruoyi-demo</module>
<module>ruoyi-generator</module>
<module>ruoyi-job</module>
<module>ruoyi-system</module>
<module>ruoyi-wechat</module>
<module>ruoyi-workflow</module>
</modules>

View File

@@ -1,69 +0,0 @@
package org.ruoyi.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 图谱构建异步任务配置
*
* @author ruoyi
* @date 2025-10-11
*/
@Slf4j
@EnableAsync
@Configuration
@ConditionalOnProperty(prefix = "knowledge.graph", name = "enabled", havingValue = "true")
public class GraphAsyncConfig {
/**
* 图谱构建专用线程池
* 用于执行图谱构建任务,避免阻塞主线程池
*/
@Bean("graphBuildExecutor")
public Executor graphBuildExecutor() {
log.info("初始化图谱构建线程池...");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数CPU核心数
int processors = Runtime.getRuntime().availableProcessors();
executor.setCorePoolSize(processors);
// 最大线程数CPU核心数 * 2
executor.setMaxPoolSize(processors * 2);
// 队列容量100个任务
executor.setQueueCapacity(100);
// 线程空闲时间60秒
executor.setKeepAliveSeconds(60);
// 线程名称前缀
executor.setThreadNamePrefix("graph-build-");
// 拒绝策略:由调用线程处理
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成后关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间60秒
executor.setAwaitTerminationSeconds(60);
// 初始化
executor.initialize();
log.info("图谱构建线程池初始化完成: corePoolSize={}, maxPoolSize={}, queueCapacity={}",
processors, processors * 2, 100);
return executor;
}
}

View File

@@ -1,175 +0,0 @@
package org.ruoyi.config;
import org.ruoyi.constant.GraphConstants;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* 图谱实体关系抽取提示词
* 参考 Microsoft GraphRAG 项目
* https://github.com/microsoft/graphrag/blob/main/graphrag/index/graph/extractors/graph/prompts.py
*
* @author ruoyi
* @date 2025-09-30
*/
public class GraphExtractPrompt {
/**
* 中文实体关系抽取提示词
*/
public static final String GRAPH_EXTRACTION_PROMPT_CN = """
-目标-
给定一个可能与此活动相关的文本文档以及实体类型列表,从文本中识别出所有这些类型的实体以及识别出的实体之间的所有关系。
-步骤-
1. 识别所有实体。对于每个识别出的实体,提取以下信息:
- entity_name实体的名称首字母大写
- entity_type以下类型之一[{entity_types}]
- entity_description实体的属性和活动的全面描述
将每个实体格式化为 ("entity"{tuple_delimiter}<entity_name>{tuple_delimiter}<entity_type>{tuple_delimiter}<entity_description>)
2. 从步骤1中识别出的实体中识别出所有明确相关的 (source_entity, target_entity) 对。
对于每对相关的实体,提取以下信息:
- source_entity在步骤1中识别的源实体的名称
- target_entity在步骤1中识别的目标实体的名称
- relationship_description解释你认为源实体和目标实体之间相关的原因
- relationship_strength一个表示源实体和目标实体之间关系强度的数字分数0-10
将每个关系格式化为 ("relationship"{tuple_delimiter}<source_entity>{tuple_delimiter}<target_entity>{tuple_delimiter}<relationship_description>{tuple_delimiter}<relationship_strength>)
3. 以英文返回输出作为所有在步骤1和步骤2中识别的实体和关系的列表。使用 **{record_delimiter}** 作为列表分隔符。
4. 完成时,输出 {completion_delimiter}
######################
-示例-
######################
示例 1:
Entity_types: ORGANIZATION,PERSON
文本:
The Verdantis's Central Institution is scheduled to meet on Monday and Thursday, with the institution planning to release its latest policy decision on Thursday at 1:30 p.m. PDT, followed by a press conference where Central Institution Chair Martin Smith will take questions. Investors expect the Market Strategy Committee to hold its benchmark interest rate steady in a range of 3.5%-3.75%.
######################
输出:
("entity"{tuple_delimiter}CENTRAL INSTITUTION{tuple_delimiter}ORGANIZATION{tuple_delimiter}The Central Institution is the Federal Reserve of Verdantis, which is setting interest rates on Monday and Thursday)
{record_delimiter}
("entity"{tuple_delimiter}MARTIN SMITH{tuple_delimiter}PERSON{tuple_delimiter}Martin Smith is the chair of the Central Institution)
{record_delimiter}
("entity"{tuple_delimiter}MARKET STRATEGY COMMITTEE{tuple_delimiter}ORGANIZATION{tuple_delimiter}The Central Institution committee makes key decisions about interest rates and the growth of Verdantis's money supply)
{record_delimiter}
("relationship"{tuple_delimiter}MARTIN SMITH{tuple_delimiter}CENTRAL INSTITUTION{tuple_delimiter}Martin Smith is the Chair of the Central Institution and will answer questions at a press conference{tuple_delimiter}9)
{completion_delimiter}
######################
示例 2:
Entity_types: ORGANIZATION
文本:
TechGlobal's (TG) stock skyrocketed in its opening day on the Global Exchange Thursday. But IPO experts warn that the semiconductor corporation's debut on the public markets isn't indicative of how other newly listed companies may perform.
TechGlobal, a formerly public company, was taken private by Vision Holdings in 2014. The well-established chip designer says it powers 85% of premium smartphones.
######################
输出:
("entity"{tuple_delimiter}TECHGLOBAL{tuple_delimiter}ORGANIZATION{tuple_delimiter}TechGlobal is a stock now listed on the Global Exchange which powers 85% of premium smartphones)
{record_delimiter}
("entity"{tuple_delimiter}VISION HOLDINGS{tuple_delimiter}ORGANIZATION{tuple_delimiter}Vision Holdings is a firm that previously owned TechGlobal)
{record_delimiter}
("relationship"{tuple_delimiter}TECHGLOBAL{tuple_delimiter}VISION HOLDINGS{tuple_delimiter}Vision Holdings formerly owned TechGlobal from 2014 until present{tuple_delimiter}5)
{completion_delimiter}
######################
示例 3:
Entity_types: ORGANIZATION,LOCATION,PERSON
文本:
Five Aurelians jailed for 8 years in Firuzabad and widely regarded as hostages are on their way home to Aurelia.
The swap orchestrated by Quintara was finalized when $8bn of Firuzi funds were transferred to financial institutions in Krohaara, the capital of Quintara.
The exchange initiated in Firuzabad's capital, Tiruzia, led to the four men and one woman, who are also Firuzi nationals, boarding a chartered flight to Krohaara.
They were welcomed by senior Aurelian officials and are now on their way to Aurelia's capital, Cashion.
The Aurelians include 39-year-old businessman Samuel Namara, who has been held in Tiruzia's Alhamia Prison, as well as journalist Durke Bataglani, 59, and environmentalist Meggie Tazbah, 53, who also holds Bratinas nationality.
######################
输出:
("entity"{tuple_delimiter}FIRUZABAD{tuple_delimiter}LOCATION{tuple_delimiter}Firuzabad held Aurelians as hostages)
{record_delimiter}
("entity"{tuple_delimiter}AURELIA{tuple_delimiter}LOCATION{tuple_delimiter}Country seeking to release hostages)
{record_delimiter}
("entity"{tuple_delimiter}QUINTARA{tuple_delimiter}LOCATION{tuple_delimiter}Country that negotiated a swap of money in exchange for hostages)
{record_delimiter}
("entity"{tuple_delimiter}TIRUZIA{tuple_delimiter}LOCATION{tuple_delimiter}Capital of Firuzabad where the Aurelians were being held)
{record_delimiter}
("entity"{tuple_delimiter}KROHAARA{tuple_delimiter}LOCATION{tuple_delimiter}Capital city in Quintara)
{record_delimiter}
("entity"{tuple_delimiter}CASHION{tuple_delimiter}LOCATION{tuple_delimiter}Capital city in Aurelia)
{record_delimiter}
("entity"{tuple_delimiter}SAMUEL NAMARA{tuple_delimiter}PERSON{tuple_delimiter}Aurelian who spent time in Tiruzia's Alhamia Prison)
{record_delimiter}
("entity"{tuple_delimiter}ALHAMIA PRISON{tuple_delimiter}LOCATION{tuple_delimiter}Prison in Tiruzia)
{record_delimiter}
("entity"{tuple_delimiter}DURKE BATAGLANI{tuple_delimiter}PERSON{tuple_delimiter}Aurelian journalist who was held hostage)
{record_delimiter}
("entity"{tuple_delimiter}MEGGIE TAZBAH{tuple_delimiter}PERSON{tuple_delimiter}Bratinas national and environmentalist who was held hostage)
{record_delimiter}
("relationship"{tuple_delimiter}FIRUZABAD{tuple_delimiter}AURELIA{tuple_delimiter}Firuzabad negotiated a hostage exchange with Aurelia{tuple_delimiter}2)
{record_delimiter}
("relationship"{tuple_delimiter}QUINTARA{tuple_delimiter}AURELIA{tuple_delimiter}Quintara brokered the hostage exchange between Firuzabad and Aurelia{tuple_delimiter}2)
{record_delimiter}
("relationship"{tuple_delimiter}SAMUEL NAMARA{tuple_delimiter}ALHAMIA PRISON{tuple_delimiter}Samuel Namara was a prisoner at Alhamia prison{tuple_delimiter}8)
{record_delimiter}
("relationship"{tuple_delimiter}SAMUEL NAMARA{tuple_delimiter}MEGGIE TAZBAH{tuple_delimiter}Samuel Namara and Meggie Tazbah were exchanged in the same hostage release{tuple_delimiter}2)
{completion_delimiter}
######################
-真实数据-
######################
Entity_types: {entity_types}
文本: {input_text}
######################
输出:
""".replace("{tuple_delimiter}", GraphConstants.GRAPH_TUPLE_DELIMITER)
.replace("{entity_types}", Arrays.stream(GraphConstants.DEFAULT_ENTITY_TYPES).collect(Collectors.joining(",")))
.replace("{completion_delimiter}", GraphConstants.GRAPH_COMPLETION_DELIMITER)
.replace("{record_delimiter}", GraphConstants.GRAPH_RECORD_DELIMITER);
/**
* 继续抽取提示词(当第一次抽取遗漏实体时使用)
*/
public static final String CONTINUE_PROMPT = """
在上一次抽取中遗漏了许多实体和关系。
请记住只提取与之前提取的类型匹配的实体。
使用相同的格式在下面添加它们:
""";
/**
* 循环检查提示词
*/
public static final String LOOP_PROMPT = """
似乎仍然可能遗漏了一些实体和关系。
如果还有需要添加的实体或关系,请回答 YES | NO。
""";
/**
* 生成提取提示词
*
* @param inputText 输入文本
* @return 完整的提示词
*/
public static String buildExtractionPrompt(String inputText) {
return GRAPH_EXTRACTION_PROMPT_CN.replace("{input_text}", inputText);
}
/**
* 生成提取提示词(自定义实体类型)
*
* @param inputText 输入文本
* @param entityTypes 实体类型列表
* @return 完整的提示词
*/
public static String buildExtractionPrompt(String inputText, String[] entityTypes) {
String entityTypesStr = Arrays.stream(entityTypes).collect(Collectors.joining(","));
return GRAPH_EXTRACTION_PROMPT_CN
.replace("{input_text}", inputText)
.replace(Arrays.stream(GraphConstants.DEFAULT_ENTITY_TYPES).collect(Collectors.joining(",")), entityTypesStr);
}
}

View File

@@ -1,113 +0,0 @@
package org.ruoyi.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 知识图谱配置属性
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@Component
@ConfigurationProperties(prefix = "knowledge.graph")
public class GraphProperties {
/**
* 是否启用知识图谱功能
*/
private Boolean enabled = false;
/**
* 图数据库类型: neo4j 或 apache-age
*/
private String databaseType = "neo4j";
/**
* 是否自动创建索引
*/
private Boolean autoCreateIndex = true;
/**
* 批量处理大小
*/
private Integer batchSize = 1000;
/**
* 最大重试次数
*/
private Integer maxRetryCount = 3;
/**
* 实体抽取配置
*/
private ExtractionConfig extraction = new ExtractionConfig();
/**
* 查询配置
*/
private QueryConfig query = new QueryConfig();
@Data
public static class ExtractionConfig {
/**
* 置信度阈值(低于此值的实体将被过滤)
*/
private Double confidenceThreshold = 0.7;
/**
* 最大实体数量(每个文档)
*/
private Integer maxEntitiesPerDoc = 100;
/**
* 最大关系数量(每个文档)
*/
private Integer maxRelationsPerDoc = 200;
/**
* 文本分片大小(用于长文档)
*/
private Integer chunkSize = 2000;
/**
* 分片重叠大小
*/
private Integer chunkOverlap = 200;
}
@Data
public static class QueryConfig {
/**
* 默认查询限制数量
*/
private Integer defaultLimit = 100;
/**
* 最大查询限制数量
*/
private Integer maxLimit = 1000;
/**
* 路径查询最大深度
*/
private Integer maxPathDepth = 5;
/**
* 查询超时时间(秒)
*/
private Integer timeoutSeconds = 30;
/**
* 是否启用查询缓存
*/
private Boolean cacheEnabled = true;
/**
* 缓存过期时间(分钟)
*/
private Integer cacheExpireMinutes = 60;
}
}

View File

@@ -1,57 +0,0 @@
package org.ruoyi.config;
import lombok.extern.slf4j.Slf4j;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Neo4j配置类
*/
@Slf4j
@Configuration
@EnableConfigurationProperties(Neo4jProperties.class)
public class Neo4jConfig {
public Neo4jConfig() {
log.warn("========== Neo4jConfig 已激活 ==========");
log.warn("知识图谱功能Neo4j: 已启用");
log.warn("========================================");
}
/**
* 创建Neo4j Driver Bean
*
* @param neo4jProperties Neo4j 配置属性
* @return Neo4j Driver
*/
@Bean
public Driver neo4jDriver(Neo4jProperties neo4jProperties) {
log.info("========== 正在初始化 Neo4j Driver ==========");
log.info("Neo4j 连接地址: {}", neo4jProperties.getUri());
log.info("Neo4j 用户名: {}", neo4jProperties.getUsername());
log.info("Neo4j 数据库: {}", neo4jProperties.getDatabase());
log.info("最大连接池大小: {}", neo4jProperties.getMaxConnectionPoolSize());
log.info("连接超时时间: {} 秒", neo4jProperties.getConnectionTimeoutSeconds());
try {
Driver driver = GraphDatabase.driver(
neo4jProperties.getUri(),
AuthTokens.basic(neo4jProperties.getUsername(), neo4jProperties.getPassword()),
org.neo4j.driver.Config.builder()
.withMaxConnectionPoolSize(neo4jProperties.getMaxConnectionPoolSize())
.withConnectionTimeout(neo4jProperties.getConnectionTimeoutSeconds(), java.util.concurrent.TimeUnit.SECONDS)
.build()
);
log.info("========== Neo4j Driver 初始化完成 ==========");
return driver;
} catch (Exception e) {
log.error("Neo4j Driver 初始化失败", e);
throw new RuntimeException("Failed to initialize Neo4j Driver", e);
}
}
}

View File

@@ -1,52 +0,0 @@
package org.ruoyi.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* Neo4j 配置属性
*
* 分离 @ConfigurationProperties 避免与 @ConditionalOnProperty 冲突
* 不使用 @Component而是在 Neo4jConfig 中通过 @EnableConfigurationProperties 启用
* 参考: https://github.com/spring-projects/spring-boot/issues/26251
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@ConfigurationProperties(prefix = "neo4j")
public class Neo4jProperties {
/**
* Neo4j连接URI
* 例如: bolt://localhost:7687
*/
private String uri;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 数据库名称Neo4j 4.0+支持多数据库)
* 默认: neo4j
*/
private String database = "neo4j";
/**
* 最大连接池大小
*/
private Integer maxConnectionPoolSize = 50;
/**
* 连接超时时间(秒)
*/
private Integer connectionTimeoutSeconds = 30;
}

View File

@@ -1,103 +0,0 @@
package org.ruoyi.constant;
/**
* 知识图谱常量
*
* @author ruoyi
* @date 2025-09-30
*/
public class GraphConstants {
/**
* 图谱记录分隔符
*/
public static final String GRAPH_RECORD_DELIMITER = "##";
/**
* 图谱元组分隔符
*/
public static final String GRAPH_TUPLE_DELIMITER = "<|>";
/**
* 图谱完成标记
*/
public static final String GRAPH_COMPLETION_DELIMITER = "<|COMPLETE|>";
/**
* 实体类型:人物
*/
public static final String ENTITY_TYPE_PERSON = "PERSON";
/**
* 实体类型:组织机构
*/
public static final String ENTITY_TYPE_ORGANIZATION = "ORGANIZATION";
/**
* 实体类型:地点
*/
public static final String ENTITY_TYPE_LOCATION = "LOCATION";
/**
* 实体类型:概念
*/
public static final String ENTITY_TYPE_CONCEPT = "CONCEPT";
/**
* 实体类型:事件
*/
public static final String ENTITY_TYPE_EVENT = "EVENT";
/**
* 实体类型:产品
*/
public static final String ENTITY_TYPE_PRODUCT = "PRODUCT";
/**
* 实体类型:技术
*/
public static final String ENTITY_TYPE_TECHNOLOGY = "TECHNOLOGY";
/**
* 默认实体抽取类型列表
*/
public static final String[] DEFAULT_ENTITY_TYPES = {
ENTITY_TYPE_PERSON,
ENTITY_TYPE_ORGANIZATION,
ENTITY_TYPE_LOCATION,
ENTITY_TYPE_CONCEPT,
ENTITY_TYPE_EVENT,
ENTITY_TYPE_PRODUCT,
ENTITY_TYPE_TECHNOLOGY
};
/**
* 元数据键知识库UUID
*/
public static final String METADATA_KB_UUID = "kb_uuid";
/**
* 元数据键知识库条目UUID
*/
public static final String METADATA_KB_ITEM_UUID = "kb_item_uuid";
/**
* 元数据键文档UUID
*/
public static final String METADATA_DOC_UUID = "doc_uuid";
/**
* 元数据键片段UUID
*/
public static final String METADATA_SEGMENT_UUID = "segment_uuid";
/**
* RAG最大片段大小token数
*/
public static final int RAG_MAX_SEGMENT_SIZE_IN_TOKENS = 512;
/**
* RAG片段重叠大小token数
*/
public static final int RAG_SEGMENT_OVERLAP_IN_TOKENS = 50;
}

View File

@@ -1,418 +0,0 @@
package org.ruoyi.controller.graph;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.web.core.BaseController;
import org.ruoyi.domain.bo.graph.GraphBuildTask;
import org.ruoyi.domain.bo.graph.GraphInstance;
import org.ruoyi.enums.GraphStatusEnum;
import org.ruoyi.service.graph.IGraphBuildTaskService;
import org.ruoyi.service.graph.IGraphInstanceService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 图谱实例管理控制器
*
* @author ruoyi
* @date 2025-09-30
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/graph/instance")
@Tag(name = "图谱实例管理", description = "知识图谱实例的创建、查询、更新、删除")
@ConditionalOnProperty(prefix = "knowledge.graph", name = "enabled", havingValue = "true")
public class GraphInstanceController extends BaseController {
private final IGraphInstanceService graphInstanceService;
private final IGraphBuildTaskService buildTaskService;
/**
* 辅助方法根据ID或UUID获取图谱实例
*/
private GraphInstance getInstanceByIdOrUuid(String id) {
GraphInstance instance = null;
// 尝试作为数字ID查询
try {
Long numericId = Long.parseLong(id);
instance = graphInstanceService.getById(numericId);
} catch (NumberFormatException e) {
// 不是数字尝试作为UUID查询
instance = graphInstanceService.getByUuid(id);
}
return instance;
}
/**
* 创建图谱实例
*/
@Operation(summary = "创建图谱实例")
@PostMapping
public R<GraphInstance> createInstance(@RequestBody GraphInstance graphInstance) {
try {
if (graphInstance.getKnowledgeId() == null || graphInstance.getKnowledgeId().trim().isEmpty()) {
return R.fail("知识库ID不能为空");
}
if (graphInstance.getInstanceName() == null || graphInstance.getInstanceName().trim().isEmpty()) {
return R.fail("图谱名称不能为空");
}
// 创建基础实例
GraphInstance instance = graphInstanceService.createInstance(
graphInstance.getKnowledgeId(),
graphInstance.getInstanceName(),
graphInstance.getConfig()
);
// 设置扩展属性
boolean needUpdate = false;
if (graphInstance.getModelName() != null) {
instance.setModelName(graphInstance.getModelName());
needUpdate = true;
}
if (graphInstance.getEntityTypes() != null) {
instance.setEntityTypes(graphInstance.getEntityTypes());
needUpdate = true;
}
if (graphInstance.getRelationTypes() != null) {
instance.setRelationTypes(graphInstance.getRelationTypes());
needUpdate = true;
}
if (graphInstance.getRemark() != null) {
instance.setRemark(graphInstance.getRemark());
needUpdate = true;
}
// 如果有扩展属性,更新到数据库
if (needUpdate) {
graphInstanceService.updateInstance(instance);
}
return R.ok(instance);
} catch (Exception e) {
return R.fail("创建图谱实例失败: " + e.getMessage());
}
}
/**
* 更新图谱实例
*/
@Operation(summary = "更新图谱实例")
@PutMapping
public R<GraphInstance> updateInstance(@RequestBody GraphInstance graphInstance) {
try {
if (graphInstance.getId() == null && (graphInstance.getGraphUuid() == null || graphInstance.getGraphUuid().trim().isEmpty())) {
return R.fail("图谱ID不能为空");
}
// 如果有 instanceName更新基本信息
if (graphInstance.getInstanceName() != null) {
// 这里可以添加更新实例名称的逻辑
}
// 更新配置
if (graphInstance.getConfig() != null) {
graphInstanceService.updateConfig(graphInstance.getGraphUuid(), graphInstance.getConfig());
}
// 更新模型名称、实体类型、关系类型等
// 注意:这里需要在 Service 层实现完整的更新逻辑
GraphInstance instance = graphInstanceService.getByUuid(graphInstance.getGraphUuid());
return R.ok(instance);
} catch (Exception e) {
return R.fail("更新图谱实例失败: " + e.getMessage());
}
}
/**
* 根据ID或UUID获取图谱实例
*/
@Operation(summary = "获取图谱实例")
@GetMapping("/{id}")
public R<GraphInstance> getByUuid(@PathVariable String id) {
try {
GraphInstance instance = getInstanceByIdOrUuid(id);
if (instance == null) {
return R.fail("图谱实例不存在");
}
return R.ok(instance);
} catch (Exception e) {
return R.fail("获取图谱实例失败: " + e.getMessage());
}
}
/**
* 获取图谱实例列表(支持分页和条件查询)
*/
@Operation(summary = "获取图谱实例列表")
@GetMapping("/list")
public R<Map<String, Object>> list(
@RequestParam(required = false) String instanceName,
@RequestParam(required = false) String knowledgeId,
@RequestParam(required = false) String status,
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
@RequestParam(required = false, defaultValue = "10") Integer pageSize) {
try {
// 使用枚举转换前端状态字符串为数字状态码
Integer graphStatus = GraphStatusEnum.getCodeByStatusKey(status);
// 创建分页对象
Page<GraphInstance> page = new Page<>(pageNum, pageSize);
// 调用 Service 层分页查询
Page<GraphInstance> result = graphInstanceService.queryPage(page, instanceName, knowledgeId, graphStatus);
// 构造返回结果
Map<String, Object> data = new HashMap<>();
data.put("rows", result.getRecords());
data.put("total", result.getTotal());
return R.ok(data);
} catch (Exception e) {
return R.fail("获取图谱列表失败: " + e.getMessage());
}
}
/**
* 根据知识库ID获取图谱列表
*/
@Operation(summary = "获取知识库的图谱列表")
@GetMapping("/knowledge/{knowledgeId}")
public R<List<GraphInstance>> listByKnowledge(@PathVariable String knowledgeId) {
try {
List<GraphInstance> instances = graphInstanceService.listByKnowledgeId(knowledgeId);
return R.ok(instances);
} catch (Exception e) {
return R.fail("获取图谱列表失败: " + e.getMessage());
}
}
/**
* 更新图谱状态
*/
@Operation(summary = "更新图谱状态")
@PutMapping("/status/{graphUuid}")
public R<Void> updateStatus(
@PathVariable String graphUuid,
@RequestParam Integer status) {
try {
boolean success = graphInstanceService.updateStatus(graphUuid, status);
return success ? R.ok() : R.fail("更新状态失败");
} catch (Exception e) {
return R.fail("更新状态失败: " + e.getMessage());
}
}
/**
* 更新图谱统计信息
*/
@Operation(summary = "更新图谱统计")
@PutMapping("/counts/{graphUuid}")
public R<Void> updateCounts(
@PathVariable String graphUuid,
@RequestParam Integer nodeCount,
@RequestParam Integer relationshipCount) {
try {
boolean success = graphInstanceService.updateCounts(graphUuid, nodeCount, relationshipCount);
return success ? R.ok() : R.fail("更新统计失败");
} catch (Exception e) {
return R.fail("更新统计失败: " + e.getMessage());
}
}
/**
* 更新图谱配置
*/
@Operation(summary = "更新图谱配置")
@PutMapping("/config/{graphUuid}")
public R<Void> updateConfig(
@PathVariable String graphUuid,
@RequestBody Map<String, String> request) {
try {
String config = request.get("config");
boolean success = graphInstanceService.updateConfig(graphUuid, config);
return success ? R.ok() : R.fail("更新配置失败");
} catch (Exception e) {
return R.fail("更新配置失败: " + e.getMessage());
}
}
/**
* 删除图谱实例(软删除)
*/
@Operation(summary = "删除图谱实例")
@DeleteMapping("/{id}")
public R<Void> deleteInstance(@PathVariable String id) {
try {
// 获取图谱实例
GraphInstance instance = getInstanceByIdOrUuid(id);
if (instance == null) {
return R.fail("图谱实例不存在");
}
boolean success = graphInstanceService.deleteInstance(instance.getGraphUuid());
return success ? R.ok() : R.fail("删除失败");
} catch (Exception e) {
return R.fail("删除图谱实例失败: " + e.getMessage());
}
}
/**
* 物理删除图谱实例及其数据
*/
@Operation(summary = "彻底删除图谱")
@DeleteMapping("/permanent/{graphUuid}")
public R<Void> deleteInstanceAndData(@PathVariable String graphUuid) {
try {
boolean success = graphInstanceService.deleteInstanceAndData(graphUuid);
return success ? R.ok() : R.fail("删除失败");
} catch (Exception e) {
return R.fail("彻底删除图谱失败: " + e.getMessage());
}
}
/**
* 获取图谱统计信息
*/
@Operation(summary = "获取图谱统计")
@GetMapping("/stats/{graphUuid}")
public R<Map<String, Object>> getStatistics(@PathVariable String graphUuid) {
try {
Map<String, Object> stats = graphInstanceService.getStatistics(graphUuid);
return R.ok(stats);
} catch (Exception e) {
return R.fail("获取统计信息失败: " + e.getMessage());
}
}
/**
* 构建图谱(全量构建知识库)
*/
@Operation(summary = "构建图谱")
@PostMapping("/build/{id}")
public R<GraphBuildTask> buildGraph(@PathVariable String id) {
try {
// 获取图谱实例
GraphInstance instance = getInstanceByIdOrUuid(id);
if (instance == null) {
return R.fail("图谱实例不存在");
}
// 更新状态为构建中
graphInstanceService.updateStatus(instance.getGraphUuid(), 10); // 10=构建中
// 创建构建任务(全量构建)
GraphBuildTask task = buildTaskService.createTask(
instance.getGraphUuid(),
instance.getKnowledgeId(),
null, // docId=null 表示全量构建
1 // taskType=1 全量构建
);
// 异步启动任务
buildTaskService.startTask(task.getTaskUuid());
return R.ok(task);
} catch (Exception e) {
return R.fail("启动构建任务失败: " + e.getMessage());
}
}
/**
* 重建图谱(清空后重新构建)
*/
@Operation(summary = "重建图谱")
@PostMapping("/rebuild/{id}")
public R<GraphBuildTask> rebuildGraph(@PathVariable String id) {
try {
// 获取图谱实例
GraphInstance instance = getInstanceByIdOrUuid(id);
if (instance == null) {
return R.fail("图谱实例不存在");
}
// 更新状态为构建中
graphInstanceService.updateStatus(instance.getGraphUuid(), 10); // 10=构建中
// 创建重建任务
GraphBuildTask task = buildTaskService.createTask(
instance.getGraphUuid(),
instance.getKnowledgeId(),
null, // docId=null 表示全量
2 // taskType=2 重建
);
// 异步启动任务
buildTaskService.startTask(task.getTaskUuid());
return R.ok(task);
} catch (Exception e) {
return R.fail("启动重建任务失败: " + e.getMessage());
}
}
/**
* 获取构建状态
*/
@Operation(summary = "获取构建状态")
@GetMapping("/status/{id}")
public R<Map<String, Object>> getBuildStatus(@PathVariable String id) {
try {
// 获取图谱实例
GraphInstance instance = getInstanceByIdOrUuid(id);
if (instance == null) {
return R.fail("图谱实例不存在");
}
// 获取最新的构建任务
GraphBuildTask latestTask = buildTaskService.getLatestTask(instance.getGraphUuid());
Map<String, Object> result = new HashMap<>();
result.put("graphStatus", instance.getGraphStatus());
result.put("nodeCount", instance.getNodeCount());
result.put("relationshipCount", instance.getRelationshipCount());
if (latestTask != null) {
result.put("taskStatus", latestTask.getTaskStatus());
// ⭐ 确保 progress 不为 null前端期望是 number 类型
Integer progress = latestTask.getProgress();
result.put("progress", progress != null ? progress : 0);
result.put("errorMessage", latestTask.getErrorMessage());
// 转换状态字符串(兼容前端)
String status = "NOT_BUILT";
if (instance.getGraphStatus() == 10) status = "BUILDING";
else if (instance.getGraphStatus() == 20) status = "COMPLETED";
else if (instance.getGraphStatus() == 30) status = "FAILED";
result.put("status", status);
} else {
// ⭐ 如果没有任务,也返回默认值
result.put("taskStatus", null);
result.put("progress", 0);
result.put("errorMessage", null);
result.put("status", "NOT_BUILT");
}
return R.ok(result);
} catch (Exception e) {
return R.fail("获取构建状态失败: " + e.getMessage());
}
}
}

View File

@@ -1,228 +0,0 @@
package org.ruoyi.controller.graph;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.web.core.BaseController;
import org.ruoyi.domain.bo.graph.GraphEdge;
import org.ruoyi.domain.bo.graph.GraphVertex;
import org.ruoyi.domain.dto.GraphExtractionResult;
import org.ruoyi.service.graph.IGraphExtractionService;
import org.ruoyi.service.graph.IGraphRAGService;
import org.ruoyi.service.graph.IGraphStoreService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 图谱查询控制器
*
* @author ruoyi
* @date 2025-09-30
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/graph/query")
@Tag(name = "图谱查询", description = "知识图谱查询相关接口")
@ConditionalOnProperty(prefix = "knowledge.graph", name = "enabled", havingValue = "true")
public class GraphQueryController extends BaseController {
private final IGraphStoreService graphStoreService;
private final IGraphExtractionService graphExtractionService;
private final IGraphRAGService graphRAGService;
/**
* 获取知识库的图谱数据
*/
@Operation(summary = "获取知识库图谱")
@GetMapping("/knowledge/{knowledgeId}")
public R<Map<String, Object>> getGraphByKnowledge(
@PathVariable String knowledgeId,
@RequestParam(defaultValue = "100") Integer limit) {
try {
// 查询节点
List<GraphVertex> vertices = graphStoreService.queryVerticesByKnowledgeId(knowledgeId, limit);
// 查询关系
List<GraphEdge> edges = graphStoreService.queryEdgesByKnowledgeId(knowledgeId, limit);
Map<String, Object> result = new HashMap<>();
result.put("vertices", vertices);
result.put("edges", edges);
result.put("vertexCount", vertices.size());
result.put("edgeCount", edges.size());
return R.ok(result);
} catch (Exception e) {
return R.fail("获取图谱数据失败: " + e.getMessage());
}
}
/**
* 搜索实体节点
*/
@Operation(summary = "搜索实体")
@GetMapping("/search/entity")
public R<List<GraphVertex>> searchEntity(
@RequestParam String keyword,
@RequestParam(required = false) String knowledgeId,
@RequestParam(defaultValue = "20") Integer limit) {
try {
List<GraphVertex> vertices = graphStoreService.searchVerticesByName(keyword, knowledgeId, limit);
return R.ok(vertices);
} catch (Exception e) {
return R.fail("搜索实体失败: " + e.getMessage());
}
}
/**
* 查询实体的邻居节点
*/
@Operation(summary = "查询邻居节点")
@GetMapping("/neighbors/{nodeId}")
public R<List<GraphVertex>> getNeighbors(
@PathVariable String nodeId,
@RequestParam(required = false) String knowledgeId,
@RequestParam(defaultValue = "20") Integer limit) {
try {
List<GraphVertex> neighbors = graphStoreService.getNeighbors(nodeId, knowledgeId, limit);
return R.ok(neighbors);
} catch (Exception e) {
return R.fail("查询邻居节点失败: " + e.getMessage());
}
}
/**
* 查询两个实体之间的路径
*/
@Operation(summary = "查询实体路径")
@GetMapping("/path")
public R<List<List<GraphVertex>>> findPath(
@RequestParam String startNodeId,
@RequestParam String endNodeId,
@RequestParam(defaultValue = "5") Integer maxDepth) {
try {
List<List<GraphVertex>> paths = graphStoreService.findPaths(startNodeId, endNodeId, maxDepth);
return R.ok(paths);
} catch (Exception e) {
return R.fail("查询路径失败: " + e.getMessage());
}
}
/**
* 从文本抽取实体和关系(测试用)
*/
@Operation(summary = "文本实体抽取")
@PostMapping("/extract")
public R<GraphExtractionResult> extractFromText(@RequestBody Map<String, String> request) {
try {
String text = request.get("text");
if (text == null || text.trim().isEmpty()) {
return R.fail("文本不能为空");
}
String modelName = request.get("modelName");
GraphExtractionResult result;
if (modelName != null && !modelName.trim().isEmpty()) {
result = graphExtractionService.extractFromTextWithModel(text, modelName);
} else {
result = graphExtractionService.extractFromText(text);
}
return R.ok(result);
} catch (Exception e) {
return R.fail("实体抽取失败: " + e.getMessage());
}
}
/**
* 将文本入库到图谱
*/
@Operation(summary = "文本入库")
@PostMapping("/ingest")
public R<GraphExtractionResult> ingestText(@RequestBody Map<String, Object> request) {
try {
String text = (String) request.get("text");
String knowledgeId = (String) request.get("knowledgeId");
String modelName = (String) request.get("modelName");
if (text == null || text.trim().isEmpty()) {
return R.fail("文本不能为空");
}
if (knowledgeId == null || knowledgeId.trim().isEmpty()) {
return R.fail("知识库ID不能为空");
}
@SuppressWarnings("unchecked")
Map<String, Object> metadata = (Map<String, Object>) request.get("metadata");
GraphExtractionResult result;
if (modelName != null && !modelName.trim().isEmpty()) {
result = graphRAGService.ingestTextWithModel(text, knowledgeId, metadata, modelName);
} else {
result = graphRAGService.ingestText(text, knowledgeId, metadata);
}
return R.ok(result);
} catch (Exception e) {
return R.fail("文本入库失败: " + e.getMessage());
}
}
/**
* 基于图谱检索
*/
@Operation(summary = "图谱检索")
@GetMapping("/retrieve")
public R<String> retrieveFromGraph(
@RequestParam String query,
@RequestParam String knowledgeId,
@RequestParam(defaultValue = "10") Integer maxResults) {
try {
String result = graphRAGService.retrieveFromGraph(query, knowledgeId, maxResults);
return R.ok(result);
} catch (Exception e) {
return R.fail("图谱检索失败: " + e.getMessage());
}
}
/**
* 删除知识库的图谱数据
*/
@Operation(summary = "删除图谱数据")
@DeleteMapping("/knowledge/{knowledgeId}")
public R<Void> deleteGraphData(@PathVariable String knowledgeId) {
try {
boolean success = graphRAGService.deleteGraphData(knowledgeId);
return success ? R.ok() : R.fail("删除失败");
} catch (Exception e) {
return R.fail("删除图谱数据失败: " + e.getMessage());
}
}
/**
* 获取图谱统计信息
*/
@Operation(summary = "图谱统计")
@GetMapping("/stats/{knowledgeId}")
public R<Map<String, Object>> getGraphStats(@PathVariable String knowledgeId) {
try {
Map<String, Object> stats = graphStoreService.getStatistics(knowledgeId);
return R.ok(stats);
} catch (Exception e) {
return R.fail("获取统计信息失败: " + e.getMessage());
}
}
}

View File

@@ -1,145 +0,0 @@
package org.ruoyi.controller.graph;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.config.GraphProperties;
import org.ruoyi.config.Neo4jProperties;
import org.ruoyi.util.Neo4jTestUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
* Neo4j测试控制器
* 仅用于开发环境测试Neo4j连接
*
* @author ruoyi
* @date 2025-09-30
*/
@RestController
@RequestMapping("/graph/test")
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "knowledge.graph", name = "enabled", havingValue = "true")
public class Neo4jTestController {
private final Neo4jTestUtil neo4jTestUtil;
private final Neo4jProperties neo4jProperties;
private final GraphProperties graphProperties;
@GetMapping("/connection")
public R<Map<String, Object>> testConnection() {
Map<String, Object> result = neo4jTestUtil.testConnection();
if ("SUCCESS".equals(result.get("connection"))) {
return R.ok("Neo4j连接成功", result);
} else {
return R.fail(result.get("error").toString());
}
}
@GetMapping("/config")
public R<Map<String, Object>> getConfig() {
Map<String, Object> config = new HashMap<>();
config.put("neo4j", Map.of(
"uri", neo4jProperties.getUri(),
"username", neo4jProperties.getUsername(),
"database", neo4jProperties.getDatabase(),
"maxConnectionPoolSize", neo4jProperties.getMaxConnectionPoolSize()
));
config.put("graph", Map.of(
"enabled", graphProperties.getEnabled(),
"databaseType", graphProperties.getDatabaseType(),
"batchSize", graphProperties.getBatchSize(),
"extraction", graphProperties.getExtraction(),
"query", graphProperties.getQuery()
));
return R.ok(config);
}
@PostMapping("/node")
public R<Map<String, Object>> createTestNode(@RequestParam String name) {
Map<String, Object> result = neo4jTestUtil.createTestNode(name);
if (Boolean.TRUE.equals(result.get("success"))) {
return R.ok("测试节点创建成功", result);
} else {
return R.fail(result.get("error").toString());
}
}
@GetMapping("/node/{name}")
public R<Map<String, Object>> queryTestNode(@PathVariable String name) {
Map<String, Object> result = neo4jTestUtil.queryTestNode(name);
if (Boolean.TRUE.equals(result.get("found"))) {
return R.ok("节点查询成功", result);
} else {
return R.ok("未找到节点", result);
}
}
@PostMapping("/relationship")
public R<Map<String, Object>> createTestRelationship(
@RequestParam String source,
@RequestParam String target) {
Map<String, Object> result = neo4jTestUtil.createTestRelationship(source, target);
if (Boolean.TRUE.equals(result.get("success"))) {
return R.ok("测试关系创建成功", result);
} else {
return R.fail(result.get("error").toString());
}
}
@DeleteMapping("/nodes")
public R<Map<String, Object>> deleteAllTestNodes() {
Map<String, Object> result = neo4jTestUtil.deleteAllTestNodes();
if (Boolean.TRUE.equals(result.get("success"))) {
return R.ok("测试节点清理完成", result);
} else {
return R.fail(result.get("error").toString());
}
}
@GetMapping("/statistics")
public R<Map<String, Object>> getStatistics() {
Map<String, Object> result = neo4jTestUtil.getStatistics();
if (result.containsKey("error")) {
return R.fail(result.get("error").toString());
}
return R.ok(result);
}
@GetMapping("/health")
public R<String> health() {
Map<String, Object> result = neo4jTestUtil.testConnection();
if ("SUCCESS".equals(result.get("connection"))) {
return R.ok("Neo4j服务正常");
} else {
return R.fail("Neo4j服务异常: " + result.get("error"));
}
}
/**
* 调试关系查询 - 查看指定知识库的所有关系
*/
@GetMapping("/debug/relationships/{knowledgeId}")
public R<Map<String, Object>> debugRelationships(@PathVariable String knowledgeId) {
Map<String, Object> result = neo4jTestUtil.debugRelationships(knowledgeId);
return R.ok(result);
}
}

View File

@@ -1,15 +0,0 @@
package org.ruoyi.controller.tripartite;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Tag(name = "任务查询")
@RestController
@RequestMapping("/mj/task")
@RequiredArgsConstructor
@Slf4j
public class TaskController {
}

View File

@@ -1,107 +0,0 @@
package org.ruoyi.domain.bo.graph;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 图谱构建任务对象 graph_build_task
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@TableName("graph_build_task")
public class GraphBuildTask extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 任务UUID
*/
private String taskUuid;
/**
* 图谱UUID
*/
private String graphUuid;
/**
* 知识库ID
*/
private String knowledgeId;
/**
* 文档ID可选null表示全量构建
*/
private String docId;
/**
* 任务类型1全量构建、2增量更新、3重建
*/
private Integer taskType;
/**
* 任务状态1待执行、2执行中、3成功、4失败
*/
private Integer taskStatus;
/**
* 进度百分比0-100
*/
private Integer progress;
/**
* 总文档数
*/
private Integer totalDocs;
/**
* 已处理文档数
*/
private Integer processedDocs;
/**
* 提取的实体数
*/
private Integer extractedEntities;
/**
* 提取的关系数
*/
private Integer extractedRelations;
/**
* 错误信息
*/
private String errorMessage;
/**
* 结果摘要(JSON格式)
*/
private String resultSummary;
/**
* 开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
}

View File

@@ -1,137 +0,0 @@
package org.ruoyi.domain.bo.graph;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
/**
* 图关系实体
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("graph_edge")
public class GraphEdge implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 图谱UUID
*/
private String graphUuid;
/**
* 关系唯一标识Neo4j中的关系ID
*/
private String edgeId;
/**
* 关系标签(类型)
*/
private String label;
/**
* 源节点ID
*/
private String sourceNodeId;
/**
* 源节点名称
*/
private String sourceName;
/**
* 目标节点ID
*/
private String targetNodeId;
/**
* 目标节点名称
*/
private String targetName;
/**
* 关系类型编码
*/
private String relationType;
/**
* 关系描述
*/
private String description;
/**
* 关系权重0.0-1.0
*/
private Double weight;
/**
* 置信度0.0-1.0
*/
private Double confidence;
/**
* 来源知识库ID
*/
private String knowledgeId;
/**
* 来源文档ID列表JSON格式
*/
private String docIds;
/**
* 来源片段ID列表JSON格式
*/
private String fragmentIds;
/**
* 文本段ID关联到具体的文本段
*/
@JsonProperty("text_segment_id")
private String textSegmentId;
/**
* 其他属性JSON格式
*/
private String properties;
/**
* 元数据JSON格式
*/
private Map<String, Object> metadata;
/**
* 源节点元数据
*/
private Map<String, Object> sourceMetadata;
/**
* 目标节点元数据
*/
private Map<String, Object> targetMetadata;
/**
* 备注
*/
private String remark;
}

View File

@@ -1,65 +0,0 @@
package org.ruoyi.domain.bo.graph;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 图谱实体类型定义对象 graph_entity_type
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("graph_entity_type")
public class GraphEntityType extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 实体类型名称
*/
private String typeName;
/**
* 类型编码
*/
private String typeCode;
/**
* 描述
*/
private String description;
/**
* 可视化颜色
*/
private String color;
/**
* 图标
*/
private String icon;
/**
* 显示顺序
*/
private Integer sort;
/**
* 是否启用0否 1是
*/
private Integer isEnable;
}

View File

@@ -1,117 +0,0 @@
package org.ruoyi.domain.bo.graph;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 知识图谱实例对象 knowledge_graph_instance
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("knowledge_graph_instance")
public class GraphInstance 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;
/**
* 图谱实例名称(前端使用,不映射到数据库)
*/
@TableField(exist = false)
private String instanceName;
/**
* 构建状态10构建中、20已完成、30失败
*/
private Integer graphStatus;
/**
* 节点数量
*/
private Integer nodeCount;
/**
* 关系数量
*/
private Integer relationshipCount;
/**
* 图谱配置(JSON格式)
*/
private String config;
/**
* LLM模型名称
*/
private String modelName;
/**
* 实体类型(逗号分隔)
*/
private String entityTypes;
/**
* 关系类型(逗号分隔)
*/
private String relationTypes;
/**
* 错误信息
*/
private String errorMessage;
/**
* 删除标志0代表存在 1代表删除
*/
private String delFlag;
/**
* 备注
*/
private String remark;
/**
* 获取实例名称(兼容前端)
*/
public String getInstanceName() {
return instanceName != null ? instanceName : graphName;
}
/**
* 设置实例名称同步到graphName
*/
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
this.graphName = instanceName;
}
}

View File

@@ -1,65 +0,0 @@
package org.ruoyi.domain.bo.graph;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 图谱关系类型定义对象 graph_relation_type
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("graph_relation_type")
public class GraphRelationType extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 关系名称
*/
private String relationName;
/**
* 关系编码
*/
private String relationCode;
/**
* 描述
*/
private String description;
/**
* 关系方向0双向、1单向
*/
private Integer direction;
/**
* 可视化样式(JSON格式)
*/
private String style;
/**
* 显示顺序
*/
private Integer sort;
/**
* 是否启用0否 1是
*/
private Integer isEnable;
}

View File

@@ -1,112 +0,0 @@
package org.ruoyi.domain.bo.graph;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
/**
* 图节点实体
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("graph_vertex")
public class GraphVertex implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 图谱UUID
*/
private String graphUuid;
/**
* 节点唯一标识Neo4j中的节点ID
*/
private String nodeId;
/**
* 节点名称
*/
private String name;
/**
* 节点标签(类型)
*/
private String label;
/**
* 节点类型编码
*/
private String type;
/**
* 描述信息
*/
private String description;
/**
* 置信度0.0-1.0
*/
private Double confidence;
/**
* 来源知识库ID
*/
private String knowledgeId;
/**
* 来源文档ID列表JSON格式
*/
private String docIds;
/**
* 来源片段ID列表JSON格式
*/
private String fragmentIds;
/**
* 文本段ID关联到具体的文本段
*/
@JsonProperty("text_segment_id")
private String textSegmentId;
/**
* 别名列表JSON格式
*/
private String aliases;
/**
* 其他属性JSON格式
*/
private String properties;
/**
* 元数据JSON格式
*/
private Map<String, Object> metadata;
/**
* 备注
*/
private String remark;
}

View File

@@ -1,96 +0,0 @@
package org.ruoyi.domain.bo.graph;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 知识图谱片段实体
*
* @author ruoyi
* @date 2025-09-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("knowledge_base_graph_segment")
public class KnowledgeBaseGraphSegment extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 片段UUID
*/
private String uuid;
/**
* 知识库UUID
*/
private String kbUuid;
/**
* 知识库条目UUID
*/
private String kbItemUuid;
/**
* 文档UUID
*/
private String docUuid;
/**
* 片段文本内容
*/
private String segmentText;
/**
* 片段索引(第几个片段)
*/
private Integer chunkIndex;
/**
* 总片段数
*/
private Integer totalChunks;
/**
* 抽取状态0-待处理 1-处理中 2-已完成 3-失败
*/
private Integer extractionStatus;
/**
* 抽取的实体数量
*/
private Integer entityCount;
/**
* 抽取的关系数量
*/
private Integer relationCount;
/**
* 消耗的token数
*/
private Integer tokenUsed;
/**
* 错误信息
*/
private String errorMessage;
/**
* 用户ID
*/
private Long userId;
}

View File

@@ -14,7 +14,8 @@ public enum ChatModeType {
ZHI_PU("zhipu", "智谱清言"),
DEEP_SEEK("deepseek", "深度求索"),
QIAN_WEN("qianwen", "通义千问"),
OPEN_AI("openai", "openai");
OPEN_AI("openai", "openai"),
PPIO("ppio", "ppio");
private final String code;
private final String description;

View File

@@ -1,78 +0,0 @@
package org.ruoyi.enums;
import lombok.Getter;
/**
* 图谱构建状态枚举
*
* @author ruoyi
* @date 2025-09-30
*/
@Getter
public enum GraphStatusEnum {
/**
* 未构建
*/
NOT_BUILT(0, "未构建", "NOT_BUILT"),
/**
* 构建中
*/
BUILDING(10, "构建中", "BUILDING"),
/**
* 已完成
*/
COMPLETED(20, "已完成", "COMPLETED"),
/**
* 失败
*/
FAILED(30, "失败", "FAILED");
private final Integer code;
private final String description;
private final String statusKey;
GraphStatusEnum(Integer code, String description, String statusKey) {
this.code = code;
this.description = description;
this.statusKey = statusKey;
}
/**
* 根据code获取枚举
*/
public static GraphStatusEnum getByCode(Integer code) {
for (GraphStatusEnum status : values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
/**
* 根据前端状态字符串获取状态码
*/
public static Integer getCodeByStatusKey(String statusKey) {
if (statusKey == null || statusKey.trim().isEmpty()) {
return null;
}
for (GraphStatusEnum status : values()) {
if (status.getStatusKey().equals(statusKey)) {
return status.getCode();
}
}
return null;
}
/**
* 根据状态码获取前端状态字符串
*/
public static String getStatusKeyByCode(Integer code) {
GraphStatusEnum status = getByCode(code);
return status != null ? status.getStatusKey() : "NOT_BUILT";
}
}

View File

@@ -36,17 +36,14 @@ public class EmbeddingModelFactory {
* 如果模型已存在于缓存中,则直接返回;否则创建新的实例
*
* @param embeddingModelName 嵌入模型名称
* @param dimension 模型维度大小
*/
public BaseEmbedModelService createModel(String embeddingModelName, Integer dimension) {
public BaseEmbedModelService createModel(String embeddingModelName) {
return modelCache.computeIfAbsent(embeddingModelName, name -> {
ChatModelVo modelConfig = chatModelService.selectModelByName(embeddingModelName);
if (modelConfig == null) {
throw new IllegalArgumentException("未找到模型配置name=" + name);
}
if (modelConfig.getDimension() != null) {
modelConfig.setDimension(dimension);
}
return createModelInstance(modelConfig.getProviderCode(), modelConfig);
});
}
@@ -58,7 +55,7 @@ public class EmbeddingModelFactory {
* @return boolean 如果模型支持多模态则返回true否则返回false
*/
public boolean isMultimodalModel(String embeddingModelName) {
return createModel(embeddingModelName, null) instanceof MultiModalEmbedModelService;
return createModel(embeddingModelName) instanceof MultiModalEmbedModelService;
}
/**
@@ -69,7 +66,7 @@ public class EmbeddingModelFactory {
* @throws IllegalArgumentException 当模型不支持多模态时抛出
*/
public MultiModalEmbedModelService createMultimodalModel(String embeddingModelName) {
BaseEmbedModelService model = createModel(embeddingModelName, null);
BaseEmbedModelService model = createModel(embeddingModelName);
if (model instanceof MultiModalEmbedModelService) {
return (MultiModalEmbedModelService) model;
}
@@ -113,7 +110,6 @@ public class EmbeddingModelFactory {
// 配置模型参数
model.configure(config);
log.info("成功创建嵌入模型: factory={}, modelId={}", config.getProviderCode(), config.getId());
return model;
} catch (NoSuchBeanDefinitionException e) {
throw new IllegalArgumentException("获取不到嵌入模型: " + factory, e);

View File

@@ -1,82 +0,0 @@
package org.ruoyi.factory;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.service.graph.IGraphLLMService;
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;
/**
* 图谱LLM服务工厂类
* 参考 ruoyi-chat 的 ChatServiceFactory 设计
* 根据模型类别自动选择对应的LLM服务实现
*
* @author ruoyi
* @date 2025-10-11
*/
@Slf4j
@Component
public class GraphLLMServiceFactory implements ApplicationContextAware {
private final Map<String, IGraphLLMService> llmServiceMap = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 初始化时收集所有 IGraphLLMService 的实现
Map<String, IGraphLLMService> serviceMap = applicationContext.getBeansOfType(IGraphLLMService.class);
for (IGraphLLMService service : serviceMap.values()) {
if (service != null) {
String category = service.getCategory();
llmServiceMap.put(category, service);
log.info("注册图谱LLM服务: category={}, service={}",
category, service.getClass().getSimpleName());
}
}
log.info("图谱LLM服务工厂初始化完成共注册 {} 个服务", llmServiceMap.size());
}
/**
* 根据模型类别获取对应的LLM服务实现
*
* @param category 模型类别(如: openai, qwen, zhipu
* @return LLM服务实现
* @throws IllegalArgumentException 如果不支持该类别
*/
public IGraphLLMService getLLMService(String category) {
IGraphLLMService service = llmServiceMap.get(category);
if (service == null) {
log.error("不支持的模型类别: {}, 可用类别: {}", category, llmServiceMap.keySet());
throw new IllegalArgumentException("不支持的模型类别: " + category +
", 可用类别: " + llmServiceMap.keySet());
}
return service;
}
/**
* 获取所有支持的模型类别
*
* @return 模型类别集合
*/
public java.util.Set<String> getSupportedCategories() {
return llmServiceMap.keySet();
}
/**
* 检查是否支持指定的模型类别
*
* @param category 模型类别
* @return 是否支持
*/
public boolean isSupported(String category) {
return llmServiceMap.containsKey(category);
}
}

View File

@@ -1,82 +0,0 @@
package org.ruoyi.listener;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.langchain4j.model.openai.internal.chat.ChatCompletionResponse;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
/**
* 图谱抽取LLM响应监听器
* 用于收集完整的LLM响应非流式
*
* @author ruoyi-ai
*/
@Slf4j
public class GraphExtractionListener extends EventSourceListener {
private final StringBuilder responseBuilder = new StringBuilder();
private final CompletableFuture<String> responseFuture;
private final ObjectMapper objectMapper = new ObjectMapper();
public GraphExtractionListener(CompletableFuture<String> responseFuture) {
this.responseFuture = responseFuture;
}
@Override
public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
log.debug("LLM连接已建立");
}
@Override
public void onEvent(@NotNull EventSource eventSource, String id, String type, @NotNull String data) {
try {
if ("[DONE]".equals(data)) {
// 响应完成,返回完整内容
responseFuture.complete(responseBuilder.toString());
return;
}
// 解析响应
ChatCompletionResponse completionResponse = objectMapper.readValue(data, ChatCompletionResponse.class);
if (completionResponse != null && !completionResponse.choices().isEmpty()) {
Object content = completionResponse.choices().get(0).delta().content();
if (content != null) {
responseBuilder.append(content);
}
}
} catch (Exception e) {
log.error("解析LLM响应失败: {}", e.getMessage(), e);
responseFuture.completeExceptionally(e);
}
}
@Override
public void onClosed(@NotNull EventSource eventSource) {
log.debug("LLM连接已关闭");
// 如果还没有完成,就用当前内容完成
if (!responseFuture.isDone()) {
responseFuture.complete(responseBuilder.toString());
}
}
@Override
public void onFailure(@NotNull EventSource eventSource, Throwable t, Response response) {
String errorMsg = "LLM调用失败";
if (response != null && response.body() != null) {
try {
errorMsg = response.body().string();
} catch (Exception e) {
errorMsg = response.toString();
}
}
log.error("LLM调用失败: {}", errorMsg, t);
responseFuture.completeExceptionally(
new RuntimeException(errorMsg, t)
);
}
}

View File

@@ -1,65 +0,0 @@
package org.ruoyi.mapper.graph;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.ruoyi.domain.bo.graph.GraphBuildTask;
import java.util.List;
/**
* 图谱构建任务Mapper接口
*
* @author ruoyi
* @date 2025-09-30
*/
public interface GraphBuildTaskMapper extends BaseMapper<GraphBuildTask> {
/**
* 根据任务UUID查询
*
* @param taskUuid 任务UUID
* @return 构建任务
*/
GraphBuildTask selectByTaskUuid(String taskUuid);
/**
* 根据图谱UUID查询任务列表
*
* @param graphUuid 图谱UUID
* @return 任务列表
*/
List<GraphBuildTask> selectByGraphUuid(String graphUuid);
/**
* 根据知识库ID查询任务列表
*
* @param knowledgeId 知识库ID
* @return 任务列表
*/
List<GraphBuildTask> selectByKnowledgeId(String knowledgeId);
/**
* 查询待执行和执行中的任务
*
* @return 任务列表
*/
List<GraphBuildTask> selectPendingAndRunningTasks();
/**
* 更新任务进度
*
* @param taskUuid 任务UUID
* @param progress 进度
* @param processedDocs 已处理文档数
* @return 影响行数
*/
int updateProgress(String taskUuid, Integer progress, Integer processedDocs);
/**
* 更新任务状态
*
* @param taskUuid 任务UUID
* @param status 状态
* @return 影响行数
*/
int updateStatus(String taskUuid, Integer status);
}

View File

@@ -1,38 +0,0 @@
package org.ruoyi.mapper.graph;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.ruoyi.domain.bo.graph.GraphEntityType;
import java.util.List;
/**
* 图谱实体类型Mapper接口
*
* @author ruoyi
* @date 2025-09-30
*/
public interface GraphEntityTypeMapper extends BaseMapper<GraphEntityType> {
/**
* 根据类型编码查询
*
* @param typeCode 类型编码
* @return 实体类型
*/
GraphEntityType selectByTypeCode(String typeCode);
/**
* 查询所有启用的实体类型
*
* @return 实体类型列表
*/
List<GraphEntityType> selectEnabledTypes();
/**
* 批量查询实体类型
*
* @param typeCodes 类型编码列表
* @return 实体类型列表
*/
List<GraphEntityType> selectByTypeCodes(List<String> typeCodes);
}

View File

@@ -1,48 +0,0 @@
package org.ruoyi.mapper.graph;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.ruoyi.domain.bo.graph.GraphInstance;
/**
* 知识图谱实例Mapper接口
*
* @author ruoyi
* @date 2025-09-30
*/
public interface GraphInstanceMapper extends BaseMapper<GraphInstance> {
/**
* 根据图谱UUID查询
*
* @param graphUuid 图谱UUID
* @return 图谱实例
*/
GraphInstance selectByGraphUuid(String graphUuid);
/**
* 根据知识库ID查询图谱列表
*
* @param knowledgeId 知识库ID
* @return 图谱实例列表
*/
java.util.List<GraphInstance> selectByKnowledgeId(String knowledgeId);
/**
* 更新节点和关系数量
*
* @param graphUuid 图谱UUID
* @param nodeCount 节点数量
* @param relationshipCount 关系数量
* @return 影响行数
*/
int updateCounts(String graphUuid, Integer nodeCount, Integer relationshipCount);
/**
* 更新图谱状态
*
* @param graphUuid 图谱UUID
* @param status 状态
* @return 影响行数
*/
int updateStatus(String graphUuid, Integer status);
}

View File

@@ -1,38 +0,0 @@
package org.ruoyi.mapper.graph;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.ruoyi.domain.bo.graph.GraphRelationType;
import java.util.List;
/**
* 图谱关系类型Mapper接口
*
* @author ruoyi
* @date 2025-09-30
*/
public interface GraphRelationTypeMapper extends BaseMapper<GraphRelationType> {
/**
* 根据关系编码查询
*
* @param relationCode 关系编码
* @return 关系类型
*/
GraphRelationType selectByRelationCode(String relationCode);
/**
* 查询所有启用的关系类型
*
* @return 关系类型列表
*/
List<GraphRelationType> selectEnabledTypes();
/**
* 批量查询关系类型
*
* @param relationCodes 关系编码列表
* @return 关系类型列表
*/
List<GraphRelationType> selectByRelationCodes(List<String> relationCodes);
}

View File

@@ -148,7 +148,6 @@ public class AgentChatHandler implements ChatHandler {
messageBO.setContent(content);
messageBO.setRole(role);
messageBO.setModelName(chatRequest.getModel());
messageBO.setBillingType(chatModelVo.getModelType());
messageBO.setRemark(null);
chatMessageService.insertByBo(messageBO);

View File

@@ -79,10 +79,8 @@ public class ChatMessageServiceImpl implements IChatMessageService {
lqw.eq(bo.getUserId() != null, ChatMessage::getUserId, bo.getUserId());
lqw.eq(StringUtils.isNotBlank(bo.getContent()), ChatMessage::getContent, bo.getContent());
lqw.eq(StringUtils.isNotBlank(bo.getRole()), ChatMessage::getRole, bo.getRole());
lqw.eq(bo.getDeductCost() != null, ChatMessage::getDeductCost, bo.getDeductCost());
lqw.eq(bo.getTotalTokens() != null, ChatMessage::getTotalTokens, bo.getTotalTokens());
lqw.like(StringUtils.isNotBlank(bo.getModelName()), ChatMessage::getModelName, bo.getModelName());
lqw.eq(StringUtils.isNotBlank(bo.getBillingType()), ChatMessage::getBillingType, bo.getBillingType());
return lqw;
}

View File

@@ -92,11 +92,7 @@ public class ChatModelServiceImpl implements IChatModelService {
lqw.like(StringUtils.isNotBlank(bo.getModelName()), ChatModel::getModelName, bo.getModelName());
lqw.like(StringUtils.isNotBlank(bo.getProviderCode()), ChatModel::getProviderCode, bo.getProviderCode());
lqw.eq(StringUtils.isNotBlank(bo.getModelDescribe()), ChatModel::getModelDescribe, bo.getModelDescribe());
lqw.eq(bo.getModelPrice() != null, ChatModel::getModelPrice, bo.getModelPrice());
lqw.eq(StringUtils.isNotBlank(bo.getModelType()), ChatModel::getModelType, bo.getModelType());
lqw.eq(StringUtils.isNotBlank(bo.getModelShow()), ChatModel::getModelShow, bo.getModelShow());
lqw.eq(StringUtils.isNotBlank(bo.getModelFree()), ChatModel::getModelFree, bo.getModelFree());
lqw.eq(bo.getPriority() != null, ChatModel::getPriority, bo.getPriority());
lqw.eq(StringUtils.isNotBlank(bo.getApiHost()), ChatModel::getApiHost, bo.getApiHost());
lqw.eq(StringUtils.isNotBlank(bo.getApiKey()), ChatModel::getApiKey, bo.getApiKey());
return lqw;

View File

@@ -0,0 +1,50 @@
package org.ruoyi.service.chat.impl.provider;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
import org.ruoyi.enums.ChatModeType;
import org.ruoyi.service.chat.impl.AbstractStreamingChatService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* OPENAI服务调用
*
* @author ageerle@163.com
* @date 2025/12/13
*/
@Service
@Slf4j
public class PPIOServiceImpl extends AbstractStreamingChatService {
@Override
public StreamingChatModel buildStreamingChatModel(ChatModelVo chatModelVo, ChatRequest chatRequest) {
return OpenAiStreamingChatModel.builder()
.baseUrl(chatModelVo.getApiHost())
.apiKey(chatModelVo.getApiKey())
.modelName(chatModelVo.getModelName())
.returnThinking(chatRequest.getEnableThinking())
.build();
}
@Override
public void doChat(ChatModelVo chatModelVo, ChatRequest chatRequest, List<ChatMessage> messagesWithMemory, StreamingChatResponseHandler handler) {
StreamingChatModel streamingChatModel = buildStreamingChatModel(chatModelVo, chatRequest);
streamingChatModel.chat(messagesWithMemory, handler);
}
@Override
public String getProviderName() {
return ChatModeType.PPIO.getCode();
}
}

View File

@@ -38,7 +38,7 @@ public class AliBaiLianBaseEmbedProvider extends OpenAiEmbeddingProvider {
return QwenEmbeddingModel.builder()
.apiKey(chatModelVo.getApiKey())
.modelName(chatModelVo.getModelName())
.dimension(1024)
.dimension(chatModelVo.getModelDimension())
.build()
.embedAll(textSegments);
}

View File

@@ -37,7 +37,7 @@ public class OpenAiEmbeddingProvider implements BaseEmbedModelService {
.baseUrl(chatModelVo.getApiHost())
.apiKey(chatModelVo.getApiKey())
.modelName(chatModelVo.getModelName())
.dimensions(chatModelVo.getDimension())
.dimensions(chatModelVo.getModelDimension())
.build()
.embedAll(textSegments);
}

View File

@@ -0,0 +1,14 @@
package org.ruoyi.service.embed.impl;
import org.springframework.stereotype.Component;
/**
* @Author: Robust_H
* @Date: 2025-09-30-下午3:59
* @Description: 硅基流动(兼容 OpenAi
*/
@Component("ppio")
public class PPIOEmbeddingProvider extends OpenAiEmbeddingProvider {
}

View File

@@ -1,44 +0,0 @@
//package org.ruoyi.service.embed.impl;
//
//import dev.langchain4j.community.model.zhipu.ZhipuAiEmbeddingModel;
//import dev.langchain4j.data.embedding.Embedding;
//import dev.langchain4j.data.segment.TextSegment;
//import dev.langchain4j.model.output.Response;
//import org.ruoyi.domain.vo.chat.ChatModelVo;
//import org.ruoyi.enums.ModalityType;
//import org.ruoyi.service.embed.BaseEmbedModelService;
//import org.springframework.stereotype.Component;
//
//import java.util.List;
//import java.util.Set;
//
///**
// * @Author: Robust_H
// * @Date: 2025-09-30-下午4:02
// * @Description: 智谱AI
// */
//@Component("zhipu")
//public class ZhiPuAiEmbeddingProvider implements BaseEmbedModelService {
// private ChatModelVo chatModelVo;
//
// @Override
// public void configure(ChatModelVo config) {
// this.chatModelVo = config;
// }
//
// @Override
// public Set<ModalityType> getSupportedModalities() {
// return Set.of();
// }
//
// @Override
// public Response<List<Embedding>> embedAll(List<TextSegment> textSegments) {
// return ZhipuAiEmbeddingModel.builder()
// .baseUrl(chatModelVo.getApiHost())
// .apiKey(chatModelVo.getApiKey())
// .model(chatModelVo.getModelName())
// .dimensions(chatModelVo.getDimension())
// .build()
// .embedAll(textSegments);
// }
//}

View File

@@ -1,136 +0,0 @@
package org.ruoyi.service.graph;
import org.ruoyi.domain.bo.graph.GraphBuildTask;
import java.util.List;
/**
* 图谱构建任务服务接口
*
* @author ruoyi
* @date 2025-09-30
*/
public interface IGraphBuildTaskService {
/**
* 创建构建任务
*
* @param graphUuid 图谱UUID
* @param knowledgeId 知识库ID
* @param docId 文档ID可选
* @param taskType 任务类型
* @return 任务信息
*/
GraphBuildTask createTask(String graphUuid, String knowledgeId, String docId, Integer taskType);
/**
* 启动构建任务(异步)
*
* @param taskUuid 任务UUID
* @return 异步结果
*/
void startTask(String taskUuid);
/**
* 根据UUID获取任务
*
* @param taskUuid 任务UUID
* @return 任务信息
*/
GraphBuildTask getByUuid(String taskUuid);
/**
* 根据图谱UUID获取任务列表
*
* @param graphUuid 图谱UUID
* @return 任务列表
*/
List<GraphBuildTask> listByGraphUuid(String graphUuid);
/**
* 获取图谱的最新构建任务
*
* @param graphUuid 图谱UUID
* @return 最新任务
*/
GraphBuildTask getLatestTask(String graphUuid);
/**
* 根据知识库ID获取任务列表
*
* @param knowledgeId 知识库ID
* @return 任务列表
*/
List<GraphBuildTask> listByKnowledgeId(String knowledgeId);
/**
* 获取待执行和执行中的任务
*
* @return 任务列表
*/
List<GraphBuildTask> getPendingAndRunningTasks();
/**
* 更新任务进度
*
* @param taskUuid 任务UUID
* @param progress 进度百分比
* @param processedDocs 已处理文档数
* @return 是否成功
*/
boolean updateProgress(String taskUuid, Integer progress, Integer processedDocs);
/**
* 更新任务状态
*
* @param taskUuid 任务UUID
* @param status 状态
* @return 是否成功
*/
boolean updateStatus(String taskUuid, Integer status);
/**
* 更新提取统计信息
*
* @param taskUuid 任务UUID
* @param extractedEntities 提取的实体数
* @param extractedRelations 提取的关系数
* @return 是否成功
*/
boolean updateExtractionStats(String taskUuid, Integer extractedEntities, Integer extractedRelations);
/**
* 标记任务为成功
*
* @param taskUuid 任务UUID
* @param resultSummary 结果摘要
* @return 是否成功
*/
boolean markSuccess(String taskUuid, String resultSummary);
/**
* 标记任务为失败
*
* @param taskUuid 任务UUID
* @param errorMessage 错误信息
* @return 是否成功
*/
boolean markFailed(String taskUuid, String errorMessage);
/**
* 取消任务
*
* @param taskUuid 任务UUID
* @return 是否成功
*/
boolean cancelTask(String taskUuid);
/**
* 重试失败的任务
*
* @param taskUuid 任务UUID
* @return 新任务UUID
*/
String retryTask(String taskUuid);
}

View File

@@ -1,47 +0,0 @@
package org.ruoyi.service.graph;
import org.ruoyi.domain.dto.GraphExtractionResult;
/**
* 图谱实体关系抽取服务接口
*
* @author ruoyi
* @date 2025-09-30
*/
public interface IGraphExtractionService {
/**
* 从文本中抽取实体和关系
*
* @param text 输入文本
* @return 抽取结果
*/
GraphExtractionResult extractFromText(String text);
/**
* 从文本中抽取实体和关系(自定义实体类型)
*
* @param text 输入文本
* @param entityTypes 实体类型列表
* @return 抽取结果
*/
GraphExtractionResult extractFromText(String text, String[] entityTypes);
/**
* 从文本中抽取实体和关系使用指定的LLM模型
*
* @param text 输入文本
* @param modelName LLM模型名称
* @return 抽取结果
*/
GraphExtractionResult extractFromTextWithModel(String text, String modelName);
/**
* 解析LLM响应为实体和关系
*
* @param response LLM响应文本
* @return 抽取结果
*/
GraphExtractionResult parseGraphResponse(String response);
}

View File

@@ -1,120 +0,0 @@
package org.ruoyi.service.graph;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.ruoyi.domain.bo.graph.GraphInstance;
import java.util.List;
/**
* 图谱实例服务接口
*
* @author ruoyi
* @date 2025-09-30
*/
public interface IGraphInstanceService {
/**
* 创建图谱实例
*
* @param knowledgeId 知识库ID
* @param graphName 图谱名称
* @param config 配置信息
* @return 图谱实例
*/
GraphInstance createInstance(String knowledgeId, String graphName, String config);
/**
* 根据主键ID获取图谱实例
*
* @param id 主键ID
* @return 图谱实例
*/
GraphInstance getById(Long id);
/**
* 根据UUID获取图谱实例
*
* @param graphUuid 图谱UUID
* @return 图谱实例
*/
GraphInstance getByUuid(String graphUuid);
/**
* 更新图谱实例
*
* @param instance 图谱实例
* @return 是否成功
*/
boolean updateInstance(GraphInstance instance);
/**
* 根据知识库ID获取图谱列表
*
* @param knowledgeId 知识库ID
* @return 图谱实例列表
*/
List<GraphInstance> listByKnowledgeId(String knowledgeId);
/**
* 条件查询图谱实例列表(分页)
*
* @param page 分页对象
* @param instanceName 图谱名称(模糊查询)
* @param knowledgeId 知识库ID
* @param graphStatus 图谱状态码
* @return 分页结果
*/
Page<GraphInstance> queryPage(Page<GraphInstance> page, String instanceName, String knowledgeId, Integer graphStatus);
/**
* 更新图谱状态
*
* @param graphUuid 图谱UUID
* @param status 状态
* @return 是否成功
*/
boolean updateStatus(String graphUuid, Integer status);
/**
* 更新图谱统计信息
*
* @param graphUuid 图谱UUID
* @param nodeCount 节点数量
* @param relationshipCount 关系数量
* @return 是否成功
*/
boolean updateCounts(String graphUuid, Integer nodeCount, Integer relationshipCount);
/**
* 更新图谱配置
*
* @param graphUuid 图谱UUID
* @param config 配置信息
* @return 是否成功
*/
boolean updateConfig(String graphUuid, String config);
/**
* 删除图谱实例(软删除)
*
* @param graphUuid 图谱UUID
* @return 是否成功
*/
boolean deleteInstance(String graphUuid);
/**
* 物理删除图谱实例及其数据
*
* @param graphUuid 图谱UUID
* @return 是否成功
*/
boolean deleteInstanceAndData(String graphUuid);
/**
* 获取图谱统计信息
*
* @param graphUuid 图谱UUID
* @return 统计信息
*/
java.util.Map<String, Object> getStatistics(String graphUuid);
}

Some files were not shown because too many files have changed in this diff Show More