|
from fastapi import FastAPI, HTTPException, File, UploadFile |
|
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 |
|
|
|
|
|
nest_asyncio.apply() |
|
|
|
DEFAULT_RAG_DIR = "index_default" |
|
app = FastAPI(title="LightRAG API", description="API for RAG operations") |
|
|
|
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) |
|
|
|
|
|
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" |
|
), |
|
), |
|
) |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|