# pyright: reportMissingImports=false from __future__ import annotations from pathlib import Path import re import fitz import numpy as np from pptx import Presentation from pptx.enum.shapes import MSO_SHAPE_TYPE from rapidocr_onnxruntime import RapidOCR ROOT = Path(__file__).resolve().parent SOURCE_DIR = ROOT.parent PDF_PATH = SOURCE_DIR / "User Journeys.pdf" PPTX_PATH = SOURCE_DIR / "零售商系统方案研讨会PPT.retro.pptx" PDF_OUTPUT = ROOT / "User Journeys.md" PPTX_OUTPUT = ROOT / "零售商系统方案研讨会PPT.retro.md" OCR = RapidOCR() def normalize_text(text: str) -> str: text = text.replace("\r\n", "\n").replace("\r", "\n") lines = [re.sub(r"\s+", " ", line).strip() for line in text.split("\n")] return "\n".join(line for line in lines if line) def extract_page_ocr_text(page: fitz.Page) -> str: pix = page.get_pixmap(matrix=fitz.Matrix(4, 4), alpha=False) image = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, pix.n) result, _ = OCR(image) if not result: return "" return normalize_text("\n".join(str(item[1]) for item in result)) def extract_pdf_to_md(pdf_path: Path, output_path: Path) -> None: doc = fitz.open(pdf_path) parts: list[str] = [f"# {pdf_path.stem}", ""] try: for index in range(doc.page_count): page = doc.load_page(index) text = normalize_text(str(page.get_text("text") or "")) if not text: text = extract_page_ocr_text(page) parts.append(f"## Page {index + 1}") parts.append("") parts.append(text or "[No extractable text]") parts.append("") finally: doc.close() output_path.write_text("\n".join(parts).strip() + "\n", encoding="utf-8") def iter_shape_text(shape) -> list[str]: chunks: list[str] = [] if hasattr(shape, "has_text_frame") and shape.has_text_frame: text = normalize_text(shape.text_frame.text) if text: chunks.append(text) if hasattr(shape, "has_table") and shape.has_table: for row in shape.table.rows: cells = [normalize_text(cell.text) for cell in row.cells] cells = [cell for cell in cells if cell] if cells: chunks.append(" | ".join(cells)) if shape.shape_type == MSO_SHAPE_TYPE.GROUP: for subshape in shape.shapes: chunks.extend(iter_shape_text(subshape)) return chunks def extract_pptx_to_md(pptx_path: Path, output_path: Path) -> None: prs = Presentation(str(pptx_path)) parts: list[str] = [f"# {pptx_path.stem}", ""] for index, slide in enumerate(prs.slides, start=1): title = "" parts.append(f"## Slide {index}") parts.append("") if slide.shapes.title and slide.shapes.title.text: title = normalize_text(slide.shapes.title.text) if title: parts.append(f"### {title}") parts.append("") seen: set[str] = set() collected = [] for shape in slide.shapes: for chunk in iter_shape_text(shape): if title and chunk == title: continue if chunk and chunk not in seen: seen.add(chunk) collected.append(chunk) if collected: parts.extend(f"- {chunk}" for chunk in collected) else: parts.append("[No extractable text]") parts.append("") output_path.write_text("\n".join(parts).strip() + "\n", encoding="utf-8") def main() -> None: extract_pdf_to_md(PDF_PATH, PDF_OUTPUT) extract_pptx_to_md(PPTX_PATH, PPTX_OUTPUT) print("Wrote PDF markdown output") print("Wrote PPTX markdown output") if __name__ == "__main__": main()