mirror of
				https://github.com/HKUDS/LightRAG.git
				synced 2025-11-04 03:39:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			189 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
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
 | 
						|
 | 
						|
# Apply nest_asyncio to solve event loop issues
 | 
						|
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}")
 | 
						|
 | 
						|
# Configure working directory
 | 
						|
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"
 | 
						|
            ),
 | 
						|
        ),
 | 
						|
    )
 | 
						|
 | 
						|
    # Add initialization code
 | 
						|
    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
 | 
						|
)
 | 
						|
 | 
						|
 | 
						|
# Data models
 | 
						|
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
 | 
						|
 | 
						|
 | 
						|
# API routes
 | 
						|
@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))
 | 
						|
 | 
						|
 | 
						|
# insert by text
 | 
						|
@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))
 | 
						|
 | 
						|
 | 
						|
# insert by file in payload
 | 
						|
@app.post("/insert_file", response_model=Response)
 | 
						|
async def insert_file(file: UploadFile = File(...)):
 | 
						|
    try:
 | 
						|
        file_content = await file.read()
 | 
						|
        # Read file content
 | 
						|
        try:
 | 
						|
            content = file_content.decode("utf-8")
 | 
						|
        except UnicodeDecodeError:
 | 
						|
            # If UTF-8 decoding fails, try other encodings
 | 
						|
            content = file_content.decode("gbk")
 | 
						|
        # Insert file content
 | 
						|
        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))
 | 
						|
 | 
						|
 | 
						|
# insert by local default file
 | 
						|
@app.post("/insert_default_file", response_model=Response)
 | 
						|
@app.get("/insert_default_file", response_model=Response)
 | 
						|
async def insert_default_file():
 | 
						|
    try:
 | 
						|
        # Read file content from book.txt
 | 
						|
        async with aiofiles.open(INPUT_FILE, "r", encoding="utf-8") as file:
 | 
						|
            content = await file.read()
 | 
						|
        print(f"read input file {INPUT_FILE} successfully")
 | 
						|
        # Insert file content
 | 
						|
        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)
 | 
						|
 | 
						|
# Usage example
 | 
						|
# To run the server, use the following command in your terminal:
 | 
						|
# python lightrag_api_openai_compatible_demo.py
 | 
						|
 | 
						|
# Example requests:
 | 
						|
# 1. Query:
 | 
						|
# curl -X POST "http://127.0.0.1:8020/query" -H "Content-Type: application/json" -d '{"query": "your query here", "mode": "hybrid"}'
 | 
						|
 | 
						|
# 2. Insert text:
 | 
						|
# curl -X POST "http://127.0.0.1:8020/insert" -H "Content-Type: application/json" -d '{"text": "your text here"}'
 | 
						|
 | 
						|
# 3. Insert file:
 | 
						|
# curl -X POST "http://127.0.0.1:8020/insert_file" -H "Content-Type: multipart/form-data" -F "file=@path/to/your/file.txt"
 | 
						|
 | 
						|
# 4. Health check:
 | 
						|
# curl -X GET "http://127.0.0.1:8020/health"
 |