Spaces:
Sleeping
Sleeping
| """Marker parser - 兜底 (Docling 失败时启用). | |
| 特性: | |
| - PDF -> Markdown 转换, 速度快 | |
| - 内置 surya-ocr, 支持 90+ 语言 | |
| - 不擅长复杂表格 / 跨页表 (不如 Docling), 但胜在稳定 | |
| """ | |
| from __future__ import annotations | |
| import asyncio | |
| import logging | |
| import time | |
| from pathlib import Path | |
| from app.services.parsers.base_parser import BaseParser, ParsedDocument | |
| logger = logging.getLogger(__name__) | |
| class MarkerParser(BaseParser): | |
| name = "marker" | |
| def supported_extensions(self) -> set[str]: | |
| # Marker 强项是 PDF; 其它类型建议直接 Docling | |
| return {".pdf"} | |
| async def parse(self, file_path: Path) -> ParsedDocument: | |
| loop = asyncio.get_running_loop() | |
| return await loop.run_in_executor(None, self._parse_sync, file_path) | |
| def _parse_sync(self, file_path: Path) -> ParsedDocument: | |
| # Marker 1.x 推荐用 marker's Python API 而非 CLI subprocess | |
| from marker.converters.pdf import PdfConverter | |
| from marker.models import create_model_dict | |
| from marker.output import text_from_rendered | |
| started = time.time() | |
| logger.info("Marker parsing: %s", file_path.name) | |
| converter = PdfConverter(artifact_dict=create_model_dict()) | |
| rendered = converter(str(file_path)) | |
| markdown, _, _ = text_from_rendered(rendered) | |
| # Marker 不直接给 page-level 拆分, 走全文 markdown | |
| elapsed_ms = int((time.time() - started) * 1000) | |
| logger.info("Marker done: %dms", elapsed_ms) | |
| # 尝试从 rendered 拿 metadata | |
| meta = rendered.metadata if hasattr(rendered, "metadata") else {} | |
| page_count = meta.get("page_stats", {}).get("total_pages") if isinstance(meta, dict) else None | |
| return ParsedDocument( | |
| markdown=markdown, | |
| pages=[], # Marker 不分页 | |
| tables=[], | |
| images=[], | |
| meta={ | |
| "parser": self.name, | |
| "page_count": page_count, | |
| "elapsed_ms": elapsed_ms, | |
| }, | |
| ) | |