Files
conti-docs/Architecture-Diagram/extract_requirements_to_md.py
T

129 lines
3.7 KiB
Python

# 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()