mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-15 19:10:47 +02:00
Feature/pdf ingestion jpdfium (#6525)
This commit is contained in:
@@ -13,6 +13,7 @@ from .common import (
|
||||
AiFile,
|
||||
ArtifactKind,
|
||||
ConversationMessage,
|
||||
ConvertMarkdownResponse,
|
||||
ExtractedFileText,
|
||||
GenerateFileResponse,
|
||||
MathAuditorToolReportArtifact,
|
||||
@@ -96,17 +97,6 @@ from .pdf_questions import (
|
||||
PdfQuestionTerminalResponse,
|
||||
)
|
||||
from .pdf_review import PdfReviewOrchestrateResponse
|
||||
from .pdf_to_markdown import (
|
||||
LayoutFragment,
|
||||
LayoutLine,
|
||||
PageLayout,
|
||||
PageLayoutArtifact,
|
||||
PageLayoutFileEntry,
|
||||
PdfToMarkdownCannotDoResponse,
|
||||
PdfToMarkdownOrchestrateResponse,
|
||||
PdfToMarkdownRequest,
|
||||
PdfToMarkdownResponse,
|
||||
)
|
||||
from .progress import (
|
||||
ProgressEvent,
|
||||
WholeDocCompressionRound,
|
||||
@@ -139,10 +129,6 @@ __all__ = [
|
||||
"ConversationMessage",
|
||||
"DeleteDocumentResponse",
|
||||
"PurgeOwnerResponse",
|
||||
"PdfToMarkdownCannotDoResponse",
|
||||
"PdfToMarkdownOrchestrateResponse",
|
||||
"PdfToMarkdownRequest",
|
||||
"PdfToMarkdownResponse",
|
||||
"Discrepancy",
|
||||
"DiscrepancyKind",
|
||||
"EditCannotDoResponse",
|
||||
@@ -166,15 +152,11 @@ __all__ = [
|
||||
"NeedContentFileRequest",
|
||||
"NeedContentResponse",
|
||||
"NeedIngestResponse",
|
||||
"ConvertMarkdownResponse",
|
||||
"NextExecutionAction",
|
||||
"OrchestratorRequest",
|
||||
"OrchestratorResponse",
|
||||
"LayoutFragment",
|
||||
"LayoutLine",
|
||||
"Page",
|
||||
"PageLayout",
|
||||
"PageLayoutArtifact",
|
||||
"PageLayoutFileEntry",
|
||||
"PageRange",
|
||||
"PageText",
|
||||
"PdfCommentInstruction",
|
||||
|
||||
@@ -62,6 +62,7 @@ class WorkflowOutcome(StrEnum):
|
||||
CANNOT_CONTINUE = "cannot_continue"
|
||||
UNSUPPORTED_CAPABILITY = "unsupported_capability"
|
||||
GENERATE_FILE = "generate_file"
|
||||
CONVERT_MARKDOWN = "convert_markdown"
|
||||
|
||||
|
||||
class ArtifactKind(StrEnum):
|
||||
@@ -183,6 +184,19 @@ class NeedIngestResponse(ApiModel):
|
||||
content_types: list[PdfContentType] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ConvertMarkdownResponse(ApiModel):
|
||||
"""Terminal signal: convert the listed files to Markdown deterministically.
|
||||
|
||||
This is a deterministic, non-AI conversion. Java runs the PDF→Markdown converter
|
||||
(``PdfMarkdownConverter``) on each file and returns the resulting ``.md`` file(s) as a
|
||||
completed result. There is no resume turn — the conversion output is the final answer.
|
||||
"""
|
||||
|
||||
outcome: Literal[WorkflowOutcome.CONVERT_MARKDOWN] = WorkflowOutcome.CONVERT_MARKDOWN
|
||||
reason: str
|
||||
files_to_ingest: list[AiFile]
|
||||
|
||||
|
||||
class ToolOperationStep(ApiModel):
|
||||
kind: Literal[StepKind.TOOL] = StepKind.TOOL
|
||||
tool: AnyToolId
|
||||
|
||||
@@ -11,6 +11,7 @@ from .common import (
|
||||
AiFile,
|
||||
ArtifactKind,
|
||||
ConversationMessage,
|
||||
ConvertMarkdownResponse,
|
||||
ExtractedFileText,
|
||||
GenerateFileResponse,
|
||||
NeedContentResponse,
|
||||
@@ -23,7 +24,6 @@ from .common import (
|
||||
from .execution import NextExecutionAction
|
||||
from .pdf_edit import PdfEditTerminalResponse
|
||||
from .pdf_questions import PdfQuestionTerminalResponse
|
||||
from .pdf_to_markdown import PageLayoutArtifact
|
||||
|
||||
|
||||
class ExtractedTextArtifact(ApiModel):
|
||||
@@ -32,7 +32,7 @@ class ExtractedTextArtifact(ApiModel):
|
||||
|
||||
|
||||
WorkflowArtifact = Annotated[
|
||||
ExtractedTextArtifact | PageLayoutArtifact | ToolReportArtifact,
|
||||
ExtractedTextArtifact | ToolReportArtifact,
|
||||
Field(discriminator="kind"),
|
||||
]
|
||||
|
||||
@@ -61,6 +61,7 @@ type OrchestratorResponse = Annotated[
|
||||
| GenerateFileResponse
|
||||
| NeedContentResponse
|
||||
| NeedIngestResponse
|
||||
| ConvertMarkdownResponse
|
||||
| AgentDraftResponse
|
||||
| NextExecutionAction
|
||||
| UnsupportedCapabilityResponse,
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
"""Contracts for the PDF to Markdown Agent.
|
||||
|
||||
The agent accepts a parsed document and returns a single Markdown document that
|
||||
faithfully reconstructs the PDF content — headings, paragraphs, and tables in
|
||||
reading order, using page_layout as the primary source of truth for structure.
|
||||
|
||||
Java extracts page layout via PdfIngester and returns it as a PageLayoutArtifact
|
||||
through the orchestrator resume_with pattern.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from stirling.models import ApiModel
|
||||
|
||||
from .common import ArtifactKind, ConversationMessage, GenerateFileResponse, NeedContentResponse
|
||||
from .pdf_edit import EditCannotDoResponse
|
||||
|
||||
# ── Input: layout models (mirror Java's RawLine / TextFragment geometry) ────────────────────────
|
||||
|
||||
|
||||
class LayoutFragment(ApiModel):
|
||||
"""One text fragment with its bounding-box geometry and font properties."""
|
||||
|
||||
text: str
|
||||
x: float
|
||||
y: float
|
||||
width: float
|
||||
font_size: float
|
||||
bold: bool
|
||||
|
||||
|
||||
class LayoutLine(ApiModel):
|
||||
"""A visual line on the page: one y-coordinate and all fragments on that line."""
|
||||
|
||||
y: float
|
||||
fragments: list[LayoutFragment]
|
||||
|
||||
|
||||
class PageLayout(ApiModel):
|
||||
"""All layout lines for a single page, in top-to-bottom order."""
|
||||
|
||||
page_number: int
|
||||
lines: list[LayoutLine]
|
||||
|
||||
|
||||
# ── Artifact: page layout (produced by Java, consumed by orchestrate()) ──────────────────────────
|
||||
|
||||
|
||||
class PageLayoutFileEntry(ApiModel):
|
||||
"""Page layout data for one file, as extracted by Java's PdfIngester."""
|
||||
|
||||
file_name: str
|
||||
pages: list[PageLayout] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PageLayoutArtifact(ApiModel):
|
||||
"""Artifact carrying full spatial page layout for all input files."""
|
||||
|
||||
kind: Literal[ArtifactKind.PAGE_LAYOUT] = ArtifactKind.PAGE_LAYOUT
|
||||
files: list[PageLayoutFileEntry] = Field(default_factory=list)
|
||||
|
||||
|
||||
# ── Input: full request ──────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class PdfToMarkdownRequest(ApiModel):
|
||||
"""Request sent by Java after PdfIngester has parsed the document.
|
||||
|
||||
page_layout: per-fragment positional data from the original (y-sorted) line order.
|
||||
Each fragment carries its x/y position, width, font size, and bold flag.
|
||||
This is the primary source of truth for column detection and heading hierarchy.
|
||||
"""
|
||||
|
||||
user_message: str
|
||||
file_names: list[str] = Field(default_factory=list)
|
||||
conversation_history: list[ConversationMessage] = Field(default_factory=list)
|
||||
page_layout: list[PageLayout] = Field(default_factory=list)
|
||||
|
||||
|
||||
# ── Output: response variants ────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class PdfToMarkdownSuccessResponse(ApiModel):
|
||||
outcome: Literal["document_reconstructed"] = "document_reconstructed"
|
||||
markdown: str
|
||||
|
||||
|
||||
class PdfToMarkdownCannotDoResponse(ApiModel):
|
||||
outcome: Literal["cannot_do"] = "cannot_do"
|
||||
reason: str
|
||||
|
||||
|
||||
type PdfToMarkdownResponse = Annotated[
|
||||
PdfToMarkdownSuccessResponse | PdfToMarkdownCannotDoResponse,
|
||||
Field(discriminator="outcome"),
|
||||
]
|
||||
|
||||
type PdfToMarkdownOrchestrateResponse = Annotated[
|
||||
GenerateFileResponse | EditCannotDoResponse | NeedContentResponse,
|
||||
Field(discriminator="outcome"),
|
||||
]
|
||||
Reference in New Issue
Block a user