openskill-ocr / download_models.py
crazylemonade's picture
Upload 7 files
0ad3f89 verified
Raw
History Blame Contribute Delete
7.91 kB
"""
Download MinerU pipeline models from Hugging Face Hub.
Called once during Docker build: python download_models.py
Optimizations vs original:
- Skip-if-exists: if models are already present (Docker layer cache reuse),
the entire download is skipped without re-downloading anything.
- MFR excluded: formula recognition models (unimernet, ~1-2 GB) are not
downloaded because formula recognition is disabled in the config. Excluding
them cuts download time and image size significantly.
- layoutreader optional: if download fails (network issue, repo unavailable),
the script logs a warning and continues. MinerU falls back to its built-in
layout ordering without layoutreader.
── FORENSIC: OCR MODEL AVAILABILITY IN opendatalab/PDF-Extract-Kit-1.0 ───────
models_config.yml in magic-pdf 1.3.12 was patched in Dockerfile Layer 3.5 to
use the weight files that ARE present in the HF repo. After the patch:
DEFAULT CPU path (ch_lite):
det: ch_PP-OCRv5_det_infer.pth ← present in HF repo βœ“
rec: ch_PP-OCRv5_rec_infer.pth ← present in HF repo βœ“
en / latin det (patched):
det: Multilingual_PP-OCRv3_det_infer.pth ← present in HF repo βœ“
NOT IN REPO (these files do NOT exist and are not needed for default usage):
ch_PP-OCRv3_det_infer.pth ← absent; patched to v5
en_PP-OCRv3_det_infer.pth ← absent; patched to multilingual
en_PP-OCRv4_rec_infer.pth ← absent; en rec unavailable
korean/japan/chinese_cht/etc v3 rec ← absent; those langs need explicit
lang= arg which is not default
BUNDLED IN WHEEL (not downloaded here):
magic_pdf/resources/slanet_plus/slanet-plus.onnx ← table model, in wheel
magic_pdf/resources/fasttext-langdetect/lid.176.ftz
magic_pdf/resources/yolov11-langdetect/yolo_v11_ft.pt
Models saved to /app/models/
Config written to /root/magic-pdf.json
"""
import json
import os
import sys
MODELS_DIR = "/app/models"
EXTRACT_KIT_DIR = os.path.join(MODELS_DIR, "PDF-Extract-Kit-1.0")
LAYOUTREADER_DIR = os.path.join(MODELS_DIR, "layoutreader")
# Canary files: both must exist for the skip-if-exists check to pass.
# Using the OCR det weight (not just the Layout dir) ensures a stale cache
# that predates the v3β†’v5 model rename cannot produce a false positive.
_CANARY_DIR = os.path.join(EXTRACT_KIT_DIR, "models", "Layout")
_CANARY_FILE = os.path.join(
EXTRACT_KIT_DIR, "models", "OCR", "paddleocr_torch",
"ch_PP-OCRv5_det_infer.pth" # patched det; absent in v3-era cache
)
def _models_present() -> bool:
"""Return True only when BOTH the Layout directory AND the OCR v5 det weight
exist. This prevents stale Docker layer caches (built before the v3β†’v5 patch)
from reporting models as present when the required file is missing."""
return os.path.isdir(_CANARY_DIR) and os.path.isfile(_CANARY_FILE)
def _write_config(layoutreader_dir: str) -> None:
config = {
"bucket_info": {},
"models-dir": os.path.join(EXTRACT_KIT_DIR, "models"),
"layoutreader-model-dir": layoutreader_dir,
"device-mode": "cpu",
"layout-config": {
"model": "doclayout_yolo"
},
"formula-config": {
"mfd_model": "yolo_v8_mfd",
"mfr_model": "unimernet_small",
"enable": False
},
"table-config": {
"model": "rapid_table",
"enable": True,
"max_time": 400
},
"backend": "pipeline"
}
config_path = os.path.expanduser("~/magic-pdf.json")
with open(config_path, "w") as f:
json.dump(config, f, indent=2)
print(f"Config written β†’ {config_path}")
return config_path
def download() -> None:
try:
from huggingface_hub import snapshot_download
except ImportError:
print("ERROR: huggingface_hub not installed", file=sys.stderr)
sys.exit(1)
# ── Skip-if-exists ────────────────────────────────────────────────────────
if _models_present():
print("Models already present β€” skipping download (Docker layer cache).")
# Config may still need writing if this is a fresh container from cached layer
lr_dir = LAYOUTREADER_DIR if os.path.isdir(LAYOUTREADER_DIR) else ""
_write_config(lr_dir)
return
os.makedirs(MODELS_DIR, exist_ok=True)
# ── PDF-Extract-Kit-1.0 ───────────────────────────────────────────────────
# Excluded via ignore_patterns:
# models/MFR β€” formula recognition (unimernet). Disabled in config.
# Saves ~1-2 GB of download and disk.
#
# OCR models (models/OCR/paddleocr_torch/) ARE included (not ignored).
# After the Layer 3.5 patch, the files models_config.yml references match
# what is actually present in the repo:
# ch_PP-OCRv5_det_infer.pth ← present βœ“
# ch_PP-OCRv5_rec_infer.pth ← present βœ“
# Multilingual_PP-OCRv3_det_infer.pth ← present βœ“
print("=" * 60)
print("Downloading PDF-Extract-Kit-1.0 ...")
print(" (MFR/formula-recognition excluded β€” disabled in config)")
print("=" * 60)
snapshot_download(
repo_id="opendatalab/PDF-Extract-Kit-1.0",
local_dir=EXTRACT_KIT_DIR,
ignore_patterns=[
"*.git*",
".gitattributes",
"models/MFR*",
"models/MFR/*",
],
)
print(f" β†’ {EXTRACT_KIT_DIR}")
# Verify canary file landed correctly
if not os.path.isfile(_CANARY_FILE):
print(
f"\nERROR: Expected OCR model not found after download:\n"
f" {_CANARY_FILE}\n"
f"The HF repo may have changed its file structure.\n"
f"Run: python3 -c \"from huggingface_hub import list_repo_files; "
f"[print(f) for f in list_repo_files('opendatalab/PDF-Extract-Kit-1.0')]\"\n"
f"to inspect the current repo contents.",
file=sys.stderr,
)
sys.exit(1)
print(f" Canary verified: {os.path.basename(_CANARY_FILE)} βœ“")
# ── layoutreader (optional) ───────────────────────────────────────────────
# Improves reading-order accuracy. If unavailable, MinerU uses fallback.
layoutreader_dir = ""
print("=" * 60)
print("Downloading layoutreader (optional, improves reading order) ...")
print("=" * 60)
try:
snapshot_download(
repo_id="hantian/layoutreader",
local_dir=LAYOUTREADER_DIR,
ignore_patterns=["*.git*", ".gitattributes"],
)
layoutreader_dir = LAYOUTREADER_DIR
print(f" β†’ {LAYOUTREADER_DIR}")
except Exception as exc:
print(f" WARNING: layoutreader download failed ({exc})")
print(" Continuing without layoutreader β€” MinerU will use fallback ordering.")
# ── Write config ──────────────────────────────────────────────────────────
_write_config(layoutreader_dir)
print("\nβœ“ Model setup complete.")
print(f" models-dir : {os.path.join(EXTRACT_KIT_DIR, 'models')}")
print(f" layoutreader-dir : {layoutreader_dir or '(not available)'}")
print(f" device-mode : cpu")
print(f" formula recognition : disabled (MFR models excluded)")
print(f" table recognition : enabled (slanet-plus.onnx bundled in wheel)")
if __name__ == "__main__":
download()