Spaces:
Sleeping
Sleeping
| """DOCX reader — extracts text with heading-based chunking via python-docx.""" | |
| from __future__ import annotations | |
| from pathlib import Path | |
| from uofa_cli.document_reader import DocumentChunk | |
| _HEADING_STYLES = {"Heading 1", "Heading 2", "Heading 3", "Heading 4"} | |
| def read_docx(path: Path) -> list[DocumentChunk]: | |
| """Read a DOCX and return chunks split by heading sections.""" | |
| import docx | |
| doc = docx.Document(path) | |
| sections: list[tuple[str | None, list[str]]] = [] | |
| current_heading: str | None = None | |
| current_paragraphs: list[str] = [] | |
| for para in doc.paragraphs: | |
| style_name = para.style.name if para.style else "" | |
| if style_name in _HEADING_STYLES: | |
| # Save previous section | |
| if current_paragraphs: | |
| sections.append((current_heading, current_paragraphs)) | |
| current_heading = para.text.strip() | |
| current_paragraphs = [] | |
| else: | |
| text = para.text.strip() | |
| if text: | |
| current_paragraphs.append(text) | |
| # Save last section | |
| if current_paragraphs: | |
| sections.append((current_heading, current_paragraphs)) | |
| # If no sections were created, treat entire doc as one chunk | |
| if not sections: | |
| full_text = "\n".join(p.text.strip() for p in doc.paragraphs if p.text.strip()) | |
| return [DocumentChunk( | |
| text=full_text or "(empty document)", | |
| source_file=path.name, | |
| source_path=str(path), | |
| format="docx", | |
| )] | |
| chunks: list[DocumentChunk] = [] | |
| for heading, paragraphs in sections: | |
| text = "\n".join(paragraphs) | |
| if heading: | |
| text = f"## {heading}\n\n{text}" | |
| chunks.append(DocumentChunk( | |
| text=text, | |
| source_file=path.name, | |
| source_path=str(path), | |
| section_heading=heading, | |
| format="docx", | |
| )) | |
| return chunks | |