daviden1013
vlm4ocr
Python

Python package and Web App for OCR with vision language models.

Last updated Jul 14, 2026
10
Stars
1
Forks
0
Issues
0
Stars/day
Attention Score
23
Language breakdown
Python 54.9%
JavaScript 24.0%
CSS 11.1%
HTML 9.7%
Dockerfile 0.4%
Files click to expand
README

Python Version PyPI Website

Vision Language Models (VLMs) for Optical Character Recognition (OCR).

| Feature | Support | | :---------------------- | :---------------------------------------------------------------------- | | File Types | :whitecheckmark: PDF, TIFF, PNG, JPG/JPEG, BMP, GIF, WEBP | | VLM Engines | :whitecheckmark: Ollama, OpenAI Compatible (vLLM, SGLang, OpenRouter), OpenAI, Azure OpenAI | | Output Modes | :whitecheckmark: Markdown, HTML, plain text, JSON, BBox | | Batch OCR | :whitecheckmark: Processes many files concurrently with Python, CLI, and web app | | Pipelines | :whitecheckmark: Per-page routing for heterogeneous documents (IndependentPagePipeline) |

🆕Recent Updates

- 📐User Guide is now available at Documentation Page - Image processing features: added rotatecorrection and maxdimension_pixels to handle misaligned scan and large images. - Optimized file staging: added maxfileload parameter to concurrent_ocr method. - Key information extraction with JSON: instead of OCR the entire document, extract only the key information and output as JSON. - Batch processing to web app: The web app now supports concurrent batch processing of multiple images using OCREngine.concurrent_ocr method as backend. - Added reasoning VLM supports: Added new configs to support reasoning VLMs (e.g., Qwen-VL-30B-A3B-Thinking, o4-mini). - Added OpenAICompatible VLM engines: Separated the OpenAI compatible VLM engines into a parent class OpenAICompatibleVLMEngine. - Few-shot examples: Added support for few-shot examples to improve OCR accuracy. - SGLang support: Added SGLangVLMEngine for serving VLMs with SGLang. - VLM-based rotation correction: rotate_correction now accepts "tesseract", "vlm", or False. Use "vlm" when Tesseract isn't installed or struggles with noisy scans. - BBox output mode: New outputmode="bbox" returns OCR text with bounding-box coordinates and labels per region. Leave userprompt empty for full-text bbox OCR or set it to a free-text instruction (e.g., "patient name and DOB") for targeted extraction. Built-in format registry covers Qwen3-VL, Gemma 3/4, and GPT-4.1. - OCR pipelines: New IndependentPagePipeline + OCREngine.ocrimageasync let you process each page differently — classify and route the pages of a heterogeneous document (e.g., mixed form types in one PDF) to different prompts/schemas, while the pipeline handles loading, concurrency, and assembly. See the OCR Pipelines guide.

Table of Contents

✨Overview

vlm4ocr provides a simple way to perform OCR using the power of modern Vision Language Models (VLMs). A drag-and-drop web application is included for easy access. The Python package supports concurrent batch processing for large amount of documents. CLI provides lightweight access to most OCR features without the burden of coding. Below are screenshots from our Web Application. Note that all contents shown in this README are synthesized. There is no real personal information.

Stream OCR resuts in real-time

A scanned lab report with tables and highlights are converted into markdown text by our OCR engine.
img/webapp/tablemarkdowndemo.PNG width=1000 >

Batch processing many files

Many scanned documents are batch processed and converted into markdown text by our OCR engine.
img/webapp/batch_processing.PNG width=1000 >

⭐Supported Models

Open-weights (ALL Supported!!)

All open-weights VLMs are supported via our Ollama and OpenAI compatible engines, including:

Proprietary

Proprietary models such as gpt-4o are supported via our OpenAI and Azure engines.

🚦Prerequisites

  • Python 3.x
  • For PDF processing: poppler library.
  • At least one VLM inference engine setup (Ollama, OpenAI/Azure API keys, or an OpenAI-compatible API endpoint).
pip install ollama # For Ollama
pip install openai # For OpenAI (compatible) and Azure OpenAI

🌎Web Application

A ready-to-use Flask web application is included. We support input preview, real-time streaming, and output export.

https://github.com/user-attachments/assets/b196453c-fd2c-491a-ba1e-0a77cf7f5941

Installation

:whale:Running with Docker

The easiest way to run VLM4OCR web application is through Docker. The image is available on Docker Hub.
docker pull daviden1013/vlm4ocr-app:latest
docker run -p 5000:5000 daviden1013/vlm4ocr-app:latest
Open your web browser and navigate to: http://localhost:5000

If port 5000 is already in use on your machine, you can map it to a different local port. For example, to map it to local port 8080:

docker run -p 8080:5000 daviden1013/vlm4ocr-app:latest
Then visit http://localhost:8080

Using Ollama with the Dockerized App
If you are running Ollama on your host machine (outside the Docker container) and want to connect to it from the VLM4OCR web app running inside Docker:

Docker Desktop (Windows/Mac): In the VLM4OCR web UI, set the Ollama Host to http://host.docker.internal:11434. Linux: Run the Docker container with host networking:

docker run --network="host" daviden1013/vlm4ocr-app:latest
With --network="host", you don't need the -p flag for port mapping (the container will use the host's network directly, so the app will be available at http://localhost:5000). Then, in the VLM4OCR web app, you can use the default http://localhost:11434 for the Ollama Host.

Install from source

Alternatively, you can clone this repo and run VLM4OCR web application from source:
# Install python package
pip install vlm4ocr

Clone source code

git clone https://github.com/daviden1013/vlm4ocr.git

Run Web App

cd vlm4ocr/services/web_app python run.py

🐍Python package

Installation

Python package is available on PyPi

pip install vlm4ocr

Quick start

In this demo, we use a locally deployed vLLM OpenAI compatible server to run Qwen3-VL-30B-A3B-Instruct model.
from vlm4ocr import VLLMVLMEngine

vlm_engine = VLLMVLMEngine(model="Qwen/Qwen3-VL-30B-A3B-Instruct")

To use other VLM inference engines:

OpenAI Compatible

from vlm4ocr import OpenAICompatibleVLMEngine

vlmengine = OpenAICompatibleVLMEngine(model="<modename>", baseurl="<baseurl>", apikey="<apikey>")

Icon Ollama

from vlm4ocr import OllamaVLMEngine

vlmengine = OllamaVLMEngine(modelname="llama3.2-vision:11b-instruct-fp16")

img/openai-logomarkwhite.png width=16 /> OpenAI API

Follow the Best Practices for API Key Safety to set up API key.

export OPENAIAPIKEY=<yourAPIkey>
from vlm4ocr import OpenAIVLMEngine

vlm_engine = OpenAIVLMEngine(model="gpt-4o-mini")

img/Azureicon.png width=32 /> Azure OpenAI API

Follow the Azure AI Services Quickstart to set up Endpoint and API key.

export AZUREOPENAIAPIKEY="<yourAPI_key>"
export AZUREOPENAIENDPOINT="<your_endpoint>"
from llm_ie.engines import AzureOpenAIVLMEngine

vlm_engine = AzureOpenAIVLMEngine(model="gpt-4o-mini", api_version="<your api version>")

We define OCR engine and specify output formats.

from vlm4ocr import OCREngine

Image/PDF paths

imagepath = "/examples/synthesizeddata/GPT-4osynthesizednote1page_1.jpg" pdfpath = "/examples/synthesizeddata/GPT-4osynthesizednote_1.pdf"

Define OCR engine

ocr = OCREngine(vlmengine, outputmode="markdown")

Run OCR sequentially (process one image at a time) for single or multiple files:

# OCR for a single image ocrresults = ocr.sequentialocr(image_path, verbose=True)

OCR for a single pdf (multiple pages)

ocrresults = ocr.sequentialocr(pdf_path, verbose=True)

OCR for multiple image and pdf files

ocrresults = ocr.sequentialocr([pdfpath, imagepath], verbose=True)

Auto-correct page rotation before OCR — "tesseract" uses Tesseract OSD, "vlm" reuses the OCR engine's VLM

ocrresults = ocr.sequentialocr(imagepath, rotatecorrection="vlm", verbose=True)

Inspect OCR results

len(ocr_results) # 2 files ocrresults[0].inputdir ocr_results[0].filename len(ocr_results[0]) # PDF file number of pages ocrtext = ocrresults[0].to_string() # OCR text (all pages concatenated)

Run OCR concurrently and write to file:

import asyncio

async def run_ocr(): response = ocr.concurrentocr([imagepath1, imagepath2], concurrentbatch_size=4) async for result in response: if result.status == "success": filename = result.filename ocrtext = result.tostring() with open(f"{filename}.md", "w", encoding="utf-8") as f: f.write(ocr_text)

asyncio.run(run_ocr())

Run OCR with bounding boxes (outputmode="bbox"). Leave userprompt empty for full-text bbox OCR, or set it to a free-text instruction for targeted extraction:

from vlm4ocr import VLLMVLMEngine, OCREngine

vlm_engine = VLLMVLMEngine(model="Qwen/Qwen3.5-35B-A3B")

Full-text OCR with bounding boxes

ocr = OCREngine(vlmengine=vlmengine, output_mode="bbox") ocrresults = ocr.sequentialocr(image_path)

Targeted extraction with bounding boxes

ocr = OCREngine( vlmengine=vlmengine, output_mode="bbox", user_prompt="Extract patient name, date of birth, Platelets, CMP glucose, BUN, and RBCs values.", ) ocrresults = ocr.sequentialocr(image_path)

Inspect bbox results

for pagenum, page in enumerate(ocrresults[0].pages): for item in page.bboxes: print(item.label, item.bbox, item.text)

# Visualize on the source page (targeted extraction: color by label, show both) annotated = page.plotbboxes(showlabel=True, show_text=True, color="label") annotated.save(f"annotatedpage{pagenum}.png")

Note that this is a synthesized data with NO real PHI!!

[ 	{"bbox_2d": [508, 143, 620, 158], "label": "patient name", "text": "Mary Johnson"}, 	{"bbox_2d": [508, 160, 610, 176], "label": "date of birth", "text": "Jan 29, 1990"}, 	{"bbox_2d": [484, 405, 569, 421], "label": "Platelets", "text": "280 x10⁹/L"}, 	{"bbox_2d": [484, 455, 560, 470], "label": "CMP glucose", "text": "90 mg/dL"}, 	{"bbox_2d": [484, 540, 562, 555], "label": "BUN", "text": "12 mg/dL"}, 	{"bbox_2d": [484, 778, 690, 794], "label": "RBCs", "text": "0 - 1 per high power field"} ]

Supply few-shot examples to improve OCR accuracy:

from PIL import Image import asyncio from vlm4ocr import FewShotExample, VLLMVLMEngine, OCREngine

Load few-shot examples

Note that the example text should be the expected OCR output for the example image. Do not include any extra instructions.

example1image = Image.open("example_1.JPG") with open("example_1.txt", "r") as f: example1text = f.read()

example2image = Image.open("example_2.JPG") with open("example_2.txt", "r") as f: example2text = f.read()

fewshotexamples = [ FewShotExample(image=example1image, text=example1text, maxdimensionpixels=512), FewShotExample(image=example2image, text=example2text, maxdimensionpixels=512) ]

async def run_ocr(): response = ocr.concurrentocr([imagepath1, imagepath2], concurrentbatchsize=4, fewshotexamples=fewshot_examples) async for result in response: if result.status == "success": filename = result.filename ocrtext = result.tostring() with open(f"{filename}.md", "w", encoding="utf-8") as f: f.write(ocr_text)

asyncio.run(run_ocr())

💻CLI

Command line interface (CLI) provides an easy way to batch process many images, PDFs, and TIFFs in a directory.

Installation

Install the Python package on PyPi and CLI tool will be automatically installed.

pip install vlm4ocr

Usage

Run OCR for all supported file types in the /examples/synthesizeddata/ folder with a locally deployed Qwen2.5-VL-7B-Instruct and generate results as markdown. OCR results and a log file (enabled by --log) will be written to the outputpath. --concurrentbatch_size deternmines the number of images/pages can be processed at a time. This is good for managing resources.
# OpenAI compatible API
vlm4ocr --inputpath /examples/synthesizeddata/ \
        --outputpath /examples/ocroutput/ \
        --output_mode markdown \
        --log \
        --vlmengine openaicompatible \
        --model Qwen/Qwen2.5-VL-7B-Instruct \
        --api_key EMPTY \
        --base_url http://localhost:8000/v1 \
        --concurrentbatchsize 4

Use gpt-4.1-mini to process a PDF with many pages. Since --output_path is not specified, outputs and logs will be written to the current work directory.

# OpenAI API export OPENAIAPIKEY=<api key> vlm4ocr --inputpath /examples/synthesizeddata/GPT-4osynthesizednote_1.pdf \         --output_mode HTML \         --log \         --vlm_engine openai \         --model gpt-4.1-mini \         --concurrentbatchsize 4

🔗 More in this category

© 2026 GitRepoTrend · daviden1013/vlm4ocr · Updated daily from GitHub