Skip to content
LiteParse 文档版本 跟随上游 源快照 d6b504a7 更新于 2026-10-16

LiteParse 的 is_complex 命令用来判断一篇文档是否“复杂”。也就是查看图片、损坏/乱码文字、大量矢量图形以及稀疏文字。

用它来:

  • 给文档分流,交给更便宜或更重的解析/OCR 后端。
  • 拒收或标记你处理不了的文档 —— 比如在 --no-ocr 模式下运行前,先找出那些会返回空内容的页。
  • 提前估算成本,方法是统计到底有多少页真的需要 OCR。

工作原理

复杂度是按页计算的。每一页都会得到一个 needs_ocr 结论,以及一份解释它为何被标记的 reasons 列表。只要文档中任意一页需要 OCR,这篇文档就是“复杂”的。

这些理由来自几路信号:

Reason含义
scanned一整张位图覆盖了几乎整页,其后几乎没有文字 —— 扫描页或拍摄页。
no-text几乎抽不出文字,也没有整页图片 —— 空白页、封面或分隔页。
sparse-text有一些真实文字,但只覆盖页面很小一部分 —— 通常是一幅图配一行短说明。
embedded-images大量内嵌位图与原生文字并排存在。
garbled原生文字解码出来是乱码,文字很可能不可读。
vector-text文字被当作填充的矢量轮廓画在文本层之外,因此没有原生文字项来表示它。
annotation-text有意义的文字存放在 PDF 批注里,而不是页面内容流中。

随着分流器学会推荐更重的流程,理由的集合还会继续增长。请把 reasons 当成一个开放的列表,按你关心的取值来分流,不要假设它已经穷尽。

版面信号

除了 OCR 结论,每一页还带一个嵌套的 layout 对象,描述这一页排版有多难 —— 多栏正文、表格、密集图形。这些信号是在空间投影之后算出来的,因此它们看到的是重建出的区域树,而不是原始文字条目。

版面复杂度是刻意与 needs_ocr 分开的。一份清晰、完全数字化的双栏论文根本不需要 OCR,但版面很复杂;版面理由永远不会让 needs_ocr 变成 true。按你真正关心的那一路来分流。

Reason含义
multi-column该页被拆成一列以上的文本栏。
table-likely在该页检测到了有边框或无边框的表格结构。
dense-graphics图形占据了页面很大一部分。
字段说明
column_count检测到的文本栏数,总是 ≥ 1。
ruled_table_count由表格线检测出的表格数量。
ruled_table_coverage有框表格覆盖页面的比例(0–1)。
text_table_run_count检测到的无边框、按文本对齐的表格段数量。
figure_count检测到的图形区域数量。
figure_coverage图形覆盖页面的比例(0–1)。
is_complex专门针对版面的结论。等价于 reasons 非空。
reasons该页被标记上的所有版面理由(见上表)。

CLI

终端窗口

lit is-complex document.pdf

该命令始终把每页的 JSON 打到 stdout,把人类可读的结论打到 stderr,并用退出码反映结果 —— 你可以按自己工作流的习惯去消费它。

// stdout
[
  {
    "page_number": 1,
    "text_length": 0,
    "text_coverage": 0.0,
    "has_substantial_images": false,
    "image_block_count": 0,
    "image_coverage": 0.0,
    "largest_image_coverage": 0.0,
    "full_page_image": true,
    "uncovered_vector_area": null,
    "is_garbled": false,
    "page_area": 482400.0,
    "needs_ocr": true,
    "reasons": ["scanned"],
    "layout": {
      "column_count": 2,
      "ruled_table_count": 1,
      "ruled_table_coverage": 0.18,
      "text_table_run_count": 0,
      "figure_count": 3,
      "figure_coverage": 0.31,
      "is_complex": true,
      "reasons": ["multi-column", "table-likely", "dense-graphics"]
    }
  }
]
# stderr
COMPLEX — 1/1 page(s) need OCR

只要有任意一页需要 OCR,退出码就非零,因此这条命令可以直接当作 shell 判断条件:

终端窗口

# Only parse with --no-ocr when the document is simple
lit is-complex document.pdf --quiet && lit parse document.pdf --no-ocr

把 JSON 管道给 jq 就能针对单页做处理。下面这个例子会列出需要 OCR 的页码:

终端窗口

lit is-complex document.pdf --compact | jq '[.[] | select(.needs_ocr) | .page_number]'

选项

参数说明
--compact输出紧凑、不含空白的 JSON,而不是美化排版。
--max-pages <N>最多检查多少页(默认:1000)。
--target-pages <SPEC>只检查指定页,例如 "1-5,10,15-20"。
--password <PASS>加密/受保护文档的密码。
-q, --quiet抑制 stderr 的日志输出。

在解析时顺带检查

lit is-complex 是一次独立的预解析检查。如果你本来就要解析文档,只希望这些信号跟内容一起出来,那就给 lit parse 传 --complexity —— 它会在 JSON 输出的每一页上加一个 complexity 对象,字段与这里描述的完全一致。

终端窗口

lit parse document.pdf --format json --complexity

这个开关默认关闭:计算版面信号需要完整的路径投影,因此只在你要求时才运行。

lit is-complex 一定会填充 layout。而在 lit parse 里,只有设置了 --complexity 时才会出现 complexity 对象(以及它的 layout)。

库

同样的检查也能以编程方式调用,它每页返回一条记录。

  • TypeScript
  • Python
  • 浏览器(WASM)
import { LiteParse } from "@llamaindex/liteparse";

const parser = new LiteParse({ ocrEnabled: false });
const pages = await parser.isComplex("document.pdf");

const complex = pages.some((p) => p.needsOcr);
if (complex) {
  // Route to a heavyweight pipeline, like LlamaParse
  ...
} else {
  // Cheap path — skip OCR entirely
  const result = await parser.parse("document.pdf");
}

// Inspect why specific pages were flagged
for (const page of pages.filter((p) => p.needsOcr)) {
  console.log(`Page ${page.pageNumber}: ${page.reasons.join(", ")}`);
}
from liteparse import LiteParse

parser = LiteParse(ocr_enabled=False)
pages = parser.is_complex("document.pdf")

if any(p.needs_ocr for p in pages):
    # Route to a heavyweight pipeline, like LlamaParse
    ...
else:
    # Cheap path — skip OCR entirely
    result = parser.parse("document.pdf")

# Inspect why specific pages were flagged
for page in pages:
    if page.needs_ocr:
        print(f"Page {page.page_number}: {', '.join(page.reasons)}")
import { LiteParse } from "@llamaindex/liteparse-wasm";

const parser = new LiteParse();
const pages = await parser.isComplex(pdfBytes); // Uint8Array

const complex = pages.some((p) => p.needsOcr);

库和 CLI 都既接受原始字节,也接受文件路径,因此你可以对已经加载进内存的文档直接跑这项检查。

每页字段

每条记录都带着结论背后的原始信号,因此你可以自己定阈值,而不必只依赖 needs_ocr:

字段说明
page_number从 1 开始的页号。
needs_ocr结论:该页不能只走廉价的纯文本路径。等价于 reasons 非空。
reasons该页被标记上的所有理由(见上表)。needs_ocr 为 false 时恰好为空。
text_length可用原生文字的长度(乱码/无法映射的文字不计入)。
text_coverage原生文字覆盖页面面积的比例(0–1)。
has_substantial_images是否存在被计入的行内位图图形。
image_block_count被计入的位图对象数量(整页背景不计入)。
image_coverage图片边界框面积之和除以页面面积,上限为 1。
largest_image_coverage被计入的最大单张图片面积除以页面面积,上限为 1。
full_page_image一整张位图覆盖了页面 ≥90% —— 这是把扫描件与空白页区分开来的信号。
uncovered_vector_area未被原生文字覆盖的填充矢量轮廓面积(pt²)。当更廉价的信号已经能定论时为 null/undefined。
is_garbled原生文字是否解码成乱码。
page_area页面面积(pt²)。
layout该页嵌套的版面信号。未计算版面时不出现。

后续步骤

  • OCR 配置:搭好你用来承接复杂文档的 OCR 后端。
  • 库用法:TypeScript 与 Python 的完整编程 API。
  • CLI 参考:完整的命令与选项参考。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。