mirror of
https://github.com/lllin000/PaperForge.git
synced 2026-07-22 06:50:53 +00:00
fix: stop paper_title pollution, text-to-heading, table HTML leak, author recovery
This commit is contained in:
parent
27511b6df6
commit
009be8c958
5 changed files with 45 additions and 19 deletions
|
|
@ -25,7 +25,7 @@ def build_structured_blocks(raw_blocks: list[dict]) -> list[dict]:
|
|||
index_default = True
|
||||
if role.role in {"noise", "page_header", "page_footer", "frontmatter_noise"}:
|
||||
render_default = False
|
||||
if role.role in {"noise", "frontmatter_noise"}:
|
||||
if role.role in {"noise", "frontmatter_noise", "table_html"}:
|
||||
index_default = False
|
||||
row = {
|
||||
"paper_id": block["paper_id"],
|
||||
|
|
|
|||
|
|
@ -78,29 +78,27 @@ def resolve_metadata(
|
|||
|
||||
# --- authors ---
|
||||
zotero_authors = source_metadata.get("authors", [])
|
||||
ocr_authors_text = frontmatter_candidates.get("authors_text", "")
|
||||
ocr_author_list = [a.strip() for a in ocr_authors_text.split(",") if a.strip()] if ocr_authors_text else []
|
||||
|
||||
if isinstance(zotero_authors, list) and len(zotero_authors) > 0:
|
||||
resolved["authors"] = {
|
||||
"value": zotero_authors,
|
||||
"source": "zotero",
|
||||
"confidence": 0.99,
|
||||
}
|
||||
elif ocr_author_list:
|
||||
resolved["authors"] = {
|
||||
"value": ocr_author_list,
|
||||
"source": "ocr_frontmatter",
|
||||
"confidence": 0.6,
|
||||
}
|
||||
else:
|
||||
resolved["authors"] = {
|
||||
"value": [],
|
||||
"source": "unknown",
|
||||
"confidence": 0.3,
|
||||
}
|
||||
ocr_authors_text = frontmatter_candidates.get("authors_text", "")
|
||||
if ocr_authors_text:
|
||||
ocr_author_list = [a.strip() for a in ocr_authors_text.split(",") if a.strip()]
|
||||
if ocr_author_list and ocr_author_list != zotero_authors:
|
||||
resolved["authors"]["alternatives"] = [
|
||||
{
|
||||
"value": ocr_author_list,
|
||||
"source": "ocr_frontmatter",
|
||||
"confidence": 0.6,
|
||||
}
|
||||
]
|
||||
|
||||
# --- year ---
|
||||
zotero_year = source_metadata.get("year", 0)
|
||||
|
|
|
|||
|
|
@ -92,10 +92,12 @@ def render_fulltext_markdown(
|
|||
if not block.get("render_default", True):
|
||||
continue
|
||||
role = block.get("role", "")
|
||||
if role in ("abstract_heading", "abstract_body", "figure_caption", "table_caption", "frontmatter_noise"):
|
||||
if role in ("abstract_heading", "abstract_body", "figure_caption", "table_caption", "frontmatter_noise", "table_html"):
|
||||
continue
|
||||
|
||||
text = _normalize_latex(block.get("text", ""))
|
||||
if text.strip().lower().startswith("<table"):
|
||||
continue
|
||||
block_page = block.get("page")
|
||||
|
||||
if block_page is not None and block_page != current_page:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class RoleAssignment:
|
|||
|
||||
|
||||
_HEADING_NUMBER_PATTERN = re.compile(
|
||||
r"^\d+(?:\.\d+)*\s+\w",
|
||||
r"^\d+(?:\.\d+)*\s+[A-Z]",
|
||||
)
|
||||
|
||||
_FIGURE_PREFIX_PATTERN = re.compile(
|
||||
|
|
@ -141,10 +141,17 @@ def assign_block_role(
|
|||
confidence=0.85,
|
||||
evidence=[f"paragraph_title label with numbering: {text[:60]}"],
|
||||
)
|
||||
page_num = block.get("page", 1) or 1
|
||||
if page_num <= 1:
|
||||
return RoleAssignment(
|
||||
role="paper_title",
|
||||
confidence=0.7,
|
||||
evidence=[f"unnumbered paragraph_title on page 1, likely paper title: {text[:60]}"],
|
||||
)
|
||||
return RoleAssignment(
|
||||
role="paper_title",
|
||||
confidence=0.7,
|
||||
evidence=[f"unnumbered paragraph_title, likely paper title: {text[:60]}"],
|
||||
role="section_heading",
|
||||
confidence=0.6,
|
||||
evidence=[f"unnumbered paragraph_title on page {page_num}, treated as heading: {text[:60]}"],
|
||||
)
|
||||
|
||||
if raw_label == "figure_title":
|
||||
|
|
@ -189,6 +196,13 @@ def assign_block_role(
|
|||
evidence=["abstract label from Paddle OCR"],
|
||||
)
|
||||
|
||||
if raw_label == "reference_content":
|
||||
return RoleAssignment(
|
||||
role="reference_item",
|
||||
confidence=0.85,
|
||||
evidence=[f"reference content label: {text[:60]}"],
|
||||
)
|
||||
|
||||
# text with reference-like pattern
|
||||
if _looks_like_reference(text):
|
||||
return RoleAssignment(
|
||||
|
|
@ -202,6 +216,14 @@ def assign_block_role(
|
|||
stripped = text.strip().lstrip("*•·-–—_")
|
||||
lower_txt = stripped.lower()
|
||||
|
||||
# Check for inline table HTML
|
||||
if text.strip().lower().startswith("<table"):
|
||||
return RoleAssignment(
|
||||
role="table_html",
|
||||
confidence=0.95,
|
||||
evidence=[f"inline table HTML"],
|
||||
)
|
||||
|
||||
# Check for abstract heading (may appear as text block, not paragraph_title)
|
||||
if lower_txt.startswith("abstract") and len(text) < 30:
|
||||
return RoleAssignment(
|
||||
|
|
@ -290,7 +312,11 @@ def assign_block_role(
|
|||
confidence=0.7,
|
||||
evidence=[f"frontmatter noise text: {text[:60]}"],
|
||||
)
|
||||
if _has_heading_numbering(text):
|
||||
if (
|
||||
_has_heading_numbering(text)
|
||||
and len(text) < 80
|
||||
and ". " not in text
|
||||
):
|
||||
return RoleAssignment(
|
||||
role="section_heading" if re.match(r"^\d+\s", text) else "subsection_heading",
|
||||
confidence=0.65,
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ def test_stabilize_role_classifies_paper_title() -> None:
|
|||
from paperforge.worker.ocr_roles import assign_block_role
|
||||
|
||||
assignment = assign_block_role(
|
||||
block={"block_label": "paragraph_title", "block_content": "Test Paper About Science"},
|
||||
block={"block_label": "paragraph_title", "block_content": "Test Paper About Science", "page": 1},
|
||||
page_blocks=[],
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue