Merge branch 'feat-edge-thickness' into merge-edge-thickness

This commit is contained in:
yangdx
2025-04-05 13:06:28 +08:00
9 changed files with 149 additions and 4 deletions

View File

@@ -655,7 +655,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. 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 ```python
rag = LightRAG(..) rag = LightRAG(..)

View File

@@ -36,6 +36,8 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
const enableEdgeEvents = useSettingsStore.use.enableEdgeEvents() const enableEdgeEvents = useSettingsStore.use.enableEdgeEvents()
const renderEdgeLabels = useSettingsStore.use.showEdgeLabel() const renderEdgeLabels = useSettingsStore.use.showEdgeLabel()
const renderLabels = useSettingsStore.use.showNodeLabel() const renderLabels = useSettingsStore.use.showNodeLabel()
const minEdgeSize = useSettingsStore.use.minEdgeSize()
const maxEdgeSize = useSettingsStore.use.maxEdgeSize()
const selectedNode = useGraphStore.use.selectedNode() const selectedNode = useGraphStore.use.selectedNode()
const focusedNode = useGraphStore.use.focusedNode() const focusedNode = useGraphStore.use.focusedNode()
const selectedEdge = useGraphStore.use.selectedEdge() const selectedEdge = useGraphStore.use.selectedEdge()
@@ -136,6 +138,51 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
registerEvents(events) registerEvents(events)
}, [registerEvents, enableEdgeEvents]) }, [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 * When component mount or hovered node change
* => Setting the sigma reducers * => Setting the sigma reducers

View File

@@ -144,6 +144,8 @@ export default function Settings() {
const enableNodeDrag = useSettingsStore.use.enableNodeDrag() const enableNodeDrag = useSettingsStore.use.enableNodeDrag()
const enableHideUnselectedEdges = useSettingsStore.use.enableHideUnselectedEdges() const enableHideUnselectedEdges = useSettingsStore.use.enableHideUnselectedEdges()
const showEdgeLabel = useSettingsStore.use.showEdgeLabel() const showEdgeLabel = useSettingsStore.use.showEdgeLabel()
const minEdgeSize = useSettingsStore.use.minEdgeSize()
const maxEdgeSize = useSettingsStore.use.maxEdgeSize()
const graphQueryMaxDepth = useSettingsStore.use.graphQueryMaxDepth() const graphQueryMaxDepth = useSettingsStore.use.graphQueryMaxDepth()
const graphMaxNodes = useSettingsStore.use.graphMaxNodes() const graphMaxNodes = useSettingsStore.use.graphMaxNodes()
const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations() const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations()
@@ -292,6 +294,40 @@ export default function Settings() {
label={t('graphPanel.sideBar.settings.edgeEvents')} label={t('graphPanel.sideBar.settings.edgeEvents')}
/> />
<div className="flex flex-col gap-2">
<label className="text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{t('graphPanel.sideBar.settings.edgeSizeRange')}
</label>
<div className="flex items-center gap-2">
<Input
type="number"
value={minEdgeSize}
onChange={(e) => {
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}
/>
<span>-</span>
<Input
type="number"
value={maxEdgeSize}
onChange={(e) => {
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}
/>
</div>
</div>
<Separator /> <Separator />
<LabeledNumberInput <LabeledNumberInput
label={t('graphPanel.sideBar.settings.maxQueryDepth')} label={t('graphPanel.sideBar.settings.maxQueryDepth')}

View File

@@ -68,7 +68,13 @@ export type NodeType = {
color: string color: string
highlighted?: boolean highlighted?: boolean
} }
export type EdgeType = { label: string } export type EdgeType = {
label: string
originalWeight?: number
size?: number
color?: string
hidden?: boolean
}
const fetchGraph = async (label: string, maxDepth: number, maxNodes: number) => { const fetchGraph = async (label: string, maxDepth: number, maxNodes: number) => {
let rawData: any = null; let rawData: any = null;
@@ -174,6 +180,9 @@ const fetchGraph = async (label: string, maxDepth: number, maxNodes: number) =>
// Create a new graph instance with the raw graph data // Create a new graph instance with the raw graph data
const createSigmaGraph = (rawGraph: RawGraph | null) => { 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 // Skip graph creation if no data or empty nodes
if (!rawGraph || !rawGraph.nodes.length) { if (!rawGraph || !rawGraph.nodes.length) {
console.log('No graph data available, skipping sigma graph creation'); 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 // Add edges from raw graph data
for (const rawEdge of rawGraph?.edges ?? []) { 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, { 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)
}) })
} }

View File

@@ -157,6 +157,7 @@
"maxNodes": "الحد الأقصى للعقد", "maxNodes": "الحد الأقصى للعقد",
"maxLayoutIterations": "أقصى تكرارات التخطيط", "maxLayoutIterations": "أقصى تكرارات التخطيط",
"resetToDefault": "إعادة التعيين إلى الافتراضي", "resetToDefault": "إعادة التعيين إلى الافتراضي",
"edgeSizeRange": "نطاق حجم الحافة",
"depth": "D", "depth": "D",
"max": "Max", "max": "Max",
"degree": "الدرجة", "degree": "الدرجة",

View File

@@ -157,6 +157,7 @@
"maxNodes": "Max Nodes", "maxNodes": "Max Nodes",
"maxLayoutIterations": "Max Layout Iterations", "maxLayoutIterations": "Max Layout Iterations",
"resetToDefault": "Reset to default", "resetToDefault": "Reset to default",
"edgeSizeRange": "Edge Size Range",
"depth": "D", "depth": "D",
"max": "Max", "max": "Max",
"degree": "Degree", "degree": "Degree",

View File

@@ -157,6 +157,7 @@
"maxNodes": "Nombre maximum de nœuds", "maxNodes": "Nombre maximum de nœuds",
"maxLayoutIterations": "Itérations maximales de mise en page", "maxLayoutIterations": "Itérations maximales de mise en page",
"resetToDefault": "Réinitialiser par défaut", "resetToDefault": "Réinitialiser par défaut",
"edgeSizeRange": "Plage de taille des arêtes",
"depth": "D", "depth": "D",
"max": "Max", "max": "Max",
"degree": "Degré", "degree": "Degré",

View File

@@ -157,6 +157,7 @@
"maxNodes": "最大返回节点数", "maxNodes": "最大返回节点数",
"maxLayoutIterations": "最大布局迭代次数", "maxLayoutIterations": "最大布局迭代次数",
"resetToDefault": "重置为默认值", "resetToDefault": "重置为默认值",
"edgeSizeRange": "边粗细范围",
"depth": "深", "depth": "深",
"max": "Max", "max": "Max",
"degree": "邻边", "degree": "邻边",

View File

@@ -24,6 +24,12 @@ interface SettingsState {
enableHideUnselectedEdges: boolean enableHideUnselectedEdges: boolean
enableEdgeEvents: boolean enableEdgeEvents: boolean
minEdgeSize: number
setMinEdgeSize: (size: number) => void
maxEdgeSize: number
setMaxEdgeSize: (size: number) => void
graphQueryMaxDepth: number graphQueryMaxDepth: number
setGraphQueryMaxDepth: (depth: number) => void setGraphQueryMaxDepth: (depth: number) => void
@@ -76,6 +82,9 @@ const useSettingsStoreBase = create<SettingsState>()(
enableHideUnselectedEdges: true, enableHideUnselectedEdges: true,
enableEdgeEvents: false, enableEdgeEvents: false,
minEdgeSize: 1,
maxEdgeSize: 1,
graphQueryMaxDepth: 3, graphQueryMaxDepth: 3,
graphMaxNodes: 1000, graphMaxNodes: 1000,
graphLayoutMaxIterations: 15, graphLayoutMaxIterations: 15,
@@ -132,6 +141,10 @@ const useSettingsStoreBase = create<SettingsState>()(
setGraphMaxNodes: (nodes: number) => set({ graphMaxNodes: nodes }), setGraphMaxNodes: (nodes: number) => set({ graphMaxNodes: nodes }),
setMinEdgeSize: (size: number) => set({ minEdgeSize: size }),
setMaxEdgeSize: (size: number) => set({ maxEdgeSize: size }),
setEnableHealthCheck: (enable: boolean) => set({ enableHealthCheck: enable }), setEnableHealthCheck: (enable: boolean) => set({ enableHealthCheck: enable }),
setApiKey: (apiKey: string | null) => set({ apiKey }), setApiKey: (apiKey: string | null) => set({ apiKey }),
@@ -150,7 +163,7 @@ const useSettingsStoreBase = create<SettingsState>()(
{ {
name: 'settings-storage', name: 'settings-storage',
storage: createJSONStorage(() => localStorage), storage: createJSONStorage(() => localStorage),
version: 10, version: 11,
migrate: (state: any, version: number) => { migrate: (state: any, version: number) => {
if (version < 2) { if (version < 2) {
state.showEdgeLabel = false state.showEdgeLabel = false
@@ -200,6 +213,10 @@ const useSettingsStoreBase = create<SettingsState>()(
delete state.graphMinDegree // 删除废弃参数 delete state.graphMinDegree // 删除废弃参数
state.graphMaxNodes = 1000 // 添加新参数 state.graphMaxNodes = 1000 // 添加新参数
} }
if (version < 11) {
state.minEdgeSize = 1
state.maxEdgeSize = 1
}
return state return state
} }
} }