Process any HF dataset with a single command using
uv-scripts/ocr:
1# Basic OCR
2hf jobs uv run --flavor l4x1 -s HF_TOKEN \
3 https://huggingface.co/datasets/uv-scripts/ocr/raw/main/dots-ocr-1.5.py \
4 your-input-dataset your-output-dataset \
5 --model davanstrien/dots.ocr-1.5
6
7# Layout analysis with bounding boxes
8hf jobs uv run --flavor l4x1 -s HF_TOKEN \
9 https://huggingface.co/datasets/uv-scripts/ocr/raw/main/dots-ocr-1.5.py \
10 your-input-dataset your-output-dataset \
11 --model davanstrien/dots.ocr-1.5 \
12 --prompt-mode layout-all
1from vllm import LLM, SamplingParams
2
3llm = LLM(
4 model="davanstrien/dots.ocr-1.5",
5 trust_remote_code=True,
6 max_model_len=24000,
7 gpu_memory_utilization=0.9,
8)
9
10sampling_params = SamplingParams(temperature=0.1, top_p=0.9, max_tokens=24000)
11
12messages = [{
13 "role": "user",
14 "content": [
15 {"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}},
16 {"type": "text", "text": "Extract the text content from this image."},
17 ],
18}]
19
20outputs = llm.chat(
21 [messages],
22 sampling_params,
23 chat_template_content_format="string", # Required!
24)
25print(outputs[0].outputs[0].text)
1vllm serve davanstrien/dots.ocr-1.5 \
2 --tensor-parallel-size 1 \
3 --gpu-memory-utilization 0.9 \
4 --chat-template-content-format string \
5 --trust-remote-code
1import torch
2from transformers import AutoModelForCausalLM, AutoProcessor
3from qwen_vl_utils import process_vision_info
4
5model = AutoModelForCausalLM.from_pretrained(
6 "davanstrien/dots.ocr-1.5",
7 attn_implementation="flash_attention_2",
8 torch_dtype=torch.bfloat16,
9 device_map="auto",
10 trust_remote_code=True,
11)
12processor = AutoProcessor.from_pretrained("davanstrien/dots.ocr-1.5", trust_remote_code=True)
13
14messages = [{
15 "role": "user",
16 "content": [
17 {"type": "image", "image": "document.jpg"},
18 {"type": "text", "text": "Extract the text content from this image."},
19 ],
20}]
21
22text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
23image_inputs, video_inputs = process_vision_info(messages)
24inputs = processor(text=[text], images=image_inputs, videos=video_inputs, padding=True, return_tensors="pt").to("cuda")
25
26generated_ids = model.generate(**inputs, max_new_tokens=24000)
27output = processor.batch_decode(
28 [out[len(inp):] for inp, out in zip(inputs.input_ids, generated_ids)],
29 skip_special_tokens=True,
30)[0]
31print(output)
1import math
2
3def smart_resize(height, width, factor=28, min_pixels=3136, max_pixels=11289600):
4 h_bar = max(factor, round(height / factor) * factor)
5 w_bar = max(factor, round(width / factor) * factor)
6 if h_bar * w_bar > max_pixels:
7 beta = math.sqrt((height * width) / max_pixels)
8 h_bar = math.floor(height / beta / factor) * factor
9 w_bar = math.floor(width / beta / factor) * factor
10 elif h_bar * w_bar < min_pixels:
11 beta = math.sqrt(min_pixels / (height * width))
12 h_bar = math.ceil(height * beta / factor) * factor
13 w_bar = math.ceil(width * beta / factor) * factor
14 return h_bar, w_bar
15
16resized_h, resized_w = smart_resize(orig_h, orig_w)
17scale_x, scale_y = orig_w / resized_w, orig_h / resized_h
18# orig_x = bbox_x * scale_x, orig_y = bbox_y * scale_y
This model is released under the
dots.ocr License Agreement, which is based on the MIT License with supplementary terms covering responsible use, attribution, and data governance. Per the license:
"If Licensee distributes modified weights or fine-tuned models based on the Model Materials, Licensee must prominently display the following statement: 'Built with dots.ocr.'"
1@misc{dots_ocr_1_5,
2 title={dots.ocr-1.5: Recognize Any Human Scripts and Symbols},
3 author={rednote-hilab},
4 year={2025},
5 url={https://github.com/rednote-hilab/dots.ocr}
6}
Built with dots.ocr.