Instructions to use datalab-to/surya-parsebench-rl with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use datalab-to/surya-parsebench-rl with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="datalab-to/surya-parsebench-rl") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("datalab-to/surya-parsebench-rl") model = AutoModelForMultimodalLM.from_pretrained("datalab-to/surya-parsebench-rl", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use datalab-to/surya-parsebench-rl with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "datalab-to/surya-parsebench-rl" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "datalab-to/surya-parsebench-rl", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/datalab-to/surya-parsebench-rl
- SGLang
How to use datalab-to/surya-parsebench-rl with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "datalab-to/surya-parsebench-rl" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "datalab-to/surya-parsebench-rl", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "datalab-to/surya-parsebench-rl" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "datalab-to/surya-parsebench-rl", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use datalab-to/surya-parsebench-rl with Docker Model Runner:
docker model run hf.co/datalab-to/surya-parsebench-rl
Download code/pbext/__init__.py from datalab-to/surya-parsebench-rl: direct link, hf CLI and curl.
- Browser
- Download file 8.6 kB
-
https://huggingface.co/datalab-to/surya-parsebench-rl/resolve/main/code/pbext/__init__.py
- Command line
-
hf download hf://datalab-to/surya-parsebench-rl/code/pbext/__init__.py
-
curl -L -o __init__.py https://huggingface.co/datalab-to/surya-parsebench-rl/resolve/main/code/pbext/__init__.py
8.6 kB
| """ParseBench provider for a Surya checkpoint served by vLLM (OpenAI API). | |
| Import this package before the parse-bench CLI (e.g. via sitecustomize) to | |
| register the provider and the `surya_vllm` pipeline. Configuration comes from | |
| the environment so one pipeline serves any checkpoint: | |
| SURYA_VLLM_URL e.g. http://127.0.0.1:8000/v1 | |
| SURYA_VLLM_MODEL the served model name | |
| SURYA_PROMPT optional prompt override (default: the short OCR prompt) | |
| SURYA_FURNITURE "1" to keep page headers/footers in markdown (default 1) | |
| SURYA_FIGTEXT "1" to keep text transcribed inside figure blocks (default 0) | |
| """ | |
| from __future__ import annotations | |
| import base64 | |
| import io | |
| import os | |
| import sys | |
| import time | |
| from datetime import datetime | |
| from pathlib import Path | |
| from typing import Any | |
| import requests | |
| sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) | |
| import surya_convert as sc # noqa: E402 | |
| from parse_bench.extensions import register_pipeline, register_provider # noqa: E402 | |
| from parse_bench.inference.providers.base import ( # noqa: E402 | |
| Provider, | |
| ProviderPermanentError, | |
| ProviderTransientError, | |
| ) | |
| from parse_bench.schemas.parse_output import ( # noqa: E402 | |
| LayoutItemIR, | |
| LayoutSegmentIR, | |
| ParseLayoutPageIR, | |
| ParseOutput, | |
| ) | |
| from parse_bench.schemas.pipeline import PipelineSpec # noqa: E402 | |
| from parse_bench.schemas.pipeline_io import ( # noqa: E402 | |
| InferenceRequest, | |
| InferenceResult, | |
| RawInferenceResult, | |
| ) | |
| from parse_bench.schemas.product import ProductType # noqa: E402 | |
| SHORT_PROMPT = ( | |
| "OCR this image to HTML. Each block is a div with data-label and data-bbox " | |
| "(x0 y0 x1 y1, normalized 0-1000)." | |
| ) | |
| def _page_pngs(path: Path, dpi: int) -> list[bytes]: | |
| if path.suffix.lower() in (".png", ".jpg", ".jpeg", ".jfif"): | |
| return [path.read_bytes()] | |
| import pymupdf | |
| doc = pymupdf.open(str(path)) | |
| out = [] | |
| for pg in doc: | |
| out.append(pg.get_pixmap(dpi=dpi).tobytes("png")) | |
| doc.close() | |
| return out | |
| def build_output(raw_output: dict, example_id: str, pipeline_name: str) -> ParseOutput: | |
| """ParseOutput (markdown + normalised layout pages) from the raw page HTML.""" | |
| pages = raw_output.get("pages_html") or [] | |
| cfg = raw_output.get("_config", {}) | |
| furniture = cfg.get("furniture", True) | |
| sc.figure_text = bool(cfg.get("figtext", sc.figure_text)) | |
| md = "\n\n".join(sc.to_markdown(h, keep_furniture=furniture) for h in pages) | |
| layout_pages = [] | |
| for i, h in enumerate(pages, 1): | |
| items = [] | |
| for it in sc.to_layout_items(h): | |
| seg = LayoutSegmentIR(x=it["x"], y=it["y"], w=it["w"], h=it["h"], | |
| confidence=1.0, label=it["label"]) | |
| items.append(LayoutItemIR(type=it["type"], value=it["text"], bbox=seg, | |
| layout_segments=[seg])) | |
| # ParseBench's is_header / is_footer rules read these per-page fields | |
| # (LlamaParse's furniture contract); without them every such rule fails. | |
| head, foot = sc.furniture_md(h) | |
| if items or head or foot: | |
| layout_pages.append(ParseLayoutPageIR(page_number=i, width=1000.0, height=1000.0, | |
| items=items, page_header_markdown=head, | |
| page_footer_markdown=foot)) | |
| return ParseOutput(task_type="parse", example_id=example_id, pipeline_name=pipeline_name, | |
| pages=[], layout_pages=layout_pages, markdown=md) | |
| class SuryaVllmProvider(Provider): | |
| def __init__(self, provider_name: str, base_config: dict[str, Any] | None = None): | |
| super().__init__(provider_name, base_config) | |
| self._url = os.environ.get("SURYA_VLLM_URL", "http://127.0.0.1:8000/v1").rstrip("/") | |
| self._model = os.environ.get("SURYA_VLLM_MODEL", "surya") | |
| p = os.environ.get("SURYA_PROMPT") or "short" | |
| self._prompt = {"short": SHORT_PROMPT}.get(p, p) | |
| self._furniture = os.environ.get("SURYA_FURNITURE", "1") == "1" | |
| self._figtext = os.environ.get("SURYA_FIGTEXT", "0") == "1" | |
| self._dpi = int(self.base_config.get("dpi", 192)) | |
| self._max_tokens = int(os.environ.get("SURYA_MAX_TOKENS") or self.base_config.get("max_tokens", 12288)) | |
| def _ocr(self, png: bytes) -> str: | |
| """Greedy OCR. If the page does not close (a loop that hit the token cap), retry with each | |
| repetition penalty in SURYA_RETRY_REP_PEN (comma list, default "1.1,1.25"; "" = no retry) | |
| and keep the first output that closes.""" | |
| out = self._ocr_once(png, 1.0) | |
| for rep in [float(x) for x in os.environ.get("SURYA_RETRY_REP_PEN", "1.1,1.25").split(",") if x]: | |
| if out.rstrip().endswith("</div>"): | |
| break | |
| retry = self._ocr_once(png, rep) | |
| if retry.rstrip().endswith("</div>"): | |
| return retry | |
| return out | |
| def _ocr_once(self, png: bytes, repetition_penalty: float) -> str: | |
| b64 = base64.b64encode(png).decode() | |
| body = { | |
| "model": self._model, | |
| "temperature": 0.0, | |
| "repetition_penalty": repetition_penalty, | |
| "max_tokens": self._max_tokens, | |
| "messages": [{"role": "user", "content": [ | |
| {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}}, | |
| {"type": "text", "text": self._prompt}, | |
| ]}], | |
| } | |
| for attempt in range(4): | |
| try: | |
| r = requests.post(f"{self._url}/chat/completions", json=body, timeout=900) | |
| if r.status_code in (408, 429, 500, 502, 503, 504): | |
| time.sleep(2 * (attempt + 1)) | |
| continue | |
| if r.status_code != 200: | |
| raise ProviderPermanentError(f"HTTP {r.status_code}: {r.text[:200]}") | |
| return r.json()["choices"][0]["message"]["content"] or "" | |
| except requests.RequestException as e: | |
| if attempt == 3: | |
| raise ProviderTransientError(str(e)) from e | |
| time.sleep(2 * (attempt + 1)) | |
| raise ProviderTransientError("vLLM unavailable") | |
| def run_inference(self, pipeline: PipelineSpec, request: InferenceRequest) -> RawInferenceResult: | |
| started = datetime.now() | |
| path = Path(request.source_file_path) | |
| if not path.exists(): | |
| raise ProviderPermanentError(f"missing {path}") | |
| pages = [self._ocr(p) for p in _page_pngs(path, self._dpi)] | |
| done = datetime.now() | |
| return RawInferenceResult( | |
| request=request, pipeline=pipeline, pipeline_name=pipeline.pipeline_name, | |
| product_type=request.product_type, | |
| raw_output={"pages_html": pages, "_config": {"model": self._model, "dpi": self._dpi, | |
| "furniture": self._furniture, | |
| "figtext": self._figtext, | |
| "prompt": self._prompt}}, | |
| started_at=started, completed_at=done, | |
| latency_in_ms=int((done - started).total_seconds() * 1000), | |
| ) | |
| def normalize(self, raw_result: RawInferenceResult) -> InferenceResult: | |
| out = build_output(raw_result.raw_output, raw_result.request.example_id, | |
| raw_result.pipeline_name) | |
| return InferenceResult( | |
| request=raw_result.request, pipeline_name=raw_result.pipeline_name, | |
| product_type=raw_result.product_type, raw_output=raw_result.raw_output, | |
| output=out, started_at=raw_result.started_at, | |
| completed_at=raw_result.completed_at, latency_in_ms=raw_result.latency_in_ms, | |
| ) | |
| register_pipeline(PipelineSpec(pipeline_name="surya_vllm", provider_name="surya_vllm", | |
| product_type=ProductType.PARSE, config={"dpi": 192})) | |
| # Without an adapter keyed to this provider, LlamaParse's priority-100 adapter | |
| # (whose matches() accepts any ParseOutput) captures the result and hard-fails | |
| # on our label vocabulary. Reuse the Datalab adapter: it reads normalised | |
| # layout_pages, which is what normalize() emits. | |
| from parse_bench.evaluation.layout_adapters.adapters import DatalabLayoutAdapter # noqa: E402 | |
| from parse_bench.evaluation.layout_adapters.registry import register_layout_adapter # noqa: E402 | |
| register_layout_adapter("surya_vllm", priority=95)( | |
| type("SuryaVllmLayoutAdapter", (DatalabLayoutAdapter,), {}) | |
| ) | |