|  | from fastapi import FastAPI, HTTPException, File, UploadFile | 
					
						
						|  | from contextlib import asynccontextmanager | 
					
						
						|  | from pydantic import BaseModel | 
					
						
						|  | import os | 
					
						
						|  | from lightrag import LightRAG, QueryParam | 
					
						
						|  | from lightrag.llm.ollama import ollama_embed, ollama_model_complete | 
					
						
						|  | from lightrag.utils import EmbeddingFunc | 
					
						
						|  | from typing import Optional | 
					
						
						|  | import asyncio | 
					
						
						|  | import nest_asyncio | 
					
						
						|  | import aiofiles | 
					
						
						|  | from lightrag.kg.shared_storage import initialize_pipeline_status | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | nest_asyncio.apply() | 
					
						
						|  |  | 
					
						
						|  | DEFAULT_RAG_DIR = "index_default" | 
					
						
						|  |  | 
					
						
						|  | DEFAULT_INPUT_FILE = "book.txt" | 
					
						
						|  | INPUT_FILE = os.environ.get("INPUT_FILE", f"{DEFAULT_INPUT_FILE}") | 
					
						
						|  | print(f"INPUT_FILE: {INPUT_FILE}") | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | WORKING_DIR = os.environ.get("RAG_DIR", f"{DEFAULT_RAG_DIR}") | 
					
						
						|  | print(f"WORKING_DIR: {WORKING_DIR}") | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | if not os.path.exists(WORKING_DIR): | 
					
						
						|  | os.mkdir(WORKING_DIR) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | async def init(): | 
					
						
						|  | rag = LightRAG( | 
					
						
						|  | working_dir=WORKING_DIR, | 
					
						
						|  | llm_model_func=ollama_model_complete, | 
					
						
						|  | llm_model_name="gemma2:9b", | 
					
						
						|  | llm_model_max_async=4, | 
					
						
						|  | llm_model_max_token_size=8192, | 
					
						
						|  | llm_model_kwargs={ | 
					
						
						|  | "host": "http://localhost:11434", | 
					
						
						|  | "options": {"num_ctx": 8192}, | 
					
						
						|  | }, | 
					
						
						|  | embedding_func=EmbeddingFunc( | 
					
						
						|  | embedding_dim=768, | 
					
						
						|  | max_token_size=8192, | 
					
						
						|  | func=lambda texts: ollama_embed( | 
					
						
						|  | texts, embed_model="nomic-embed-text", host="http://localhost:11434" | 
					
						
						|  | ), | 
					
						
						|  | ), | 
					
						
						|  | ) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | await rag.initialize_storages() | 
					
						
						|  | await initialize_pipeline_status() | 
					
						
						|  |  | 
					
						
						|  | return rag | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | @asynccontextmanager | 
					
						
						|  | async def lifespan(app: FastAPI): | 
					
						
						|  | global rag | 
					
						
						|  | rag = await init() | 
					
						
						|  | print("done!") | 
					
						
						|  | yield | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | app = FastAPI( | 
					
						
						|  | title="LightRAG API", description="API for RAG operations", lifespan=lifespan | 
					
						
						|  | ) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | class QueryRequest(BaseModel): | 
					
						
						|  | query: str | 
					
						
						|  | mode: str = "hybrid" | 
					
						
						|  | only_need_context: bool = False | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | class InsertRequest(BaseModel): | 
					
						
						|  | text: str | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | class Response(BaseModel): | 
					
						
						|  | status: str | 
					
						
						|  | data: Optional[str] = None | 
					
						
						|  | message: Optional[str] = None | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | @app.post("/query", response_model=Response) | 
					
						
						|  | async def query_endpoint(request: QueryRequest): | 
					
						
						|  | try: | 
					
						
						|  | loop = asyncio.get_event_loop() | 
					
						
						|  | result = await loop.run_in_executor( | 
					
						
						|  | None, | 
					
						
						|  | lambda: rag.query( | 
					
						
						|  | request.query, | 
					
						
						|  | param=QueryParam( | 
					
						
						|  | mode=request.mode, only_need_context=request.only_need_context | 
					
						
						|  | ), | 
					
						
						|  | ), | 
					
						
						|  | ) | 
					
						
						|  | return Response(status="success", data=result) | 
					
						
						|  | except Exception as e: | 
					
						
						|  | raise HTTPException(status_code=500, detail=str(e)) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | @app.post("/insert", response_model=Response) | 
					
						
						|  | async def insert_endpoint(request: InsertRequest): | 
					
						
						|  | try: | 
					
						
						|  | loop = asyncio.get_event_loop() | 
					
						
						|  | await loop.run_in_executor(None, lambda: rag.insert(request.text)) | 
					
						
						|  | return Response(status="success", message="Text inserted successfully") | 
					
						
						|  | except Exception as e: | 
					
						
						|  | raise HTTPException(status_code=500, detail=str(e)) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | @app.post("/insert_file", response_model=Response) | 
					
						
						|  | async def insert_file(file: UploadFile = File(...)): | 
					
						
						|  | try: | 
					
						
						|  | file_content = await file.read() | 
					
						
						|  |  | 
					
						
						|  | try: | 
					
						
						|  | content = file_content.decode("utf-8") | 
					
						
						|  | except UnicodeDecodeError: | 
					
						
						|  |  | 
					
						
						|  | content = file_content.decode("gbk") | 
					
						
						|  |  | 
					
						
						|  | loop = asyncio.get_event_loop() | 
					
						
						|  | await loop.run_in_executor(None, lambda: rag.insert(content)) | 
					
						
						|  |  | 
					
						
						|  | return Response( | 
					
						
						|  | status="success", | 
					
						
						|  | message=f"File content from {file.filename} inserted successfully", | 
					
						
						|  | ) | 
					
						
						|  | except Exception as e: | 
					
						
						|  | raise HTTPException(status_code=500, detail=str(e)) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | @app.post("/insert_default_file", response_model=Response) | 
					
						
						|  | @app.get("/insert_default_file", response_model=Response) | 
					
						
						|  | async def insert_default_file(): | 
					
						
						|  | try: | 
					
						
						|  |  | 
					
						
						|  | async with aiofiles.open(INPUT_FILE, "r", encoding="utf-8") as file: | 
					
						
						|  | content = await file.read() | 
					
						
						|  | print(f"read input file {INPUT_FILE} successfully") | 
					
						
						|  |  | 
					
						
						|  | loop = asyncio.get_event_loop() | 
					
						
						|  | await loop.run_in_executor(None, lambda: rag.insert(content)) | 
					
						
						|  |  | 
					
						
						|  | return Response( | 
					
						
						|  | status="success", | 
					
						
						|  | message=f"File content from {INPUT_FILE} inserted successfully", | 
					
						
						|  | ) | 
					
						
						|  | except Exception as e: | 
					
						
						|  | raise HTTPException(status_code=500, detail=str(e)) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | @app.get("/health") | 
					
						
						|  | async def health_check(): | 
					
						
						|  | return {"status": "healthy"} | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | if __name__ == "__main__": | 
					
						
						|  | import uvicorn | 
					
						
						|  |  | 
					
						
						|  | uvicorn.run(app, host="0.0.0.0", port=8020) | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  |  |