From cd3817ce30ede239fd15877d6b59002ca8d37ee5 Mon Sep 17 00:00:00 2001 From: choizhang Date: Tue, 1 Apr 2025 00:36:32 +0800 Subject: [PATCH 1/4] feat (graph settings): Add edge thickness range configuration function --- .../src/components/graph/GraphControl.tsx | 47 +++++++++++++++++++ .../src/components/graph/Settings.tsx | 36 ++++++++++++++ lightrag_webui/src/hooks/useLightragGraph.tsx | 45 +++++++++++++++++- lightrag_webui/src/lib/constants.ts | 2 +- lightrag_webui/src/locales/en.json | 1 + lightrag_webui/src/locales/zh.json | 1 + lightrag_webui/src/stores/settings.ts | 17 +++++++ 7 files changed, 146 insertions(+), 3 deletions(-) diff --git a/lightrag_webui/src/components/graph/GraphControl.tsx b/lightrag_webui/src/components/graph/GraphControl.tsx index baa98bfe..aca8a9c4 100644 --- a/lightrag_webui/src/components/graph/GraphControl.tsx +++ b/lightrag_webui/src/components/graph/GraphControl.tsx @@ -36,6 +36,8 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean }) const enableEdgeEvents = useSettingsStore.use.enableEdgeEvents() const renderEdgeLabels = useSettingsStore.use.showEdgeLabel() const renderLabels = useSettingsStore.use.showNodeLabel() + const minEdgeSize = useSettingsStore.use.minEdgeSize() + const maxEdgeSize = useSettingsStore.use.maxEdgeSize() const selectedNode = useGraphStore.use.selectedNode() const focusedNode = useGraphStore.use.focusedNode() const selectedEdge = useGraphStore.use.selectedEdge() @@ -136,6 +138,51 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean }) registerEvents(events) }, [registerEvents, enableEdgeEvents]) + /** + * When edge size settings change, recalculate edge sizes and refresh the sigma instance + * to ensure changes take effect immediately + */ + useEffect(() => { + if (sigma && sigmaGraph) { + // Get the graph from sigma + const graph = sigma.getGraph() + + // Find min and max weight values + let minWeight = Number.MAX_SAFE_INTEGER + let maxWeight = 0 + + graph.forEachEdge(edge => { + // Get original weight (before scaling) + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + if (typeof weight === 'number') { + minWeight = Math.min(minWeight, weight) + maxWeight = Math.max(maxWeight, weight) + } + }) + + // Scale edge sizes based on weight range and current min/max edge size settings + const weightRange = maxWeight - minWeight + if (weightRange > 0) { + const sizeScale = maxEdgeSize - minEdgeSize + graph.forEachEdge(edge => { + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + if (typeof weight === 'number') { + const scaledSize = minEdgeSize + sizeScale * Math.pow((weight - minWeight) / weightRange, 0.5) + graph.setEdgeAttribute(edge, 'size', scaledSize) + } + }) + } else { + // If all weights are the same, use default size + graph.forEachEdge(edge => { + graph.setEdgeAttribute(edge, 'size', minEdgeSize) + }) + } + + // Refresh the sigma instance to apply changes + sigma.refresh() + } + }, [sigma, sigmaGraph, minEdgeSize, maxEdgeSize]) + /** * When component mount or hovered node change * => Setting the sigma reducers diff --git a/lightrag_webui/src/components/graph/Settings.tsx b/lightrag_webui/src/components/graph/Settings.tsx index 1989a01e..b2f46203 100644 --- a/lightrag_webui/src/components/graph/Settings.tsx +++ b/lightrag_webui/src/components/graph/Settings.tsx @@ -120,6 +120,8 @@ export default function Settings() { const enableNodeDrag = useSettingsStore.use.enableNodeDrag() const enableHideUnselectedEdges = useSettingsStore.use.enableHideUnselectedEdges() const showEdgeLabel = useSettingsStore.use.showEdgeLabel() + const minEdgeSize = useSettingsStore.use.minEdgeSize() + const maxEdgeSize = useSettingsStore.use.maxEdgeSize() const graphQueryMaxDepth = useSettingsStore.use.graphQueryMaxDepth() const graphMinDegree = useSettingsStore.use.graphMinDegree() const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations() @@ -269,6 +271,40 @@ export default function Settings() { label={t('graphPanel.sideBar.settings.edgeEvents')} /> +
+ +
+ { + const newValue = Number(e.target.value); + if (!isNaN(newValue) && newValue >= 1 && newValue <= maxEdgeSize) { + useSettingsStore.setState({ minEdgeSize: newValue }); + } + }} + className="h-6 w-16 min-w-0 pr-1" + min={1} + max={maxEdgeSize} + /> + - + { + const newValue = Number(e.target.value); + if (!isNaN(newValue) && newValue >= minEdgeSize && newValue >= 1) { + useSettingsStore.setState({ maxEdgeSize: newValue }); + } + }} + className="h-6 w-16 min-w-0 pr-1" + min={minEdgeSize} + /> +
+
+ { let rawData: any = null; @@ -174,6 +180,9 @@ const fetchGraph = async (label: string, maxDepth: number, minDegree: number) => // Create a new graph instance with the raw graph data const createSigmaGraph = (rawGraph: RawGraph | null) => { + // Get edge size settings from store + const minEdgeSize = useSettingsStore.getState().minEdgeSize + const maxEdgeSize = useSettingsStore.getState().maxEdgeSize // Skip graph creation if no data or empty nodes if (!rawGraph || !rawGraph.nodes.length) { console.log('No graph data available, skipping sigma graph creation'); @@ -204,8 +213,40 @@ const createSigmaGraph = (rawGraph: RawGraph | null) => { // Add edges from raw graph data for (const rawEdge of rawGraph?.edges ?? []) { + // Get weight from edge properties or default to 1 + const weight = rawEdge.properties?.weight !== undefined ? Number(rawEdge.properties.weight) : 1 + rawEdge.dynamicId = graph.addDirectedEdge(rawEdge.source, rawEdge.target, { - label: rawEdge.properties?.keywords || undefined + label: rawEdge.properties?.keywords || undefined, + size: weight, // Set initial size based on weight + originalWeight: weight, // Store original weight for recalculation + }) + } + + // Calculate edge size based on weight range, similar to node size calculation + let minWeight = Number.MAX_SAFE_INTEGER + let maxWeight = 0 + + // Find min and max weight values + graph.forEachEdge(edge => { + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + minWeight = Math.min(minWeight, weight) + maxWeight = Math.max(maxWeight, weight) + }) + + // Scale edge sizes based on weight range + const weightRange = maxWeight - minWeight + if (weightRange > 0) { + const sizeScale = maxEdgeSize - minEdgeSize + graph.forEachEdge(edge => { + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + const scaledSize = minEdgeSize + sizeScale * Math.pow((weight - minWeight) / weightRange, 0.5) + graph.setEdgeAttribute(edge, 'size', scaledSize) + }) + } else { + // If all weights are the same, use default size + graph.forEachEdge(edge => { + graph.setEdgeAttribute(edge, 'size', minEdgeSize) }) } diff --git a/lightrag_webui/src/lib/constants.ts b/lightrag_webui/src/lib/constants.ts index 048ae8f7..87db8cea 100644 --- a/lightrag_webui/src/lib/constants.ts +++ b/lightrag_webui/src/lib/constants.ts @@ -1,6 +1,6 @@ import { ButtonVariantType } from '@/components/ui/Button' -export const backendBaseUrl = '' +export const backendBaseUrl = 'http://localhost:9621' export const webuiPrefix = '/webui/' export const controlButtonVariant: ButtonVariantType = 'ghost' diff --git a/lightrag_webui/src/locales/en.json b/lightrag_webui/src/locales/en.json index d7c68c73..53505eb6 100644 --- a/lightrag_webui/src/locales/en.json +++ b/lightrag_webui/src/locales/en.json @@ -141,6 +141,7 @@ "maxQueryDepth": "Max Query Depth", "minDegree": "Minimum Degree", "maxLayoutIterations": "Max Layout Iterations", + "edgeSizeRange": "Edge Size Range", "depth": "Depth", "degree": "Degree", "apiKey": "API Key", diff --git a/lightrag_webui/src/locales/zh.json b/lightrag_webui/src/locales/zh.json index bd1a1841..7ff58d5d 100644 --- a/lightrag_webui/src/locales/zh.json +++ b/lightrag_webui/src/locales/zh.json @@ -141,6 +141,7 @@ "maxQueryDepth": "最大查询深度", "minDegree": "最小邻边数", "maxLayoutIterations": "最大布局迭代次数", + "edgeSizeRange": "边粗细范围", "depth": "深度", "degree": "邻边", "apiKey": "API密钥", diff --git a/lightrag_webui/src/stores/settings.ts b/lightrag_webui/src/stores/settings.ts index 311e5061..0acbbb86 100644 --- a/lightrag_webui/src/stores/settings.ts +++ b/lightrag_webui/src/stores/settings.ts @@ -24,6 +24,12 @@ interface SettingsState { enableHideUnselectedEdges: boolean enableEdgeEvents: boolean + minEdgeSize: number + setMinEdgeSize: (size: number) => void + + maxEdgeSize: number + setMaxEdgeSize: (size: number) => void + graphQueryMaxDepth: number setGraphQueryMaxDepth: (depth: number) => void @@ -76,6 +82,9 @@ const useSettingsStoreBase = create()( enableHideUnselectedEdges: true, enableEdgeEvents: false, + minEdgeSize: 1, + maxEdgeSize: 1, + graphQueryMaxDepth: 3, graphMinDegree: 0, graphLayoutMaxIterations: 15, @@ -132,6 +141,10 @@ const useSettingsStoreBase = create()( setGraphMinDegree: (degree: number) => set({ graphMinDegree: degree }), + setMinEdgeSize: (size: number) => set({ minEdgeSize: size }), + + setMaxEdgeSize: (size: number) => set({ maxEdgeSize: size }), + setEnableHealthCheck: (enable: boolean) => set({ enableHealthCheck: enable }), setApiKey: (apiKey: string | null) => set({ apiKey }), @@ -196,6 +209,10 @@ const useSettingsStoreBase = create()( if (version < 9) { state.showFileName = false } + if (version < 10) { + state.minEdgeSize = 1 + state.maxEdgeSize = 1 + } return state } } From 109b2d3a4103c103e12527218b58bb235b44870a Mon Sep 17 00:00:00 2001 From: choizhang Date: Tue, 1 Apr 2025 00:39:37 +0800 Subject: [PATCH 2/4] docs: Fix spelling errors in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c8861a2..68e601d0 100644 --- a/README.md +++ b/README.md @@ -607,7 +607,7 @@ The `apipeline_enqueue_documents` and `apipeline_process_enqueue_documents` func This is useful for scenarios where you want to process documents in the background while still allowing the main thread to continue executing. -And using a routine to process news documents. +And using a routine to process new documents. ```python rag = LightRAG(..) From 7831f49665ef8db3cc271eecebbb680761217690 Mon Sep 17 00:00:00 2001 From: choizhang Date: Tue, 1 Apr 2025 00:52:11 +0800 Subject: [PATCH 3/4] docs(locales): Add translation for edgeSizeRange --- lightrag_webui/src/locales/ar.json | 1 + lightrag_webui/src/locales/fr.json | 1 + 2 files changed, 2 insertions(+) diff --git a/lightrag_webui/src/locales/ar.json b/lightrag_webui/src/locales/ar.json index d7cff8e3..04dc755e 100644 --- a/lightrag_webui/src/locales/ar.json +++ b/lightrag_webui/src/locales/ar.json @@ -141,6 +141,7 @@ "maxQueryDepth": "أقصى عمق للاستعلام", "minDegree": "الدرجة الدنيا", "maxLayoutIterations": "أقصى تكرارات التخطيط", + "edgeSizeRange": "نطاق حجم الحافة", "depth": "العمق", "degree": "الدرجة", "apiKey": "مفتاح واجهة برمجة التطبيقات", diff --git a/lightrag_webui/src/locales/fr.json b/lightrag_webui/src/locales/fr.json index f40d43f6..d7c31bfb 100644 --- a/lightrag_webui/src/locales/fr.json +++ b/lightrag_webui/src/locales/fr.json @@ -141,6 +141,7 @@ "maxQueryDepth": "Profondeur maximale de la requête", "minDegree": "Degré minimum", "maxLayoutIterations": "Itérations maximales de mise en page", + "edgeSizeRange": "Plage de taille des arêtes", "depth": "Profondeur", "degree": "Degré", "apiKey": "Clé API", From e04670d8e63f1a7c09c157cf1db0d24ba40da6d8 Mon Sep 17 00:00:00 2001 From: choizhang Date: Tue, 1 Apr 2025 00:59:15 +0800 Subject: [PATCH 4/4] refactor: constants --- lightrag_webui/src/lib/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lightrag_webui/src/lib/constants.ts b/lightrag_webui/src/lib/constants.ts index 87db8cea..048ae8f7 100644 --- a/lightrag_webui/src/lib/constants.ts +++ b/lightrag_webui/src/lib/constants.ts @@ -1,6 +1,6 @@ import { ButtonVariantType } from '@/components/ui/Button' -export const backendBaseUrl = 'http://localhost:9621' +export const backendBaseUrl = '' export const webuiPrefix = '/webui/' export const controlButtonVariant: ButtonVariantType = 'ghost'