Structured Data from Unstructured content
Discover how PyMuPDF can transform unstructured PDF content into structured, machine-readable data, enabling efficient processing with layout analysis.
- Source exactly where the answers come from in the document.
- Ensure transparency and verifiability in your AI workflows.
Extract
Read the document's native structure instead of flattening it into images. PyMuPDF is trained on a Graph Neural Network to understand and preserve the document's layout.
Format
Convert the content into structured data that keeps context and hierarchy intact. Deliver it as structured Markdown, JSON or Text. Chunk it for retrieval or further processing.
Ingest
Send the output to your vector store, prompt, or document workflow.
Turn every answer into verifiable evidence
Use to_json() when your AI workflow needs more than text. The output keeps each extracted item tied to its page and bounding box, giving you deterministic positional data for locating the exact source region in the original PDF.
Page address
Record the page number with every text element so a response can point back to the exact PDF page that supplied its context.
Bounding box
Preserve the element's coordinates as a four-value rectangle in PDF space, ready to highlight or inspect the precise source location.
Evidence object
Return the answer with its supporting text, page, and box metadata so users can verify the claim instead of trusting an untraceable generated sentence.
Build grounded answers from source locations
Store these evidence objects alongside embeddings or attach them to the LLM response. Your application can then link to a page, draw the bounding box, or show the exact passage that supports an answer.
The following code sample demonstrates the retrieval of evidence objects from source locations.
import json
import pymupdf
doc = pymupdf.open("input.pdf") # open the document
json_text = doc.to_json()
document = json.loads(json_text)
def get_box_content(box):
"""Return content according to the box's object type."""
object_type = box.get("boxclass")
if object_type == "table":
table = box.get("table") or {}
return {
"rows": table.get("extract", []),
"markdown": table.get("markdown", ""),
}
if object_type == "picture":
return box.get("image")
lines = []
for line in box.get("textlines") or []:
line_text = ""
for span in line.get("spans", []):
line_text += span.get("text", "")
lines.append(line_text)
return "\n".join(lines)
# traverse the document's pages and get the box content
for page in document.get("pages", []):
print(f"\nPage: {page.get('page_number')}")
for box in page.get("boxes", []):
object_type = box.get("boxclass")
bounding_box = (
box.get("x0"),
box.get("y0"),
box.get("x1"),
box.get("y1"),
)
content = get_box_content(box)
print(f"Object type: {object_type}")
print(f"Bounding box: {bounding_box}")
if object_type == "table":
print("Table content:")
print(content["markdown"])
print("Table rows:", content["rows"])
elif object_type == "picture":
print(f"Picture content: {content}")
else:
print(f"Text content: {content}")
print("-" * 50)