From 465be4ca041b6f4eec5adc09c095417197ecabf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 27 Jun 2026 13:04:47 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20PyPDF2=20=E2=86=92=20pdfplumber=20?= =?UTF-8?q?=E2=80=94=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D0=B5?= =?UTF-8?q?=D1=82=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=83?= =?UTF-8?q?=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=20=D0=B2=20PDF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/services/parse.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/deploy/services/parse.py b/deploy/services/parse.py index 0576809..20cc37e 100644 --- a/deploy/services/parse.py +++ b/deploy/services/parse.py @@ -1,6 +1,5 @@ -"""Parse service — PDF (PyPDF2), DOCX (python-docx), plain text fallback.""" +"""Parse service — PDF (pdfplumber), DOCX (python-docx), plain text fallback.""" import io -from PyPDF2 import PdfReader def parse_file(filename, data): @@ -20,15 +19,30 @@ def parse_file(filename, data): def _parse_pdf(data): - reader = PdfReader(io.BytesIO(data)) + """Parse PDF with pdfplumber — preserves table structure (unlike PyPDF2).""" + import pdfplumber elements = [] - for page in reader.pages: - text = page.extract_text() - if text: - for line in text.split("\n"): - line = line.strip() - if line: - elements.append({"type": "paragraph", "text": line, "style": ""}) + with pdfplumber.open(io.BytesIO(data)) as pdf: + for page in pdf.pages: + # Tables first — preserves column structure critical for specs + tables = page.extract_tables() + for table in tables: + if table: + rows = [] + for row in table: + if row: + cells = [str(cell or "").strip() for cell in row] + if any(cells): + rows.append(cells) + if rows: + elements.append({"type": "table", "rows": rows}) + # Remaining text as paragraphs + text = page.extract_text() + if text: + for line in text.split("\n"): + line = line.strip() + if line: + elements.append({"type": "paragraph", "text": line, "style": ""}) return {"status": "parsed", "element_count": len(elements), "elements": elements}