From 5d724d81978216b24fe2e055b7468d07784512d2 Mon Sep 17 00:00:00 2001 From: zrguo <49157727+LarFii@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:44:00 +0800 Subject: [PATCH 1/3] Update README.md From 9fef519caf41c2d97395714a859fddf228c21f2b Mon Sep 17 00:00:00 2001 From: I561043 Date: Mon, 9 Dec 2024 15:11:03 +0800 Subject: [PATCH 2/3] add demo for ollama api service --- examples/lightrag_api_ollama_demo.py | 160 +++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 examples/lightrag_api_ollama_demo.py diff --git a/examples/lightrag_api_ollama_demo.py b/examples/lightrag_api_ollama_demo.py new file mode 100644 index 00000000..8a0fffc7 --- /dev/null +++ b/examples/lightrag_api_ollama_demo.py @@ -0,0 +1,160 @@ +from fastapi import FastAPI, HTTPException, File, UploadFile +from pydantic import BaseModel +import os +from lightrag import LightRAG, QueryParam +from lightrag.llm import ollama_embedding, ollama_model_complete +from lightrag.utils import EmbeddingFunc +from typing import Optional +import asyncio +import nest_asyncio +import aiofiles + +# Apply nest_asyncio to solve event loop issues +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}") + +# 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) + + +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_embedding( + texts, embed_model="nomic-embed-text", host="http://localhost:11434" + ), + ), +) + + +# 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: application/json" -d '{"file_path": "path/to/your/file.txt"}' + +# 4. Health check: +# curl -X GET "http://127.0.0.1:8020/health" From a2f3de25f83d43dc0fdc1e06f6c7f2fa23100eb6 Mon Sep 17 00:00:00 2001 From: I561043 Date: Mon, 9 Dec 2024 17:06:52 +0800 Subject: [PATCH 3/3] fix format --- examples/lightrag_api_ollama_demo.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/lightrag_api_ollama_demo.py b/examples/lightrag_api_ollama_demo.py index 8a0fffc7..36df1262 100644 --- a/examples/lightrag_api_ollama_demo.py +++ b/examples/lightrag_api_ollama_demo.py @@ -24,7 +24,6 @@ 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) @@ -81,6 +80,7 @@ async def query_endpoint(request: QueryRequest): 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): @@ -91,6 +91,7 @@ async def insert_endpoint(request: InsertRequest): 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(...)): @@ -113,6 +114,7 @@ async def insert_file(file: UploadFile = File(...)): 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) @@ -133,6 +135,7 @@ async def insert_default_file(): except Exception as e: raise HTTPException(status_code=500, detail=str(e)) + @app.get("/health") async def health_check(): return {"status": "healthy"} @@ -140,6 +143,7 @@ async def health_check(): if __name__ == "__main__": import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8020) # Usage example