mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-09-05 11:01:09 +00:00
feat(web):Add GraphRAG web statics (#1943)
This commit is contained in:
@@ -1,35 +1,18 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Button, Spin } from "antd";
|
||||
import { RollbackOutlined } from "@ant-design/icons";
|
||||
import { apiInterceptors, getGraphVis } from "@/client/api";
|
||||
import { useRouter } from "next/router";
|
||||
import { idOf } from "@antv/g6";
|
||||
import type {
|
||||
Graph,
|
||||
GraphData,
|
||||
GraphOptions,
|
||||
ID,
|
||||
IPointerEvent,
|
||||
PluginOptions,
|
||||
} from "@antv/g6";
|
||||
import type { GraphVisResult } from "../../../types/knowledge";
|
||||
import { Graphin } from "@antv/graphin";
|
||||
import { getDegree, getSize, isInCommunity } from "../../../utils/graph";
|
||||
import { groupBy } from "lodash";
|
||||
import { apiInterceptors, getGraphVis } from '@/client/api';
|
||||
import { RollbackOutlined } from '@ant-design/icons';
|
||||
import type { Graph, GraphData, GraphOptions, ID, IPointerEvent, PluginOptions } from '@antv/g6';
|
||||
import { idOf } from '@antv/g6';
|
||||
import { Graphin } from '@antv/graphin';
|
||||
import { Button, Spin } from 'antd';
|
||||
import { groupBy } from 'lodash';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import type { GraphVisResult } from '../../../types/knowledge';
|
||||
import { getDegree, getSize, isInCommunity } from '../../../utils/graph';
|
||||
|
||||
type GraphVisData = GraphVisResult | null;
|
||||
|
||||
const PALETTE = [
|
||||
"#5F95FF",
|
||||
"#61DDAA",
|
||||
"#F6BD16",
|
||||
"#7262FD",
|
||||
"#78D3F8",
|
||||
"#9661BC",
|
||||
"#F6903D",
|
||||
"#008685",
|
||||
"#F08BB4",
|
||||
];
|
||||
const PALETTE = ['#5F95FF', '#61DDAA', '#F6BD16', '#7262FD', '#78D3F8', '#9661BC', '#F6903D', '#008685', '#F08BB4'];
|
||||
|
||||
function GraphVis() {
|
||||
const LIMIT = 500;
|
||||
@@ -39,17 +22,15 @@ function GraphVis() {
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
|
||||
const fetchGraphVis = async () => {
|
||||
const [_, data] = await apiInterceptors(
|
||||
getGraphVis(spaceName as string, { limit: LIMIT })
|
||||
);
|
||||
const [_, data] = await apiInterceptors(getGraphVis(spaceName as string, { limit: LIMIT }));
|
||||
setData(data);
|
||||
};
|
||||
|
||||
const transformData = (data: GraphVisData): GraphData => {
|
||||
if (!data) return { nodes: [], edges: [] };
|
||||
|
||||
const nodes = data.nodes.map((node) => ({ id: node.id, data: node }));
|
||||
const edges = data.edges.map((edge) => ({
|
||||
const nodes = data.nodes.map(node => ({ id: node.id, data: node }));
|
||||
const edges = data.edges.map(edge => ({
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
data: edge,
|
||||
@@ -74,19 +55,14 @@ function GraphVis() {
|
||||
|
||||
useEffect(() => {
|
||||
if (isReady && graphRef.current) {
|
||||
const groupedNodes = groupBy(
|
||||
graphData.nodes,
|
||||
(node) => node.data!.communityId
|
||||
);
|
||||
const groupedNodes = groupBy(graphData.nodes, node => node.data!.communityId);
|
||||
const plugins: PluginOptions = [];
|
||||
Object.entries(groupedNodes).forEach(([key, nodes]) => {
|
||||
if (!key || nodes.length < 2) return;
|
||||
const color = graphRef.current?.getElementRenderStyle(
|
||||
idOf(nodes[0])
|
||||
).fill;
|
||||
const color = graphRef.current?.getElementRenderStyle(idOf(nodes[0])).fill;
|
||||
plugins.push({
|
||||
key,
|
||||
type: "bubble-sets",
|
||||
type: 'bubble-sets',
|
||||
members: nodes.map(idOf),
|
||||
stroke: color,
|
||||
fill: color,
|
||||
@@ -94,7 +70,7 @@ function GraphVis() {
|
||||
});
|
||||
});
|
||||
|
||||
graphRef.current.setPlugins((prev) => [...prev, ...plugins]);
|
||||
graphRef.current.setPlugins(prev => [...prev, ...plugins]);
|
||||
}
|
||||
}, [isReady]);
|
||||
|
||||
@@ -109,9 +85,9 @@ function GraphVis() {
|
||||
|
||||
const options: GraphOptions = {
|
||||
data: graphData,
|
||||
autoFit: "center",
|
||||
autoFit: 'center',
|
||||
node: {
|
||||
style: (d) => {
|
||||
style: d => {
|
||||
const style = {
|
||||
size: getNodeSize(idOf(d)),
|
||||
label: true,
|
||||
@@ -119,14 +95,14 @@ function GraphVis() {
|
||||
labelText: d.data?.name as string,
|
||||
labelFontSize: 10,
|
||||
labelBackground: true,
|
||||
labelBackgroundFill: "#e5e7eb",
|
||||
labelBackgroundFill: '#e5e7eb',
|
||||
labelPadding: [0, 6],
|
||||
labelBackgroundRadius: 4,
|
||||
labelMaxWidth: "400%",
|
||||
labelMaxWidth: '400%',
|
||||
labelWordWrap: true,
|
||||
};
|
||||
if (!isInCommunity(graphData, idOf(d))) {
|
||||
Object.assign(style, { fill: "#b0b0b0" });
|
||||
Object.assign(style, { fill: '#b0b0b0' });
|
||||
}
|
||||
return style;
|
||||
},
|
||||
@@ -135,40 +111,40 @@ function GraphVis() {
|
||||
lineWidth: 2,
|
||||
labelWordWrap: false,
|
||||
labelFontSize: 12,
|
||||
labelFontWeight: "bold",
|
||||
labelFontWeight: 'bold',
|
||||
},
|
||||
inactive: {
|
||||
label: false,
|
||||
},
|
||||
},
|
||||
palette: {
|
||||
type: "group",
|
||||
field: "communityId",
|
||||
type: 'group',
|
||||
field: 'communityId',
|
||||
color: PALETTE,
|
||||
},
|
||||
},
|
||||
edge: {
|
||||
style: {
|
||||
lineWidth: 1,
|
||||
stroke: "#e2e2e2",
|
||||
stroke: '#e2e2e2',
|
||||
endArrow: true,
|
||||
endArrowType: "vee",
|
||||
endArrowType: 'vee',
|
||||
label: true,
|
||||
labelFontSize: 8,
|
||||
labelBackground: true,
|
||||
labelText: (e) => e.data!.name as string,
|
||||
labelBackgroundFill: "#e5e7eb",
|
||||
labelText: e => e.data!.name as string,
|
||||
labelBackgroundFill: '#e5e7eb',
|
||||
labelPadding: [0, 6],
|
||||
labelBackgroundRadius: 4,
|
||||
labelMaxWidth: "60%",
|
||||
labelMaxWidth: '60%',
|
||||
labelWordWrap: true,
|
||||
},
|
||||
state: {
|
||||
active: {
|
||||
stroke: "#b0b0b0",
|
||||
stroke: '#b0b0b0',
|
||||
labelWordWrap: false,
|
||||
labelFontSize: 10,
|
||||
labelFontWeight: "bold",
|
||||
labelFontWeight: 'bold',
|
||||
},
|
||||
inactive: {
|
||||
label: false,
|
||||
@@ -176,52 +152,46 @@ function GraphVis() {
|
||||
},
|
||||
},
|
||||
behaviors: [
|
||||
"drag-canvas",
|
||||
"zoom-canvas",
|
||||
"drag-element",
|
||||
'drag-canvas',
|
||||
'zoom-canvas',
|
||||
'drag-element',
|
||||
{
|
||||
type: "hover-activate",
|
||||
type: 'hover-activate',
|
||||
degree: 1,
|
||||
state: "active",
|
||||
enable: (event: IPointerEvent) => ["node"].includes(event.targetType),
|
||||
state: 'active',
|
||||
enable: (event: IPointerEvent) => ['node'].includes(event.targetType),
|
||||
},
|
||||
],
|
||||
animation: false,
|
||||
layout: {
|
||||
type: "force",
|
||||
type: 'force',
|
||||
preventOverlap: true,
|
||||
nodeSize: (d) => getNodeSize(d?.id as ID),
|
||||
linkDistance: (edge) => {
|
||||
nodeSize: d => getNodeSize(d?.id as ID),
|
||||
linkDistance: edge => {
|
||||
const { source, target } = edge as { source: ID; target: ID };
|
||||
const nodeSize = Math.min(getNodeSize(source), getNodeSize(target));
|
||||
const degree = Math.min(getNodeDegree(source), getNodeDegree(target));
|
||||
return degree === 1
|
||||
? nodeSize * 2
|
||||
: Math.min(degree * nodeSize * 1.5, 700);
|
||||
return degree === 1 ? nodeSize * 2 : Math.min(degree * nodeSize * 1.5, 700);
|
||||
},
|
||||
},
|
||||
transforms: ["process-parallel-edges"],
|
||||
transforms: ['process-parallel-edges'],
|
||||
};
|
||||
|
||||
if (!data) return <Spin className="h-full justify-center content-center" />;
|
||||
if (!data) return <Spin className='h-full justify-center content-center' />;
|
||||
|
||||
return (
|
||||
<div className="p-4 h-full overflow-y-scroll relative px-2">
|
||||
<div className='p-4 h-full overflow-y-scroll relative px-2'>
|
||||
<Graphin
|
||||
ref={(ref) => {
|
||||
ref={ref => {
|
||||
graphRef.current = ref;
|
||||
}}
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
options={options}
|
||||
onReady={() => {
|
||||
setIsReady(true);
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{ background: "#fff" }}
|
||||
onClick={back}
|
||||
icon={<RollbackOutlined />}
|
||||
>
|
||||
<Button style={{ background: '#fff' }} onClick={back} icon={<RollbackOutlined />}>
|
||||
Back
|
||||
</Button>
|
||||
</Graphin>
|
||||
|
Reference in New Issue
Block a user