-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathauto_convert.py
More file actions
209 lines (159 loc) · 5.71 KB
/
auto_convert.py
File metadata and controls
209 lines (159 loc) · 5.71 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
#!/usr/bin/env python3
"""
Auto-select best PDF engine based on content type.
Usage:
python auto_convert.py input_directory [output_directory]
This script automatically:
1. Detects if PDF is digital (has text) or scanned (image-only)
2. Uses pymupdf for digital PDFs (fast, no GPU)
3. Uses marker for scanned PDFs (with OCR)
"""
from __future__ import annotations
import sys
from pathlib import Path
def is_digital_pdf(pdf_path: Path) -> bool:
"""Check if PDF has extractable text (digital) or is image-only (scanned)."""
try:
import fitz
doc = fitz.open(str(pdf_path))
total_text = 0
# Check first 3 pages
for page_num in range(min(3, len(doc))):
page = doc[page_num]
text = page.get_text()
total_text += len(text.strip())
doc.close()
# If less than 50 chars total, likely scanned
return total_text >= 50
except Exception as e:
print(f"Warning: Could not check {pdf_path}: {e}")
return True # Assume digital
def convert_pdf_smart(
input_path: Path,
output_path: Path | None = None,
) -> bool:
"""Convert PDF using optimal engine."""
from nuoyi.converter import get_converter, DocxConverter
if output_path is None:
output_path = input_path.with_suffix(".md")
print(f"\n{'=' * 60}")
print(f"Processing: {input_path.name}")
print(f"{'=' * 60}")
# Detect PDF type
is_digital = is_digital_pdf(input_path)
if is_digital:
print(f"Type: Digital PDF (has text)")
print(f"Engine: pymupdf (fast, no GPU)")
try:
from nuoyi.converter import PyMuPDFConverter
converter = PyMuPDFConverter()
content, images = converter.convert_file(str(input_path))
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(content, encoding="utf-8")
print(f"✅ Success: {output_path}")
return True
except Exception as e:
print(f"❌ Failed: {e}")
return False
else:
print(f"Type: Scanned PDF (image-only)")
print(f"Engine: marker (with OCR, low VRAM mode)")
try:
converter = get_converter(
engine="marker",
low_vram=True,
device="auto",
)
content, images = converter.convert_file(str(input_path))
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(content, encoding="utf-8")
print(f"✅ Success: {output_path}")
return True
except Exception as e:
print(f"❌ Failed: {e}")
return False
def batch_convert_directory(
input_dir: Path,
output_dir: Path | None = None,
recursive: bool = False,
) -> dict:
"""Batch convert all PDFs in directory with smart engine selection."""
if output_dir is None:
output_dir = input_dir
# Find all PDF files
from nuoyi.utils import find_documents
files = find_documents(input_dir, recursive=recursive)
pdf_files = [f for f in files if f.suffix.lower() == ".pdf"]
print(f"\nFound {len(pdf_files)} PDF files to process")
print(f"Input: {input_dir}")
print(f"Output: {output_dir}")
print(f"Recursive: {recursive}")
results = {
"total": len(pdf_files),
"success": 0,
"failed": 0,
"digital": 0,
"scanned": 0,
}
for i, pdf_file in enumerate(pdf_files, 1):
print(f"\n[{i}/{len(pdf_files)}]")
# Determine output path
if recursive:
try:
rel_path = pdf_file.relative_to(input_dir)
output_path = output_dir / rel_path.with_suffix(".md")
except ValueError:
output_path = output_dir / f"{pdf_file.stem}.md"
else:
output_path = output_dir / f"{pdf_file.stem}.md"
# Check PDF type for statistics
is_digital = is_digital_pdf(pdf_file)
if is_digital:
results["digital"] += 1
else:
results["scanned"] += 1
# Convert
success = convert_pdf_smart(pdf_file, output_path)
if success:
results["success"] += 1
else:
results["failed"] += 1
# Print summary
print(f"\n{'=' * 60}")
print("Conversion Summary")
print(f"{'=' * 60}")
print(f"Total files: {results['total']}")
print(f"Digital PDFs: {results['digital']}")
print(f"Scanned PDFs: {results['scanned']}")
print(f"Success: {results['success']}")
print(f"Failed: {results['failed']}")
print(f"{'=' * 60}\n")
return results
def main():
"""Main entry point."""
if len(sys.argv) < 2:
print("Usage: python auto_convert.py <input_dir> [output_dir]")
print("\nOptions:")
print(" input_dir Directory containing PDF files")
print(" output_dir Output directory (default: same as input)")
print("\nExamples:")
print(" python auto_convert.py ./pdfs")
print(" python auto_convert.py ./pdfs ./output")
sys.exit(1)
input_dir = Path(sys.argv[1])
if not input_dir.exists():
print(f"Error: Directory not found: {input_dir}")
sys.exit(1)
output_dir = Path(sys.argv[2]) if len(sys.argv) > 2 else None
# Ask about recursive
recursive = False
try:
response = input("Process subdirectories recursively? [y/N]: ").strip().lower()
recursive = response in ("y", "yes")
except (EOFError, KeyboardInterrupt):
print()
results = batch_convert_directory(input_dir, output_dir, recursive)
if results["failed"] > 0:
sys.exit(1)
if __name__ == "__main__":
main()