| """ |
| schema.py — Paper2Lab data contracts. |
| |
| Field-agnostic contracts for PDF extraction across ML, NLP, CV, biomedical, |
| physics, education, social-science, economics, and interdisciplinary papers. |
| """ |
|
|
| from __future__ import annotations |
|
|
| from dataclasses import asdict, dataclass, field |
| from typing import Any, Dict, List, Optional |
|
|
|
|
| KNOWN_ROLES = frozenset({ |
| "front_matter", |
| "abstract", |
| "keywords", |
| "introduction", |
| "related_work", |
| "background", |
| "theory", |
| "methodology", |
| "experiments", |
| "results", |
| "discussion", |
| "limitations", |
| "future_work", |
| "conclusion", |
| "references", |
| "appendix", |
| "boilerplate", |
| "other", |
| }) |
|
|
|
|
| @dataclass |
| class Section: |
| title: str |
| text: str |
| level: int = 1 |
| page_start: Optional[int] = None |
| page_end: Optional[int] = None |
| role: str = "other" |
| word_count: int = 0 |
|
|
| def __post_init__(self) -> None: |
| if self.role not in KNOWN_ROLES: |
| self.role = "other" |
| if not self.word_count: |
| self.word_count = len((self.text or "").split()) |
|
|
|
|
| @dataclass |
| class Caption: |
| label: str |
| caption: str |
| page_number: Optional[int] = None |
|
|
|
|
| @dataclass |
| class Table: |
| page_number: Optional[int] |
| table_index: int |
| data: Any |
| engine: str = "unknown" |
| caption: Optional[str] = None |
|
|
|
|
| @dataclass |
| class DocumentExtraction: |
| source_pdf: str |
| title: Optional[str] |
| abstract: Optional[str] |
| text: str |
| clean_text: str |
| raw_text: str = "" |
| num_pages: Optional[int] = None |
| sections: List[Section] = field(default_factory=list) |
| all_sections: List[Section] = field(default_factory=list) |
| references: List[str] = field(default_factory=list) |
| references_text: str = "" |
| appendix_text: str = "" |
| boilerplate_text: str = "" |
| captions: List[Caption] = field(default_factory=list) |
| tables: List[Table] = field(default_factory=list) |
| pages: List[Dict[str, Any]] = field(default_factory=list) |
| metadata: Dict[str, Any] = field(default_factory=dict) |
| quality: Dict[str, Any] = field(default_factory=dict) |
| extraction_engine: str = "unknown" |
|
|
| def to_dict(self) -> Dict[str, Any]: |
| return asdict(self) |
|
|