74 lines
2.7 KiB
Python
74 lines
2.7 KiB
Python
"""Parse service — PDF (PyPDF2), DOCX (python-docx), plain text fallback."""
|
|
import io
|
|
from PyPDF2 import PdfReader
|
|
|
|
|
|
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):
|
|
reader = PdfReader(io.BytesIO(data))
|
|
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": ""})
|
|
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]}
|