yangdx
commited on
Commit
·
a80bf0f
1
Parent(s):
fba7aaa
Fit linting
Browse files- .gitignore +1 -1
- lightrag/api/lightrag_server.py +11 -5
- lightrag/api/routers/document_routes.py +76 -21
- lightrag/api/routers/graph_routes.py +2 -1
- lightrag/api/routers/query_routes.py +6 -2
- lightrag/api/utils_api.py +1 -0
- requirements.txt +1 -1
.gitignore
CHANGED
@@ -62,4 +62,4 @@ lightrag-dev/
|
|
62 |
gui/
|
63 |
|
64 |
# unit-test files
|
65 |
-
test_*
|
|
|
62 |
gui/
|
63 |
|
64 |
# unit-test files
|
65 |
+
test_*
|
lightrag/api/lightrag_server.py
CHANGED
@@ -4,7 +4,6 @@ LightRAG FastAPI Server
|
|
4 |
|
5 |
from fastapi import (
|
6 |
FastAPI,
|
7 |
-
HTTPException,
|
8 |
Depends,
|
9 |
)
|
10 |
from fastapi.responses import FileResponse
|
@@ -14,7 +13,7 @@ import os
|
|
14 |
from fastapi.staticfiles import StaticFiles
|
15 |
import logging
|
16 |
import argparse
|
17 |
-
from typing import
|
18 |
from pathlib import Path
|
19 |
import configparser
|
20 |
from ascii_colors import ASCIIColors
|
@@ -73,6 +72,7 @@ scan_progress: Dict = {
|
|
73 |
# Lock for thread-safe operations
|
74 |
progress_lock = threading.Lock()
|
75 |
|
|
|
76 |
def get_default_host(binding_type: str) -> str:
|
77 |
default_hosts = {
|
78 |
"ollama": os.getenv("LLM_BINDING_HOST", "http://localhost:11434"),
|
@@ -624,7 +624,9 @@ def create_app(args):
|
|
624 |
scan_progress["indexed_count"] = 0
|
625 |
scan_progress["progress"] = 0
|
626 |
# Create background task
|
627 |
-
task = asyncio.create_task(
|
|
|
|
|
628 |
app.state.background_tasks.add(task)
|
629 |
task.add_done_callback(app.state.background_tasks.discard)
|
630 |
ASCIIColors.info(
|
@@ -876,8 +878,12 @@ def create_app(args):
|
|
876 |
# Webui mount webui/index.html
|
877 |
static_dir = Path(__file__).parent / "webui"
|
878 |
static_dir.mkdir(exist_ok=True)
|
879 |
-
app.mount(
|
880 |
-
|
|
|
|
|
|
|
|
|
881 |
@app.get("/webui/")
|
882 |
async def webui_root():
|
883 |
return FileResponse(static_dir / "index.html")
|
|
|
4 |
|
5 |
from fastapi import (
|
6 |
FastAPI,
|
|
|
7 |
Depends,
|
8 |
)
|
9 |
from fastapi.responses import FileResponse
|
|
|
13 |
from fastapi.staticfiles import StaticFiles
|
14 |
import logging
|
15 |
import argparse
|
16 |
+
from typing import Dict
|
17 |
from pathlib import Path
|
18 |
import configparser
|
19 |
from ascii_colors import ASCIIColors
|
|
|
72 |
# Lock for thread-safe operations
|
73 |
progress_lock = threading.Lock()
|
74 |
|
75 |
+
|
76 |
def get_default_host(binding_type: str) -> str:
|
77 |
default_hosts = {
|
78 |
"ollama": os.getenv("LLM_BINDING_HOST", "http://localhost:11434"),
|
|
|
624 |
scan_progress["indexed_count"] = 0
|
625 |
scan_progress["progress"] = 0
|
626 |
# Create background task
|
627 |
+
task = asyncio.create_task(
|
628 |
+
run_scanning_process(rag, doc_manager)
|
629 |
+
)
|
630 |
app.state.background_tasks.add(task)
|
631 |
task.add_done_callback(app.state.background_tasks.discard)
|
632 |
ASCIIColors.info(
|
|
|
878 |
# Webui mount webui/index.html
|
879 |
static_dir = Path(__file__).parent / "webui"
|
880 |
static_dir.mkdir(exist_ok=True)
|
881 |
+
app.mount(
|
882 |
+
"/webui",
|
883 |
+
StaticFiles(directory=static_dir, html=True, check_dir=True),
|
884 |
+
name="webui",
|
885 |
+
)
|
886 |
+
|
887 |
@app.get("/webui/")
|
888 |
async def webui_root():
|
889 |
return FileResponse(static_dir / "index.html")
|
lightrag/api/routers/document_routes.py
CHANGED
@@ -14,9 +14,7 @@ from pathlib import Path
|
|
14 |
from typing import Dict, List, Optional, Any
|
15 |
|
16 |
from fastapi import APIRouter, BackgroundTasks, Depends, File, HTTPException, UploadFile
|
17 |
-
from fastapi.security import APIKeyHeader
|
18 |
from pydantic import BaseModel, Field, field_validator
|
19 |
-
from starlette.status import HTTP_403_FORBIDDEN
|
20 |
|
21 |
from lightrag.base import DocProcessingStatus, DocStatus
|
22 |
from ..utils_api import get_api_key_dependency
|
@@ -39,6 +37,7 @@ progress_lock = asyncio.Lock()
|
|
39 |
# Temporary file prefix
|
40 |
temp_prefix = "__tmp__"
|
41 |
|
|
|
42 |
class InsertTextRequest(BaseModel):
|
43 |
text: str = Field(
|
44 |
min_length=1,
|
@@ -50,6 +49,7 @@ class InsertTextRequest(BaseModel):
|
|
50 |
def strip_after(cls, text: str) -> str:
|
51 |
return text.strip()
|
52 |
|
|
|
53 |
class InsertTextsRequest(BaseModel):
|
54 |
texts: list[str] = Field(
|
55 |
min_length=1,
|
@@ -61,10 +61,12 @@ class InsertTextsRequest(BaseModel):
|
|
61 |
def strip_after(cls, texts: list[str]) -> list[str]:
|
62 |
return [text.strip() for text in texts]
|
63 |
|
|
|
64 |
class InsertResponse(BaseModel):
|
65 |
status: str = Field(description="Status of the operation")
|
66 |
message: str = Field(description="Message describing the operation result")
|
67 |
|
|
|
68 |
class DocStatusResponse(BaseModel):
|
69 |
@staticmethod
|
70 |
def format_datetime(dt: Any) -> Optional[str]:
|
@@ -84,9 +86,11 @@ class DocStatusResponse(BaseModel):
|
|
84 |
error: Optional[str] = None
|
85 |
metadata: Optional[dict[str, Any]] = None
|
86 |
|
|
|
87 |
class DocsStatusesResponse(BaseModel):
|
88 |
statuses: Dict[DocStatus, List[DocStatusResponse]] = {}
|
89 |
|
|
|
90 |
class DocumentManager:
|
91 |
def __init__(
|
92 |
self,
|
@@ -129,6 +133,7 @@ class DocumentManager:
|
|
129 |
def is_supported_file(self, filename: str) -> bool:
|
130 |
return any(filename.lower().endswith(ext) for ext in self.supported_extensions)
|
131 |
|
|
|
132 |
async def pipeline_enqueue_file(rag, file_path: Path) -> bool:
|
133 |
try:
|
134 |
content = ""
|
@@ -145,7 +150,7 @@ async def pipeline_enqueue_file(rag, file_path: Path) -> bool:
|
|
145 |
case ".pdf":
|
146 |
if not pm.is_installed("pypdf2"):
|
147 |
pm.install("pypdf2")
|
148 |
-
from PyPDF2 import PdfReader
|
149 |
from io import BytesIO
|
150 |
|
151 |
pdf_file = BytesIO(file)
|
@@ -184,10 +189,17 @@ async def pipeline_enqueue_file(rag, file_path: Path) -> bool:
|
|
184 |
for sheet in wb:
|
185 |
content += f"Sheet: {sheet.title}\n"
|
186 |
for row in sheet.iter_rows(values_only=True):
|
187 |
-
content +=
|
|
|
|
|
|
|
|
|
|
|
188 |
content += "\n"
|
189 |
case _:
|
190 |
-
logging.error(
|
|
|
|
|
191 |
return False
|
192 |
|
193 |
# Insert into the RAG queue
|
@@ -209,6 +221,7 @@ async def pipeline_enqueue_file(rag, file_path: Path) -> bool:
|
|
209 |
logging.error(f"Error deleting file {file_path}: {str(e)}")
|
210 |
return False
|
211 |
|
|
|
212 |
async def pipeline_index_file(rag, file_path: Path):
|
213 |
"""Index a file
|
214 |
|
@@ -231,7 +244,7 @@ async def pipeline_index_file(rag, file_path: Path):
|
|
231 |
case ".pdf":
|
232 |
if not pm.is_installed("pypdf2"):
|
233 |
pm.install("pypdf2")
|
234 |
-
from PyPDF2 import PdfReader
|
235 |
from io import BytesIO
|
236 |
|
237 |
pdf_file = BytesIO(file)
|
@@ -270,10 +283,17 @@ async def pipeline_index_file(rag, file_path: Path):
|
|
270 |
for sheet in wb:
|
271 |
content += f"Sheet: {sheet.title}\n"
|
272 |
for row in sheet.iter_rows(values_only=True):
|
273 |
-
content +=
|
|
|
|
|
|
|
|
|
|
|
274 |
content += "\n"
|
275 |
case _:
|
276 |
-
logging.error(
|
|
|
|
|
277 |
return
|
278 |
|
279 |
# Insert into the RAG queue
|
@@ -288,6 +308,7 @@ async def pipeline_index_file(rag, file_path: Path):
|
|
288 |
logging.error(f"Error indexing file {file_path.name}: {str(e)}")
|
289 |
logging.error(traceback.format_exc())
|
290 |
|
|
|
291 |
async def pipeline_index_files(rag, file_paths: List[Path]):
|
292 |
if not file_paths:
|
293 |
return
|
@@ -305,12 +326,14 @@ async def pipeline_index_files(rag, file_paths: List[Path]):
|
|
305 |
logging.error(f"Error indexing files: {str(e)}")
|
306 |
logging.error(traceback.format_exc())
|
307 |
|
|
|
308 |
async def pipeline_index_texts(rag, texts: List[str]):
|
309 |
if not texts:
|
310 |
return
|
311 |
await rag.apipeline_enqueue_documents(texts)
|
312 |
await rag.apipeline_process_enqueue_documents()
|
313 |
|
|
|
314 |
async def save_temp_file(input_dir: Path, file: UploadFile = File(...)) -> Path:
|
315 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
316 |
unique_filename = f"{temp_prefix}{timestamp}_{file.filename}"
|
@@ -320,6 +343,7 @@ async def save_temp_file(input_dir: Path, file: UploadFile = File(...)) -> Path:
|
|
320 |
shutil.copyfileobj(file.file, buffer)
|
321 |
return temp_path
|
322 |
|
|
|
323 |
async def run_scanning_process(rag, doc_manager: DocumentManager):
|
324 |
"""Background task to scan and index documents"""
|
325 |
try:
|
@@ -349,7 +373,10 @@ async def run_scanning_process(rag, doc_manager: DocumentManager):
|
|
349 |
async with progress_lock:
|
350 |
scan_progress["is_scanning"] = False
|
351 |
|
352 |
-
|
|
|
|
|
|
|
353 |
optional_api_key = get_api_key_dependency(api_key)
|
354 |
|
355 |
@router.post("/scan", dependencies=[Depends(optional_api_key)])
|
@@ -437,8 +464,12 @@ def create_document_routes(rag, doc_manager: DocumentManager, api_key: Optional[
|
|
437 |
logging.error(traceback.format_exc())
|
438 |
raise HTTPException(status_code=500, detail=str(e))
|
439 |
|
440 |
-
@router.post(
|
441 |
-
|
|
|
|
|
|
|
|
|
442 |
"""
|
443 |
Insert text into the RAG system.
|
444 |
|
@@ -466,8 +497,14 @@ def create_document_routes(rag, doc_manager: DocumentManager, api_key: Optional[
|
|
466 |
logging.error(traceback.format_exc())
|
467 |
raise HTTPException(status_code=500, detail=str(e))
|
468 |
|
469 |
-
@router.post(
|
470 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
471 |
"""
|
472 |
Insert multiple texts into the RAG system.
|
473 |
|
@@ -495,8 +532,12 @@ def create_document_routes(rag, doc_manager: DocumentManager, api_key: Optional[
|
|
495 |
logging.error(traceback.format_exc())
|
496 |
raise HTTPException(status_code=500, detail=str(e))
|
497 |
|
498 |
-
@router.post(
|
499 |
-
|
|
|
|
|
|
|
|
|
500 |
"""
|
501 |
Insert a file directly into the RAG system.
|
502 |
|
@@ -532,8 +573,14 @@ def create_document_routes(rag, doc_manager: DocumentManager, api_key: Optional[
|
|
532 |
logging.error(traceback.format_exc())
|
533 |
raise HTTPException(status_code=500, detail=str(e))
|
534 |
|
535 |
-
@router.post(
|
536 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
537 |
"""
|
538 |
Process multiple files in batch mode.
|
539 |
|
@@ -587,7 +634,9 @@ def create_document_routes(rag, doc_manager: DocumentManager, api_key: Optional[
|
|
587 |
logging.error(traceback.format_exc())
|
588 |
raise HTTPException(status_code=500, detail=str(e))
|
589 |
|
590 |
-
@router.delete(
|
|
|
|
|
591 |
async def clear_documents():
|
592 |
"""
|
593 |
Clear all documents from the RAG system.
|
@@ -605,7 +654,9 @@ def create_document_routes(rag, doc_manager: DocumentManager, api_key: Optional[
|
|
605 |
rag.text_chunks = []
|
606 |
rag.entities_vdb = None
|
607 |
rag.relationships_vdb = None
|
608 |
-
return InsertResponse(
|
|
|
|
|
609 |
except Exception as e:
|
610 |
logging.error(f"Error DELETE /documents: {str(e)}")
|
611 |
logging.error(traceback.format_exc())
|
@@ -651,8 +702,12 @@ def create_document_routes(rag, doc_manager: DocumentManager, api_key: Optional[
|
|
651 |
content_summary=doc_status.content_summary,
|
652 |
content_length=doc_status.content_length,
|
653 |
status=doc_status.status,
|
654 |
-
created_at=DocStatusResponse.format_datetime(
|
655 |
-
|
|
|
|
|
|
|
|
|
656 |
chunks_count=doc_status.chunks_count,
|
657 |
error=doc_status.error,
|
658 |
metadata=doc_status.metadata,
|
|
|
14 |
from typing import Dict, List, Optional, Any
|
15 |
|
16 |
from fastapi import APIRouter, BackgroundTasks, Depends, File, HTTPException, UploadFile
|
|
|
17 |
from pydantic import BaseModel, Field, field_validator
|
|
|
18 |
|
19 |
from lightrag.base import DocProcessingStatus, DocStatus
|
20 |
from ..utils_api import get_api_key_dependency
|
|
|
37 |
# Temporary file prefix
|
38 |
temp_prefix = "__tmp__"
|
39 |
|
40 |
+
|
41 |
class InsertTextRequest(BaseModel):
|
42 |
text: str = Field(
|
43 |
min_length=1,
|
|
|
49 |
def strip_after(cls, text: str) -> str:
|
50 |
return text.strip()
|
51 |
|
52 |
+
|
53 |
class InsertTextsRequest(BaseModel):
|
54 |
texts: list[str] = Field(
|
55 |
min_length=1,
|
|
|
61 |
def strip_after(cls, texts: list[str]) -> list[str]:
|
62 |
return [text.strip() for text in texts]
|
63 |
|
64 |
+
|
65 |
class InsertResponse(BaseModel):
|
66 |
status: str = Field(description="Status of the operation")
|
67 |
message: str = Field(description="Message describing the operation result")
|
68 |
|
69 |
+
|
70 |
class DocStatusResponse(BaseModel):
|
71 |
@staticmethod
|
72 |
def format_datetime(dt: Any) -> Optional[str]:
|
|
|
86 |
error: Optional[str] = None
|
87 |
metadata: Optional[dict[str, Any]] = None
|
88 |
|
89 |
+
|
90 |
class DocsStatusesResponse(BaseModel):
|
91 |
statuses: Dict[DocStatus, List[DocStatusResponse]] = {}
|
92 |
|
93 |
+
|
94 |
class DocumentManager:
|
95 |
def __init__(
|
96 |
self,
|
|
|
133 |
def is_supported_file(self, filename: str) -> bool:
|
134 |
return any(filename.lower().endswith(ext) for ext in self.supported_extensions)
|
135 |
|
136 |
+
|
137 |
async def pipeline_enqueue_file(rag, file_path: Path) -> bool:
|
138 |
try:
|
139 |
content = ""
|
|
|
150 |
case ".pdf":
|
151 |
if not pm.is_installed("pypdf2"):
|
152 |
pm.install("pypdf2")
|
153 |
+
from PyPDF2 import PdfReader # type: ignore
|
154 |
from io import BytesIO
|
155 |
|
156 |
pdf_file = BytesIO(file)
|
|
|
189 |
for sheet in wb:
|
190 |
content += f"Sheet: {sheet.title}\n"
|
191 |
for row in sheet.iter_rows(values_only=True):
|
192 |
+
content += (
|
193 |
+
"\t".join(
|
194 |
+
str(cell) if cell is not None else "" for cell in row
|
195 |
+
)
|
196 |
+
+ "\n"
|
197 |
+
)
|
198 |
content += "\n"
|
199 |
case _:
|
200 |
+
logging.error(
|
201 |
+
f"Unsupported file type: {file_path.name} (extension {ext})"
|
202 |
+
)
|
203 |
return False
|
204 |
|
205 |
# Insert into the RAG queue
|
|
|
221 |
logging.error(f"Error deleting file {file_path}: {str(e)}")
|
222 |
return False
|
223 |
|
224 |
+
|
225 |
async def pipeline_index_file(rag, file_path: Path):
|
226 |
"""Index a file
|
227 |
|
|
|
244 |
case ".pdf":
|
245 |
if not pm.is_installed("pypdf2"):
|
246 |
pm.install("pypdf2")
|
247 |
+
from PyPDF2 import PdfReader # type: ignore
|
248 |
from io import BytesIO
|
249 |
|
250 |
pdf_file = BytesIO(file)
|
|
|
283 |
for sheet in wb:
|
284 |
content += f"Sheet: {sheet.title}\n"
|
285 |
for row in sheet.iter_rows(values_only=True):
|
286 |
+
content += (
|
287 |
+
"\t".join(
|
288 |
+
str(cell) if cell is not None else "" for cell in row
|
289 |
+
)
|
290 |
+
+ "\n"
|
291 |
+
)
|
292 |
content += "\n"
|
293 |
case _:
|
294 |
+
logging.error(
|
295 |
+
f"Unsupported file type: {file_path.name} (extension {ext})"
|
296 |
+
)
|
297 |
return
|
298 |
|
299 |
# Insert into the RAG queue
|
|
|
308 |
logging.error(f"Error indexing file {file_path.name}: {str(e)}")
|
309 |
logging.error(traceback.format_exc())
|
310 |
|
311 |
+
|
312 |
async def pipeline_index_files(rag, file_paths: List[Path]):
|
313 |
if not file_paths:
|
314 |
return
|
|
|
326 |
logging.error(f"Error indexing files: {str(e)}")
|
327 |
logging.error(traceback.format_exc())
|
328 |
|
329 |
+
|
330 |
async def pipeline_index_texts(rag, texts: List[str]):
|
331 |
if not texts:
|
332 |
return
|
333 |
await rag.apipeline_enqueue_documents(texts)
|
334 |
await rag.apipeline_process_enqueue_documents()
|
335 |
|
336 |
+
|
337 |
async def save_temp_file(input_dir: Path, file: UploadFile = File(...)) -> Path:
|
338 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
339 |
unique_filename = f"{temp_prefix}{timestamp}_{file.filename}"
|
|
|
343 |
shutil.copyfileobj(file.file, buffer)
|
344 |
return temp_path
|
345 |
|
346 |
+
|
347 |
async def run_scanning_process(rag, doc_manager: DocumentManager):
|
348 |
"""Background task to scan and index documents"""
|
349 |
try:
|
|
|
373 |
async with progress_lock:
|
374 |
scan_progress["is_scanning"] = False
|
375 |
|
376 |
+
|
377 |
+
def create_document_routes(
|
378 |
+
rag, doc_manager: DocumentManager, api_key: Optional[str] = None
|
379 |
+
):
|
380 |
optional_api_key = get_api_key_dependency(api_key)
|
381 |
|
382 |
@router.post("/scan", dependencies=[Depends(optional_api_key)])
|
|
|
464 |
logging.error(traceback.format_exc())
|
465 |
raise HTTPException(status_code=500, detail=str(e))
|
466 |
|
467 |
+
@router.post(
|
468 |
+
"/text", response_model=InsertResponse, dependencies=[Depends(optional_api_key)]
|
469 |
+
)
|
470 |
+
async def insert_text(
|
471 |
+
request: InsertTextRequest, background_tasks: BackgroundTasks
|
472 |
+
):
|
473 |
"""
|
474 |
Insert text into the RAG system.
|
475 |
|
|
|
497 |
logging.error(traceback.format_exc())
|
498 |
raise HTTPException(status_code=500, detail=str(e))
|
499 |
|
500 |
+
@router.post(
|
501 |
+
"/texts",
|
502 |
+
response_model=InsertResponse,
|
503 |
+
dependencies=[Depends(optional_api_key)],
|
504 |
+
)
|
505 |
+
async def insert_texts(
|
506 |
+
request: InsertTextsRequest, background_tasks: BackgroundTasks
|
507 |
+
):
|
508 |
"""
|
509 |
Insert multiple texts into the RAG system.
|
510 |
|
|
|
532 |
logging.error(traceback.format_exc())
|
533 |
raise HTTPException(status_code=500, detail=str(e))
|
534 |
|
535 |
+
@router.post(
|
536 |
+
"/file", response_model=InsertResponse, dependencies=[Depends(optional_api_key)]
|
537 |
+
)
|
538 |
+
async def insert_file(
|
539 |
+
background_tasks: BackgroundTasks, file: UploadFile = File(...)
|
540 |
+
):
|
541 |
"""
|
542 |
Insert a file directly into the RAG system.
|
543 |
|
|
|
573 |
logging.error(traceback.format_exc())
|
574 |
raise HTTPException(status_code=500, detail=str(e))
|
575 |
|
576 |
+
@router.post(
|
577 |
+
"/file_batch",
|
578 |
+
response_model=InsertResponse,
|
579 |
+
dependencies=[Depends(optional_api_key)],
|
580 |
+
)
|
581 |
+
async def insert_batch(
|
582 |
+
background_tasks: BackgroundTasks, files: List[UploadFile] = File(...)
|
583 |
+
):
|
584 |
"""
|
585 |
Process multiple files in batch mode.
|
586 |
|
|
|
634 |
logging.error(traceback.format_exc())
|
635 |
raise HTTPException(status_code=500, detail=str(e))
|
636 |
|
637 |
+
@router.delete(
|
638 |
+
"", response_model=InsertResponse, dependencies=[Depends(optional_api_key)]
|
639 |
+
)
|
640 |
async def clear_documents():
|
641 |
"""
|
642 |
Clear all documents from the RAG system.
|
|
|
654 |
rag.text_chunks = []
|
655 |
rag.entities_vdb = None
|
656 |
rag.relationships_vdb = None
|
657 |
+
return InsertResponse(
|
658 |
+
status="success", message="All documents cleared successfully"
|
659 |
+
)
|
660 |
except Exception as e:
|
661 |
logging.error(f"Error DELETE /documents: {str(e)}")
|
662 |
logging.error(traceback.format_exc())
|
|
|
702 |
content_summary=doc_status.content_summary,
|
703 |
content_length=doc_status.content_length,
|
704 |
status=doc_status.status,
|
705 |
+
created_at=DocStatusResponse.format_datetime(
|
706 |
+
doc_status.created_at
|
707 |
+
),
|
708 |
+
updated_at=DocStatusResponse.format_datetime(
|
709 |
+
doc_status.updated_at
|
710 |
+
),
|
711 |
chunks_count=doc_status.chunks_count,
|
712 |
error=doc_status.error,
|
713 |
metadata=doc_status.metadata,
|
lightrag/api/routers/graph_routes.py
CHANGED
@@ -4,12 +4,13 @@ This module contains all graph-related routes for the LightRAG API.
|
|
4 |
|
5 |
from typing import Optional
|
6 |
|
7 |
-
from fastapi import APIRouter, Depends
|
8 |
|
9 |
from ..utils_api import get_api_key_dependency
|
10 |
|
11 |
router = APIRouter(tags=["graph"])
|
12 |
|
|
|
13 |
def create_graph_routes(rag, api_key: Optional[str] = None):
|
14 |
optional_api_key = get_api_key_dependency(api_key)
|
15 |
|
|
|
4 |
|
5 |
from typing import Optional
|
6 |
|
7 |
+
from fastapi import APIRouter, Depends
|
8 |
|
9 |
from ..utils_api import get_api_key_dependency
|
10 |
|
11 |
router = APIRouter(tags=["graph"])
|
12 |
|
13 |
+
|
14 |
def create_graph_routes(rag, api_key: Optional[str] = None):
|
15 |
optional_api_key = get_api_key_dependency(api_key)
|
16 |
|
lightrag/api/routers/query_routes.py
CHANGED
@@ -4,7 +4,6 @@ This module contains all query-related routes for the LightRAG API.
|
|
4 |
|
5 |
import json
|
6 |
import logging
|
7 |
-
import traceback
|
8 |
from typing import Any, Dict, List, Literal, Optional
|
9 |
|
10 |
from fastapi import APIRouter, Depends, HTTPException
|
@@ -16,6 +15,7 @@ from ascii_colors import trace_exception
|
|
16 |
|
17 |
router = APIRouter(tags=["query"])
|
18 |
|
|
|
19 |
class QueryRequest(BaseModel):
|
20 |
query: str = Field(
|
21 |
min_length=1,
|
@@ -131,15 +131,19 @@ class QueryRequest(BaseModel):
|
|
131 |
param.stream = is_stream
|
132 |
return param
|
133 |
|
|
|
134 |
class QueryResponse(BaseModel):
|
135 |
response: str = Field(
|
136 |
description="The generated response",
|
137 |
)
|
138 |
|
|
|
139 |
def create_query_routes(rag, api_key: Optional[str] = None, top_k: int = 60):
|
140 |
optional_api_key = get_api_key_dependency(api_key)
|
141 |
|
142 |
-
@router.post(
|
|
|
|
|
143 |
async def query_text(request: QueryRequest):
|
144 |
"""
|
145 |
Handle a POST request at the /query endpoint to process user queries using RAG capabilities.
|
|
|
4 |
|
5 |
import json
|
6 |
import logging
|
|
|
7 |
from typing import Any, Dict, List, Literal, Optional
|
8 |
|
9 |
from fastapi import APIRouter, Depends, HTTPException
|
|
|
15 |
|
16 |
router = APIRouter(tags=["query"])
|
17 |
|
18 |
+
|
19 |
class QueryRequest(BaseModel):
|
20 |
query: str = Field(
|
21 |
min_length=1,
|
|
|
131 |
param.stream = is_stream
|
132 |
return param
|
133 |
|
134 |
+
|
135 |
class QueryResponse(BaseModel):
|
136 |
response: str = Field(
|
137 |
description="The generated response",
|
138 |
)
|
139 |
|
140 |
+
|
141 |
def create_query_routes(rag, api_key: Optional[str] = None, top_k: int = 60):
|
142 |
optional_api_key = get_api_key_dependency(api_key)
|
143 |
|
144 |
+
@router.post(
|
145 |
+
"/query", response_model=QueryResponse, dependencies=[Depends(optional_api_key)]
|
146 |
+
)
|
147 |
async def query_text(request: QueryRequest):
|
148 |
"""
|
149 |
Handle a POST request at the /query endpoint to process user queries using RAG capabilities.
|
lightrag/api/utils_api.py
CHANGED
@@ -7,6 +7,7 @@ from fastapi import HTTPException, Security
|
|
7 |
from fastapi.security import APIKeyHeader
|
8 |
from starlette.status import HTTP_403_FORBIDDEN
|
9 |
|
|
|
10 |
def get_api_key_dependency(api_key: Optional[str]):
|
11 |
"""
|
12 |
Create an API key dependency for route protection.
|
|
|
7 |
from fastapi.security import APIKeyHeader
|
8 |
from starlette.status import HTTP_403_FORBIDDEN
|
9 |
|
10 |
+
|
11 |
def get_api_key_dependency(api_key: Optional[str]):
|
12 |
"""
|
13 |
Create an API key dependency for route protection.
|
requirements.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
-
future
|
2 |
aiohttp
|
3 |
configparser
|
|
|
4 |
|
5 |
# Basic modules
|
6 |
numpy
|
|
|
|
|
1 |
aiohttp
|
2 |
configparser
|
3 |
+
future
|
4 |
|
5 |
# Basic modules
|
6 |
numpy
|