llmPDF 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- llmpdf-0.7.0/LICENSE +103 -0
- llmpdf-0.7.0/MANIFEST.in +1 -0
- llmpdf-0.7.0/PKG-INFO +488 -0
- llmpdf-0.7.0/README.md +455 -0
- llmpdf-0.7.0/SDK.md +258 -0
- llmpdf-0.7.0/pyproject.toml +68 -0
- llmpdf-0.7.0/setup.cfg +4 -0
- llmpdf-0.7.0/src/llmPDF.egg-info/PKG-INFO +488 -0
- llmpdf-0.7.0/src/llmPDF.egg-info/SOURCES.txt +100 -0
- llmpdf-0.7.0/src/llmPDF.egg-info/dependency_links.txt +1 -0
- llmpdf-0.7.0/src/llmPDF.egg-info/entry_points.txt +3 -0
- llmpdf-0.7.0/src/llmPDF.egg-info/requires.txt +9 -0
- llmpdf-0.7.0/src/llmPDF.egg-info/top_level.txt +2 -0
- llmpdf-0.7.0/src/llmpdf/__init__.py +36 -0
- llmpdf-0.7.0/src/llmpdf/__main__.py +3 -0
- llmpdf-0.7.0/src/llmpdf/agent_scheduler.py +221 -0
- llmpdf-0.7.0/src/llmpdf/assets_task.py +174 -0
- llmpdf-0.7.0/src/llmpdf/batch.py +418 -0
- llmpdf-0.7.0/src/llmpdf/cli.py +472 -0
- llmpdf-0.7.0/src/llmpdf/detection_task.py +543 -0
- llmpdf-0.7.0/src/llmpdf/docling_task.py +342 -0
- llmpdf-0.7.0/src/llmpdf/docling_worker.py +37 -0
- llmpdf-0.7.0/src/llmpdf/extraction_task.py +371 -0
- llmpdf-0.7.0/src/llmpdf/image_analysis_task.py +1210 -0
- llmpdf-0.7.0/src/llmpdf/images_task.py +122 -0
- llmpdf-0.7.0/src/llmpdf/io_utils.py +62 -0
- llmpdf-0.7.0/src/llmpdf/merge_rules/__init__.py +9 -0
- llmpdf-0.7.0/src/llmpdf/merge_rules/find_image_absorbed_blocks.py +29 -0
- llmpdf-0.7.0/src/llmpdf/merge_rules/find_table_absorbed_blocks.py +18 -0
- llmpdf-0.7.0/src/llmpdf/merge_rules/is_protected_block.py +6 -0
- llmpdf-0.7.0/src/llmpdf/merge_task.py +639 -0
- llmpdf-0.7.0/src/llmpdf/metrics_task.py +236 -0
- llmpdf-0.7.0/src/llmpdf/models.py +150 -0
- llmpdf-0.7.0/src/llmpdf/pages.py +69 -0
- llmpdf-0.7.0/src/llmpdf/pi_runtime.py +5 -0
- llmpdf-0.7.0/src/llmpdf/pipeline.py +164 -0
- llmpdf-0.7.0/src/llmpdf/preflight.py +97 -0
- llmpdf-0.7.0/src/llmpdf/progress.py +12 -0
- llmpdf-0.7.0/src/llmpdf/rerun.py +205 -0
- llmpdf-0.7.0/src/llmpdf/retention.py +185 -0
- llmpdf-0.7.0/src/llmpdf/review.py +43 -0
- llmpdf-0.7.0/src/llmpdf/review_discovery.py +54 -0
- llmpdf-0.7.0/src/llmpdf/review_project.py +42 -0
- llmpdf-0.7.0/src/llmpdf/review_server.py +114 -0
- llmpdf-0.7.0/src/llmpdf/review_source.py +431 -0
- llmpdf-0.7.0/src/llmpdf/review_static/assets/index-Ch2-xtmb.js +90 -0
- llmpdf-0.7.0/src/llmpdf/review_static/assets/index-DYQ2zsXw.css +1 -0
- llmpdf-0.7.0/src/llmpdf/review_static/assets/pdf.worker.min-Dswkl-cV.mjs +29 -0
- llmpdf-0.7.0/src/llmpdf/review_static/index.html +14 -0
- llmpdf-0.7.0/src/llmpdf/review_tables.py +101 -0
- llmpdf-0.7.0/src/llmpdf/run_status.py +206 -0
- llmpdf-0.7.0/src/llmpdf/screenshots_task.py +151 -0
- llmpdf-0.7.0/src/llmpdf/sdk.py +477 -0
- llmpdf-0.7.0/src/llmpdf/table/__init__.py +3 -0
- llmpdf-0.7.0/src/llmpdf/table/__main__.py +5 -0
- llmpdf-0.7.0/src/llmpdf/table/agent_runner.py +229 -0
- llmpdf-0.7.0/src/llmpdf/table/cli.py +176 -0
- llmpdf-0.7.0/src/llmpdf/table/io_utils.py +64 -0
- llmpdf-0.7.0/src/llmpdf/table/models.py +49 -0
- llmpdf-0.7.0/src/llmpdf/table/orchestration.py +436 -0
- llmpdf-0.7.0/src/llmpdf/table/pi_runtime.py +65 -0
- llmpdf-0.7.0/src/llmpdf/table/prepare.py +222 -0
- llmpdf-0.7.0/src/llmpdf/table/prompt.py +253 -0
- llmpdf-0.7.0/src/llmpdf/table/run_all.py +63 -0
- llmpdf-0.7.0/src/llmpdf/table/runner.py +41 -0
- llmpdf-0.7.0/src/llmpdf/table/runtime.py +170 -0
- llmpdf-0.7.0/src/llmpdf/table/table_guard.py +230 -0
- llmpdf-0.7.0/src/llmpdf/task.py +117 -0
- llmpdf-0.7.0/src/llmpdf/validate_task.py +309 -0
- llmpdf-0.7.0/tests/test_agent_scheduler.py +68 -0
- llmpdf-0.7.0/tests/test_assets.py +21 -0
- llmpdf-0.7.0/tests/test_batch.py +112 -0
- llmpdf-0.7.0/tests/test_cli.py +240 -0
- llmpdf-0.7.0/tests/test_detection.py +316 -0
- llmpdf-0.7.0/tests/test_docling.py +149 -0
- llmpdf-0.7.0/tests/test_executable_discovery.py +18 -0
- llmpdf-0.7.0/tests/test_extraction.py +110 -0
- llmpdf-0.7.0/tests/test_image_analysis.py +211 -0
- llmpdf-0.7.0/tests/test_image_optimization.py +31 -0
- llmpdf-0.7.0/tests/test_images.py +18 -0
- llmpdf-0.7.0/tests/test_io_utils.py +67 -0
- llmpdf-0.7.0/tests/test_merge.py +307 -0
- llmpdf-0.7.0/tests/test_merge_rules.py +37 -0
- llmpdf-0.7.0/tests/test_metrics.py +47 -0
- llmpdf-0.7.0/tests/test_models.py +15 -0
- llmpdf-0.7.0/tests/test_pages.py +26 -0
- llmpdf-0.7.0/tests/test_pipeline_sessions.py +89 -0
- llmpdf-0.7.0/tests/test_preflight.py +46 -0
- llmpdf-0.7.0/tests/test_render_budget.py +27 -0
- llmpdf-0.7.0/tests/test_rerun.py +112 -0
- llmpdf-0.7.0/tests/test_retention.py +113 -0
- llmpdf-0.7.0/tests/test_review.py +250 -0
- llmpdf-0.7.0/tests/test_run_status.py +94 -0
- llmpdf-0.7.0/tests/test_sdk.py +213 -0
- llmpdf-0.7.0/tests/test_table_guard.py +21 -0
- llmpdf-0.7.0/tests/test_table_models.py +30 -0
- llmpdf-0.7.0/tests/test_table_prompt.py +89 -0
- llmpdf-0.7.0/tests/test_table_run_all.py +41 -0
- llmpdf-0.7.0/tests/test_table_runner.py +323 -0
- llmpdf-0.7.0/tests/test_table_runtime.py +118 -0
- llmpdf-0.7.0/tests/test_task_cache.py +63 -0
- llmpdf-0.7.0/tests/test_validate.py +77 -0
llmpdf-0.7.0/LICENSE
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
llmPDF Limited Use License 1.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yechenyan. All rights reserved.
|
|
4
|
+
|
|
5
|
+
1. Definitions
|
|
6
|
+
|
|
7
|
+
"Software" means the llmPDF software distributed with this license, including
|
|
8
|
+
its source code, object code, documentation, and original assets.
|
|
9
|
+
|
|
10
|
+
"Unmodified Copy" means a complete copy of the Software whose contents have
|
|
11
|
+
not been altered. Ordinary installation, execution, configuration through
|
|
12
|
+
documented options, creation of bytecode or caches, and use through documented
|
|
13
|
+
command-line or programming interfaces do not make a copy modified.
|
|
14
|
+
|
|
15
|
+
2. License Grant
|
|
16
|
+
|
|
17
|
+
Subject to this license, the copyright holder grants you a worldwide,
|
|
18
|
+
royalty-free, non-exclusive license to:
|
|
19
|
+
|
|
20
|
+
a. install, execute, and use Unmodified Copies for any purpose, including
|
|
21
|
+
commercial purposes;
|
|
22
|
+
|
|
23
|
+
b. integrate an Unmodified Copy with other software through the Software's
|
|
24
|
+
documented command-line and programming interfaces; and
|
|
25
|
+
|
|
26
|
+
c. reproduce and redistribute Unmodified Copies, either separately or together
|
|
27
|
+
with other software, provided that you comply with Section 3.
|
|
28
|
+
|
|
29
|
+
3. Attribution and Notices
|
|
30
|
+
|
|
31
|
+
Every redistributed copy must include this license and all copyright,
|
|
32
|
+
attribution, and proprietary notices supplied with the Software.
|
|
33
|
+
|
|
34
|
+
Any product, distribution, documentation, credits page, or other materials that
|
|
35
|
+
accompany a redistributed copy must display the following notice in a
|
|
36
|
+
reasonably prominent manner:
|
|
37
|
+
|
|
38
|
+
This product includes llmPDF, Copyright (c) 2026 yechenyan,
|
|
39
|
+
used under the llmPDF Limited Use License 1.0.
|
|
40
|
+
|
|
41
|
+
If the distribution has no documentation or credits page, the notice must be
|
|
42
|
+
provided in another reasonably prominent location accompanying the Software.
|
|
43
|
+
|
|
44
|
+
4. Restrictions
|
|
45
|
+
|
|
46
|
+
Except where applicable law expressly permits and does not allow the
|
|
47
|
+
restriction to be waived, you may not:
|
|
48
|
+
|
|
49
|
+
a. modify, adapt, translate, transform, or create derivative works of the
|
|
50
|
+
Software;
|
|
51
|
+
|
|
52
|
+
b. distribute or make available a modified version or derivative work of the
|
|
53
|
+
Software;
|
|
54
|
+
|
|
55
|
+
c. remove, obscure, or alter any copyright, attribution, license, or
|
|
56
|
+
proprietary notice;
|
|
57
|
+
|
|
58
|
+
d. sublicense the Software or grant rights in it beyond those provided by this
|
|
59
|
+
license; or
|
|
60
|
+
|
|
61
|
+
e. use the names, logos, or trademarks of llmPDF or the copyright holder to
|
|
62
|
+
imply endorsement, sponsorship, or affiliation.
|
|
63
|
+
|
|
64
|
+
5. Ownership
|
|
65
|
+
|
|
66
|
+
The Software is licensed, not sold. The copyright holder retains all rights,
|
|
67
|
+
title, and interest in the Software except for the limited permissions expressly
|
|
68
|
+
granted by this license. No patent or trademark rights are granted.
|
|
69
|
+
|
|
70
|
+
6. Third-Party Components
|
|
71
|
+
|
|
72
|
+
Third-party software and assets included with or required by the Software are
|
|
73
|
+
licensed under their respective terms. This license applies only to the rights
|
|
74
|
+
held by the llmPDF copyright holder and does not replace or limit any
|
|
75
|
+
third-party license.
|
|
76
|
+
|
|
77
|
+
7. Termination
|
|
78
|
+
|
|
79
|
+
Your rights under this license terminate automatically if you breach its terms.
|
|
80
|
+
Upon termination, you must stop using and redistributing the Software and
|
|
81
|
+
destroy copies in your possession or control, except where retention is required
|
|
82
|
+
by law. The copyright holder may reinstate your rights in writing.
|
|
83
|
+
|
|
84
|
+
8. Disclaimer of Warranty
|
|
85
|
+
|
|
86
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
87
|
+
IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
88
|
+
PURPOSE, TITLE, AND NON-INFRINGEMENT. YOU BEAR ALL RISK ARISING FROM USE OF THE
|
|
89
|
+
SOFTWARE.
|
|
90
|
+
|
|
91
|
+
9. Limitation of Liability
|
|
92
|
+
|
|
93
|
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE COPYRIGHT HOLDER WILL NOT BE LIABLE
|
|
94
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, CONSEQUENTIAL, OR
|
|
95
|
+
OTHER DAMAGES ARISING FROM OR RELATED TO THE SOFTWARE OR THIS LICENSE, EVEN IF
|
|
96
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
97
|
+
|
|
98
|
+
10. Severability
|
|
99
|
+
|
|
100
|
+
If any provision of this license is held unenforceable, it will be limited or
|
|
101
|
+
removed only to the minimum extent necessary, and the remaining provisions will
|
|
102
|
+
remain in effect.
|
|
103
|
+
|
llmpdf-0.7.0/MANIFEST.in
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include SDK.md
|
llmpdf-0.7.0/PKG-INFO
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: llmPDF
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: Task-oriented PDF conversion and review toolkit
|
|
5
|
+
Author-email: yechenyan <ccyechenyan@gmail.com>
|
|
6
|
+
License-Expression: LicenseRef-llmPDF-Limited-Use-1.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/yechenyan/llmPDF
|
|
8
|
+
Project-URL: Repository, https://github.com/yechenyan/llmPDF
|
|
9
|
+
Project-URL: Issues, https://github.com/yechenyan/llmPDF/issues
|
|
10
|
+
Keywords: pdf,markdown,docling,document-processing,llm
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
21
|
+
Requires-Python: <3.15,>=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: docling<2.124,>=2.123
|
|
25
|
+
Requires-Dist: pdfplumber<0.12,>=0.11
|
|
26
|
+
Requires-Dist: Pillow<13,>=11
|
|
27
|
+
Requires-Dist: pypdf<7,>=6
|
|
28
|
+
Requires-Dist: PyYAML<7,>=6
|
|
29
|
+
Provides-Extra: review
|
|
30
|
+
Requires-Dist: fastapi<1,>=0.115; extra == "review"
|
|
31
|
+
Requires-Dist: uvicorn<1,>=0.30; extra == "review"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# llmPDF
|
|
35
|
+
|
|
36
|
+
Convert PDFs into Markdown that is suitable for reading, search, and downstream processing. The tool preserves document structure, extracts tables, and can analyze images and charts. A local review UI lets you compare the generated Markdown with the source PDF.
|
|
37
|
+
|
|
38
|
+
Use `llmpdf convert` for normal operation. One command runs the complete conversion.
|
|
39
|
+
|
|
40
|
+
## Requirements
|
|
41
|
+
|
|
42
|
+
- Python 3.11–3.14
|
|
43
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
44
|
+
- Poppler's `pdftoppm`
|
|
45
|
+
- Node.js 20.6+
|
|
46
|
+
- A working Codex/Pi login and network connection
|
|
47
|
+
|
|
48
|
+
Install Poppler on macOS with Homebrew:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
brew install poppler
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
On Ubuntu or Debian, install `poppler-utils`:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
sudo apt-get install poppler-utils
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The first run may download document-analysis models and can take longer than later runs.
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
From the project directory, run:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
uv sync --extra review --locked
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This installs both the converter and the optional local review UI.
|
|
71
|
+
|
|
72
|
+
Verify the installation:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uv run llmpdf --help
|
|
76
|
+
uv run llmpdf convert --help
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv run llmpdf convert \
|
|
83
|
+
"/absolute/path/to/input.pdf" \
|
|
84
|
+
--output-dir "/absolute/path/to/results"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
On success, the command prints JSON to standard output. It includes `output_markdown`, `output_dir`, token usage, and elapsed time.
|
|
88
|
+
|
|
89
|
+
The default result directory is:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
<output-dir>/<UTC batch timestamp>/<PDF filename>/
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Set a stable batch name when you need a predictable path or resumable retries:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
uv run llmpdf convert \
|
|
99
|
+
"/absolute/path/to/input.pdf" \
|
|
100
|
+
--output-dir "/absolute/path/to/results" \
|
|
101
|
+
--batch-id "edis-2024"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
After a failure, rerun with the same PDF, `--output-dir`, and `--batch-id`. Completed results that remain valid are reused. Use `--force` only when every stage must run again.
|
|
105
|
+
|
|
106
|
+
To process selected pages while retaining their original PDF page numbers:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run llmpdf convert \
|
|
110
|
+
"/absolute/path/to/input.pdf" \
|
|
111
|
+
--output-dir "/absolute/path/to/results" \
|
|
112
|
+
--pages "1,3,8-12"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Only selected pages are rendered, detected, analyzed, and written to `output.md`. Docling receives the smallest continuous physical-page range covering the selection, then its output is filtered to the exact selected pages. For example, `8,9` processes only pages 8–9 in Docling, while `1,3,8-12` processes pages 1–12 in Docling and retains only the requested pages downstream. Metadata records both the complete PDF page count and `selected_pages`; the review comparison displays only those physical pages.
|
|
116
|
+
|
|
117
|
+
During conversion, concise progress is written to standard error: pipeline stages, rendered-page counts, detection batches, and completed table/image Agent tasks. The final machine-readable result remains the only content written to standard output.
|
|
118
|
+
|
|
119
|
+
Docling runs in an isolated child process. If that process fails during PDF parsing, the converter keeps the main pipeline alive and retries that PDF once with one Docling parsing thread and batch sizes of one. This fallback is part of the core converter, so it applies equally to `convert`, `run-all`, SDK-driven conversions, and directory batches. User-supplied Docling options, including OCR settings, are retained during the fallback. A second failure is reported normally and can be resumed by running the same command again.
|
|
120
|
+
|
|
121
|
+
All Agent work uses one dynamic scheduler with at most five workers. Whenever a worker becomes free, it selects the first ready task type in this order: Find, cross-page table, ordinary table, image. Completed Find batches can release bounded table groups before the remaining Find batches finish. Tasks with unresolved neighboring-page dependencies remain blocked rather than being extracted prematurely.
|
|
122
|
+
|
|
123
|
+
## `convert` parameters
|
|
124
|
+
|
|
125
|
+
Syntax:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
llmpdf convert PDF --output-dir OUTPUT_DIR [OPTIONS]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Input and output
|
|
132
|
+
|
|
133
|
+
| Parameter | Default | Description |
|
|
134
|
+
| --- | --- | --- |
|
|
135
|
+
| `PDF` | Required | Input PDF path. |
|
|
136
|
+
| `--output-dir PATH` | Required | Root directory for all batch results. |
|
|
137
|
+
| `--batch-id NAME` | UTC timestamp | Batch directory name. It must be a single path component and remain unchanged for retries. |
|
|
138
|
+
| `--pages PAGES` | All pages | One-based PDF pages, such as `1-25` or `1,3,8-12`. Pages are de-duplicated and processed in source order. |
|
|
139
|
+
| `--force` | Disabled | Ignore existing results and run the conversion again. |
|
|
140
|
+
| `--retain-docling-tables` / `--no-retain-docling-tables` | Enabled | Preserve original Docling table Markdown for review. |
|
|
141
|
+
|
|
142
|
+
### Table and page detection
|
|
143
|
+
|
|
144
|
+
| Parameter | Default | Description |
|
|
145
|
+
| --- | --- | --- |
|
|
146
|
+
| `--model MODEL` | `gpt-5.6-sol` | Model used for table detection and extraction. |
|
|
147
|
+
| `--thinking LEVEL` | `medium` | Reasoning effort for table operations, such as `low`, `medium`, or `high`. |
|
|
148
|
+
| `--detection-dpi N` | `96` | Page-rendering DPI for detection. Higher values improve detail but cost more time and memory. |
|
|
149
|
+
| `--contact-sheet-size N` | `8` | Number of PDF pages per detection contact sheet. |
|
|
150
|
+
| `--agent-concurrency N` | `5` | Maximum concurrent Agent tasks across all task types. Must be between `1` and `5`. |
|
|
151
|
+
| `--find-concurrency N` | `5` | Maximum concurrent Find Agent tasks within the global limit. |
|
|
152
|
+
| `--confidence-threshold N` | `0.35` | Minimum candidate confidence, from `0` to `1`. |
|
|
153
|
+
| `--table-concurrency N` | `5` | Table-processing concurrency. Must be greater than `0`. |
|
|
154
|
+
| `--table-image-max-patches N` | `30000` | Maximum 32x32-pixel patches per table Agent image. Oversized table pages lower only their own render DPI. |
|
|
155
|
+
|
|
156
|
+
### Images and charts
|
|
157
|
+
|
|
158
|
+
| Parameter | Default | Description |
|
|
159
|
+
| --- | --- | --- |
|
|
160
|
+
| `--analyze-images` / `--no-analyze-images` | Enabled | Analyze meaningful images and charts. |
|
|
161
|
+
| `--image-model MODEL` | `gpt-5.6-terra` | Model used for image analysis. |
|
|
162
|
+
| `--image-thinking LEVEL` | `medium` | Reasoning effort for image analysis. |
|
|
163
|
+
| `--image-render-dpi N` | `240` | Page-rendering DPI for image analysis. |
|
|
164
|
+
| `--image-max-patches N` | `10000` | Maximum 32x32-pixel patches per image-analysis model image. Oversized pages automatically use a lower DPI; normal pages keep `--image-render-dpi`. |
|
|
165
|
+
| `--image-concurrency N` | `5` | Image-processing concurrency. Must be greater than `0`. |
|
|
166
|
+
|
|
167
|
+
When an image is a readable chart, the tool attempts to produce structured table data. Visually estimated results are prefixed with “AI visual extraction; values may be inaccurate”. If values cannot be read reliably, the result keeps the image description and does not invent table data.
|
|
168
|
+
|
|
169
|
+
### Runtime and advanced options
|
|
170
|
+
|
|
171
|
+
| Parameter | Default | Description |
|
|
172
|
+
| --- | --- | --- |
|
|
173
|
+
| `--agent-timeout-seconds N` | `1800` | Timeout for each model call, in seconds. |
|
|
174
|
+
| `--pdftoppm PATH` | `pdftoppm` | Command name or executable path for `pdftoppm`. |
|
|
175
|
+
| `--pi-executable PATH` | Auto-detected | Explicit Pi executable path. Normally unnecessary. |
|
|
176
|
+
| `--docling-options-file PATH` | None | JSON file containing additional document-analysis options. |
|
|
177
|
+
| `--keep-sessions` | Disabled | Keep model session files for troubleshooting. |
|
|
178
|
+
| `--keep-work` | Disabled | Keep all intermediate files after success. By default, reproducible work files are removed after metrics and validation are complete. |
|
|
179
|
+
| `--llmpdf-table-executable PATH` | None | Deprecated compatibility option; avoid it in new integrations. |
|
|
180
|
+
|
|
181
|
+
Use the built-in help as the authoritative parameter reference for the installed version:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
uv run llmpdf convert --help
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Common commands
|
|
188
|
+
|
|
189
|
+
### Convert a directory of PDFs
|
|
190
|
+
|
|
191
|
+
Use `convert-dir` to recursively find PDFs and convert them in place:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
uv run llmpdf convert-dir "/absolute/path/to/pdf-root" --jobs 3
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Each PDF remains beside its generated `output.md`, `assets/`, and `work/` directories. Because these names are shared, in-place mode requires exactly one PDF in each containing directory. Directories containing multiple PDFs are reported as invalid instead of overwriting one result with another.
|
|
198
|
+
|
|
199
|
+
The directory command skips a PDF only when all of the following are true: `work/status.json` is completed, validation passed, `output.md` is non-empty, and the source SHA-256 in `assets/metadata.json` still matches the PDF. Interrupted, failed, stale, or incomplete results are resumed using valid stage caches.
|
|
200
|
+
|
|
201
|
+
All PDF workers start immediately. To process up to three PDFs concurrently, run:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
uv run llmpdf convert-dir "/absolute/path/to/pdf-root" \
|
|
205
|
+
--jobs 3
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
When a running PDF finishes, its slot starts the next queued PDF immediately. Status heartbeats are printed every 30 seconds. Combined output is appended to `<pdf-root>/log.md` and synchronized to disk every 300 lines; use `--log-file PATH` to choose another file.
|
|
209
|
+
|
|
210
|
+
Preview the decisions without converting anything:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
uv run llmpdf convert-dir "/absolute/path/to/pdf-root" --dry-run
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Options for each individual conversion can be forwarded after `--`:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
uv run llmpdf convert-dir "/absolute/path/to/pdf-root" \
|
|
220
|
+
--jobs 2 -- --no-analyze-images
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Use `--no-recursive` to inspect only PDFs directly inside the specified directory. The process exits nonzero if any PDF fails or any directory contains multiple PDFs.
|
|
224
|
+
|
|
225
|
+
The final directory layout is:
|
|
226
|
+
|
|
227
|
+
```text
|
|
228
|
+
<pdf-root>/
|
|
229
|
+
├── log.md
|
|
230
|
+
└── company-or-document/
|
|
231
|
+
├── source.pdf
|
|
232
|
+
├── output.md
|
|
233
|
+
├── assets/
|
|
234
|
+
└── work/
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Other examples
|
|
238
|
+
|
|
239
|
+
Process text and tables without analyzing images:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
uv run llmpdf convert input.pdf \
|
|
243
|
+
--output-dir results \
|
|
244
|
+
--batch-id text-and-tables \
|
|
245
|
+
--no-analyze-images
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Reduce concurrency on a resource-constrained machine:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
uv run llmpdf convert input.pdf \
|
|
252
|
+
--output-dir results \
|
|
253
|
+
--batch-id low-load \
|
|
254
|
+
--agent-concurrency 2 \
|
|
255
|
+
--find-concurrency 2 \
|
|
256
|
+
--table-concurrency 2 \
|
|
257
|
+
--image-concurrency 2
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
For a scanned document, create `docling-options.json` to enable OCR:
|
|
261
|
+
|
|
262
|
+
```json
|
|
263
|
+
{
|
|
264
|
+
"do_ocr": true,
|
|
265
|
+
"images_scale": 2.0,
|
|
266
|
+
"ocr_options": {
|
|
267
|
+
"lang": ["de", "en"]
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Then run:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
uv run llmpdf convert scanned.pdf \
|
|
276
|
+
--output-dir results \
|
|
277
|
+
--batch-id scanned-document \
|
|
278
|
+
--docling-options-file docling-options.json
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Line breaks inside table cells are converted to spaces. Final Markdown does not use `<br>` for cell-internal line breaks.
|
|
282
|
+
|
|
283
|
+
## Output files
|
|
284
|
+
|
|
285
|
+
A successful conversion produces:
|
|
286
|
+
|
|
287
|
+
```text
|
|
288
|
+
<output-dir>/<batch-id>/<pdf-stem>/
|
|
289
|
+
├── output.md
|
|
290
|
+
├── assets/
|
|
291
|
+
│ ├── metadata.json
|
|
292
|
+
│ ├── tables/
|
|
293
|
+
│ ├── images/
|
|
294
|
+
│ ├── chart-tables/
|
|
295
|
+
│ └── docling-tables/
|
|
296
|
+
└── work/
|
|
297
|
+
├── status.json
|
|
298
|
+
├── metrics.json
|
|
299
|
+
├── run-manifest.json
|
|
300
|
+
├── run-blocks.json.gz
|
|
301
|
+
├── table-code/ # Agent-authored table extractors
|
|
302
|
+
├── diagnostics/
|
|
303
|
+
└── review/ # Created only after review activity
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
- `output.md`: final Markdown.
|
|
307
|
+
- `assets/tables/`: extracted table CSV files.
|
|
308
|
+
- `assets/images/`: images retained from the PDF.
|
|
309
|
+
- `assets/chart-tables/`: CSV files extracted from charts.
|
|
310
|
+
- `assets/metadata.json`: page, source, and artifact relationships.
|
|
311
|
+
- `work/status.json`: live and final run state, elapsed time, pipeline and Agent task counts, token usage, and Pi's API-price estimate.
|
|
312
|
+
- `work/metrics.json`: elapsed time, token usage, and status for the full run and individual model calls.
|
|
313
|
+
- `work/run-manifest.json`: source, model, and candidate-page information required to regenerate tables.
|
|
314
|
+
- `work/run-blocks.json.gz`: compressed document structure used when regenerated tables are merged back into Markdown.
|
|
315
|
+
- `work/table-code/`: the generated `extract.py` for every table plus a compact page-mapping index.
|
|
316
|
+
- `work/diagnostics/`: troubleshooting information.
|
|
317
|
+
|
|
318
|
+
### Run status
|
|
319
|
+
|
|
320
|
+
`work/status.json` shows whether a conversion is `running`, `completed`, or `failed`. It is updated during the run and retained after cleanup. It also records elapsed time, successful and failed task counts, token usage, and Pi's estimated API cost.
|
|
321
|
+
|
|
322
|
+
Example:
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"status": "completed",
|
|
327
|
+
"elapsed_seconds": 130.0,
|
|
328
|
+
"pipeline": {
|
|
329
|
+
"successful_tasks": 11,
|
|
330
|
+
"failed_tasks": 0
|
|
331
|
+
},
|
|
332
|
+
"agents": {
|
|
333
|
+
"successful_tasks": 12,
|
|
334
|
+
"failed_tasks": 0
|
|
335
|
+
},
|
|
336
|
+
"usage": {
|
|
337
|
+
"total_tokens": 1700,
|
|
338
|
+
"pi_api_price_estimate_usd": 0.012345
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
`pi_api_price_estimate_usd` is an estimate for comparing runs, not the actual charge against a Codex plan. See `work/metrics.json` for detailed timing and token information.
|
|
344
|
+
|
|
345
|
+
Successful conversions use minimal retention by default. Raw Agent logs, page renders, single-page PDFs, Docling work files, and duplicate table/image intermediates are removed only after validation passes and metrics are written. Failed conversions keep their work files so the same batch can resume. Use `--keep-work` for a successful diagnostic run that must retain all intermediates. `--keep-sessions` also prevents minimal cleanup.
|
|
346
|
+
|
|
347
|
+
Artifact paths in `output.md` and metadata are POSIX paths relative to the current result directory, so the entire directory can be moved. Keep `output.md`, `assets/`, and `work/` together. The source PDF must remain available at the path recorded in `assets/metadata.json` for review and table regeneration.
|
|
348
|
+
|
|
349
|
+
Large images created from full-page vision analysis are stored as WebP at their original pixel dimensions when that representation is smaller. This changes encoding, not resolution.
|
|
350
|
+
|
|
351
|
+
## Regenerate tables
|
|
352
|
+
|
|
353
|
+
Regenerate table extraction from a successful minimal result:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
uv run llmpdf rerun-tables \
|
|
357
|
+
"/absolute/path/to/results/edis-2024/input"
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The command verifies the source PDF against the saved SHA-256, reruns all table candidates, rebuilds table assets and `output.md`, validates the result, updates metrics, and restores minimal retention. Image analysis and table detection are not rerun. Table regeneration is rejected after review decisions have been saved, preventing accidental loss of review work.
|
|
361
|
+
|
|
362
|
+
## Manual review
|
|
363
|
+
|
|
364
|
+
Start the local review UI:
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
uv run --extra review llmpdf review \
|
|
368
|
+
--result "/absolute/path/to/results/edis-2024/input"
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
The UI opens at `http://127.0.0.1:8765/` by default. Its document-comparison view displays the PDF on the left and generated Markdown on the right, with synchronized scrolling, a collapsible sidebar, and PDF zoom controls.
|
|
372
|
+
|
|
373
|
+
Load multiple results by repeating `--result`:
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
uv run --extra review llmpdf review \
|
|
377
|
+
--result "/path/to/result-a" \
|
|
378
|
+
--result "/path/to/result-b"
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
You can also load a complete batch or a review-project file:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
uv run --extra review llmpdf review --batch "/path/to/batch"
|
|
385
|
+
uv run --extra review llmpdf review --project review-project.json
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### `review` parameters
|
|
389
|
+
|
|
390
|
+
| Parameter | Default | Description |
|
|
391
|
+
| --- | --- | --- |
|
|
392
|
+
| `--result PATH` | None | Load a result directory. May be repeated. |
|
|
393
|
+
| `--batch PATH` | None | Load a batch directory. May be repeated. |
|
|
394
|
+
| `--project PATH` | None | Load a review-project JSON file. |
|
|
395
|
+
| `--host HOST` | `127.0.0.1` | Listening address. |
|
|
396
|
+
| `--port N` | `8765` | Listening port. |
|
|
397
|
+
| `--no-open` | Disabled | Start the server without opening a browser. |
|
|
398
|
+
|
|
399
|
+
The review UI operates on local results and does not make model calls.
|
|
400
|
+
|
|
401
|
+
## AI and automation usage
|
|
402
|
+
|
|
403
|
+
For non-interactive calls, always provide absolute input and output paths and a stable `--batch-id`:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
uv run llmpdf convert \
|
|
407
|
+
"/data/in/report.pdf" \
|
|
408
|
+
--output-dir "/data/out" \
|
|
409
|
+
--batch-id "report-2026-09-03"
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Calling programs should follow these conventions:
|
|
413
|
+
|
|
414
|
+
1. Use the process exit code to determine success or failure.
|
|
415
|
+
2. On success, parse JSON from standard output and read the final Markdown path from `output_markdown`.
|
|
416
|
+
3. On failure, parse JSON from standard error. If it contains `batch_id` or `recovery`, retry with the original parameters.
|
|
417
|
+
4. Do not copy `output.md` without its referenced resources; preserve at least `assets/` with it.
|
|
418
|
+
5. Read `work/metrics.json` for cost reporting or slow-call diagnostics.
|
|
419
|
+
|
|
420
|
+
## Python SDK
|
|
421
|
+
|
|
422
|
+
```python
|
|
423
|
+
from pathlib import Path
|
|
424
|
+
|
|
425
|
+
from llmpdf import ConvertOptions, convert
|
|
426
|
+
|
|
427
|
+
result = convert(
|
|
428
|
+
ConvertOptions(
|
|
429
|
+
pdf=Path("/data/in/report.pdf"),
|
|
430
|
+
output_root=Path("/data/out"),
|
|
431
|
+
batch_id="report-2026-09-03",
|
|
432
|
+
pages="1-25",
|
|
433
|
+
analyze_images=True,
|
|
434
|
+
agent_concurrency=5,
|
|
435
|
+
find_concurrency=5,
|
|
436
|
+
table_concurrency=5,
|
|
437
|
+
image_concurrency=5,
|
|
438
|
+
)
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
print(result.output_markdown)
|
|
442
|
+
print(result.total_tokens)
|
|
443
|
+
print(result.elapsed_seconds)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Path attributes on the SDK result are absolute `Path` objects that can be accessed directly. Artifact paths in `result.to_dict()` are relative to the result directory for portability. See [SDK.md](SDK.md) for all fields and exception types.
|
|
447
|
+
|
|
448
|
+
## Troubleshooting
|
|
449
|
+
|
|
450
|
+
### `pdftoppm` is not found
|
|
451
|
+
|
|
452
|
+
Install Poppler and verify the command:
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
pdftoppm -v
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
If the executable is outside `PATH`, pass `--pdftoppm /absolute/path/to/pdftoppm`.
|
|
459
|
+
|
|
460
|
+
### Model authentication fails
|
|
461
|
+
|
|
462
|
+
Confirm that the local Codex/Pi login is valid and that network access works. Use `--pi-executable` when a custom executable path is required.
|
|
463
|
+
|
|
464
|
+
### Conversion times out
|
|
465
|
+
|
|
466
|
+
Complex pages and high-resolution images may need more time. Increase `--agent-timeout-seconds`, or lower `--agent-concurrency` when local resources are limited.
|
|
467
|
+
|
|
468
|
+
### Resume after a failure
|
|
469
|
+
|
|
470
|
+
Run the same command with the same `--batch-id`. A new batch name starts a new conversion.
|
|
471
|
+
|
|
472
|
+
### Regenerate everything
|
|
473
|
+
|
|
474
|
+
Keep the same path and add `--force`:
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
uv run llmpdf convert input.pdf \
|
|
478
|
+
--output-dir results \
|
|
479
|
+
--batch-id existing-batch \
|
|
480
|
+
--force
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
## License
|
|
484
|
+
|
|
485
|
+
llmPDF is distributed under the [llmPDF Limited Use License 1.0](LICENSE).
|
|
486
|
+
Unmodified copies may be used for any purpose, including commercial use, and
|
|
487
|
+
may be redistributed with other software when the required attribution is
|
|
488
|
+
provided. Modification, adaptation, and derivative works are not permitted.
|