-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocessor.py
More file actions
222 lines (192 loc) · 8.3 KB
/
processor.py
File metadata and controls
222 lines (192 loc) · 8.3 KB
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
import httpx
from io import BytesIO
from pathlib import Path
from docling.document_converter import (
DocumentConverter,
PdfFormatOption,
ImageFormatOption,
CsvFormatOption,
ExcelFormatOption,
WordFormatOption,
PowerpointFormatOption,
MarkdownFormatOption,
AsciiDocFormatOption,
HTMLFormatOption,
PatentUsptoFormatOption,
XMLJatsFormatOption,
AudioFormatOption,
FormatOption
)
from docling.backend.json.docling_json_backend import DoclingJSONBackend
from docling.pipeline.simple_pipeline import SimplePipeline
from docling_core.types.io import DocumentStream
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import (
PdfPipelineOptions,
TableFormerMode,
EasyOcrOptions,
TesseractCliOcrOptions,
smolvlm_picture_description
)
from docling.pipeline.vlm_pipeline import VlmPipeline
import os
DEVICE_CAPABILITY = os.getenv("DEVICE_CAPABILITY", "high").lower()
VALID_CAPABILITIES = {"low", "medium", "high"}
if DEVICE_CAPABILITY not in VALID_CAPABILITIES:
print(f"[Doc Processor] Unknown DEVICE_CAPABILITY='{DEVICE_CAPABILITY}', falling back to 'high'.")
DEVICE_CAPABILITY = "high"
def _build_pipeline_options(capability: str) -> PdfFormatOption:
"""Return a PdfFormatOption tuned for *capability* tier."""
pipeline_options = PdfPipelineOptions()
if capability == "low":
# Disable the heaviest enrichments to minimise CPU/GPU & memory usage.
pipeline_options.do_code_enrichment = False
pipeline_options.do_formula_enrichment = False
pipeline_options.generate_picture_images = False
pipeline_options.do_picture_classification = False
pipeline_options.do_picture_description = False
pipeline_options.do_table_structure = True
pipeline_options.do_ocr = True
pipeline_options.ocr_options = TesseractCliOcrOptions(
force_full_page_ocr=True,
)
elif capability == "medium":
# Keep most textual enrichments but skip vision heavy ones.
pipeline_options.do_code_enrichment = True
pipeline_options.do_formula_enrichment = True
pipeline_options.generate_picture_images = False # skip PNG rendering
pipeline_options.do_picture_classification = False
pipeline_options.do_picture_description = False
pipeline_options.do_table_structure = True
pipeline_options.do_ocr = True
pipeline_options.ocr_options = TesseractCliOcrOptions(
force_full_page_ocr=True,
)
else: # "high"
# Full-fat experience with all enrichments switched on.
pipeline_options.do_code_enrichment = True
pipeline_options.do_formula_enrichment = True
pipeline_options.generate_picture_images = True
pipeline_options.images_scale = 2
pipeline_options.do_picture_classification = True
pipeline_options.do_picture_description = True
pipeline_options.picture_description_options = smolvlm_picture_description
pipeline_options.do_table_structure = True
pipeline_options.table_structure_options.do_cell_matching = True
pipeline_options.table_structure_options.mode = TableFormerMode.ACCURATE
pipeline_options.do_ocr = True
pipeline_options.ocr_options = TesseractCliOcrOptions(
force_full_page_ocr=True,
)
return pipeline_options
def create_converter() -> DocumentConverter:
"""Create a DocumentConverter configured from environment variables."""
pipeline_options = _build_pipeline_options(DEVICE_CAPABILITY)
format_options = {
# PDF with custom pipeline options
InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
}
return DocumentConverter(format_options=format_options)
converter = create_converter()
def handler(source: str):
"""Enhanced handler function with full document processing capabilities."""
# Configuration options from input
export_format = 'markdown' # markdown, html, json, text
max_pages = None
max_file_size = 100 * 1024 * 1024 # 100MB default
result = None
try:
# Download document
with httpx.Client(timeout=60.0) as client:
response = client.get(source)
response.raise_for_status()
# Create document stream
stream = BytesIO(response.content)
filename = source.split("/")[-1] if "/" in source else "document"
doc_stream = DocumentStream(name=filename, stream=stream)
# Convert with limits
convert_kwargs = {}
if max_pages:
convert_kwargs['max_num_pages'] = max_pages
if max_file_size:
convert_kwargs['max_file_size'] = max_file_size
print(f"Converting {filename} with {DEVICE_CAPABILITY} capability pipeline...")
result = converter.convert(doc_stream, **convert_kwargs)
doc = result.document
# Export in requested format
if export_format.lower() == 'markdown':
output_content = doc.export_to_markdown()
elif export_format.lower() == 'html':
output_content = doc.export_to_html()
elif export_format.lower() == 'json':
output_content = doc.export_to_json()
elif export_format.lower() == 'text':
output_content = doc.export_to_text()
else:
output_content = doc.export_to_markdown() # fallback
# Collect processing metadata
# Flag which enrichments were *actually* enabled based on DEVICE_CAPABILITY
enrichment_flags = {
"low": {
"code_enrichment": False,
"formula_enrichment": False,
"picture_classification": False,
"picture_description": False,
"table_structure": False,
"ocr": False,
},
"medium": {
"code_enrichment": True,
"formula_enrichment": True,
"picture_classification": False,
"picture_description": False,
"table_structure": True,
"ocr": True,
},
"high": {
"code_enrichment": True,
"formula_enrichment": True,
"picture_classification": True,
"picture_description": True,
"table_structure": True,
"ocr": True,
},
}
metadata = {
"source": source,
"filename": filename,
"page_count": len(doc.pages) if hasattr(doc, 'pages') else None,
"export_format": export_format,
"device_capability": DEVICE_CAPABILITY,
"enrichments_applied": enrichment_flags[DEVICE_CAPABILITY],
}
# Count enriched elements
enrichment_stats = {
"code_blocks": 0,
"formulas": 0,
"images": 0,
"tables": 0
}
# Count different element types
for item in doc.texts:
if hasattr(item, 'label'):
if item.label == 'FORMULA':
enrichment_stats["formulas"] += 1
if hasattr(doc, 'pictures'):
enrichment_stats["images"] = len(doc.pictures)
if hasattr(doc, 'tables'):
enrichment_stats["tables"] = len(doc.tables)
if hasattr(doc, 'code'):
enrichment_stats["code_blocks"] = len(doc.code)
metadata["enrichment_stats"] = enrichment_stats
result = {
"content": output_content,
"metadata": metadata,
"status": "success"
}
except httpx.RequestError as e:
raise Exception(f"HTTP request failed: {str(e)}")
except Exception as e:
raise Exception(f"Processing failed: {str(e)}")
return result