Repository navigation
Conversation
Adds PP-OCR (Baidu PaddleOCR) as a second OCR lane alongside the existing chandra provider, selectable at deploy time with OCR_PROVIDER=paddleocr. Why - chandra is the high-accuracy lane but needs a remote vLLM server on a GPU host. PaddleOCR is the opposite trade: PP-OCRv6 is a 34.5M-parameter detection+recognition pair that runs on CPU in-process, reads 50 languages from one checkpoint, and needs no external inference server. What - pipeline/ocr/paddleocr_local.py: new provider, one class per model per the repo provider-plugin convention. - Model choice is a deploy-time setting, not a code change: PADDLEOCR_MODEL selects a PP-OCRv6 tier (medium | small | tiny) or an explicit "<det>,<rec>" pair; PADDLEOCR_DET_MODEL/PADDLEOCR_REC_MODEL override it; PADDLEOCR_OCR_VERSION/LANG/DEVICE/MIN_SCORE/IMAGE_DPI cover the rest. - Weights are NOT baked into the image. PaddleX downloads the selected checkpoint on first use into PADDLE_PDX_CACHE_HOME, which docker-compose points at the mounted HF_HOME volume so it survives a rebuild. - Dockerfile: install libgomp1 (paddle core links against it and refuses to import without it) and libgl1/libglib2.0-0 (opencv-contrib loads them at import time). - pyproject.toml: paddleocr/paddlepaddle gated to linux/amd64 by marker. paddlepaddle publishes no aarch64 wheels, so the arm64 image cannot carry this lane; the marker keeps uv sync resolving on both architectures. Verified - uv sync --frozen (the CI command) resolves; 726 tests pass; ruff clean. - Built the image and ran a real PDF through it from an empty cache: the checkpoint downloaded on demand (133M) and the text came back correctly. - All three PP-OCRv6 tiers (medium/small/tiny) resolve to their own checkpoints and OCR correctly. Known workaround - PaddlePaddle 3.3 crashes on CPU in the PIR -> oneDNN conversion (ConvertPirAttribute2RuntimeAttribute not support). The FLAGS_* env vars do not fix it because PaddleX picks run_mode=mkldnn independently, so the pipeline is constructed with enable_mkldnn=False. Exposed as PADDLEOCR_ENABLE_MKLDNN, default false.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds Baidu PaddleOCR (PP-OCR) as a selectable OCR provider alongside the existing
chandraoption. The user picks the model at deploy time viaOCR_PROVIDER, and the weights are downloaded on the fly.Why two lanes
chandra(existing)paddleocr(new)PADDLE_PDX_CACHE_HOMEchandrastays the high-accuracy lane. PaddleOCR is the lane that works on a self-hosted box with no GPU and no external inference server.Selecting the model
OCR_PROVIDER=paddleocr(aliasespaddle,baidu), then:PADDLEOCR_MODELmediummedium/small/tiny), or an explicit<det>,<rec>pairPADDLEOCR_DET_MODEL/PADDLEOCR_REC_MODEL''PADDLEOCR_MODELPADDLEOCR_OCR_VERSIONPP-OCRv6PP-OCRv6/PP-OCRv5/PP-OCRv4PADDLEOCR_LANG''en,ch,dev, ...)PADDLEOCR_DEVICEcpucpuorgpu/gpu:0PADDLEOCR_MIN_SCORE0PADDLEOCR_IMAGE_DPI192The three PP-OCRv6 tiers are all verified working — each resolves to its own checkpoint and OCRs correctly.
On-the-fly model download
The weights are not baked into the image. PaddleX downloads the selected checkpoint on first use into
PADDLE_PDX_CACHE_HOME, whichdocker-compose.ymlpoints at the mountedHF_HOMEvolume — so the download happens once and survives a container rebuild.Verified from a completely empty cache: checkpoint downloaded on demand (133M) and the text came back correctly.
Packaging notes
Dockerfile— installslibgomp1(paddle core links against it and refuses to import without it: "Can not import paddle core") andlibgl1/libglib2.0-0(opencv-contrib loads them at import time).pyproject.toml—paddleocr/paddlepaddleare gated tolinux/amd64by marker.paddlepaddlepublishes no aarch64 wheels, so the arm64 image cannot carry this lane; the marker keepsuv syncresolving on both architectures. The arm64 image keeps working withchandra/mistralunchanged.Known workaround
PaddlePaddle 3.3 crashes on CPU in the PIR -> oneDNN conversion:
The
FLAGS_*env vars do not fix it (PaddleX picksrun_mode=mkldnnindependently), so the pipeline is constructed withenable_mkldnn=False. Exposed asPADDLEOCR_ENABLE_MKLDNN, defaultfalse.Verification
uv sync --frozen(the exact CI command) resolves —uv.lockregenerated.726 passed— full suite, including 14 new unit tests.ruff check .— clean.medium/small/tiny) verified.Files
pipeline/ocr/paddleocr_local.py— new provider (one class per model, per the provider-plugin convention inCONVENTIONS.md)pipeline/ocr/base.py— theOcrConfigcontract gains the PaddleOCR knobspipeline/ocr/service.py— provider registered + env-var mappingpipeline/ocr/__init__.py— exportDockerfile,docker-compose.yml,pyproject.toml,uv.lock— packaging.env.example,ENV.md— operator-facing docstests/test_ocr_paddleocr.py— 14 new unit testsNote: I have read access to this repo but not push access, so this is from a fork. Happy to rebase onto
mainif the branch has drifted.