StarDoc-AI/TeleOCR

Hugging Face Models Trending 模型

摘要

TeleOCR 是一个轻量级的开源视觉-语言模型,专为文档解析设计,统一处理数字文档和相机拍摄文档,并在基准测试中达到了最先进的性能。

任务: image-text-to-text 标签: transformers, safetensors, qwen2_5_vl, image-text-to-text, ocr, document-parsing, multimodal, conversational, custom_code, zh, en, arxiv:2608.12898, license:apache-2.0, eval-results, text-generation-inference, endpoints_compatible, region:us
查看原文
查看缓存全文

缓存时间: 2026/09/25 21:13

StarDoc-AI/TeleOCR · Hugging Face 来源:https://huggingface.co/StarDoc-AI/TeleOCR

https://huggingface.co/StarDoc-AI/TeleOCR#%F0%9F%94%A5-news🔥 最新动态

  • 2026/09/10
    • 我们已将 NaviDC-OCR 更名为 TeleOCR,后续所有模型迭代将在 TeleOCR 版本下开发和发布。
  • 2026/09/01
    • 我们注意到 EMNLP 2026 正在举办 Dr.DocBench 挑战赛 (https://eval.ai/web/challenges/challenge-page/2717/overview),这是一个文档解析竞赛。我们使用 NaviDC-OCR 的原生权重进行了评估,取得了优于 MinerU 2.5 Pro 和 PaddleOCR-VL 1.6 的结果。详细结果如下表 dr.docbench-challenge 所示。我们欢迎使用 NaviDC-OCR 参加竞赛。未来,我们将继续为社区提供有竞争力的解析模型。
  • 2026/08/29
    • 感谢 Nandraj 提供的 GGUF 转换和 llama.cpp 支持 🔗 NaviDC-OCR-GGUF (https://huggingface.co/nandraj/NaviDC-OCR-GGUF),以及社区分享的在 Ascend 910B 上部署 NaviDC-OCR 的经验!(https://zhuanlan.zhihu.com/p/2078516899093155893)
  • 2026/08/17
    • NaviDC-OCR 模型权重 (https://huggingface.co/StarDoc-AI/NaviDC-OCR) 和技术报告 (https://arxiv.org/pdf/2608.12898) 已发布。

https://huggingface.co/StarDoc-AI/TeleOCR#%F0%9F%93%96-introduction📖 简介

TeleOCR 是一个轻量级(约 1.2B 参数)的开源视觉语言模型,专为文档解析设计。与现有主要针对数字文档或相机捕获文档的方法不同,TeleOCR 将这两种场景统一在一个框架内。与之前的文档解析模型相比,TeleOCR 引入了:

  • 用于自动生成伪标签的多节点共识投票 (Multi-node Consensus Voting, MCV)
  • 针对相机捕获文档的几何感知文档建模
  • 曲率引导的道格拉斯-普克采样 (Curvature-Guided Douglas-Peucker Sampling, CGDP)
  • 用于自动数据精炼的图像到图像自验证
  • 渐进式四阶段训练流程
  • 用于表格和公式的“内容-结构解耦学习” 这些技术使得 TeleOCR 在数字文档和相机捕获文档基准测试中均达到了最先进的性能,同时保持了足够的轻量级以供实际部署。

https://huggingface.co/StarDoc-AI/TeleOCR#%F0%9F%93%8A-experimental-results📊 实验结果

TeleOCR 在多个公开的文档解析基准测试中取得了最先进的性能。

https://huggingface.co/StarDoc-AI/TeleOCR#layout-visualization-of-distorted-documents扭曲文档的布局可视化

为了评估模型理解复杂文档形变的能力,我们在公开的去畸变数据集 DocUNet 和 DIR300 上进行了视觉评估,代表性结果如图所示。TeleOCR 直接对扭曲文档进行布局和内容解析,无需去畸变预处理或专门的矫正模型,展示了在复杂几何形变下的稳健解析能力。

  • DIR300 数据集上的解析评估。
  • DocUNET 数据集上的解析评估。

https://huggingface.co/StarDoc-AI/TeleOCR#drdocbench-challengeDr.DocBench 挑战赛

模型类型参数overall ↑Text edit ↓formula cdm ↑Table teds ↑order edit ↓
专用 VLM
TeleOCR67.960.19030.0264.970.398
Mineru 2.5 pro62.260.34020.0467.750.356
OvisOCR259.250.38830.0061.590.379
PaddleOCRvl 1.655.110.43640.2151.340.412

https://huggingface.co/StarDoc-AI/TeleOCR#omnidocbench-v16OmniDocBench v1.6

模型类型方法参数Overall ↑Text Edit ↓Formula CDM ↑Table TEDS ↑Table TEDS-S ↑Read Order Edit ↓
专用 VLM
TeleOCR1.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
通用 VLM
Ovis2.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

https://huggingface.co/StarDoc-AI/TeleOCR#wild_omnidocbenchWild_OmniDocBench

模型类型方法参数Overall ↑Text Edit ↓Formula CDM ↑Table TEDS ↑Table TEDS-S ↑Read Order Edit ↓
解耦 VLM
TeleOCR1.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
端到端 VLM
OvisOCR20.8B87.910.12990.3785.1389.110.2021
dots.ocr3B81.840.148385.0775.3280.200.2200
HunyuanOCR-1.51B77.620.197985.1267.5470.670.2750
Logics-Parsing-v24B77.100.402991.480.1987.160.2355

https://huggingface.co/StarDoc-AI/TeleOCR#puredocbenchPureDocBench

模型类型模型Clean 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 ↑
解耦 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
端到端 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
通用 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

https://huggingface.co/StarDoc-AI/TeleOCR#icdar2026-sci-imageminerICDAR2026 Sci-ImageMiner

#团队RMSTEDS加权
1TeleOCR17.23
2VLMinators17.29
3Ricoh_SRCB16.23
4Vassilis Sioros14.94
5DocMiner12.67
6Qwen3 VL 8B14.08

https://huggingface.co/StarDoc-AI/TeleOCR#%F0%9F%9A%80-installation🚀 安装

pip install transformers torch pillow

https://huggingface.co/StarDoc-AI/TeleOCR#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 = ""
OTSL_FCEL = ""
OTSL_ECEL = ""
OTSL_LCEL = ""
OTSL_UCEL = ""
OTSL_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("<"):
        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()

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

# 表格
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))

# 公式
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)

# 代码
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())

# 布局
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())

# 扭曲文档布局
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())

# 科学图表
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))

如需执行完整的文档解析,请参考我们的 GitHub 仓库:https://github.com/caipeng328/NaviDC-OCR。

https://huggingface.co/StarDoc-AI/TeleOCR#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}
}

https://huggingface.co/StarDoc-AI/TeleOCR#community-contributions社区贡献

感谢 Nandraj 提供的 GGUF 转换和 llama.cpp 支持 🔗 NaviDC-OCR-GGUF

https://huggingface.co/StarDoc-AI/TeleOCR#acknowledgements致谢

TeleOCR 构建于以下项目:

  • MinerU
  • Qwen2.5-VL
  • Qwen3
  • Transformers
  • PyTorch
  • FlashAttention 我们衷心感谢这些优秀的开源项目。

https://huggingface.co/StarDoc-AI/TeleOCR#contact联系我们

如果您有任何问题,请随时提交 issue 或联系我们。

相似文章

XingChen-AGI/TeleOCR

Hugging Face Models Trending

TeleOCR 是一款轻量级的开源视觉语言模型,专注于文档解析,通过多节点共识投票等技术,在数字和相机拍摄的文档上均达到了行业领先水平。

ATH-MaaS/OvisOCR2

Hugging Face Models Trending

OvisOCR2 是一个紧凑的0.8B端到端模型,用于页面级文档解析,在OmniDocBench和PureDocBench基准测试中达到了最先进的性能。

OvisOCR3 技术报告

Hugging Face Daily Papers

OvisOCR3 是一款紧凑的 0.8B 视觉语言模型,通过多教师在线策略蒸馏和混合任务强化学习,将文档解析、通用 OCR、关键信息提取、图表描述和跨页表格重建统一起来,在 OmniDocBench v1.6、OCRBench v2 和 PureDocBench 等基准测试中取得了最先进的成绩。

MonkeyOCRv2: 用于文档AI的视觉-文本基础模型

Hugging Face Daily Papers

MonkeyOCRv2是一个用于文档AI的视觉-文本基础模型,在涵盖17种语言的1.13亿张图像的大规模语料库上进行了预训练,采用联合图像到文本生成和像素级文档重建。它在文档解析和理解任务上取得了最先进的结果,以更小的视觉编码器超越了之前的模型。