natural-pdf 0.1.3__py3-none-any.whl → 0.1.5__py3-none-any.whl

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.
Files changed (132) hide show
  1. docs/api/index.md +386 -0
  2. docs/assets/favicon.png +3 -0
  3. docs/assets/favicon.svg +3 -0
  4. docs/assets/javascripts/custom.js +17 -0
  5. docs/assets/logo.svg +3 -0
  6. docs/assets/sample-screen.png +0 -0
  7. docs/assets/social-preview.png +17 -0
  8. docs/assets/social-preview.svg +17 -0
  9. docs/assets/stylesheets/custom.css +65 -0
  10. docs/document-qa/index.ipynb +435 -0
  11. docs/document-qa/index.md +79 -0
  12. docs/element-selection/index.ipynb +915 -0
  13. docs/element-selection/index.md +229 -0
  14. docs/index.md +170 -0
  15. docs/installation/index.md +69 -0
  16. docs/interactive-widget/index.ipynb +962 -0
  17. docs/interactive-widget/index.md +12 -0
  18. docs/layout-analysis/index.ipynb +818 -0
  19. docs/layout-analysis/index.md +185 -0
  20. docs/ocr/index.md +222 -0
  21. docs/pdf-navigation/index.ipynb +314 -0
  22. docs/pdf-navigation/index.md +97 -0
  23. docs/regions/index.ipynb +816 -0
  24. docs/regions/index.md +294 -0
  25. docs/tables/index.ipynb +658 -0
  26. docs/tables/index.md +144 -0
  27. docs/text-analysis/index.ipynb +370 -0
  28. docs/text-analysis/index.md +105 -0
  29. docs/text-extraction/index.ipynb +1478 -0
  30. docs/text-extraction/index.md +292 -0
  31. docs/tutorials/01-loading-and-extraction.ipynb +1696 -0
  32. docs/tutorials/01-loading-and-extraction.md +95 -0
  33. docs/tutorials/02-finding-elements.ipynb +340 -0
  34. docs/tutorials/02-finding-elements.md +149 -0
  35. docs/tutorials/03-extracting-blocks.ipynb +147 -0
  36. docs/tutorials/03-extracting-blocks.md +48 -0
  37. docs/tutorials/04-table-extraction.ipynb +114 -0
  38. docs/tutorials/04-table-extraction.md +50 -0
  39. docs/tutorials/05-excluding-content.ipynb +270 -0
  40. docs/tutorials/05-excluding-content.md +109 -0
  41. docs/tutorials/06-document-qa.ipynb +332 -0
  42. docs/tutorials/06-document-qa.md +91 -0
  43. docs/tutorials/07-layout-analysis.ipynb +260 -0
  44. docs/tutorials/07-layout-analysis.md +66 -0
  45. docs/tutorials/07-working-with-regions.ipynb +409 -0
  46. docs/tutorials/07-working-with-regions.md +151 -0
  47. docs/tutorials/08-spatial-navigation.ipynb +508 -0
  48. docs/tutorials/08-spatial-navigation.md +190 -0
  49. docs/tutorials/09-section-extraction.ipynb +2434 -0
  50. docs/tutorials/09-section-extraction.md +256 -0
  51. docs/tutorials/10-form-field-extraction.ipynb +484 -0
  52. docs/tutorials/10-form-field-extraction.md +201 -0
  53. docs/tutorials/11-enhanced-table-processing.ipynb +54 -0
  54. docs/tutorials/11-enhanced-table-processing.md +9 -0
  55. docs/tutorials/12-ocr-integration.ipynb +586 -0
  56. docs/tutorials/12-ocr-integration.md +188 -0
  57. docs/tutorials/13-semantic-search.ipynb +1888 -0
  58. docs/tutorials/13-semantic-search.md +77 -0
  59. docs/visual-debugging/index.ipynb +2970 -0
  60. docs/visual-debugging/index.md +157 -0
  61. docs/visual-debugging/region.png +0 -0
  62. natural_pdf/__init__.py +39 -20
  63. natural_pdf/analyzers/__init__.py +2 -1
  64. natural_pdf/analyzers/layout/base.py +32 -24
  65. natural_pdf/analyzers/layout/docling.py +131 -72
  66. natural_pdf/analyzers/layout/layout_analyzer.py +156 -113
  67. natural_pdf/analyzers/layout/layout_manager.py +98 -58
  68. natural_pdf/analyzers/layout/layout_options.py +32 -17
  69. natural_pdf/analyzers/layout/paddle.py +152 -95
  70. natural_pdf/analyzers/layout/surya.py +164 -92
  71. natural_pdf/analyzers/layout/tatr.py +149 -84
  72. natural_pdf/analyzers/layout/yolo.py +84 -44
  73. natural_pdf/analyzers/text_options.py +22 -15
  74. natural_pdf/analyzers/text_structure.py +131 -85
  75. natural_pdf/analyzers/utils.py +30 -23
  76. natural_pdf/collections/pdf_collection.py +126 -98
  77. natural_pdf/core/__init__.py +1 -1
  78. natural_pdf/core/element_manager.py +416 -337
  79. natural_pdf/core/highlighting_service.py +268 -196
  80. natural_pdf/core/page.py +910 -516
  81. natural_pdf/core/pdf.py +387 -289
  82. natural_pdf/elements/__init__.py +1 -1
  83. natural_pdf/elements/base.py +302 -214
  84. natural_pdf/elements/collections.py +714 -514
  85. natural_pdf/elements/line.py +39 -36
  86. natural_pdf/elements/rect.py +32 -30
  87. natural_pdf/elements/region.py +854 -883
  88. natural_pdf/elements/text.py +122 -99
  89. natural_pdf/exporters/__init__.py +0 -1
  90. natural_pdf/exporters/searchable_pdf.py +261 -102
  91. natural_pdf/ocr/__init__.py +23 -14
  92. natural_pdf/ocr/engine.py +17 -8
  93. natural_pdf/ocr/engine_easyocr.py +63 -47
  94. natural_pdf/ocr/engine_paddle.py +97 -68
  95. natural_pdf/ocr/engine_surya.py +54 -44
  96. natural_pdf/ocr/ocr_manager.py +88 -62
  97. natural_pdf/ocr/ocr_options.py +16 -10
  98. natural_pdf/qa/__init__.py +1 -1
  99. natural_pdf/qa/document_qa.py +119 -111
  100. natural_pdf/search/__init__.py +37 -31
  101. natural_pdf/search/haystack_search_service.py +312 -189
  102. natural_pdf/search/haystack_utils.py +186 -122
  103. natural_pdf/search/search_options.py +25 -14
  104. natural_pdf/search/search_service_protocol.py +12 -6
  105. natural_pdf/search/searchable_mixin.py +261 -176
  106. natural_pdf/selectors/__init__.py +2 -1
  107. natural_pdf/selectors/parser.py +159 -316
  108. natural_pdf/templates/__init__.py +1 -1
  109. natural_pdf/utils/highlighting.py +8 -2
  110. natural_pdf/utils/reading_order.py +65 -63
  111. natural_pdf/utils/text_extraction.py +195 -0
  112. natural_pdf/utils/visualization.py +70 -61
  113. natural_pdf/widgets/__init__.py +2 -3
  114. natural_pdf/widgets/viewer.py +749 -718
  115. {natural_pdf-0.1.3.dist-info → natural_pdf-0.1.5.dist-info}/METADATA +29 -15
  116. natural_pdf-0.1.5.dist-info/RECORD +134 -0
  117. natural_pdf-0.1.5.dist-info/top_level.txt +5 -0
  118. notebooks/Examples.ipynb +1293 -0
  119. pdfs/.gitkeep +0 -0
  120. pdfs/01-practice.pdf +543 -0
  121. pdfs/0500000US42001.pdf +0 -0
  122. pdfs/0500000US42007.pdf +0 -0
  123. pdfs/2014 Statistics.pdf +0 -0
  124. pdfs/2019 Statistics.pdf +0 -0
  125. pdfs/Atlanta_Public_Schools_GA_sample.pdf +0 -0
  126. pdfs/needs-ocr.pdf +0 -0
  127. tests/test_loading.py +50 -0
  128. tests/test_optional_deps.py +298 -0
  129. natural_pdf-0.1.3.dist-info/RECORD +0 -61
  130. natural_pdf-0.1.3.dist-info/top_level.txt +0 -1
  131. {natural_pdf-0.1.3.dist-info → natural_pdf-0.1.5.dist-info}/WHEEL +0 -0
  132. {natural_pdf-0.1.3.dist-info → natural_pdf-0.1.5.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,314 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "bba1860e",
6
+ "metadata": {},
7
+ "source": [
8
+ "# PDF Navigation\n",
9
+ "\n",
10
+ "This guide covers the basics of working with PDFs in Natural PDF - opening documents, accessing pages, and navigating through content.\n",
11
+ "\n",
12
+ "## Opening a PDF\n",
13
+ "\n",
14
+ "The main entry point to Natural PDF is the `PDF` class:"
15
+ ]
16
+ },
17
+ {
18
+ "cell_type": "code",
19
+ "execution_count": 1,
20
+ "id": "56d12ab5",
21
+ "metadata": {
22
+ "execution": {
23
+ "iopub.execute_input": "2025-04-03T14:50:38.434157Z",
24
+ "iopub.status.busy": "2025-04-03T14:50:38.433170Z",
25
+ "iopub.status.idle": "2025-04-03T14:50:49.768101Z",
26
+ "shell.execute_reply": "2025-04-03T14:50:49.767384Z"
27
+ }
28
+ },
29
+ "outputs": [],
30
+ "source": [
31
+ "from natural_pdf import PDF\n",
32
+ "\n",
33
+ "# Open a PDF file\n",
34
+ "pdf = PDF(\"https://github.com/jsoma/natural-pdf/raw/refs/heads/main/pdfs/0500000US42001.pdf\")"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "markdown",
39
+ "id": "c425482a",
40
+ "metadata": {},
41
+ "source": [
42
+ "## Accessing Pages\n",
43
+ "\n",
44
+ "Once you have a PDF object, you can access its pages:"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": 2,
50
+ "id": "a3405aa9",
51
+ "metadata": {
52
+ "execution": {
53
+ "iopub.execute_input": "2025-04-03T14:50:49.770604Z",
54
+ "iopub.status.busy": "2025-04-03T14:50:49.770419Z",
55
+ "iopub.status.idle": "2025-04-03T14:50:50.700808Z",
56
+ "shell.execute_reply": "2025-04-03T14:50:50.699634Z"
57
+ }
58
+ },
59
+ "outputs": [
60
+ {
61
+ "name": "stdout",
62
+ "output_type": "stream",
63
+ "text": [
64
+ "This PDF has 153 pages\n",
65
+ "Page 1 has 985 characters\n",
66
+ "Page 2 has 778 characters\n",
67
+ "Page 3 has 522 characters\n",
68
+ "Page 4 has 984 characters\n",
69
+ "Page 5 has 778 characters\n",
70
+ "Page 6 has 523 characters\n"
71
+ ]
72
+ },
73
+ {
74
+ "name": "stdout",
75
+ "output_type": "stream",
76
+ "text": [
77
+ "Page 7 has 982 characters\n",
78
+ "Page 8 has 772 characters\n",
79
+ "Page 9 has 522 characters\n",
80
+ "Page 10 has 1008 characters\n"
81
+ ]
82
+ },
83
+ {
84
+ "name": "stdout",
85
+ "output_type": "stream",
86
+ "text": [
87
+ "Page 11 has 796 characters\n",
88
+ "Page 12 has 532 characters\n",
89
+ "Page 13 has 986 characters\n",
90
+ "Page 14 has 780 characters\n",
91
+ "Page 15 has 523 characters\n",
92
+ "Page 16 has 990 characters\n",
93
+ "Page 17 has 782 characters\n"
94
+ ]
95
+ },
96
+ {
97
+ "name": "stdout",
98
+ "output_type": "stream",
99
+ "text": [
100
+ "Page 18 has 520 characters\n",
101
+ "Page 19 has 1006 characters\n",
102
+ "Page 20 has 795 characters\n"
103
+ ]
104
+ }
105
+ ],
106
+ "source": [
107
+ "# Get the total number of pages\n",
108
+ "num_pages = len(pdf)\n",
109
+ "print(f\"This PDF has {num_pages} pages\")\n",
110
+ "\n",
111
+ "# Get a specific page (0-indexed)\n",
112
+ "first_page = pdf.pages[0]\n",
113
+ "last_page = pdf.pages[-1]\n",
114
+ "\n",
115
+ "# Iterate through the first 20 pages\n",
116
+ "for page in pdf.pages[:20]:\n",
117
+ " print(f\"Page {page.number} has {len(page.extract_text())} characters\")"
118
+ ]
119
+ },
120
+ {
121
+ "cell_type": "markdown",
122
+ "id": "2eca7327",
123
+ "metadata": {},
124
+ "source": [
125
+ "## Page Properties\n",
126
+ "\n",
127
+ "Each `Page` object has useful properties:"
128
+ ]
129
+ },
130
+ {
131
+ "cell_type": "code",
132
+ "execution_count": 3,
133
+ "id": "348f28d7",
134
+ "metadata": {
135
+ "execution": {
136
+ "iopub.execute_input": "2025-04-03T14:50:50.713325Z",
137
+ "iopub.status.busy": "2025-04-03T14:50:50.711638Z",
138
+ "iopub.status.idle": "2025-04-03T14:50:50.738737Z",
139
+ "shell.execute_reply": "2025-04-03T14:50:50.726839Z"
140
+ }
141
+ },
142
+ "outputs": [
143
+ {
144
+ "name": "stdout",
145
+ "output_type": "stream",
146
+ "text": [
147
+ "612 792\n",
148
+ "20\n",
149
+ "19\n"
150
+ ]
151
+ }
152
+ ],
153
+ "source": [
154
+ "# Page dimensions in points (1/72 inch)\n",
155
+ "print(page.width, page.height)\n",
156
+ "\n",
157
+ "# Page number (1-indexed as shown in PDF viewers)\n",
158
+ "print(page.number)\n",
159
+ "\n",
160
+ "# Page index (0-indexed position in the PDF)\n",
161
+ "print(page.index)"
162
+ ]
163
+ },
164
+ {
165
+ "cell_type": "markdown",
166
+ "id": "c7cf1839",
167
+ "metadata": {},
168
+ "source": [
169
+ "## Working Across Pages\n",
170
+ "\n",
171
+ "Natural PDF makes it easy to work with content across multiple pages:"
172
+ ]
173
+ },
174
+ {
175
+ "cell_type": "code",
176
+ "execution_count": 4,
177
+ "id": "71a8f1ec",
178
+ "metadata": {
179
+ "execution": {
180
+ "iopub.execute_input": "2025-04-03T14:50:50.765495Z",
181
+ "iopub.status.busy": "2025-04-03T14:50:50.764444Z",
182
+ "iopub.status.idle": "2025-04-03T14:50:57.735494Z",
183
+ "shell.execute_reply": "2025-04-03T14:50:57.726489Z"
184
+ }
185
+ },
186
+ "outputs": [
187
+ {
188
+ "data": {
189
+ "text/plain": [
190
+ "<natural_pdf.core.pdf.PDF at 0x1045224d0>"
191
+ ]
192
+ },
193
+ "execution_count": 4,
194
+ "metadata": {},
195
+ "output_type": "execute_result"
196
+ }
197
+ ],
198
+ "source": [
199
+ "# Extract text from all pages\n",
200
+ "all_text = pdf.extract_text()\n",
201
+ "\n",
202
+ "# Find elements across all pages\n",
203
+ "all_headings = pdf.find_all('text[size>=14]:bold')\n",
204
+ "\n",
205
+ "# Add exclusion zones to all pages (like headers/footers)\n",
206
+ "pdf.add_exclusion(\n",
207
+ " lambda page: page.find('text:contains(\"CONFIDENTIAL\")').above() if page.find('text:contains(\"CONFIDENTIAL\")') else None,\n",
208
+ " label=\"header\"\n",
209
+ ")"
210
+ ]
211
+ },
212
+ {
213
+ "cell_type": "markdown",
214
+ "id": "e18051a4",
215
+ "metadata": {},
216
+ "source": [
217
+ "## The Page Collection\n",
218
+ "\n",
219
+ "The `pdf.pages` object is a `PageCollection` that allows batch operations on pages:"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": 5,
225
+ "id": "e5f1c662",
226
+ "metadata": {
227
+ "execution": {
228
+ "iopub.execute_input": "2025-04-03T14:50:57.752240Z",
229
+ "iopub.status.busy": "2025-04-03T14:50:57.751868Z",
230
+ "iopub.status.idle": "2025-04-03T14:50:57.770738Z",
231
+ "shell.execute_reply": "2025-04-03T14:50:57.759415Z"
232
+ }
233
+ },
234
+ "outputs": [],
235
+ "source": [
236
+ "# Extract text from specific pages\n",
237
+ "text = pdf.pages[2:5].extract_text()\n",
238
+ "\n",
239
+ "# Find elements across specific pages\n",
240
+ "elements = pdf.pages[2:5].find_all('text:contains(\"Annual Report\")')"
241
+ ]
242
+ },
243
+ {
244
+ "cell_type": "markdown",
245
+ "id": "9713e392",
246
+ "metadata": {},
247
+ "source": [
248
+ "## Document Sections Across Pages\n",
249
+ "\n",
250
+ "You can extract sections that span across multiple pages:"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "code",
255
+ "execution_count": 6,
256
+ "id": "d5b89a2b",
257
+ "metadata": {
258
+ "execution": {
259
+ "iopub.execute_input": "2025-04-03T14:50:57.782621Z",
260
+ "iopub.status.busy": "2025-04-03T14:50:57.781776Z",
261
+ "iopub.status.idle": "2025-04-03T14:50:57.811508Z",
262
+ "shell.execute_reply": "2025-04-03T14:50:57.805310Z"
263
+ }
264
+ },
265
+ "outputs": [],
266
+ "source": [
267
+ "# Get sections with headings as section starts\n",
268
+ "sections = pdf.pages.get_sections(\n",
269
+ " start_elements='text[size>=14]:bold',\n",
270
+ " new_section_on_page_break=False\n",
271
+ ")"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "markdown",
276
+ "id": "f51594ce",
277
+ "metadata": {},
278
+ "source": [
279
+ "## Next Steps\n",
280
+ "\n",
281
+ "Now that you know how to navigate PDFs, you can:\n",
282
+ "\n",
283
+ "- [Find elements using selectors](../element-selection/index.ipynb)\n",
284
+ "- [Extract text from your documents](../text-extraction/index.ipynb)\n",
285
+ "- [Work with specific regions](../regions/index.ipynb)"
286
+ ]
287
+ }
288
+ ],
289
+ "metadata": {
290
+ "jupytext": {
291
+ "cell_metadata_filter": "-all",
292
+ "main_language": "python",
293
+ "notebook_metadata_filter": "-all",
294
+ "text_representation": {
295
+ "extension": ".md",
296
+ "format_name": "markdown"
297
+ }
298
+ },
299
+ "language_info": {
300
+ "codemirror_mode": {
301
+ "name": "ipython",
302
+ "version": 3
303
+ },
304
+ "file_extension": ".py",
305
+ "mimetype": "text/x-python",
306
+ "name": "python",
307
+ "nbconvert_exporter": "python",
308
+ "pygments_lexer": "ipython3",
309
+ "version": "3.10.13"
310
+ }
311
+ },
312
+ "nbformat": 4,
313
+ "nbformat_minor": 5
314
+ }
@@ -0,0 +1,97 @@
1
+ # PDF Navigation
2
+
3
+ This guide covers the basics of working with PDFs in Natural PDF - opening documents, accessing pages, and navigating through content.
4
+
5
+ ## Opening a PDF
6
+
7
+ The main entry point to Natural PDF is the `PDF` class:
8
+
9
+ ```python
10
+ from natural_pdf import PDF
11
+
12
+ # Open a PDF file
13
+ pdf = PDF("https://github.com/jsoma/natural-pdf/raw/refs/heads/main/pdfs/0500000US42001.pdf")
14
+ ```
15
+
16
+ ## Accessing Pages
17
+
18
+ Once you have a PDF object, you can access its pages:
19
+
20
+ ```python
21
+ # Get the total number of pages
22
+ num_pages = len(pdf)
23
+ print(f"This PDF has {num_pages} pages")
24
+
25
+ # Get a specific page (0-indexed)
26
+ first_page = pdf.pages[0]
27
+ last_page = pdf.pages[-1]
28
+
29
+ # Iterate through the first 20 pages
30
+ for page in pdf.pages[:20]:
31
+ print(f"Page {page.number} has {len(page.extract_text())} characters")
32
+ ```
33
+
34
+ ## Page Properties
35
+
36
+ Each `Page` object has useful properties:
37
+
38
+ ```python
39
+ # Page dimensions in points (1/72 inch)
40
+ print(page.width, page.height)
41
+
42
+ # Page number (1-indexed as shown in PDF viewers)
43
+ print(page.number)
44
+
45
+ # Page index (0-indexed position in the PDF)
46
+ print(page.index)
47
+ ```
48
+
49
+ ## Working Across Pages
50
+
51
+ Natural PDF makes it easy to work with content across multiple pages:
52
+
53
+ ```python
54
+ # Extract text from all pages
55
+ all_text = pdf.extract_text()
56
+
57
+ # Find elements across all pages
58
+ all_headings = pdf.find_all('text[size>=14]:bold')
59
+
60
+ # Add exclusion zones to all pages (like headers/footers)
61
+ pdf.add_exclusion(
62
+ lambda page: page.find('text:contains("CONFIDENTIAL")').above() if page.find('text:contains("CONFIDENTIAL")') else None,
63
+ label="header"
64
+ )
65
+ ```
66
+
67
+ ## The Page Collection
68
+
69
+ The `pdf.pages` object is a `PageCollection` that allows batch operations on pages:
70
+
71
+ ```python
72
+ # Extract text from specific pages
73
+ text = pdf.pages[2:5].extract_text()
74
+
75
+ # Find elements across specific pages
76
+ elements = pdf.pages[2:5].find_all('text:contains("Annual Report")')
77
+ ```
78
+
79
+ ## Document Sections Across Pages
80
+
81
+ You can extract sections that span across multiple pages:
82
+
83
+ ```python
84
+ # Get sections with headings as section starts
85
+ sections = pdf.pages.get_sections(
86
+ start_elements='text[size>=14]:bold',
87
+ new_section_on_page_break=False
88
+ )
89
+ ```
90
+
91
+ ## Next Steps
92
+
93
+ Now that you know how to navigate PDFs, you can:
94
+
95
+ - [Find elements using selectors](../element-selection/index.ipynb)
96
+ - [Extract text from your documents](../text-extraction/index.ipynb)
97
+ - [Work with specific regions](../regions/index.ipynb)