| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- """不依赖AI或Office进程的PDF/DOCX正文提取与检索文本构建。"""
- from __future__ import annotations
- import logging
- from dataclasses import dataclass
- from datetime import datetime, timezone
- from pathlib import Path
- import fitz
- from docx import Document as WordDocument
- from dms.common.enums import ContentExtractStatus
- logger = logging.getLogger(__name__)
- @dataclass(frozen=True, slots=True)
- class ContentExtraction:
- text: str | None
- status: str
- extracted_at: datetime | None
- def build_search_text(
- name: str,
- summary: str | None,
- tags: list[str] | None,
- content_text: str | None,
- ) -> str:
- return " ".join(
- part for part in [name, summary or "", *(tags or []), content_text or ""]
- if part
- ).strip()
- def _word_text(path: Path) -> str:
- document = WordDocument(path)
- values: list[str] = []
- def add_paragraphs(paragraphs) -> None:
- values.extend(
- paragraph.text.strip()
- for paragraph in paragraphs
- if paragraph.text.strip()
- )
- def add_tables(tables) -> None:
- for table in tables:
- for row in table.rows:
- for cell in row.cells:
- add_paragraphs(cell.paragraphs)
- add_tables(cell.tables)
- add_paragraphs(document.paragraphs)
- add_tables(document.tables)
- for section in document.sections:
- add_paragraphs(section.header.paragraphs)
- add_tables(section.header.tables)
- add_paragraphs(section.footer.paragraphs)
- add_tables(section.footer.tables)
- return "\n".join(values).strip()
- def _pdf_text(path: Path) -> str:
- with fitz.open(stream=path.read_bytes(), filetype="pdf") as document:
- return "\n".join(page.get_text("text") for page in document).strip()
- def extract_document_content(path: Path, extension: str) -> ContentExtraction:
- normalized = extension.lower().lstrip(".")
- if normalized not in {"pdf", "docx"}:
- return ContentExtraction(
- text=None,
- status=ContentExtractStatus.UNSUPPORTED.value,
- extracted_at=None,
- )
- extracted_at = datetime.now(timezone.utc).replace(tzinfo=None)
- try:
- text = _pdf_text(path) if normalized == "pdf" else _word_text(path)
- except Exception:
- logger.exception("文档正文提取失败:extension=%s", normalized)
- return ContentExtraction(
- text=None,
- status=ContentExtractStatus.FAILED.value,
- extracted_at=extracted_at,
- )
- return ContentExtraction(
- text=text or None,
- status=(
- ContentExtractStatus.SUCCESS.value
- if text
- else ContentExtractStatus.EMPTY.value
- ),
- extracted_at=extracted_at,
- )
- __all__ = ["ContentExtraction", "build_search_text", "extract_document_content"]
|