Files
ai-doc-template-system/backend/app/services/doc_parser.py
T
2026-07-01 19:50:29 +08:00

87 lines
2.6 KiB
Python

"""Word 文档解析引擎"""
from docx import Document
from docx.paragraph import Paragraph
from docx.table import Table as DocxTable
from typing import List, Dict, Any
def parse_document(file_path: str) -> List[Dict[str, Any]]:
"""
解析 Word 文档,返回 block 列表(不含表格数据,仅标记位置)。
每个 block 包含:type, text, level, style
"""
doc = Document(file_path)
blocks = []
for para in doc.paragraphs:
block = classify_paragraph(para)
if block:
blocks.append(block)
return blocks
def classify_paragraph(para: Paragraph) -> Dict[str, Any] | None:
"""识别段落类型"""
text = para.text.strip()
style_name = para.style.name if para.style else ""
if not text and "Heading" not in style_name:
return None # 跳过空段落
if "Heading" in style_name:
level = int(style_name.replace("Heading", "").strip()) if style_name.replace("Heading", "").strip().isdigit() else 1
return {"type": "heading", "text": text, "level": level, "style": style_name}
else:
return {"type": "paragraph", "text": text, "level": 0, "style": style_name}
def parse_tables(doc: Document) -> List[Dict[str, Any]]:
"""解析 Word 表格"""
tables = []
for i, table in enumerate(doc.tables):
headers = [cell.text.strip() for cell in table.rows[0].cells] if table.rows else []
tables.append({
"type": "table",
"text": " | ".join(headers),
"level": 0,
"rows": len(table.rows),
"cols": len(table.columns),
"headers": headers,
"table_index": i,
})
return tables
def generate_block_id(index: int) -> str:
"""生成 block_id,格式:block_001"""
return f"block_{index:03d}"
def build_tree(blocks: List[Dict]) -> Dict:
"""构建层级树结构"""
tree = []
stack = [] # 存父级节点
for block in blocks:
node = {"block_id": block["block_id"], "text": block["text"][:50], "children": []}
level = block.get("level", 0)
# 回退栈
while stack and stack[-1]["level"] >= level:
stack.pop()
if stack:
parent = stack[-1]["node"]
parent["children"].append(node)
block["parent_block_id"] = parent["block_id"]
else:
tree.append(node)
block["parent_block_id"] = None
# 非叶子节点入栈
if level < 2 or block["type"] == "heading":
stack.append({"level": level, "node": node})
return {"blocks": tree}