File size: 4,653 Bytes
9abace2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | """
DOCX Parser
Part of SOVEREIGN PYTHON LLM ENGINE
Parse Microsoft Word documents (.docx).
"""
from typing import Any
from pathlib import Path
from dataclasses import dataclass
import io
from ...core.evidence import WORMLedger
@dataclass
class DOCXDocument:
"""Parsed DOCX document"""
text: str
paragraphs: list[str]
tables: list[list[list[str]]]
metadata: dict[str, Any]
class DOCXParser:
"""
DOCX document parser using python-docx.
"""
def __init__(self, worm_ledger: WORMLedger | None = None):
"""
Initialize DOCX parser.
Args:
worm_ledger: Optional WORM ledger
"""
self.worm_ledger = worm_ledger
async def parse(self, file_path: Path) -> DOCXDocument:
"""
Parse DOCX file.
Args:
file_path: Path to DOCX file
Returns:
DOCXDocument with extracted content
"""
try:
from docx import Document
except ImportError:
raise ImportError("python-docx is required. Install: pip install python-docx")
import asyncio
def _sync_parse():
doc = Document(file_path)
# Extract paragraphs
paragraphs = []
for para in doc.paragraphs:
if para.text.strip():
paragraphs.append(para.text)
# Extract text
text = "\n\n".join(paragraphs)
# Extract tables
tables = []
for table in doc.tables:
table_data = []
for row in table.rows:
row_data = [cell.text for cell in row.cells]
table_data.append(row_data)
tables.append(table_data)
# Extract metadata
metadata = {}
if doc.core_properties:
props = doc.core_properties
metadata = {
"title": props.title or "",
"author": props.author or "",
"subject": props.subject or "",
"keywords": props.keywords or "",
"created": props.created.isoformat() if props.created else None,
"modified": props.modified.isoformat() if props.modified else None,
}
return DOCXDocument(
text=text,
paragraphs=paragraphs,
tables=tables,
metadata=metadata
)
return await asyncio.to_thread(_sync_parse)
async def parse_bytes(self, docx_bytes: bytes) -> DOCXDocument:
"""
Parse DOCX from bytes.
Args:
docx_bytes: DOCX file bytes
Returns:
DOCXDocument
"""
try:
from docx import Document
except ImportError:
raise ImportError("python-docx is required")
import asyncio
def _sync_parse():
doc = Document(io.BytesIO(docx_bytes))
paragraphs = []
for para in doc.paragraphs:
if para.text.strip():
paragraphs.append(para.text)
text = "\n\n".join(paragraphs)
tables = []
for table in doc.tables:
table_data = []
for row in table.rows:
row_data = [cell.text for cell in row.cells]
table_data.append(row_data)
tables.append(table_data)
metadata = {}
if doc.core_properties:
props = doc.core_properties
metadata = {
"title": props.title or "",
"author": props.author or "",
}
return DOCXDocument(
text=text,
paragraphs=paragraphs,
tables=tables,
metadata=metadata
)
return await asyncio.to_thread(_sync_parse)
# Tool registration helper
async def parse_docx_tool(file_path: str) -> dict:
"""
Tool wrapper for DOCX parsing.
Args:
file_path: Path to DOCX file
Returns:
Dictionary with parsed content
"""
parser = DOCXParser()
result = await parser.parse(Path(file_path))
return {
"text": result.text,
"paragraphs_count": len(result.paragraphs),
"tables_count": len(result.tables),
"metadata": result.metadata
}
|