From d52b6bead10d2486f07a712aeef944c4d5ed08c7 Mon Sep 17 00:00:00 2001 From: yangdx Date: Wed, 5 Mar 2025 10:39:27 +0800 Subject: [PATCH] Refactor graph search and add local Vite config. - Simplify graph search parameters in API - Add inclusive search and min degree options - Update Vite config for local development - Enhance graph query endpoint in web UI - Add new Vite config file for local setup --- lightrag/api/routers/graph_routes.py | 45 ++++------------------------ lightrag/lightrag.py | 4 +-- lightrag_webui/package.json | 4 +-- lightrag_webui/src/api/lightrag.ts | 8 +++-- lightrag_webui/vite.config.local.js | 38 +++++++++++++++++++++++ 5 files changed, 53 insertions(+), 46 deletions(-) create mode 100644 lightrag_webui/vite.config.local.js diff --git a/lightrag/api/routers/graph_routes.py b/lightrag/api/routers/graph_routes.py index ddaac676..4d685cc2 100644 --- a/lightrag/api/routers/graph_routes.py +++ b/lightrag/api/routers/graph_routes.py @@ -3,9 +3,9 @@ This module contains all graph-related routes for the LightRAG API. """ from typing import Optional - from fastapi import APIRouter, Depends +from ...utils import logger from ..utils_api import get_api_key_dependency router = APIRouter(tags=["graph"]) @@ -25,7 +25,7 @@ def create_graph_routes(rag, api_key: Optional[str] = None): return await rag.get_graph_labels() @router.get("/graphs", dependencies=[Depends(optional_api_key)]) - async def get_knowledge_graph(label: str, max_depth: int = 3): + async def get_knowledge_graph(label: str, max_depth: int = 3, inclusive: bool = False, min_degree: int = 0): """ Retrieve a connected subgraph of nodes where the label includes the specified label. Maximum number of nodes is constrained by the environment variable `MAX_GRAPH_NODES` (default: 1000). @@ -34,50 +34,17 @@ def create_graph_routes(rag, api_key: Optional[str] = None): 2. Followed by nodes directly connected to the matching nodes 3. Finally, the degree of the nodes Maximum number of nodes is limited to env MAX_GRAPH_NODES(default: 1000) - Control search mode by label content: - 1. only label-name : exact search with the label name (selecting from the label list return previously) - 2. label-name follow by '>n' : exact search of nodes with degree more than n - 3. label-name follow by* : inclusive search of nodes with degree more than n - 4. label-name follow by '>n*' : inclusive search Args: label (str): Label to get knowledge graph for max_depth (int, optional): Maximum depth of graph. Defaults to 3. + inclusive_search (bool, optional): If True, search for nodes that include the label. Defaults to False. + min_degree (int, optional): Minimum degree of nodes. Defaults to 0. Returns: Dict[str, List[str]]: Knowledge graph for label """ - # Parse label to extract search mode and min degree if specified - search_mode = "exact" # Default search mode - min_degree = 0 # Default minimum degree - original_label = label - - # First check if label ends with * - if label.endswith("*"): - search_mode = "inclusive" # Always set to inclusive if ends with * - label = label[:-1].strip() # Remove trailing * - - # Try to parse >n if it exists - if ">" in label: - try: - degree_pos = label.rfind(">") - degree_str = label[degree_pos + 1:].strip() - min_degree = int(degree_str) + 1 - label = label[:degree_pos].strip() - except ValueError: - # If degree parsing fails, just remove * and keep the rest as label - label = original_label[:-1].strip() - # If no *, check for >n pattern - elif ">" in label: - try: - degree_pos = label.rfind(">") - degree_str = label[degree_pos + 1:].strip() - min_degree = int(degree_str) + 1 - label = label[:degree_pos].strip() - except ValueError: - # If degree parsing fails, treat the whole string as label - label = original_label - - return await rag.get_knowledge_graph(node_label=label, max_depth=max_depth, search_mode=search_mode, min_degree=min_degree) + logger.info(f"Inclusive search : {inclusive}, Min degree: {min_degree}, Label: {label}") + return await rag.get_knowledge_graph(node_label=label, max_depth=max_depth, inclusive=inclusive, min_degree=min_degree) return router diff --git a/lightrag/lightrag.py b/lightrag/lightrag.py index 2dfd95ef..ce02ad92 100644 --- a/lightrag/lightrag.py +++ b/lightrag/lightrag.py @@ -504,7 +504,7 @@ class LightRAG: return text async def get_knowledge_graph( - self, node_label: str, max_depth: int, search_mode: str = "exact", min_degree: int = 0 + self, node_label: str, max_depth: int, inclusive: bool = False, min_degree: int = 0 ) -> KnowledgeGraph: """Get knowledge graph for a given label @@ -520,8 +520,6 @@ class LightRAG: return await self.chunk_entity_relation_graph.get_knowledge_graph( node_label=node_label, max_depth=max_depth, - search_mode=search_mode, - min_degree=min_degree ) def _get_storage_class(self, storage_name: str) -> Callable[..., Any]: diff --git a/lightrag_webui/package.json b/lightrag_webui/package.json index 578ee36f..8160a6d0 100644 --- a/lightrag_webui/package.json +++ b/lightrag_webui/package.json @@ -4,11 +4,11 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "bunx --bun vite", + "dev": "bunx --bun vite --config vite.config.local.js", "build": "bunx --bun vite build", "lint": "eslint .", "preview": "bunx --bun vite preview", - "dev-no-bun": "vite", + "dev-no-bun": "vite --config vite.config.local.js", "build-no-bun": "vite build --emptyOutDir", "preview-no-bun": "vite preview" }, diff --git a/lightrag_webui/src/api/lightrag.ts b/lightrag_webui/src/api/lightrag.ts index c9838335..dbee1954 100644 --- a/lightrag_webui/src/api/lightrag.ts +++ b/lightrag_webui/src/api/lightrag.ts @@ -161,8 +161,12 @@ axiosInstance.interceptors.response.use( ) // API methods -export const queryGraphs = async (label: string, maxDepth: number): Promise => { - const response = await axiosInstance.get(`/graphs?label=${label}&max_depth=${maxDepth}`) +export const queryGraphs = async ( + label: string, + maxDepth: number, + inclusive: boolean = false +): Promise => { + const response = await axiosInstance.get(`/graphs?label=${encodeURIComponent(label)}&max_depth=${maxDepth}&inclusive=${inclusive}`) return response.data } diff --git a/lightrag_webui/vite.config.local.js b/lightrag_webui/vite.config.local.js new file mode 100644 index 00000000..7be89fb2 --- /dev/null +++ b/lightrag_webui/vite.config.local.js @@ -0,0 +1,38 @@ +import { defineConfig } from 'vite' +import baseConfig from './vite.config' +import { mergeConfig } from 'vite' + +export default mergeConfig( + baseConfig, + defineConfig({ + server: { + proxy: { + '/api': { + target: 'http://localhost:9621', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, '') + }, + '/documents': { + target: 'http://localhost:9621', + changeOrigin: true + }, + '/graphs': { + target: 'http://localhost:9621', + changeOrigin: true + }, + '/graph': { + target: 'http://localhost:9621', + changeOrigin: true + }, + '/health': { + target: 'http://localhost:9621', + changeOrigin: true + }, + '/query': { + target: 'http://localhost:9621', + changeOrigin: true + } + } + } + }) +)