{"id":51522652,"url":"https://github.com/baidu/unlimited-ocr","last_synced_at":"2026-07-08T17:30:27.271Z","repository":{"id":366740002,"uuid":"1273138090","full_name":"baidu/Unlimited-OCR","owner":"baidu","description":"Unlimited OCR Works: Welcome the Era of One-shot Long-horizon Parsing.","archived":false,"fork":false,"pushed_at":"2026-06-28T06:53:59.000Z","size":91749,"stargazers_count":12292,"open_issues_count":44,"forks_count":967,"subscribers_count":54,"default_branch":"main","last_synced_at":"2026-06-30T11:04:12.064Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/baidu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-18T08:40:15.000Z","updated_at":"2026-06-30T10:58:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/baidu/Unlimited-OCR","commit_stats":null,"previous_names":["baidu/unlimited-ocr"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/baidu/Unlimited-OCR","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2FUnlimited-OCR","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2FUnlimited-OCR/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2FUnlimited-OCR/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2FUnlimited-OCR/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/baidu","download_url":"https://codeload.github.com/baidu/Unlimited-OCR/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baidu%2FUnlimited-OCR/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35178364,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-08T17:30:26.774Z","updated_at":"2026-07-08T17:30:27.254Z","avatar_url":"https://github.com/baidu.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/baidu.png\" width=\"40%\" alt=\"Baidu Inc.\" /\u003e\n\u003c/p\u003e\n\n\u003chr\u003e\n\n\u003ch1 align=\"center\"\u003eUnlimited OCR Works\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/baidu/Unlimited-OCR\"\u003e\n    \u003cimg alt=\"GitHub\" src=\"https://img.shields.io/badge/GitHub-Code-181717?logo=github\u0026logoColor=white\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://huggingface.co/baidu/Unlimited-OCR\"\u003e\n    \u003cimg alt=\"Hugging Face\" src=\"https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Model-ffc107?color=ffc107\u0026logoColor=white\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://arxiv.org/abs/2606.23050\"\u003e\n    \u003cimg alt=\"arXiv\" src=\"https://img.shields.io/badge/arXiv-Unlimited OCR Works-b31b1b?logo=arxiv\u0026logoColor=white\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://x.com/Baidu_Inc\" target=\"_blank\"\u003e\n    \u003cimg alt=\"Twitter Follow\" src=\"https://img.shields.io/badge/Twitter-Baidu Inc.-white?logo=x\u0026logoColor=white\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003ch3 align=\"center\"\u003eWelcome the Era of One-shot Long-horizon Parsing.\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"assets/Unlimited-OCR.png\" width=\"1000\" alt=\"Unlimited OCR overview\" /\u003e\n\u003c/p\u003e\n\n\n## Release\n- [2026/06/24] 🤝 Thanks to [AK](https://x.com/_akhaliq) for creating a demo for us. It is now available at [Hugging Face Spaces](https://huggingface.co/spaces/baidu/Unlimited-OCR).\n- [2026/06/23] 📄 Our paper is now available on [arXiv](https://arxiv.org/abs/2606.23050).\n- [2026/06/23] 🤝 Thanks to the ModelScope community for their support. Our model is now available at [ModelScope](https://modelscope.cn/models/PaddlePaddle/Unlimited-OCR).\n- [2026/06/22] 🚀 We present [Unlimited-OCR](https://github.com/baidu/Unlimited-OCR), aiming to push [Deepseek-OCR](https://github.com/deepseek-ai/DeepSeek-OCR) one step further.\n\n## Inference\n\n### Transformers\nInference using Huggingface transformers on NVIDIA GPUs. Requirements tested on python 3.12.3 + CUDA12.9：\n\n```\ntorch==2.10.0\ntorchvision==0.25.0\ntransformers==4.57.1\nPillow==12.1.1\nmatplotlib==3.10.8\neinops==0.8.2\naddict==2.4.0\neasydict==1.13\npymupdf==1.27.2.2\npsutil==7.2.2\n```\n\n```python\nimport os\nimport torch\nfrom transformers import AutoModel, AutoTokenizer\n\nmodel_name = 'baidu/Unlimited-OCR'\n\ntokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)\nmodel = AutoModel.from_pretrained(\n    model_name,\n    trust_remote_code=True,\n    use_safetensors=True,\n    torch_dtype=torch.bfloat16,\n)\nmodel = model.eval().cuda()\n\n# ── Single image supports two configs: gundam or base ──\n# gundam: base_size=1024, image_size=640, crop_mode=True\n# base: base_size=1024, image_size=1024, crop_mode=False\nmodel.infer(\n    tokenizer,\n    prompt='\u003cimage\u003edocument parsing.',\n    image_file='your_image.jpg',\n    output_path='your/output/dir',\n    base_size=1024, image_size=640, crop_mode=True,\n    max_length=32768,\n    no_repeat_ngram_size=35, ngram_window=128,\n    save_results=True,\n)\n\n# ── Multi page / PDF only uses base (image_size=1024) ──\nmodel.infer_multi(\n    tokenizer,\n    prompt='\u003cimage\u003eMulti page parsing.',\n    image_files=['page1.png', 'page2.png', 'page3.png'],\n    output_path='your/output/dir',\n    image_size=1024,\n    max_length=32768,\n    no_repeat_ngram_size=35, ngram_window=1024,\n    save_results=True,\n)\n\n# ── PDF (convert pages to images, then multi-page parsing) ──\nimport tempfile, fitz  # PyMuPDF\n\ndef pdf_to_images(pdf_path, dpi=300):\n    doc = fitz.open(pdf_path)\n    tmp_dir = tempfile.mkdtemp(prefix='pdf_ocr_')\n    mat = fitz.Matrix(dpi / 72, dpi / 72)\n    paths = []\n    for i, page in enumerate(doc):\n        out = os.path.join(tmp_dir, f'page_{i+1:04d}.png')\n        page.get_pixmap(matrix=mat).save(out)\n        paths.append(out)\n    doc.close()\n    return paths\n\nmodel.infer_multi(\n    tokenizer,\n    prompt='\u003cimage\u003eMulti page parsing.',\n    image_files=pdf_to_images('your_doc.pdf', dpi=300),\n    output_path='your/output/dir',\n    image_size=1024,\n    max_length=32768,\n    no_repeat_ngram_size=35, ngram_window=1024,\n    save_results=True,\n)\n```\n\n### SGLang\n\nSet up the environment (uv-managed virtualenv). Install the local SGLang wheel first,\nthen pin `kernels==0.9.0` and install PyMuPDF for PDF-to-image conversion:\n```shell\nuv venv --python 3.12\nsource .venv/bin/activate\n\nuv pip install wheel/sglang-0.0.0.dev11416+g92e8bb79e-py3-none-any.whl\nuv pip install kernels==0.11.7\nuv pip install pymupdf==1.27.2.2\n```\n\nStart the SGLang server:\n```shell\npython -m sglang.launch_server \\\n    --model baidu/Unlimited-OCR \\\n    --served-model-name Unlimited-OCR \\\n    --attention-backend fa3 \\\n    --page-size 1 \\\n    --mem-fraction-static 0.8 \\\n    --context-length 32768 \\\n    --enable-custom-logit-processor \\\n    --disable-overlap-schedule \\\n    --skip-server-warmup \\\n    --host 0.0.0.0 \\\n    --port 10000\n```\n\nSend streaming requests to the OpenAI-compatible API:\n```python\nimport base64\nimport json\nimport os\nimport tempfile\n\nimport fitz\nimport requests\nfrom sglang.srt.sampling.custom_logit_processor import DeepseekOCRNoRepeatNGramLogitProcessor\n\nserver_url = \"http://127.0.0.1:10000\"\n\nsession = requests.Session()\nsession.trust_env = False\n\n\ndef pdf_to_images(pdf_path, dpi=300):\n    doc = fitz.open(pdf_path)\n    tmp_dir = tempfile.mkdtemp(prefix=\"pdf_ocr_\")\n    mat = fitz.Matrix(dpi / 72, dpi / 72)\n    image_paths = []\n    for i, page in enumerate(doc):\n        image_path = os.path.join(tmp_dir, f\"page_{i + 1:04d}.png\")\n        page.get_pixmap(matrix=mat).save(image_path)\n        image_paths.append(image_path)\n    doc.close()\n    return image_paths\n\n\ndef encode_image(image_path):\n    ext = os.path.splitext(image_path)[1].lower()\n    mime = \"image/jpeg\" if ext in (\".jpg\", \".jpeg\") else f\"image/{ext.lstrip('.')}\"\n    with open(image_path, \"rb\") as f:\n        data = base64.b64encode(f.read()).decode(\"utf-8\")\n    return {\"type\": \"image_url\", \"image_url\": {\"url\": f\"data:{mime};base64,{data}\"}}\n\n\ndef build_content(prompt, image_paths):\n    return [{\"type\": \"text\", \"text\": prompt}] + [encode_image(path) for path in image_paths]\n\n\ndef generate(prompt, image_paths, image_mode, ngram_window):\n    payload = {\n        \"model\": \"Unlimited-OCR\",\n        \"messages\": [{\"role\": \"user\", \"content\": build_content(prompt, image_paths)}],\n        \"temperature\": 0,\n        \"skip_special_tokens\": False,\n        \"images_config\": {\"image_mode\": image_mode},\n        \"custom_logit_processor\": DeepseekOCRNoRepeatNGramLogitProcessor.to_str(),\n        \"custom_params\": {\n            \"ngram_size\": 35,\n            \"window_size\": ngram_window,\n        },\n        \"stream\": True,\n    }\n    response = session.post(\n        f\"{server_url}/v1/chat/completions\",\n        headers={\"Content-Type\": \"application/json\"},\n        data=json.dumps(payload),\n        timeout=1200,\n        stream=True,\n    )\n    response.raise_for_status()\n\n    chunks = []\n    for line in response.iter_lines(chunk_size=1, decode_unicode=True):\n        if not line or not line.startswith(\"data: \"):\n            continue\n        data = line[len(\"data: \"):]\n        if data == \"[DONE]\":\n            break\n        event = json.loads(data)\n        delta = event[\"choices\"][0].get(\"delta\", {}).get(\"content\", \"\")\n        if delta:\n            print(delta, end=\"\", flush=True)\n            chunks.append(delta)\n    print()\n    return \"\".join(chunks)\n\n\n# Single image supports two configs: gundam or base. Example below uses gundam.\ngenerate(\"document parsing.\", [\"your_image.jpg\"], image_mode=\"gundam\", ngram_window=128)\n\n# Multi image (base only)\ngenerate(\"Multi page parsing.\", [\"page1.png\", \"page2.png\"], image_mode=\"base\", ngram_window=1024)\n\n# PDF (base only)\ngenerate(\"Multi page parsing.\", pdf_to_images(\"your_doc.pdf\", dpi=300), image_mode=\"base\", ngram_window=1024)\n```\n\nFor batch inference, `infer.py` starts the SGLang server automatically and sends concurrent requests for an image directory or PDF:\n```shell\n# Image directory\npython infer.py \\\n    --image_dir ./examples/images \\\n    --output_dir ./outputs \\\n    --concurrency 8 \\\n    --image_mode gundam\n\n# PDF pages\npython infer.py \\\n    --pdf ./examples/document.pdf \\\n    --output_dir ./outputs \\\n    --concurrency 8 \\\n    --image_mode gundam\n```\n\nUseful options:\n```shell\n--model_dir baidu/Unlimited-OCR   # Local path or Hugging Face model ID\n--gpu 0                           # CUDA_VISIBLE_DEVICES value\n--server_log ./log/sglang_server.log\n```\n\n\n## Visualization\n\n\u003cimg src=\"assets/long-horizon-ocr.gif\" width=\"100%\" alt=\"Long-horizon OCR demo\" /\u003e\n\n## Acknowledgement\n\nWe would like to thank [Deepseek-OCR](https://github.com/deepseek-ai/DeepSeek-OCR), [Deepseek-OCR-2](https://github.com/deepseek-ai/DeepSeek-OCR-2), [PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR) for their valuable models and ideas.\n\n## Citation\n```bibtex\n@misc{yin2026unlimitedocrworks,\n      title={Unlimited OCR Works}, \n      author={Youyang Yin and Huanhuan Liu and YY and Qunyi Xie and Chaorun Liu and Shiqi Yang and Shaohua Wang and Zhanlong Liu and Hao Zou and Jinyue Chen and Shu Wei and Jingjing Wu and Mingxin Huang and Zhen Wu and Guibin Wang and Tengyu Du and Lei Jia},\n      year={2026},\n      eprint={2606.23050},\n      archivePrefix={arXiv},\n      primaryClass={cs.CV},\n      url={https://arxiv.org/abs/2606.23050}, \n}\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaidu%2Funlimited-ocr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaidu%2Funlimited-ocr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaidu%2Funlimited-ocr/lists"}