Skip to main content

MinerU output linter/fixer — LLM tool-use loop that restructures (never generates) MinerU content_list. Machine-verified fidelity: C_out ⊆ C_in.

Project description

mineru-refine

🌏 中文文档:README.zh-CN.md

A post-processor (linter / fixer) for MinerU parse results.

It takes MinerU's content_list (an array of item objects), fixes the high-frequency structural problems that parsing introduces — pseudo-headings, cross-page sentence breaks, cross-page split tables, headers/footers mixed into the body, LaTeX / link residue — and returns a content_list with the same schema, so downstream consumers need zero changes.

Two core promises:

  • Never adds a single character: it only removes and reorganizes; every content character in the output comes from the input, verified step by step by machine, and any violation is rolled back automatically (not enforced by prompting the LLM).
  • fail-open: any exception / LLM unavailability → the input is returned unchanged (report["failOpen"] == True), never breaking the upstream pipeline.

This package is a native PyO3 binding of the Rust core implementation; its options and return values are structurally identical to the JS / Rust / HTTP versions.

Install

pip install mineru-refine

Requires Python ≥ 3.9.

Usage

import json
import mineru_refine

items = json.load(open("content_list.json"))

result = mineru_refine.refine(
    items,                              # content_list (list[dict])
    sha256="...",                       # optional: source-file SHA256; enables the in-process cache
    max_iterations=None,                # optional: hard cap on the fix loop; defaults to adaptive with suspect count
    concurrency=8,                      # optional: number of suspects judged in parallel; 1 = strictly serial
    image_dir="/abs/mineru/out",        # optional: MinerU output dir; enables vision judging for split tables
    fix_ocr_confusion=False,            # optional: opt-in OCR character-confusion fix layer (CE0→CEO, etc.)
    extra_confusion_pairs=None,         # optional: extra allowlist pairs for confusion, e.g. ["0D"]
    rewrite_garbled_tables=False,       # optional: opt-in vision re-transcription layer for garbled tables (needs image_dir)
    degrade_garbled_tables=False,       # optional: opt-in fallback that demotes unrecoverable garbled tables to images
    model_config=None,                  # optional: config-driven model swap (see "Swapping models" below)
    chat=None,                          # optional: custom text-LLM callback (escape hatch; takes priority over model_config)
    vision=None,                        # optional: custom vision-LLM object (escape hatch)
)

result["items"]    # cleaned content_list (same schema; unknown fields passed through verbatim)
result["report"]   # audit report: iterations / opCounts / dismissed / removedSpans
                   #               / violations / tokenUsage / failOpen
                   #               (with fix_ocr_confusion on, also confusionFixes etc.; see the main README)

Every removed span is recorded in report["removedSpans"] (itemId / original text / reason), auditable line by line. fix_ocr_confusion=True turns on the confusion-fix layer (direct replacement, LLM proposal + mechanical gates); once on, the output contract changes from "remove-only" to a dual contract — see the "Confusion-fix layer" section of the main README. rewrite_garbled_tables=True turns on vision re-transcription for heavily garbled tables (mechanical detection selects tables judged whole-table junk, Qwen-VL re-transcribes cell by cell against the crop, all recorded in report["tableRewrites"]) — see the "Garbled-table re-transcription layer" section of the main README. degrade_garbled_tables=True turns on the garbled-table fallback (purely mechanical, runs after the re-transcription layer: tables still judged junk that have an img_path are demoted to image, counted in report["tableDegraded"]) — see the "Fallback demotion" section of the main README.

Standalone helper functions (none call the LLM):

mineru_refine.render_markdown(items)    # items → full.md text (deterministic re-render)
mineru_refine.detect_suspects(items)    # detect suspects only, returns the suspect list

Swapping models (custom LLMs)

By default the text role is DeepSeek and the vision role is Qwen-VL. Two mechanisms let you point them at any other LLM (e.g. MiniMax); see the main README for the full explanation.

1. model_config — config-driven, multi-vendor (recommended). A dict with two independent roles (reasoning for text, vision for vision); each is {provider?, model, key?, baseUrl?} (camelCase keys). Omit a role to fall back to the env default.

mineru_refine.refine(
    items,
    image_dir="/abs/mineru/out",
    model_config={
        # MiniMax-M3 is OpenAI-compatible and multimodal, so one model serves both roles
        "reasoning": {"provider": "openai", "model": "MiniMax-M3", "key": key, "baseUrl": "https://api.minimaxi.com/v1"},
        "vision":    {"provider": "openai", "model": "MiniMax-M3", "key": key, "baseUrl": "https://api.minimaxi.com/v1"},
    },
)

provider accepts deepseek / aliyun (qwen, dashscope) / openai (openai-compatible, custom) / anthropic (claude) / gemini (google) / ollama / groq / xai (grok); omit it to infer from the model name.

2. Custom callbacks — the escape hatch (take priority over model_config). Pass your own implementations when you need auth/proxy/model logic model_config can't express:

def chat(messages, tools):
    # messages: list[dict] (OpenAI-style), tools: list[dict]
    return {
        "message": {"content": "...", "tool_calls": [...]},  # tool_calls optional
        "finishReason": "stop",
        "usage": {"prompt_tokens": 0, "completion_tokens": 0},
    }

class Vision:
    def judge_split_table(self, img_a: bytes, img_b: bytes):
        return {"verdict": "merge", "reason": "...", "usage": {}}   # verdict: "merge" | "dismiss"
    def transcribe_table(self, img: bytes, cells_render: str):      # optional; only for rewrite_garbled_tables
        return {"cells": [{"row": 0, "col": 0, "text": "..."}], "usage": {}}

mineru_refine.refine(items, image_dir="/abs/mineru/out", chat=chat, vision=Vision())

Environment variables

Variable Required Purpose
DEEPSEEK_APIKEY Yes Text judging (DeepSeek). If missing, refine goes straight to fail-open
QWEN_APIKEY For vision judging Qwen-VL judging of cross-page split tables; if missing, those suspects are skipped and the tables kept as-is

The library itself does not read .env; set the environment variables in the host program (or load .env yourself).

Building locally

just py-dev        # repo root: build the wheel and install it into bindings/python/.venv
just publish-py    # publish to PyPI: current-platform wheel + sdist (needs MATURIN_PYPI_TOKEN)

The full design docs for the detector, the fix operation set, and the fidelity gates are in the repository README.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mineru_refine-0.12.0.tar.gz (493.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

mineru_refine-0.12.0-cp39-abi3-macosx_11_0_arm64.whl (3.3 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

mineru_refine-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file mineru_refine-0.12.0.tar.gz.

File metadata

  • Download URL: mineru_refine-0.12.0.tar.gz
  • Upload date:
  • Size: 493.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mineru_refine-0.12.0.tar.gz
Algorithm Hash digest
SHA256 70f4e08844194d8bd985f1db0815b44218401787607aac7b911d9bd09d8da1c4
MD5 84bb49374467b04bde70fc00a6499348
BLAKE2b-256 da6b564ea23845fbac3905d3eff50a86319e5728a1ff18c7dae10d4a7e64f461

See more details on using hashes here.

Provenance

The following attestation bundles were made for mineru_refine-0.12.0.tar.gz:

Publisher: py-release.yml on LcpMarvel/mineru-refine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a6fa884ed3f10de471812fc5bf45d1fae00bb38683e95067be57e148e3757246
MD5 acf329868edb6c7df9e098ca2f29417f
BLAKE2b-256 d1a35efe46b333d6e78f301136767355efa6e725bf56729eec26ffc9b73b1a79

See more details on using hashes here.

Provenance

The following attestation bundles were made for mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: py-release.yml on LcpMarvel/mineru-refine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 34da5a23afbf9eef5177d6abc1df36d4010fd11cad6240eaa8912caa65ed66cc
MD5 bee5d387582f62c4ebee1ab0403050ae
BLAKE2b-256 14b50eb43b3abfb667eb5034621327b2a15201e85a33fb9c719aebb0e3b80785

See more details on using hashes here.

Provenance

The following attestation bundles were made for mineru_refine-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: py-release.yml on LcpMarvel/mineru-refine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mineru_refine-0.12.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mineru_refine-0.12.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 cfc373b56b1043004eb5a0a6bac0782209279a6729a494b61665ce64abf45fa5
MD5 96582f79f3ca63103ff8e2f016adb0da
BLAKE2b-256 930487191c03714f0362d10a1d45776b8cd657826d205c5dc3a9c9aa8b5a5613

See more details on using hashes here.

Provenance

The following attestation bundles were made for mineru_refine-0.12.0-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: py-release.yml on LcpMarvel/mineru-refine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mineru_refine-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for mineru_refine-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 6d38d680e731cea1395300a8d108fb8792b16777925c0dcc25d257668a6409c1
MD5 8c2b72dde9905384f387afe172feee3f
BLAKE2b-256 486880fca93033ce08be3bef358699561597a23f228d6e9a8d759c26102454c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for mineru_refine-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: py-release.yml on LcpMarvel/mineru-refine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page