/ Модель

Характеристики

Контекст
128 000 токенов
Параметры
508 млн
Лицензия
Apache 2.0
Архитектура
qwen2_5_vl · dense
Библиотека
transformers
Опубликована
14 авг 2026

TeleOCR

Генерация текстаТекст → текст12 профессий

Компактная модель StarDoc-AI на базе Qwen2.5-VL, которая извлекает текст и структуру из цифровых и сфотографированных документов.

27 837скачиваний за 30 дней590лайковвеса обновлены22 сен 2026

Бенчмарки

Как модель справилась с задачами пользователей ailist и что о ней публикуют открытые лидерборды

Тесты пользователейпока нет

Никто ещё не опубликовал тест этой модели. Соберите бенчмарк из своих задач — результат появится здесь.

  1. Добавьте модель в бенчмарк

    Вместе с другими моделями категории «Текст» — сравнение идёт внутри одной категории.

  2. Опишите свои задачи

    Напишите запросы, при необходимости приложите файлы и эталонные ответы.

  3. Запустите и опубликуйте

    Модели ответят на каждую задачу, судья оценит ответы. Опубликованный результат появится на этой странице.

Публичные оценки

Из открытых лидербордов. Сравнивайте результаты одного теста при одинаковых условиях — отсутствие оценки не значит, что модель хуже.

В подключённых источниках результатов для этой модели пока нет.

Что умеет модель

Описание составлено по карточке модели и метаданным Hugging Face

TeleOCR — компактная мультимодальная модель StarDoc-AI для разбора документов по изображениям. В метаданных указаны архитектура Qwen2.5-VL, 507,9 млн параметров, контекст 128 000 токенов и библиотека Transformers; README описывает модель как примерно 1,2-миллиардную. Эти сведения о размере расходятся между источниками.

Модель предназначена для извлечения текста и структуры из цифровых и снятых камерой документов, включая искажённые страницы, таблицы и формулы. В README заявлены геометрически ориентированное моделирование, автоматическая генерация и проверка обучающих данных и поэтапное обучение. Модель принимает изображения документов и формирует текстовый разбор; в метаданных также отмечена поддержка чата. Заявлены результаты на нескольких тестах разбора документов, но они приведены авторами и сами по себе не гарантируют качество на конкретных данных.

Модель опубликована под лицензией Apache-2.0. Для запуска README предлагает Transformers, PyTorch и Pillow; для полного разбора документов авторы отсылают к отдельному репозиторию.

Сценарии применения

  • извлечение текста и структуры из сканов документов
  • разбор таблиц и формул на изображениях страниц
  • распознавание и разбор документов, снятых камерой
  • анализ искажённых или деформированных страниц
  • определение порядка чтения элементов документа

Ограничения

Размер модели указан неодинаково: метаданные сообщают 507,9 млн параметров, а README — около 1,2 млрд. Для полного разбора документов README направляет к отдельному репозиторию; опубликованные результаты тестов не гарантируют качество на произвольных документах.

Для каких профессий подходит12

Разделы каталога профессий, в задачах которых используется эта модель

Все профессии

Также подходит для

Карточка модели

README от автора на Hugging Face, как он его опубликовал

Открыть на Hugging Face

License GitHub Papers with Code: SOTA on OmniDocBench v1.6 TeleAI arXiv

🔥 News

  • 2026/09/10 - We have renamed NaviDC-OCR to TeleOCR, and all subsequent model iterations will be developed and released under the TeleOCR version.
  • 2026/09/01 - We noticed that EMNLP 2026 is hosting the Dr.DocBench Challenge, a document parsing competition. We evaluated NaviDC-OCR with its native weights, achieving better results than MinerU 2.5 Pro and PaddleOCR-VL 1.6. Detailed results are shown below dr.docbench-challenge. We welcome the use of NaviDC‑OCR for competitions. Going forward, we will continue to deliver competitive parsing models for the community.
  • 2026/08/29 — Thanks to Nandraj for the GGUF conversion and llama.cpp support 🔗 NaviDC-OCR-GGUF, and to the community for sharing their experience deploying NaviDC-OCR on Ascend 910B!
  • 2026/08/17 — NaviDC-OCR model weights and technical report have been released.

📖 Introduction

TeleOCR is a lightweight (~1.2B parameters), open-source Vision-Language Model designed specifically for document parsing.

Unlike existing methods that mainly target either digital documents or camera-captured documents, TeleOCR unifies both scenarios within a single framework.

Compared with previous document parsing models, TeleOCR introduces

  • Multi-node Consensus Voting (MCV) for automatic pseudo-label generation
  • Geometry-aware document modeling for camera-captured documents
  • Curvature-Guided Douglas-Peucker Sampling (CGDP)
  • Image-to-image self-verification for automatic data refinement
  • Progressive four-stage training pipeline
  • Content-Structure Decoupled Learning for tables and formulas

These techniques enable TeleOCR to achieve state-of-the-art performance on both digital and camera-captured document benchmarks while remaining lightweight enough for practical deployment.

📊 Experimental Results

TeleOCR achieves state-of-the-art performance on multiple public document parsing benchmarks.

Layout Visualization of Distorted Documents

To evaluate the model's ability to understand complex document deformations, we conduct a visual evaluation on the public dewarping datasets DocUNet and DIR300, with representative results shown in Figure. TeleOCR directly performs layout and content parsing on distorted documents without dewarping preprocessing or a dedicated rectification model, demonstrating robust parsing under complex geometric deformations.


Dr.DocBench Challenge

模型overall ↑Text edit ↓formula cdm ↑Table teds ↑order edit ↓
Specialized VLMs
TeleOCR67.960.19030.0264.970.398
Mineru 2.5 pro62.260.34020.0467.750.356
OvisOCR259.250.38830.0061.590.3791
PaddleOCRvl 1.655.110.43640.2151.340.412

OmniDocBench v1.6

Model TypeMethodsParamOverall ↑Text Edit ↓Formula CDM ↑Table TEDS ↑Table TEDS-S ↑Read Order Edit ↓
Specialized VLMsTeleOCR1.2B96.870.02796.3697.0598.520.122
OvisOCR20.8B96.580.02597.5394.7697.160.111
PaddleOCR-VL-1.60.9B96.330.03397.4994.7697.110.127
MinerU2.5-Pro1.2B95.750.03697.4593.4295.920.120
GLM-OCR0.9B95.220.04497.1892.8395.390.133
PaddleOCR-VL-1.50.9B94.870.03896.6991.6794.370.130
HunyuanOCR-1.51B94.740.03397.4994.7697.110.127
PaddleOCR-VL0.9B94.110.04095.7090.6593.740.135
Youtu-Parsing2.5B93.680.04493.4592.0295.000.116
Logics-Parsing-v24B93.270.04195.4788.4291.980.137
FireRed-OCR2B93.200.03795.2788.0491.060.131
MinerU2.51.2B92.980.04595.5987.8891.470.130
OpenDoc-0.1B0.1B90.640.04992.9383.8887.450.140
dots.ocr3B90.500.04889.1287.1890.580.138
DeepSeek-OCR 23B90.170.05091.5983.8987.750.144
HunyuanOCR1B89.870.08987.4491.0193.230.171
Dolphin-v23B89.340.06990.5384.4087.440.150
OCRVerse4B88.440.06389.1482.4486.270.163
MonkeyOCR-pro-3B3B88.430.07488.3384.3588.620.189
General VLMsOvis2.6-30B-A3B30B93.620.03594.9389.4492.400.135
Gemini 3 Pro--92.850.06495.8389.1592.960.165
Gemini 3 Flash--92.580.06695.0389.2993.510.173
Qwen3-VL-235B235B89.780.06392.5383.0786.750.166
GPT-5.2--86.520.11488.0082.9587.930.193
InternVL3.5-241B241B83.610.13089.5274.3579.780.215

Wild_OmniDocBench

Model TypeMethodsParamOverall ↑Text Edit ↓Formula CDM ↑Table TEDS ↑Table TEDS-S ↑Read Order Edit ↓
Decoupled VLMsTeleOCR1.2B88.530.117388.2689.0592.140.2011
PaddleOCR-VL-1.60.9B87.360.136988.4285.7690.140.2057
MinerU2.5-Pro1.2B87.330.136290.1585.4690.120.2013
GLM-OCR0.9B85.080.151489.0981.3185.900.2228
PaddleOCR-VL-1.50.9B84.640.146186.7281.8086.520.2138
End-to-End VLMsOvisOCR20.8B87.910.12990.3785.1389.110.2021
dots.ocr3B81.840.148385.075.3280.200.2200
HunyuanOCR-1.51B77.620.197985.1267.5470.670.2750
Logics-Parsing-v24B77.100.402991.480.1987.160.2355

PureDocBench

Model TypeModelClean Overall ↑Clean Text ↓Clean Formula ↑Clean Table ↑Digital Degraded Overall ↑Digital Degraded Text ↓Digital Degraded Formula ↑Digital Degraded Table ↑Real Degraded Overall ↑Real Degraded Text ↓Real Degraded Formula ↑Real Degraded Table ↑
Decoupled VLMTeleOCR86.900.11181.0191.0977.470.20672.5980.4570.850.30265.1177.66
DotsMOCR76.270.15166.2377.6573.160.19864.3274.9561.730.31254.3961.97
MinerU2.5-Pro75.870.22265.1484.6871.770.27261.7980.7362.560.37552.7072.47
YouTu-Parsing75.020.23067.3480.7469.660.27061.4474.4960.290.36052.2064.69
PaddleOCR-VL-1.573.010.26663.5382.1266.730.33958.0376.0760.500.39854.0067.33
GLM-OCR68.650.31457.8979.4463.060.38353.2374.2158.310.43350.3467.83
Dolphin-v265.900.34259.8072.1260.240.39352.2067.8644.920.55339.9850.04
MonkeyOCR-pro-3B62.230.34648.4672.8357.400.39745.5766.3246.490.51138.1852.43
End-to-End VLMOvisOCR282.140.14971.2990.1277.770.19267.8784.7166.610.31657.6473.79
FD-RL78.380.19368.2186.2276.330.21467.1683.2267.040.29858.8272.08
Logics-Parsing-v276.350.21367.6782.6773.850.24867.3379.0267.640.30461.6571.64
dots.ocr72.010.24861.3779.5165.950.30756.6771.8655.680.40347.7059.63
Qianfan-OCR57.220.37049.7958.8350.850.43844.4151.9645.060.49439.0845.53
General VLMsQwen3-VL-8B72.440.26165.1078.3572.030.26664.8877.8262.730.34255.5566.81
Kimi K2.672.320.30366.9380.3069.950.32264.6977.3168.020.33562.4475.14
Gemini-3.1-Pro70.040.30665.6375.0869.280.32265.8174.2471.980.30068.6277.26
Qwen3.5-397B-A17B69.120.23365.2665.4068.340.24463.9165.5362.700.28760.7056.12

ICDAR2026 Sci-ImageMiner

#TeamRMSTEDSWeighted
1TeleOCR17.2366.3941.81
2VLMinators17.2964.3140.80
3Ricoh_SRCB16.2361.1238.67
4Vassilis Sioros14.9455.2035.07
5DocMiner12.6753.7233.19
6Qwen3 VL 8B14.0857.8635.97

🚀 Installation

pip install transformers torch pillow

Quick Start

import html
import itertools
import json
import re
from dataclasses import dataclass

from PIL import Image
import torch
from transformers import AutoProcessor, AutoModel

@dataclass
class ContentBlock:
    type: str
    bbox: list[float]
    angle: int | None = None
    content: str | None = None


@dataclass
class TableCell:
    text: str
    start_row_offset_idx: int
    end_row_offset_idx: int
    start_col_offset_idx: int
    end_col_offset_idx: int
    row_span: int = 1
    col_span: int = 1


OTSL_NL = "<nl>"
OTSL_FCEL = "<fcel>"
OTSL_ECEL = "<ecel>"
OTSL_LCEL = "<lcel>"
OTSL_UCEL = "<ucel>"
OTSL_XCEL = "<xcel>"
OTSL_TOKENS = [OTSL_NL, OTSL_FCEL, OTSL_ECEL, OTSL_LCEL, OTSL_UCEL, OTSL_XCEL]


def _otsl_extract_tokens_and_text(text: str):
    pattern = "(" + "|".join(map(re.escape, OTSL_TOKENS)) + ")"
    tokens = re.findall(pattern, text)
    parts = [part for part in re.split(pattern, text) if part.strip()]
    return tokens, parts


def _count_right(rows, row_idx, col_idx, tokens):
    span = 0
    while col_idx < len(rows[row_idx]) and rows[row_idx][col_idx] in tokens:
        span += 1
        col_idx += 1
    return span


def _count_down(rows, row_idx, col_idx, tokens):
    span = 0
    while row_idx < len(rows) and col_idx < len(rows[row_idx]) and rows[row_idx][col_idx] in tokens:
        span += 1
        row_idx += 1
    return span


def _otsl_parse_texts(parts, tokens):
    rows = [list(row) for is_nl, row in itertools.groupby(tokens, lambda token: token == OTSL_NL) if not is_nl]
    if not rows:
        return [], []

    max_cols = max(len(row) for row in rows)
    for row in rows:
        row.extend([OTSL_ECEL] * (max_cols - len(row)))

    cells = []
    row_idx = 0
    col_idx = 0
    for idx, part in enumerate(parts):
        if part in (OTSL_FCEL, OTSL_ECEL):
            cell_text = ""
            right_offset = 1
            if part != OTSL_ECEL and idx + 1 < len(parts) and parts[idx + 1] not in OTSL_TOKENS:
                cell_text = parts[idx + 1].strip()
                right_offset = 2

            next_right = parts[idx + right_offset] if idx + right_offset < len(parts) else ""
            next_bottom = rows[row_idx + 1][col_idx] if row_idx + 1 < len(rows) and col_idx < len(rows[row_idx + 1]) else ""
            col_span = 1 + (_count_right(rows, row_idx, col_idx + 1, {OTSL_LCEL, OTSL_XCEL}) if next_right in {OTSL_LCEL, OTSL_XCEL} else 0)
            row_span = 1 + (_count_down(rows, row_idx + 1, col_idx, {OTSL_UCEL, OTSL_XCEL}) if next_bottom in {OTSL_UCEL, OTSL_XCEL} else 0)
            cells.append(TableCell(
                text=cell_text,
                row_span=row_span,
                col_span=col_span,
                start_row_offset_idx=row_idx,
                end_row_offset_idx=row_idx + row_span,
                start_col_offset_idx=col_idx,
                end_col_offset_idx=col_idx + col_span,
            ))
        if part in (OTSL_FCEL, OTSL_ECEL, OTSL_LCEL, OTSL_UCEL, OTSL_XCEL):
            col_idx += 1
        elif part == OTSL_NL:
            row_idx += 1
            col_idx = 0
    return cells, rows


def convert_otsl_to_html(otsl_content: str) -> str:
    if otsl_content.startswith("<table") and otsl_content.endswith("</table>"):
        return otsl_content

    tokens, parts = _otsl_extract_tokens_and_text(otsl_content)
    cells, rows = _otsl_parse_texts(parts, tokens)
    if not cells or not rows:
        return ""

    grid = [[None for _ in range(len(rows[0]))] for _ in range(len(rows))]
    for cell in cells:
        for row_idx in range(cell.start_row_offset_idx, min(cell.end_row_offset_idx, len(rows))):
            for col_idx in range(cell.start_col_offset_idx, min(cell.end_col_offset_idx, len(rows[0]))):
                grid[row_idx][col_idx] = cell

    html_rows = []
    for row_idx, row in enumerate(grid):
        html_rows.append("<tr>")
        for col_idx, cell in enumerate(row):
            if cell is None or cell.start_row_offset_idx != row_idx or cell.start_col_offset_idx != col_idx:
                continue
            attrs = ""
            if cell.row_span > 1:
                attrs += f' rowspan="{cell.row_span}"'
            if cell.col_span > 1:
                attrs += f' colspan="{cell.col_span}"'
            html_rows.append(f"<td{attrs}>{html.escape(cell.text.strip())}</td>")
        html_rows.append("</tr>")
    return "<table>" + "".join(html_rows) + "</table>"


def post_process(blocks: list[ContentBlock]) -> list[ContentBlock]:
    for block in blocks:
        if block.type == "table" and block.content:
            block.content = convert_otsl_to_html(block.content)
        elif block.type == "equation" and block.content:
            content = block.content.strip()
            content = content.removeprefix("\\[").removesuffix("\\]").strip()
            if not (content.startswith("$") and content.endswith("$")):
                content = f"$${content}$$"
            block.content = content
    return [block for block in blocks if block.type != "equation_block"]

def infer(image: Image.Image, prompt: str) -> str:
    messages = [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": [
            {"type": "image"},
            {"type": "text", "text": prompt},
        ]},
    ]
    chat_prompt = processor.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True,
    )
    inputs = processor(
        text=[chat_prompt],
        images=[image.convert("RGB")],
        padding=True,
        return_tensors="pt",
    ).to(device=model.device, dtype=model.dtype)
    output_ids = model.generate(
        **inputs,
        use_cache=True,
        max_new_tokens=4096,
        do_sample=False,
    )
    output_ids = output_ids.cpu().tolist()[0][len(inputs.input_ids[0]):]
    return processor.batch_decode(
        [output_ids],
        skip_special_tokens=True,
        clean_up_tokenization_spaces=False,
    )[0].strip()



processor = AutoProcessor.from_pretrained("StarDoc-AI/TeleOCR", trust_remote_code=True, use_fast=True)
model = AutoModel.from_pretrained(
    "StarDoc-AI/TeleOCR",
    trust_remote_code=True,
    torch_dtype=torch.bfloat16,
).cuda().eval()

# text
image=Image.open("./assets/text.png").convert("RGB")
raw_text = infer(image, "Please output the text content from the image.")
print(raw_text.strip())

# table
image=Image.open("./assets/table.png").convert("RGB")
raw_otsl = infer(image, "This is the image of a table. Please output the table in OTSL format.")
print(convert_otsl_to_html(raw_otsl))

# formula 
image=Image.open("./assets/formula.png").convert("RGB")
raw_formula = infer(image, "Please write out the expression of the formula in the image using LaTeX format.")
formula_block = ContentBlock("equation", [0.0, 0.0, 1.0, 1.0], content=raw_formula)
formula = post_process([formula_block])[0].content
print(formula)

#code
image=Image.open("./assets/code.png").convert("RGB")
raw_code = infer(image,"The image contains a code snippet, please output the parsing result.")
print(raw_code.strip())

# layout
image=Image.open("./assets/layout.jpg").convert("RGB")
image = image.resize((1036, 1036), Image.Resampling.BICUBIC)
raw_layout = infer(image, "Analyze the image layout.")
print(raw_layout.strip())

# Distorted document layout
layout_image = Image.open("./assets/layout_distorted.jpg").convert("RGB")
layout_image = layout_image.resize((1036, 1036), Image.Resampling.BICUBIC)
raw_layout = infer(layout_image, "\nMulti-point Layout Segmentation Analysis.")
print(raw_layout.strip())

#scientific figure
image=Image.open("./assets/scientific_figure.png").convert("RGB")
raw_scientific_figure = infer(image, "This is a scientific figure. Please extract the table implied by this figure.")
print(convert_otsl_to_html(raw_scientific_figure))

If you would like to perform complete document parsing, please refer to our GitHub repository: https://github.com/caipeng328/NaviDC-OCR.

Citation

@article{teleocr,
  title={TeleOCR: Navigating Document Parsing Across Digital and Camera-Captured Documents},
  author={Cai, Peng and Zou, Zhaofan and Liu, Shifa and Wang, Yikun and Tang, Jiawei and Yang, Kaicheng and Tong, Meng and He, Zhongjiang and Sun, Hao},
  journal={arXiv preprint arXiv:2608.12898},
  year={2026}
}

Community Contributions

Thanks to Nandraj for the GGUF conversion and llama.cpp support! 🔗 NaviDC-OCR-GGUF

Acknowledgements

TeleOCR is built upon

  • MinerU
  • Qwen2.5-VL
  • Qwen3
  • Transformers
  • PyTorch
  • FlashAttention

We sincerely thank these excellent open-source projects.


Contact

If you have any questions, feel free to open an issue or contact us.

Как запустить

На своей GPU в ailist. Цена — по текущим предложениям провайдеров

GPU в ailist

Универсальный рантайм · transformers

Можно запустить

Подбираем GPU…

Класс архитектуры
Qwen2_5_VLForConditionalGeneration
Ревизия весов
a614331

0 моделей