Question-Generator / extractor.py
Awab-Elsadig's picture
feat: add Latest Saved inspector page + OCR fallback + Docker setup
9691380
Raw
History Blame Contribute Delete
3.11 kB
import fitz
import re
from pathlib import Path
from typing import Any, Dict, List, Tuple
IMAGE_MIN_WIDTH = 80
IMAGE_MIN_HEIGHT = 80
def _ocr_page(page) -> str:
"""Render page to image and run Tesseract OCR. Falls back to empty string if unavailable."""
try:
import pytesseract
from PIL import Image
import io
import sys
if sys.platform == "win32":
import os
default = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
if os.path.exists(default):
pytesseract.pytesseract.tesseract_cmd = default
mat = fitz.Matrix(2.0, 2.0) # 2x zoom β†’ ~144 dpi, good OCR accuracy
pix = page.get_pixmap(matrix=mat, colorspace=fitz.csRGB)
img = Image.open(io.BytesIO(pix.tobytes("png")))
return pytesseract.image_to_string(img, config="--psm 3")
except Exception:
return ""
def clean_text(text: str) -> str:
replacements = {
"ff": "ff", "fi": "fi", "fl": "fl",
"Β ": " ", "βˆ’": "-", "–": "-", "β€”": "-",
}
for old, new in replacements.items():
text = text.replace(old, new)
text = re.sub(r"[ \t]+", " ", text)
text = re.sub(r"\n{3,}", "\n\n", text)
return text.strip()
def extract_page_range(
pdf_path: str,
start_page: int,
end_page: int,
output_dir: Path,
prefix: str = "img",
) -> Tuple[str, List[Dict[str, Any]]]:
"""
Extract text and embedded images from a 1-indexed page range.
Images are saved to output_dir. Returns (full_text, images_list).
"""
doc = fitz.open(pdf_path)
full_text = ""
images: List[Dict[str, Any]] = []
start = max(0, start_page - 1)
end = min(len(doc) - 1, end_page - 1)
seen_xrefs: set = set()
for page_idx in range(start, end + 1):
page = doc[page_idx]
page_num = page_idx + 1
text = clean_text(page.get_text("text", sort=True))
if not text.strip():
text = clean_text(_ocr_page(page))
full_text += f"\n\n--- PAGE {page_num} ---\n{text}"
for img_idx, img_info in enumerate(page.get_images(full=True)):
try:
xref = img_info[0]
width = img_info[2]
height = img_info[3]
if width < IMAGE_MIN_WIDTH or height < IMAGE_MIN_HEIGHT:
continue
if xref in seen_xrefs:
continue
seen_xrefs.add(xref)
base_image = doc.extract_image(xref)
img_ext = base_image["ext"]
filename = f"{prefix}_page{page_num}_img{img_idx + 1}.{img_ext}"
img_path = output_dir / filename
with open(img_path, "wb") as f:
f.write(base_image["image"])
images.append({
"filename": filename,
"page": page_num,
"width": width,
"height": height,
})
except Exception:
continue
doc.close()
return full_text, images