Files

88 lines
3.4 KiB
Python

"""Parse service — PDF (pdfplumber), DOCX (python-docx), plain text fallback."""
import io
def parse_file(filename, data):
"""Parse file bytes → {status, elements, element_count}."""
ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else ""
try:
if ext == "pdf":
return _parse_pdf(data)
elif ext == "docx":
return _parse_docx(data)
elif ext == "doc":
return _parse_docx(data) # python-docx handles most .doc
else:
return _parse_text(data)
except Exception as e:
return {"status": "error", "error": str(e), "element_count": 0}
def _parse_pdf(data):
"""Parse PDF with pdfplumber — preserves table structure (unlike PyPDF2)."""
import pdfplumber
elements = []
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}
def _parse_docx(data):
import docx
doc = docx.Document(io.BytesIO(data))
elements = []
for block in doc.element.body:
tag = block.tag.split("}")[-1] if "}" in block.tag else block.tag
if tag == "p":
text = _extract_paragraph_text(block)
if text:
elements.append({"type": "paragraph", "text": text, "style": ""})
elif tag == "tbl":
rows = []
for tr in block.findall(".//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tr"):
cells = []
for tc in tr.findall(".//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tc"):
cell_text = "".join(t.text or "" for t in tc.findall(".//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}t"))
cells.append(cell_text.strip())
if cells:
rows.append(cells)
if rows:
elements.append({"type": "table", "rows": rows})
return {"status": "parsed", "element_count": len(elements), "elements": elements}
def _extract_paragraph_text(p_elem):
texts = []
for t in p_elem.findall(".//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}t"):
if t.text:
texts.append(t.text)
return "".join(texts).strip()
def _parse_text(data):
text = data.decode("utf-8", errors="ignore")[:5000]
lines = [l.strip() for l in text.split("\n") if l.strip()]
return {"status": "parsed", "element_count": len(lines),
"elements": [{"type": "paragraph", "text": l, "style": ""} for l in lines]}