
今天要为大家介绍的就是这款最新开源的Nanonets-OCR-s,它是一款功能强大 OCR 模型,统一了文本处理与图像识别。它能够将文档转换为结构化的 Markdown,并具备智能内容识别和语义标记功能,非常适合 LLM 或者 RAG 文档处理。
它非常擅长复杂表格提取、水印提取、LaTeX 公式识别、签名检测与隔离和智能复选框处理,最有意思的是它统一了文本与图像的解析,还能够输出图像描述。以往或许文档中解析出的图像,要么保存为链接,要么单独解析出来使用图像 Embedding 实现多模态。不同于 MinerU 的 Pipeline 解析,Nanonets-OCR-s 一次解析,直接输出文档中的所有内容,真正做到端到端,一站式解析。我们先演示功能,稍后简单介绍一下原理以及如何部署。
分别演示复杂表格提取,智能图像描述、水印提取、公式识别和签名检测与隔离,智能复选框就不赘述了。
文档中提取复杂表格并将其转换为 markdown 和 html 表格。
输入文档,表格非常复杂了可以说:
表格输入
输出的 Markdown,其中表格以 html 表示。
TABLE OUTPUT
使用结构化标签描述文档中的图像,使其易于 LLM 处理。该模型可以根据内容、样式和上下文描述单幅或多幅图像(徽标、图表、图形、二维码等),会将图像描述输出到**标签内。页码则预测于<page_number>**标签内。
BLIP 输入
输出 Markdown,注意下图中关于[img]标签,其内是图像的描述,以及尾部有[page_number]标签。
BLIP OUTPUT
该模型可以检测并提取文档中的水印文本,并将水印文本输出到标签内。
输入文档:
image-20250625082714793
输出 Markdown 文档,注意 001 中的[watermark]PAID[/watermark]:
自动将数学方程式和公式转换为正确格式的 LaTeX 语法。内联数学表达式将转换为 LaTeX 内联方程式,而显示的方程式将转换为 LaTeX 显示方程式。
输入文档:
LATEX INPUT
输出的 Markdown 文本,标准的 Latex:
识别文档中的签名并将其与文档中的其他文本区分开来,这对于法律和商业文档处理至关重要。该模型会将签名文本输出到标签内。
image-20250625082021771
输出 Markdown,注意签名在标签<signature>中。
SIGNATURE OUTPUT
Nanonets-OCR-s 是基于视觉语言模型 Qwen2.5-VL-3B,精选超过 25 万页的数据集微调而来。所以它能够直接输出图像描述就不难理解了是吧?这个 25 万页数据集涵盖以下文档类型:研究论文、财务文档、法律文档、医疗保健文档、税务表单、收据和发票。此外,该数据集还包含包含图像、图表、公式、签名、水印、复选框和复杂表格的文档。
注意,既然是 VLM 模型,意味着它的输入限定了是图像,因此针对各种文档,我们可能需要先转换为图像。其中 pdf2image、python-docx 以及 pptx 都可以将原始文档转换为一页页的图像。
模型权重已经开源:
https://huggingface.co/nanonets/Nanonets-OCR-s
测试地址:
https://huggingface.co/spaces/Souvik3333/Nanonets-ocr-s
比如上传一张 PPT:
WX20250625-084806@2x
然后获得输出如下
如使用 VLLM 部署:
vllm serve nanonets/Nanonets-OCR-s
或者使用量化后的模型,有很多 GGUF 的模型,可以在 ollama 或者 LMStudio 中部署,其中 unsloth 量化了 IQ1 到 Q8 的多个模型:
https://huggingface.co/unsloth/Nanonets-OCR-s-GGUF
所以解析文档第一步要将原始文档处理为图像,第二步就是将图像编码为 base64 然后请求大模型。
from openai import OpenAI
import base64
client = OpenAI(api_key="123", base_url="http://localhost:8000/v1")
model = "nanonets/Nanonets-OCR-s"
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode("utf-8")
def ocr_page_with_nanonets_s(img_base64):
response = client.chat.completions.create(
model=model,
messages=[
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{img_base64}"},
},
{
"type": "text",
"text": "Extract the text from the above document as if you were reading it naturally. Return the tables in html format. Return the equations in LaTeX representation. If there is an image in the document and image caption is not present, add a small description of the image inside the <img></img> tag; otherwise, add the image caption inside <img></img>. Watermarks should be wrapped in brackets. Ex: <watermark>OFFICIAL COPY</watermark>. Page numbers should be wrapped in brackets. Ex: <page_number>14</page_number> or <page_number>9/22</page_number>. Prefer using ☐ and ☑ for check boxes.",
},
],
}
],
temperature=0.0,
max_tokens=
)
return response.choices[].message.content
test_img_path = "/path/to/your/document.jpg"
img_base64 = encode_image(test_img_path)
print(ocr_page_with_nanonets_s(img_base64))