Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ jobs:
retention-days: 7

- name: SonarQube Scan
if: env.SONAR_TOKEN != ''
uses: SonarSource/sonarqube-scan-action@v5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Expand Down
3 changes: 3 additions & 0 deletions .trivyignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ecdsa: Minerva attack - no fixed version available (status: affected)
# Transitive dependency via authlib. Monitor for upstream fix.
CVE-2024-23342
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ dependencies = [
"docling>=2.64.0",
"fastapi>=0.124.0",
"authlib>=1.6.9",
"fastmcp>=2.14.3",
"fastmcp>=3.2.0",
"cryptography>=46.0.5",
"httpx>=0.27.0",
"lightrag-hku>=1.4.9.8",
"lightrag-hku[api]>=1.4.9.8",
Expand Down
38 changes: 30 additions & 8 deletions src/application/api/indexing_routes.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
from fastapi import APIRouter, BackgroundTasks, Depends, status
import asyncio
import logging

from fastapi import APIRouter, Depends, status

from application.requests.indexing_request import IndexFileRequest, IndexFolderRequest
from application.use_cases.index_file_use_case import IndexFileUseCase
from application.use_cases.index_folder_use_case import IndexFolderUseCase
from dependencies import get_index_file_use_case, get_index_folder_use_case

logger = logging.getLogger(__name__)

indexing_router = APIRouter(tags=["Multimodal Indexing"])

_background_tasks: set[asyncio.Task] = set()


async def _run_in_background(coro, label: str) -> None:
try:
await coro
except Exception:
logger.exception("Background %s failed", label)


@indexing_router.post(
"/file/index", response_model=dict, status_code=status.HTTP_202_ACCEPTED
)
async def index_file(
request: IndexFileRequest,
background_tasks: BackgroundTasks,
use_case: IndexFileUseCase = Depends(get_index_file_use_case),
):
background_tasks.add_task(
use_case.execute,
file_name=request.file_name,
working_dir=request.working_dir,
task = asyncio.create_task(
_run_in_background(
use_case.execute(file_name=request.file_name, working_dir=request.working_dir),
label=f"file indexing {request.file_name}",
)
)
_background_tasks.add(task)
task.add_done_callback(_background_tasks.discard)
return {"status": "accepted", "message": "File indexing started in background"}


Expand All @@ -29,8 +45,14 @@ async def index_file(
)
async def index_folder(
request: IndexFolderRequest,
background_tasks: BackgroundTasks,
use_case: IndexFolderUseCase = Depends(get_index_folder_use_case),
):
background_tasks.add_task(use_case.execute, request=request)
task = asyncio.create_task(
_run_in_background(
use_case.execute(request=request),
label=f"folder indexing {request.working_dir}",
)
)
_background_tasks.add(task)
task.add_done_callback(_background_tasks.discard)
return {"status": "accepted", "message": "Folder indexing started in background"}
14 changes: 8 additions & 6 deletions src/application/api/mcp_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,32 @@
from fastmcp import FastMCP

from application.requests.query_request import MultimodalContentItem
from application.responses.query_response import ChunkResponse, QueryResponse
from dependencies import get_multimodal_query_use_case, get_query_use_case

mcp = FastMCP("RAGAnything")


@mcp.tool()
async def query_knowledge_base(
working_dir: str, query: str, mode: str = "naive", top_k: int = 10
) -> dict:
working_dir: str, query: str, mode: str = "hybrid", top_k: int = 5
) -> list[ChunkResponse]:
"""Search the RAGAnything knowledge base for relevant document chunks.

Args:
working_dir: RAG workspace directory for this project
query: The user's question or search query
mode: Search mode - "naive" (default), "local", "global", "hybrid", "mix"
top_k: Number of chunks to retrieve (default 10)
top_k: Number of chunks to retrieve (default 5)

Returns:
Query response from LightRAG
"""
use_case = get_query_use_case()
return await use_case.execute(
response = QueryResponse(**await use_case.execute(
working_dir=working_dir, query=query, mode=mode, top_k=top_k
)
))
return response.data.chunks


@mcp.tool()
Expand All @@ -38,7 +40,7 @@ async def query_knowledge_base_multimodal(
query: str,
multimodal_content: list[MultimodalContentItem],
mode: str = "hybrid",
top_k: int = 10,
top_k: int = 5,
) -> dict:
"""Query the knowledge base with multimodal content (images, tables, equations).

Expand Down
13 changes: 9 additions & 4 deletions src/application/api/query_routes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from fastapi import APIRouter, Depends, status

from application.requests.query_request import MultimodalQueryRequest, QueryRequest
from application.responses.query_response import MultimodalQueryResponse, QueryResponse
from application.responses.query_response import (
ChunkResponse,
MultimodalQueryResponse,
QueryResponse,
)
from application.use_cases.multimodal_query_use_case import MultimodalQueryUseCase
from application.use_cases.query_use_case import QueryUseCase
from dependencies import get_multimodal_query_use_case, get_query_use_case
Expand All @@ -10,19 +14,20 @@


@query_router.post(
"/query", response_model=QueryResponse, status_code=status.HTTP_200_OK
"/query", response_model=list[ChunkResponse], status_code=status.HTTP_200_OK
)
async def query_knowledge_base(
request: QueryRequest,
use_case: QueryUseCase = Depends(get_query_use_case),
) -> QueryResponse:
) -> list[ChunkResponse]:
result = await use_case.execute(
working_dir=request.working_dir,
query=request.query,
mode=request.mode,
top_k=request.top_k,
)
return QueryResponse(**result)
response = QueryResponse(**result)
return response.data.chunks


@query_router.post(
Expand Down
2 changes: 1 addition & 1 deletion src/application/use_cases/index_file_use_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ async def execute(self, file_name: str, working_dir: str) -> FileIndexingResult:
)

logger.info(f"Indexation finished: {result.model_dump()}")

return result
4 changes: 2 additions & 2 deletions src/application/use_cases/index_folder_use_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(

async def execute(self, request: IndexFolderRequest) -> FolderIndexingResult:
local_folder = os.path.join(self.output_dir, request.working_dir)

os.makedirs(local_folder, exist_ok=True)

files = await self.storage.list_objects(
Expand All @@ -52,7 +52,7 @@ async def _download(file_name: str) -> None:
await asyncio.gather(*[_download(f) for f in files])

self.rag_engine.init_project(request.working_dir)

result = await self.rag_engine.index_folder(
folder_path=local_folder,
output_dir=self.output_dir,
Expand Down
Loading
Loading