mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
Add Java orchestrator to connect to the AI engine (#6003)
# Description of Changes Add Java orchestration layer which can connect and go back and forth with the AI engine to get results for the user. It's expected that the AI engine will not be publicly available and this Java layer will always be in front of it, to manage sessions and auth etc.
This commit is contained in:
@@ -4,8 +4,11 @@ from pydantic_ai import Agent
|
||||
from pydantic_ai.output import NativeOutput
|
||||
|
||||
from stirling.contracts import (
|
||||
ExtractedFileText,
|
||||
NeedContentFileRequest,
|
||||
PdfContentType,
|
||||
PdfQuestionAnswerResponse,
|
||||
PdfQuestionNeedTextResponse,
|
||||
PdfQuestionNeedContentResponse,
|
||||
PdfQuestionNotFoundResponse,
|
||||
PdfQuestionRequest,
|
||||
PdfQuestionResponse,
|
||||
@@ -14,6 +17,9 @@ from stirling.services import AppRuntime
|
||||
|
||||
|
||||
class PdfQuestionAgent:
|
||||
DEFAULT_MAX_PAGES = 12
|
||||
DEFAULT_MAX_CHARACTERS = 24_000
|
||||
|
||||
def __init__(self, runtime: AppRuntime) -> None:
|
||||
self.runtime = runtime
|
||||
self.agent = Agent(
|
||||
@@ -25,18 +31,27 @@ class PdfQuestionAgent:
|
||||
]
|
||||
),
|
||||
system_prompt=(
|
||||
"Answer questions about a PDF using only the extracted text provided in the prompt. "
|
||||
"Answer questions about PDFs using only the extracted page text provided in the prompt. "
|
||||
"Do not guess or use outside knowledge. "
|
||||
"If the answer is not supported by the provided text, return not_found. "
|
||||
"When answering, include a short list of evidence snippets copied from the provided text."
|
||||
"When answering, include a short list of evidence snippets with their page numbers."
|
||||
),
|
||||
model_settings=runtime.smart_model_settings,
|
||||
)
|
||||
|
||||
async def handle(self, request: PdfQuestionRequest) -> PdfQuestionResponse:
|
||||
if not request.extracted_text.strip():
|
||||
return PdfQuestionNeedTextResponse(
|
||||
reason="No extracted PDF text was provided, so the question cannot be answered yet."
|
||||
if not self._has_page_text(request.page_text):
|
||||
return PdfQuestionNeedContentResponse(
|
||||
reason="No extracted PDF page text was provided, so the question cannot be answered yet.",
|
||||
files=[
|
||||
NeedContentFileRequest(
|
||||
file_name=file_name,
|
||||
content_types=[PdfContentType.PAGE_TEXT],
|
||||
)
|
||||
for file_name in request.file_names
|
||||
],
|
||||
max_pages=self.DEFAULT_MAX_PAGES,
|
||||
max_characters=self.DEFAULT_MAX_CHARACTERS,
|
||||
)
|
||||
return await self._run_answer_agent(request)
|
||||
|
||||
@@ -45,5 +60,14 @@ class PdfQuestionAgent:
|
||||
return result.output
|
||||
|
||||
def _build_prompt(self, request: PdfQuestionRequest) -> str:
|
||||
file_name = request.file_name or "Unknown file"
|
||||
return f"File: {file_name}\nQuestion: {request.question}\nExtracted text:\n{request.extracted_text}"
|
||||
file_names = ", ".join(request.file_names) if request.file_names else "Unknown files"
|
||||
sections = [
|
||||
f"[File: {file_text.file_name}, Page {selection.page_number or '?'}]\n{selection.text}"
|
||||
for file_text in request.page_text
|
||||
for selection in file_text.pages
|
||||
]
|
||||
pages = "\n\n".join(sections)
|
||||
return f"Files: {file_names}\nQuestion: {request.question}\nExtracted page text:\n{pages}"
|
||||
|
||||
def _has_page_text(self, page_text: list[ExtractedFileText]) -> bool:
|
||||
return any(selection.text.strip() for file_text in page_text for selection in file_text.pages)
|
||||
|
||||
Reference in New Issue
Block a user