HK-UTM-LLM / src /regx /parse_pdf.py
GordonUK's picture
Create src/regx/parse_pdf.py
da859e8 verified
Raw
History Blame Contribute Delete
2.09 kB
from __future__ import annotations
import fitz # PyMuPDF
from .models import Node, SourceMeta
from .ids import stable_id
from .normalize import normalize_text
def parse_pdf(manifest_path: str, source: SourceMeta) -> Node:
# Very light heuristic: create sections when font size increases significantly
import json
with open(manifest_path) as f:
m = json.load(f)
doc = fitz.open(m["artifact_path"])
pages = doc.page_count
root = Node(node_id=stable_id(source.sha256 or source.url, "PDF"), path=[], label="ROOT", text="", children=[])
current = Node(node_id=stable_id(source.sha256 or source.url, "PDF_BODY"), path=["Body"], label="Body", title="Body", text="", children=[], page_span=(1, pages))
root.children.append(current)
for i in range(pages):
page = doc.load_page(i)
blocks = page.get_text("dict")["blocks"]
for b in blocks:
if "lines" not in b: continue
# compute an average font size in the block
sizes = []
texts = []
for l in b["lines"]:
for s in l["spans"]:
sizes.append(s.get("size", 0))
texts.append(s.get("text", ""))
text = normalize_text(" ".join(texts))
if not text: continue
avg = sum(sizes)/len(sizes) if sizes else 0
# Simple split: treat abnormally large text as a heading
if avg >= 14 and len(text) <= 140:
# start a new subsection
sec_path = ["Body", text]
node = Node(node_id=stable_id(source.sha256 or source.url, "/".join(sec_path)),
path=sec_path, label=text, title=text, text="", page_span=(i+1, i+1))
current.children.append(node)
else:
if current.children:
current.children[-1].text += (("\n\n" if current.children[-1].text else "") + text)
else:
current.text += (("\n\n" if current.text else "") + text)
doc.close()
return root