重构图谱系统架构,引入适配器模式支持多种图数据库类型。主要变更包括: 1. 新增 GraphAdapter 基类及 LightRAG/Upload 适配器实现 2. 重构前端组件结构,新增 GraphDetailPanel 等可复用组件 3. 实现 useGraph 组合式函数统一管理图谱状态 4. 优化 Neo4j 节点/边数据标准化处理 5. 新增统一图谱 API 接口及对应测试用例 6. 改进前端交互体验,增加节点详情展示等功能 前端组件库重构为模块化结构,提升代码复用性。适配器模式使系统可灵活支持不同图数据源,为后续扩展奠定基础。 Next:上传图谱文件的时候,支持属性解析
243 lines
7.5 KiB
JavaScript
243 lines
7.5 KiB
JavaScript
import { apiGet, apiPost } from './base'
|
||
|
||
/**
|
||
* 图数据库API模块
|
||
* 包含LightRAG图知识库和Neo4j图数据库两种接口
|
||
* 采用命名空间分组模式,清晰区分接口类型
|
||
*/
|
||
|
||
// =============================================================================
|
||
// === 统一图谱接口 (Unified Graph API) ===
|
||
// =============================================================================
|
||
|
||
export const unifiedApi = {
|
||
/**
|
||
* 获取所有可用的知识图谱列表
|
||
* @returns {Promise} - 图谱列表
|
||
*/
|
||
getGraphs: async () => {
|
||
return await apiGet('/api/graph/list', {}, true)
|
||
},
|
||
|
||
/**
|
||
* 获取子图数据 (统一接口)
|
||
* @param {Object} params - 查询参数
|
||
* @param {string} params.db_id - 图谱ID
|
||
* @param {string} params.node_label - 节点标签/关键词
|
||
* @param {number} params.max_depth - 最大深度
|
||
* @param {number} params.max_nodes - 最大节点数
|
||
* @returns {Promise} - 子图数据
|
||
*/
|
||
getSubgraph: async (params) => {
|
||
const { db_id, node_label = "*", max_depth = 2, max_nodes = 100 } = params
|
||
|
||
if (!db_id) {
|
||
throw new Error('db_id is required')
|
||
}
|
||
|
||
const queryParams = new URLSearchParams({
|
||
db_id: db_id,
|
||
node_label: node_label,
|
||
max_depth: max_depth.toString(),
|
||
max_nodes: max_nodes.toString()
|
||
})
|
||
|
||
return await apiGet(`/api/graph/subgraph?${queryParams.toString()}`, {}, true)
|
||
},
|
||
|
||
/**
|
||
* 获取图谱统计信息 (统一接口)
|
||
* @param {string} db_id - 图谱ID
|
||
* @returns {Promise} - 统计信息
|
||
*/
|
||
getStats: async (db_id) => {
|
||
if (!db_id) {
|
||
throw new Error('db_id is required')
|
||
}
|
||
|
||
const queryParams = new URLSearchParams({
|
||
db_id: db_id
|
||
})
|
||
|
||
return await apiGet(`/api/graph/stats?${queryParams.toString()}`, {}, true)
|
||
},
|
||
|
||
/**
|
||
* 获取图谱标签列表 (统一接口)
|
||
* @param {string} db_id - 图谱ID
|
||
* @returns {Promise} - 标签列表
|
||
*/
|
||
getLabels: async (db_id) => {
|
||
if (!db_id) {
|
||
throw new Error('db_id is required')
|
||
}
|
||
|
||
const queryParams = new URLSearchParams({
|
||
db_id: db_id
|
||
})
|
||
|
||
return await apiGet(`/api/graph/labels?${queryParams.toString()}`, {}, true)
|
||
}
|
||
}
|
||
|
||
|
||
// =============================================================================
|
||
// === Neo4j图数据库接口分组 ===
|
||
// =============================================================================
|
||
|
||
export const neo4jApi = {
|
||
/**
|
||
* 获取Neo4j图数据库样例节点
|
||
* @param {string} kgdb_name - Neo4j数据库名称(默认为'neo4j')
|
||
* @param {number} num - 节点数量
|
||
* @returns {Promise} - 样例节点数据
|
||
*/
|
||
getSampleNodes: async (kgdb_name = 'neo4j', num = 100) => {
|
||
const queryParams = new URLSearchParams({
|
||
kgdb_name: kgdb_name,
|
||
num: num.toString()
|
||
})
|
||
|
||
return await apiGet(`/api/graph/neo4j/nodes?${queryParams.toString()}`, {}, true)
|
||
},
|
||
|
||
/**
|
||
* 根据实体名称查询Neo4j图节点
|
||
* @param {string} entity_name - 实体名称
|
||
* @returns {Promise} - 节点数据
|
||
*/
|
||
queryNode: async (entity_name) => {
|
||
if (!entity_name) {
|
||
throw new Error('entity_name is required')
|
||
}
|
||
|
||
const queryParams = new URLSearchParams({
|
||
entity_name: entity_name
|
||
})
|
||
|
||
return await apiGet(`/api/graph/neo4j/node?${queryParams.toString()}`, {}, true)
|
||
},
|
||
|
||
/**
|
||
* 通过JSONL文件添加图谱实体到Neo4j
|
||
* @param {string} file_path - JSONL文件路径
|
||
* @param {string} kgdb_name - Neo4j数据库名称(默认为'neo4j')
|
||
* @returns {Promise} - 添加结果
|
||
*/
|
||
addEntities: async (file_path, kgdb_name = 'neo4j') => {
|
||
return await apiPost('/api/graph/neo4j/add-entities', {
|
||
file_path: file_path,
|
||
kgdb_name: kgdb_name
|
||
}, {}, true)
|
||
},
|
||
|
||
/**
|
||
* 为Neo4j图谱节点添加嵌入向量索引
|
||
* @param {string} kgdb_name - Neo4j数据库名称(默认为'neo4j')
|
||
* @returns {Promise} - 索引结果
|
||
*/
|
||
indexEntities: async (kgdb_name = 'neo4j') => {
|
||
return await apiPost('/api/graph/neo4j/index-entities', {
|
||
kgdb_name: kgdb_name
|
||
}, {}, true)
|
||
},
|
||
|
||
/**
|
||
* 获取Neo4j图数据库信息
|
||
* @returns {Promise} - 图数据库信息
|
||
*/
|
||
getInfo: async () => {
|
||
return await apiGet('/api/graph/neo4j/info', {}, true)
|
||
}
|
||
}
|
||
|
||
// =============================================================================
|
||
// === 工具函数分组 ===
|
||
// =============================================================================
|
||
|
||
/**
|
||
* 根据实体类型获取颜色
|
||
* @param {string} entityType - 实体类型
|
||
* @returns {string} - 颜色值
|
||
*/
|
||
export const getEntityTypeColor = (entityType) => {
|
||
const colorMap = {
|
||
'person': '#FF6B6B', // 红色 - 人物
|
||
'organization': '#4ECDC4', // 青色 - 组织
|
||
'location': '#45B7D1', // 蓝色 - 地点
|
||
'geo': '#45B7D1', // 蓝色 - 地理位置
|
||
'event': '#96CEB4', // 绿色 - 事件
|
||
'category': '#FFEAA7', // 黄色 - 分类
|
||
'equipment': '#DDA0DD', // 紫色 - 设备
|
||
'athlete': '#FF7675', // 红色 - 运动员
|
||
'record': '#FD79A8', // 粉色 - 记录
|
||
'year': '#FDCB6E', // 橙色 - 年份
|
||
'UNKNOWN': '#B2BEC3', // 灰色 - 未知
|
||
'unknown': '#B2BEC3' // 灰色 - 未知
|
||
}
|
||
|
||
return colorMap[entityType] || colorMap['unknown']
|
||
}
|
||
|
||
/**
|
||
* 根据权重计算边的粗细
|
||
* @param {number} weight - 权重值
|
||
* @param {number} minWeight - 最小权重
|
||
* @param {number} maxWeight - 最大权重
|
||
* @returns {number} - 边的粗细
|
||
*/
|
||
export const calculateEdgeWidth = (weight, minWeight = 1, maxWeight = 10) => {
|
||
const minWidth = 1
|
||
const maxWidth = 5
|
||
const normalizedWeight = (weight - minWeight) / (maxWeight - minWeight)
|
||
return minWidth + normalizedWeight * (maxWidth - minWidth)
|
||
}
|
||
|
||
// =============================================================================
|
||
// === 兼容性导出(可选,用于平滑迁移)===
|
||
// =============================================================================
|
||
|
||
// 保持向后兼容的导出,后续可以移除
|
||
export const getGraphNodes = async (params = {}) => {
|
||
console.warn('getGraphNodes is deprecated, use neo4jApi.getSampleNodes instead')
|
||
return neo4jApi.getSampleNodes(params.kgdb_name || 'neo4j', params.num || 100)
|
||
}
|
||
|
||
export const getGraphNode = async (params = {}) => {
|
||
console.warn('getGraphNode is deprecated, use neo4jApi.queryNode instead')
|
||
return neo4jApi.queryNode(params.entity_name)
|
||
}
|
||
|
||
export const addByJsonl = async (file_path, kgdb_name = 'neo4j') => {
|
||
console.warn('addByJsonl is deprecated, use neo4jApi.addEntities instead')
|
||
return neo4jApi.addEntities(file_path, kgdb_name)
|
||
}
|
||
|
||
export const indexNodes = async (kgdb_name = 'neo4j') => {
|
||
console.warn('indexNodes is deprecated, use neo4jApi.indexEntities instead')
|
||
return neo4jApi.indexEntities(kgdb_name)
|
||
}
|
||
|
||
export const getGraphStats = async () => {
|
||
console.warn('getGraphStats is deprecated, use neo4jApi.getInfo instead')
|
||
return neo4jApi.getInfo()
|
||
}
|
||
|
||
// 兼容性导出 - 使用统一接口替代旧有的 graphApi
|
||
export const graphApi = {
|
||
// 使用统一接口替代 LightRAG 接口
|
||
getSubgraph: unifiedApi.getSubgraph,
|
||
getDatabases: async () => {
|
||
// 使用统一接口获取所有图谱,然后过滤出 LightRAG 类型的
|
||
const response = await unifiedApi.getGraphs()
|
||
if (response.success) {
|
||
const lightragDbs = response.data.filter(graph => graph.type === 'lightrag')
|
||
return { success: true, data: { databases: lightragDbs } }
|
||
}
|
||
return response
|
||
},
|
||
getLabels: unifiedApi.getLabels,
|
||
getStats: unifiedApi.getStats,
|
||
// 保留 Neo4j 接口
|
||
...neo4jApi
|
||
} |