aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuri Victorovich <yuri@FreeBSD.org>2026-04-08 01:37:34 +0000
committerYuri Victorovich <yuri@FreeBSD.org>2026-04-08 02:45:26 +0000
commitc61790d933741f0db49e7715d3a4fe64e689b945 (patch)
treef8755067e5c82294fb6a7be70cb133c8516c1220
parent8121ef893ee99cc2578c0ecbd8904aad996cc7ab (diff)
graphics/py-olmocr: New port: PDF and image OCR toolkit using visual language models
-rw-r--r--graphics/Makefile1
-rw-r--r--graphics/py-olmocr/Makefile47
-rw-r--r--graphics/py-olmocr/distinfo3
-rw-r--r--graphics/py-olmocr/files/patch-olmocr_pipeline.py54
-rw-r--r--graphics/py-olmocr/files/patch-pyproject.toml13
-rw-r--r--graphics/py-olmocr/pkg-descr10
6 files changed, 128 insertions, 0 deletions
diff --git a/graphics/Makefile b/graphics/Makefile
index 50a6c9fb5271..341697adaae9 100644
--- a/graphics/Makefile
+++ b/graphics/Makefile
@@ -983,6 +983,7 @@
SUBDIR += py-napari-console
SUBDIR += py-napari-plugin-engine
SUBDIR += py-nwdiag
+ SUBDIR += py-olmocr
SUBDIR += py-opencolorio
SUBDIR += py-opencv-python-headless
SUBDIR += py-openimageio
diff --git a/graphics/py-olmocr/Makefile b/graphics/py-olmocr/Makefile
new file mode 100644
index 000000000000..2150805c4329
--- /dev/null
+++ b/graphics/py-olmocr/Makefile
@@ -0,0 +1,47 @@
+PORTNAME= olmocr
+DISTVERSION= 0.4.27
+CATEGORIES= graphics python
+MASTER_SITES= PYPI
+PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
+
+MAINTAINER= yuri@FreeBSD.org
+COMMENT= PDF and image OCR toolkit using visual language models
+WWW= https://olmocr.allenai.org/ \
+ https://github.com/allenai/olmocr
+
+LICENSE= APACHE20
+LICENSE_FILE= ${WRKSRC}/LICENSE
+
+BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}setuptools>0:devel/py-setuptools@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}wheel>0:devel/py-wheel@${PY_FLAVOR}
+RUN_DEPENDS= pdftoppm:graphics/poppler-utils \
+ ${PYTHON_PKGNAMEPREFIX}bleach>0:www/py-bleach@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}boto3>0:www/py-boto3@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}cached-path>0:devel/py-cached-path@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}cryptography>0:security/py-cryptography@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}filelock>0:sysutils/py-filelock@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}ftfy>0:textproc/py-ftfy@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}httpx>0:www/py-httpx@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}lingua-language-detector>0:textproc/py-lingua-language-detector@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}markdown2>0:textproc/py-markdown2@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}markdownify>0:textproc/py-markdownify@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}orjson>0:devel/py-orjson@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}pillow>0:graphics/py-pillow@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}pypdf>=5.2.0:print/py-pypdf@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}pypdfium2>0:graphics/py-pypdfium2@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}requests>0:www/py-requests@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}smart-open>0:net/py-smart-open@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}zstandard>0:archivers/py-zstandard@${PY_FLAVOR}
+RUN_DEPENDS_gpu= \
+ ${PYTHON_PKGNAMEPREFIX}pytorch>0:misc/py-pytorch@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}transformers>=4.57.3:misc/py-transformers@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}vllm>=0.11.2:misc/py-vllm@${PY_FLAVOR}
+RUN_DEPENDS+= ${RUN_DEPENDS_gpu}
+TEST_DEPENDS= ${PYTHON_PKGNAMEPREFIX}pytest>0:devel/py-pytest@${PY_FLAVOR}
+
+USES= python
+USE_PYTHON= pep517 concurrent autoplist
+
+NO_ARCH= yes
+
+.include <bsd.port.mk>
diff --git a/graphics/py-olmocr/distinfo b/graphics/py-olmocr/distinfo
new file mode 100644
index 000000000000..504681120d06
--- /dev/null
+++ b/graphics/py-olmocr/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1775589887
+SHA256 (olmocr-0.4.27.tar.gz) = 7da74f37a3e987f966765503c59913c2268289c9ecb14b4c5f40c89a0e8e5393
+SIZE (olmocr-0.4.27.tar.gz) = 410438
diff --git a/graphics/py-olmocr/files/patch-olmocr_pipeline.py b/graphics/py-olmocr/files/patch-olmocr_pipeline.py
new file mode 100644
index 000000000000..ea3871e620f9
--- /dev/null
+++ b/graphics/py-olmocr/files/patch-olmocr_pipeline.py
@@ -0,0 +1,54 @@
+--- olmocr/pipeline.py.orig 2026-03-12 16:30:29 UTC
++++ olmocr/pipeline.py
+@@ -811,7 +811,7 @@ async def vllm_server_task(model_name_or_path, args, u
+ model_name_or_path,
+ "--port",
+ str(args.port),
+- "--disable-log-requests",
++ "--no-enable-log-requests",
+ "--uvicorn-log-level",
+ "warning",
+ "--served-model-name",
+@@ -833,12 +833,15 @@ async def vllm_server_task(model_name_or_path, args, u
+ if unknown_args:
+ cmd.extend(unknown_args)
+
++ if getattr(args, "device", "cpu") == "cpu":
++ cmd.append("--enforce-eager")
++
+ proc = await asyncio.create_subprocess_exec(
+ *cmd,
+ stdout=asyncio.subprocess.PIPE,
+ stderr=asyncio.subprocess.PIPE,
+ # OMP_NUM_THREADS needs to be 1, otherwise you could have contention if you are running multiple copies of olmOCR on a machine with several GPUS
+- env={**os.environ, "OMP_NUM_THREADS": "1"},
++ env={**os.environ, "OMP_NUM_THREADS": str(os.cpu_count()) if getattr(args, "device", "cpu") == "cpu" else "1"},
+ )
+
+ # Ensure the subprocess is terminated on exit
+@@ -1211,7 +1214,7 @@ async def main():
+ parser.add_argument(
+ "--model",
+ help="Path where the model is located, allenai/olmOCR-2-7B-1025-FP8 is the default, can be local, s3, or hugging face.",
+- default="allenai/olmOCR-2-7B-1025-FP8",
++ default="allenai/olmOCR-2-7B-1025",
+ )
+
+ # More detailed config options, usually you shouldn't have to change these
+@@ -1256,6 +1259,7 @@ async def main():
+ vllm_group.add_argument("--tensor-parallel-size", "-tp", type=int, default=1, help="Tensor parallel size for vLLM")
+ vllm_group.add_argument("--data-parallel-size", "-dp", type=int, default=1, help="Data parallel size for vLLM")
+ vllm_group.add_argument("--port", type=int, default=30024, help="Port to use for the VLLM server")
++ vllm_group.add_argument("--device", type=str, default="cpu", help="Device to use for inference (cpu, cuda, etc.)")
+
+ # Beaker/job running stuff
+ beaker_group = parser.add_argument_group("beaker/cluster execution")
+@@ -1421,7 +1425,7 @@ async def main():
+
+ # If you get this far, then you are doing inference and need a GPU
+ # check_sglang_version()
+- if use_internal_server:
++ if use_internal_server and args.device != "cpu":
+ check_torch_gpu_available()
+
+ logger.info(f"Starting pipeline with PID {os.getpid()}")
diff --git a/graphics/py-olmocr/files/patch-pyproject.toml b/graphics/py-olmocr/files/patch-pyproject.toml
new file mode 100644
index 000000000000..797bc8cd210d
--- /dev/null
+++ b/graphics/py-olmocr/files/patch-pyproject.toml
@@ -0,0 +1,13 @@
+--- pyproject.toml.orig 2026-04-07 19:24:23 UTC
++++ pyproject.toml
+@@ -52,8 +52,8 @@ gpu = [
+ [project.optional-dependencies]
+ gpu = [
+ "torch>=2.7.0",
+- "transformers==4.57.3",
+- "vllm==0.11.2"
++ "transformers>=4.57.3",
++ "vllm>=0.11.2"
+ ]
+
+ beaker = [
diff --git a/graphics/py-olmocr/pkg-descr b/graphics/py-olmocr/pkg-descr
new file mode 100644
index 000000000000..4e4bda2276ad
--- /dev/null
+++ b/graphics/py-olmocr/pkg-descr
@@ -0,0 +1,10 @@
+olmocr is a toolkit for converting PDFs and other image-based document formats
+into clean, readable, plain text format.
+
+Features:
+* Convert PDF, PNG, and JPEG based documents into clean Markdown
+* Support for equations, tables, handwriting, and complex formatting
+* Automatically removes headers and footers
+* Convert into text with a natural reading order, even in the presence of
+ figures, multi-column layouts, and insets
+* Efficient, less than $200 USD per million pages converted