SuperAPI AI Directory

legal-ocr

Data & analytics

View repository

Updated 10-15 20:10

About this skill

Legal OCR

This skill is used for OCR, scan recognition, image text recognition, document recognition, and converting PDFs, images, Office documents, and URLs into Markdown that can continue to be edited, analyzed, and archived. It is first a general OCR entry point; when the result is identified as legal material, conservative legal post-processing is then automatically enabled. By default, it uses configuration-prioritized automatic routing:

  • For local PDFs, the native text layer is probed first by default: for court electronic service judgments, electronic contracts, government official documents, and other PDFs with a reliable text layer, direct reading is more accurate, faster, and more quota-efficient than OCR. If quality meets the standard, text is extracted directly and converted to Markdown; only if it does not meet the standard does it fall back to OCR. See "PDF Text Layer Dual Path" for details.
  • Only PaddleOCR configured: PDFs/images supported by PaddleOCR are prioritized through PaddleOCR; when beyond its capability boundary, prompt the user or switch to a MinerU-supported path.
  • Only MinerU Token configured: all inputs supported by MinerU go uniformly through MinerU, including PDFs, images, Office files, remote document URLs, and web URLs.
  • Both API sets configured: local PDFs/images prioritize PaddleOCR, while Office files/web URLs prioritize MinerU; when the preferred backend encounters quota, rate, authentication, network, or service failures, the candidate backend is automatically tried.
  • When RapidOCR is already installed on the local machine, for local PDFs/images, local RapidOCR serves as the last-level candidate after cloud failure.
  • Neither API set configured: when RapidOCR is already installed on the local machine, local recognition is prioritized (materials do not leave the local machine), and the MinerU lightweight interface becomes the fallback; when RapidOCR is not installed, use the MinerU lightweight interface to process small files, and prompt the user to add a Token when the limit is exceeded.
  • When sensitive materials are not allowed to be transmitted externally, explicitly use --backend rapid(local onnx inference, never leaves the local machine throughout the process).

The old paddle-ocr and mineru-ocr remain available; this skill is the new unified entry point, aiming to cover the common OCR/conversion scenarios of both.

When to Use

Use this skill in the following scenarios:

  • The user explicitly needs OCR, scan recognition, image text recognition, or document recognition.
  • The input may be a PDF, image, Office document, remote document URL, or web URL, and the user wants it converted to Markdown.
  • The user wants to preserve an archive for reviewing the original file, backend results, Markdown, and image resources.
  • The user needs automatic selection of the OCR backend rather than manually determining whether to use PaddleOCR or MinerU.
  • The user wants non-legal materials to retain general OCR output, while legal materials receive terminology and document structure optimization.

Scenarios where this skill is not prioritized:

  • Only a short piece of clear text needs to be read quickly, and no Markdown file or archive is needed.
  • The user needs context-based fact rewriting, supplementation of missing information, in-depth seal annotation, or chart semantic analysis; these capabilities are still in the follow-up plan.

Dependencies

System Dependencies

Dependency Installation Method
python3 Usually built in on macOS
uv macOS: brew install uv

Python Packages

Scripts use uv run for execution, and dependencies are written at the top of the scripts; it is recommended to use uv run scripts/convert.pydirectly, without the need to separately maintain requirements.txt。

Package Name Purpose Installation Commands
httpx Call PaddleOCR and MinerU API pip install httpx
pypdfium2 Read PDF page count and split page ranges pip install pypdfium2
rapidocr + onnxruntime Optional: local RapidOCR backend (--backend rapid) uv run --with rapidocr --with onnxruntime scripts/convert.py ... or pip install rapidocr

If you run directly with python scripts/convert.py and dependencies are missing, the script will provide installation hints.

Capability boundaries of the local RapidOCR backend

  • Text detection + recognition only, no layout analysis: paragraphs are reconstructed by a unified post-processing chain; single-column documents (judgments, scanned contracts, etc.) are reliable, multi-column layouts may be out of order.
  • Does not extract image assets: seals, signatures, and charts will not appear in the Markdown.
  • Office documents and URLs are not supported (still use MinerU).
  • Default rendering DPI is 220, adjustable with LEGAL_OCR_RAPID_DPI ; confidence threshold LEGAL_OCR_RAPID_MIN_SCORE(default 0.5).

Initial Setup

Copy the configuration template:

cd legal-ocr/config
cp .env.example .env
nano .env

Optional configuration:

  • PaddleOCR: fill in PADDLEOCR_DOC_PARSING_API_URL and PADDLEOCR_ACCESS_TOKEN。
  • MinerU Token: fill in MINERU_API_TOKEN; if left empty, small files default to the MinerU lightweight interface.
  • Auto-routing: keep LEGAL_OCR_BACKEND=auto。
  • Legal terminology optimization: keep LEGAL_OCR_LEGAL_TERMS=auto, enabled only when legal materials are detected; to force enable, set to true, to disable, set to false。
  • General hard line break optimization: keep LEGAL_OCR_LINE_MERGE=true; to load custom legal terminology, set LEGAL_OCR_CUSTOM_TERMS_PATH。

This skill will also try to read the MinerU Token from environment variables and ~/.mineru/config.yaml . PaddleOCR also supports the pdf-processor used by PADDLE_OCR_API_ENDPOINT / PADDLE_OCR_API_KEY, and supports the /api/v2/ocr/jobs asynchronous task interface.

Common Commands

Run in the skill root directory:

uv run scripts/convert.py "/path/to/file.pdf"
uv run scripts/convert.py "/path/to/file.pdf" --pages "1-20"
uv run scripts/convert.py "/path/to/file.pdf" --backend paddle
uv run scripts/convert.py "/path/to/file.pdf" --backend paddle --paddle-model PaddleOCR-VL-1.5
uv run scripts/convert.py "https://example.com/document.pdf" --backend auto
uv run scripts/convert.py "https://example.com/article" --backend mineru
uv run scripts/convert.py "/path/to/judgment.pdf" --legal-terms always
uv run scripts/convert.py checktoken

Local recognition of sensitive materials (does not leave this machine):

uv run --with rapidocr --with onnxruntime scripts/convert.py "/path/to/scan.pdf" --backend rapid

JXA-compatible entry point:

/usr/bin/osascript -l JavaScript scripts/convert.js "/path/to/file.pdf"

Optional parameters:

Parameter Description
`--backend auto paddle
`--text-layer auto never
--output <path> Output Markdown path or directory
--pages <spec> Page range, e.g. 1-20、1-5,8,10-12
--archive-name <name> Custom archive directory name
--no-archive Do not write to archive
--no-post-process Skip all post-processing
--no-legal-terms Skip legal terminology optimization
`--legal-terms auto always
--no-line-merge Skip OCR hard line break cleanup
`--model pipeline vlm`
`--paddle-model PP-OCRv5 PaddleOCR-VL-1.5`
`--paddle-api-protocol auto sync
--paddle-api-extra-json <path> Merge additional PaddleOCR optionalPayload

The PaddleOCR synchronous interface verifies the actual number of pages returned by the backend. If the number of returned pages is less than the number of pages in the local PDF batch, the conversion will fail and prompt you to lower PADDLEOCR_BATCH_PAGES or use --pages to rerun, preventing missing-page results from being mistaken for success.

PDF Text Layer Dual Path

Before a local PDF enters the OCR backend, it first detects whether it has a usable native text layer (v1.5.0+). This is a high-frequency optimization in legal scenarios: PDFs such as court electronically served judgments, electronic contracts, and government documents usually already have a reliable text layer, and direct reading is more accurate, faster, and does not consume API quota than OCR.

Workflow

  1. Triggered only for local .pdf ; images, Office, and URLs are not involved.
  2. Use pypdfium2 to extract text page by page, and calculate 4 metrics: text page coverage, average CJK per page, garbled text ratio (PUA + replacement characters + uncommon characters), and total character count.
  3. All thresholds met → convert directly to Markdown, reusing the existing post-process (legal terminology → hard line break cleanup → basic cleanup).
  4. If any criterion is not met → fall back to the original OCR candidates (PaddleOCR → MinerU), fully compatible with the old workflow.

Mode (CLI --text-layer or env LEGAL_OCR_TEXT_LAYER)

Mode Behavior
auto(default) After detection, use the text layer if criteria are met; otherwise fall back to OCR
never Completely disable the text layer, reverting to the old pure OCR behavior
always Force use of the text layer; if unavailable, fail directly with exit=2, for easier troubleshooting

and --backend priority

  • --backend auto + --text-layer auto: optimal path, text layer first, then OCR if criteria are not met.
  • --backend paddle|mineru: treat as the user explicitly wanting OCR, skip the text layer branch (unless --text-layer always is also set to force an override).

Thresholds (conservative defaults, ideal values pending calibration on real case files)

env Default Meaning
LEGAL_OCR_TEXT_LAYER_MIN_COVERAGE 0.8 Lower bound on the proportion of text pages among probed pages
LEGAL_OCR_TEXT_LAYER_MIN_CHARS_PER_PAGE 50 Lower bound on the average CJK character count of text pages
LEGAL_OCR_TEXT_LAYER_MAX_GARBLE_RATIO 0.05 Upper bound on the proportion of PUA + replacement characters + uncommon characters
LEGAL_OCR_TEXT_LAYER_MIN_TOTAL_CHARS 100 Lower bound on the total number of non-whitespace characters

For the rationale behind the default threshold values, see references/text-layer-detection.md and DECISIONS.md. If you get a batch of real case files and find misjudgments (for example, a PDF that should go through OCR goes through the text layer, or vice versa), feed the metrics and samples back to the maintainers, then adjust the thresholds or add new rules.

archive record

Regardless of whether the text layer is used, PDF input will leave a metadata.json field in text_layer :

  • Text layer used:enabled=true + probe full metrics (page count, coverage, garbled_ratio, threshold snapshot).
  • Text layer not used:enabled=false + probe.reason(such as no_text_layer / high_garbled_ratio), for reviewing why it fell back to OCR.

Automatic routing

  • auto first looks at which APIs the user has actually configured; when only one set is configured, try to route everything through that set to reduce the user's decision burden.
  • When both sets of APIs are configured, choose the preferred backend by material type, and use the other available backend as a candidate.
  • If the backend returns 429, insufficient quota, insufficient balance, rate limiting, authentication failure, network timeout, or service failure, the failure category will be recorded in result.json and metadata.json of route.attempts ; if a candidate backend exists, conversion will continue automatically.
  • Currently there is no separate quota pre-check interface integrated; quota determination comes from API response codes and error messages. If the service provider offers a stable quota endpoint, add a pre-conversion check.

Automatic retry for transient errors

  • Scope: all HTTP calls (synchronous submission, asynchronous submission, asynchronous polling, MinerU upload/polling/download, Token self-check) are wrapped with transient error classification and retry.
  • Transient definition: currently httpx.RequestError(DNS resolution failure, connection failure, connection/read timeout, remote closed connection, protocol error). HTTP 4xx is still raised immediately (authentication, quota, parameter errors); HTTP 5xx and 429 are covered by the same retry wrapper on the polling path.
  • Default parameters: 3 attempts (including the first), 1.0 second before the first retry, maximum wait of 30.0 seconds per retry (exponential backoff 1 → 2 → 4 → 8 → ...).
  • Configuration items: uniformly use LEGAL_OCR_RETRY_ATTEMPTS / LEGAL_OCR_RETRY_BASE_DELAY / LEGAL_OCR_RETRY_MAX_DELAY; you can use PADDLEOCR_RETRY_* and MINERU_RETRY_* to override a single backend. Setting it to 1 is equivalent to disabling retries.
  • Before retrying, a line is output to stderr PaddleOCR/MinerU 瞬态错误 … logs, making it easier to troubleshoot real network issues.

OCR and Legal Enhancement

  • Non-legal materials only undergo general Markdown cleanup, blank line tidying, and hard line break tidying by default.
  • Legal enhancement is in auto mode by default: OCR raw text and file names are scanned first, and legal terminology optimization runs only when sufficient signals such as courts, case numbers, party labels, and judgment/ruling structures are matched.
  • Detection results are written to the result.json and metadata.json fields of postprocess.legal_context / legal_context .
  • If the user confirms that the input is definitely legal material, --legal-terms always or LEGAL_OCR_LEGAL_TERMS=true can be used to force it on.
  • If processing non-legal materials and you want to completely disable legal replacement, use --legal-terms never、--no-legal-terms or LEGAL_OCR_LEGAL_TERMS=false。

Legal Terminology Optimization

  • By default, conservative legal terminology post-processing is enabled only when legal material is detected; it only handles high-confidence OCR broken characters and common misrecognitions, and does not perform fact completion or semantic rewriting.
  • By default, it covers common terms such as document names, subject labels, litigation procedures, evidence materials, and court document structure words.
  • By default, it tidies obvious OCR hard line breaks, merging only physical line breaks within the same Chinese paragraph; titles, party labels, numbering, tables, quotations, and Markdown structures are preserved.
  • Each replacement is written to postprocess_log.json, and result_raw.md is retained for review.
  • For the custom terminology format, see references/legal_terms.md。

Output

  • Markdown is saved by default in the same directory as the source file; remote URLs are saved by default in the current directory.
  • Image resources are saved by default in the same directory as the Markdown, in <文件名>_images/。
  • archive is saved by default in legal-ocr/archive/时间戳_文件名/。

Input/Output

Input

  • Required: local file path, remote URL, or checktoken。
  • Optional:--backend、--output、--pages、--archive-name、--model and PaddleOCR-related parameters.

Output

  • Markdown main file: the converted editable text.
  • Image directory: image resources returned by the backend or referenced by the Markdown.
  • Archive: by default saves the original result, final result, backend response, routing record, and post-processing log; the input file's path / sha256 / size_bytes(local) or original URL (remote) is recorded through the metadata.json field of source , and the input copy is no longer duplicated separately.

The archive contains:

  • output/result.md
  • output/result_raw.md
  • output/result.json
  • backend_result/
  • metadata.json(the input file's path / sha256 / size_bytes or remote URL is recorded through the source field; the input copy is not saved separately)
  • Includes image resources and postprocess_log.json

For the detailed structure, see references/output_schema.md。

Troubleshooting

Issue Solution
PaddleOCR is not configured Add PADDLEOCR_DOC_PARSING_API_URL and PADDLEOCR_ACCESS_TOKEN, or explicitly use --backend mineru
MinerU lightweight API limit exceeded Configure MINERU_API_TOKEN and retry, or install RapidOCR to use local recognition
Sensitive materials are not allowed to be transmitted externally uv run --with rapidocr --with onnxruntime scripts/convert.py <文件> --backend rapid
--backend rapid shows as not installed Use uv run --with rapidocr --with onnxruntime ..., or pip install rapidocr and then use python3 to run directly
One API quota is exhausted Configure the other API set at the same time and keep --backend auto; during conversion, candidate backends will be tried automatically
Web page URL failed Web page URLs require a MinerU Token; lightweight mode is not supported
DOCX/PPTX via PaddleOCR failed Office documents can only go through MinerU; use --backend auto or --backend mineru
PaddleOCR returned insufficient pages Lower PADDLEOCR_BATCH_PAGES or use --pages to rerun with a smaller range; the current cloud API has been measured to reliably return a maximum of about 100 pages per call
Conversion quality needs review Check the result_raw.md、result.json and backend_result/

Maintenance

After modifying this skill, synchronously update the TASKS.md、DECISIONS.md and CHANGELOG.md。