Spaces:
Sleeping
Sleeping
File size: 8,286 Bytes
c6c9042 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | # PDF Accessibility Pipeline
Automatically analyses a PDF document and produces a fully tagged, screen-reader-accessible PDF conforming to the **PDF/UA-1** standard.
---
## How it works
```
data/input.pdf
β
βΌ Part 1 β generate_metadata (Python)
β
ββ YOLOv11 layout detection βββΊ segmented regions
ββ Tesseract OCR βββΊ extracted text
ββ LaTeX chunking βββΊ document order + reading order
ββ GPT-4o labeling + alt-text
β
βΌ
output/elements.txt
β
βΌ Part 2 β embed_metadata (Java / iText 9)
β
ββ PDF structure tree (tags) βββΊ output/tagged_output.pdf (PDF/UA-1)
```
---
## Prerequisites
### 1 Β· Python (β₯ 3.9)
```bash
pip install -r requirements.txt
```
> **System packages also needed:**
> | Tool | Purpose | macOS | Linux (apt) |
> |------|---------|-------|-------------|
> | **Tesseract** | OCR engine | `brew install tesseract` | `apt install tesseract-ocr` |
> | **Poppler** | PDF β image | `brew install poppler` | `apt install poppler-utils` |
### 2 Β· Java (β₯ 11) + Maven (β₯ 3.6)
```bash
brew install openjdk@11 maven # macOS
# or: apt install openjdk-11-jdk maven (Linux)
```
### 3 Β· YOLOv11 model weights
Download the pre-trained document-layout model:
```
https://github.com/moured/YOLOv11-Document-Layout-Analysis/releases
β yolov11x_best.pt
```
Save it anywhere and set the path (see Configuration below).
### 4 Β· OpenAI API key
Required for LaTeX chunk mapping and figure alt-text generation.
---
## Configuration
Create a `.env` file in the project root (or export as environment variables):
```dotenv
# .env β copy this block and fill in your values
# REQUIRED: OpenAI API key
OPENAI_API_KEY=sk-...
# REQUIRED: Path to downloaded YOLOv11 weights
YOLO_MODEL_PATH=/absolute/path/to/yolov11x_best.pt
```
All other settings can be tweaked in [`generate_metadata/config.py`](generate_metadata/config.py).
---
## Input files
Place both inputs in the `data/` directory before running:
| What | Where to put it |
|------|----------------|
| Input PDF | `data/input.pdf` |
| LaTeX source | any subfolder inside `data/` e.g. `data/my-paper/` |
The pipeline auto-detects the LaTeX subfolder inside `data/`.
Everything else (`elements.txt`, tagged PDF, visualizations) is generated by the pipeline into `output/`.
---
## Quick start
```bash
# 1. Clone and enter the repo
git clone <repo-url>
cd pdf-script
# 2. Configure
cp .env.example .env # then fill in OPENAI_API_KEY and YOLO_MODEL_PATH
# (or just export them in your shell)
# 3. Install Python dependencies
pip install -r requirements.txt
# 4. Build the Java tagger
mvn package -DskipTests # creates pdftagger.jar
# 5. Place your inputs in data/
cp your-paper.pdf data/input.pdf
cp -r your-latex-project/ data/my-paper/ # any subfolder name works
# 6. Run the full pipeline
python pipeline.py
```
Outputs land in `output/`:
```
output/
βββ elements.txt β structured metadata (roles + bboxes)
βββ tagged_output.pdf β accessible PDF/UA-1 output
βββ latex_chunks.txt β debug: LaTeX semantic chunks
βββ segments2chunks_gpt.txt β debug: OCR β chunk mapping log
βββ pdf-imgs/ β per-page PNG images
βββ segmentations-1/ β YOLO detection visualisations
βββ segmentations-2/ β refined segment visualisations
βββ visualizations/
βββ labels.pdf β annotated pages with element labels
βββ reading_order.pdf β annotated pages with reading-order numbers
```
---
## Usage reference
### Full pipeline
```bash
# Place data/input.pdf and data/<your-latex-folder>/ first, then:
python pipeline.py # auto-detects everything in data/
python pipeline.py --pdf path/to/paper.pdf # custom PDF location
python pipeline.py --latex path/to/latex-dir/ # custom LaTeX parent directory
python pipeline.py --pages 3 # first 3 pages only
```
### Part 1 only (analysis β elements.txt)
```bash
python -m generate_metadata.main \
--pdf data/input.pdf \
--output output/
```
### Part 2 only (tag an existing elements.txt)
```bash
python pipeline.py --skip-metadata
# or call the Java tagger directly:
java -jar pdftagger.jar data/input.pdf output/elements.txt output/tagged_output.pdf
```
### Rebuild JAR (after changing Java code)
```bash
python pipeline.py --rebuild-jar
# or:
mvn package -DskipTests
```
### CLI reference
```
python pipeline.py --help
--pdf PATH Input PDF (default: data/input.pdf)
--latex DIR Directory containing the LaTeX source subfolder (default: data/)
--output DIR Output directory (default: output/)
--pages N Process first N pages only (-1 = all)
--skip-metadata Skip Part 1, reuse existing output/elements.txt
--skip-tagging Skip Part 2 (Java tagger)
--rebuild-jar Force rebuild of pdftagger.jar
```
---
## Project structure
```
pdf-script/
β
βββ pipeline.py β Main entry point (runs both parts)
βββ requirements.txt β Python dependencies
βββ pom.xml β Maven build (embed_metadata JAR)
βββ .env β Your secrets (not committed)
β
βββ data/
β βββ input.pdf β Place your PDF here
β
βββ output/ β All generated files (gitignored)
β
βββ generate_metadata/ β Part 1: Python analysis pipeline
β βββ main.py β Entry point for Part 1
β βββ config.py β API keys, model paths, settings
β βββ pdf_loader.py ββ PDF β page images (pdf2image)
β βββ segmentation.py ββ YOLOv11 layout detection + bbox utils
β βββ ocr.py ββ Tesseract OCR
β βββ latex_processor.py ββ LaTeX flattening + semantic chunking
β βββ mapping.py ββ OCR β YOLO mapping + refinement
β βββ chunk_mapper.py ββ Segment β LaTeX chunk matching (GPT-4o)
β βββ refinement.py ββ Semantic split / merge / clean
β βββ labeling.py ββ Accessibility role labeling
β βββ reading_order.py ββ Reading order determination
β βββ alt_text.py ββ Figure alt-text (\\Description or GPT-4o)
β βββ sanity_check.py ββ GPT-4o label + reading-order QA pass
β βββ output.py ββ Write elements.txt + visualisation PDFs
β
βββ embed_metadata/ β Part 2: Java PDF tagger (iText 9 / PDF/UA-1)
βββ src/main/java/com/pdftag/
βββ itagpdf.java β CLI entry point
βββ TagPDF.java β Core tagging logic
```
---
## elements.txt format
Pipe-delimited, with leading `|` characters indicating nesting depth:
```
Sect|1|100|50|800|900|
|H1|1|120|60|780|120|Introduction
|P|1|120|130|780|200|This paper presentsβ¦
|FIGURE|1|120|210|500|450|Chart showing accuracy over time
|TABLE|1|120|460|780|650|
||TR|1|125|465|775|495|
|||TH|1|125|465|300|495|Method
|||TH|1|305|465|500|495|Accuracy
```
Columns: `[depth-pipes] role | page | x1 | y1 | x2 | y2 | text`
**Supported roles:** `H1` `H2` `H3` `P` `Sect` `FIGURE` `CAPTION` `TABLE` `TR` `TH` `TD` `L` `LI` `AUTHOR` `BIBENTRY` `FORMULA` `NOTE` `ARTIFACT`
---
## Troubleshooting
| Error | Fix |
|-------|-----|
| `OPENAI_API_KEY is not set` | Add key to `.env` or export in shell |
| `YOLO_MODEL_PATH` not found | Download weights and update `.env` |
| `tesseract: command not found` | `brew install tesseract` / `apt install tesseract-ocr` |
| `pdftoppm: command not found` | `brew install poppler` / `apt install poppler-utils` |
| `mvn: command not found` | `brew install maven` / `apt install maven` |
| JAR build fails | Check `java -version` β needs Java 11+. On macOS: `export JAVA_HOME=$(/usr/libexec/java_home -v 11)` |
|