space ocr
指南文章价格文档
developer

从扫描件里取出人会读的那个顺序的文本

用 POST /ocr/text 提取阅读顺序纯文本,并按需获取仅含内容的 blocks、按 path 索引的原图坐标和明确的复核清单。

7 分钟阅读· 2026-08-31

“只要把文字给我”听起来是最简单的 OCR 请求,却也最容易悄悄破坏搜索索引。视觉 OCR 可能找对了每个词,却按检测顺序返回:左栏第一行、右栏第一行、再回到左栏。系统没有报错,文档却不再是人能顺着读的文档。

POST /ocr/text 把这个问题与字段抽取、Markdown 转换分开处理。默认的 useLlm: true 会按人的阅读顺序重排区块,并重新连接因换行断开的内容。同时,文字和来源位置仍与 Vision 观测交叉核对,不会把语言模型的转写无条件当作真值。

控制请求的两个开关

useLlm 默认为 true。多栏排版、侧栏、倾斜扫描,或要交给人阅读的文字,都应保持开启。设为 false 时会跳过 LLM 步骤,按 raw OCR 顺序返回纯 Vision 转写;该路径仍会返回文档级校验对象。

includeBlocks 默认为 false。只要全文时读取 data.values.text 即可。需要自行分块、在原图高亮或制作复核界面时再开启。开启后会增加仅含内容的 data.values.blocks、形如 data.cells["blocks[0]"] 的元数据,以及 data.review.flagged 中的区块 path。

一次请求

下面开启 includeBlocks,以便把待复核文字追溯到原图。认证和全部参数见 API 文档

1
2
3
4
5
6
7
8
9
curl -X POST https://api.space-ocr.com/ocr/text \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://example.com/page.jpg",
    "imageType": "url",
    "useLlm": true,
    "includeBlocks": true
  }'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{
  "status": "success",
  "data": {
    "values": {
      "text": "樱花贸易有限公司\n发票\n合计 1,451元",
      "blocks": [
        {
          "text": "樱花贸易有限公司"
        },
        {
          "text": "发票\n合计 1,451元"
        }
      ]
    },
    "cells": {
      "blocks[0]": {
        "box": {
          "xmin": 60,
          "ymin": 48,
          "xmax": 470,
          "ymax": 92
        },
        "quad": [
          {
            "x": 60,
            "y": 48
          },
          {
            "x": 470,
            "y": 48
          },
          {
            "x": 470,
            "y": 92
          },
          {
            "x": 60,
            "y": 92
          }
        ],
        "verified": true,
        "review": null,
        "evidence": {
          "text_match": true,
          "source": "token_id"
        }
      },
      "blocks[1]": {
        "box": {
          "xmin": 58,
          "ymin": 190,
          "xmax": 510,
          "ymax": 274
        },
        "quad": [
          {
            "x": 58,
            "y": 190
          },
          {
            "x": 510,
            "y": 190
          },
          {
            "x": 510,
            "y": 274
          },
          {
            "x": 58,
            "y": 274
          }
        ],
        "verified": false,
        "review": {
          "reasons": [
            "text_mismatch"
          ]
        },
        "evidence": {
          "text_match": false,
          "source": "char_matcher_fallback"
        }
      }
    },
    "review": {
      "unit": "block",
      "total": 2,
      "boxed": 2,
      "verified": 1,
      "flagged": [
        {
          "path": "blocks[1]",
          "reasons": [
            "text_mismatch"
          ]
        }
      ],
      "by_reason": {
        "text_mismatch": 1
      },
      "coverage": {
        "recovered_blocks": 0,
        "vision_tokens": 8,
        "tokens_claimed": 8,
        "token_coverage": 1
      }
    },
    "image": {
      "width": 1654,
      "height": 2339
    },
    "source": "llm"
  }
}

按职责读取响应

  • data.values.text 是全文。开启 blocks 后,同样内容还会按 { text } 单元放在 data.values.blocks,内容中不混入坐标。
  • data.cells[path] 是原图证据的旁路数据。boxquad 使用 0~1000 页面坐标,可结合 data.image.widthheight 投影到处理后图像。verified 表示区块与对应位置的 Vision 文字在规范化后是否一致,不是准确率百分比。
  • data.review.flagged 是实际复核清单。每个 path 都能直接查找 data.cells[path]review.reasons 给出建议检查的原因。
  • data.source 在阅读顺序路径中为 llm,在 Vision 路径中为 vision

索引程序可以只消费 values.text,复核界面则消费 reviewcells,无需从正文中拆坐标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const { data } = await response.json();

indexDocument(data.values.text);

for (const flag of data.review.flagged) {
  const cell = data.cells?.[flag.path];
  queueForReview({
    path: flag.path,
    reasons: flag.reasons,
    box: cell?.box,
    quad: cell?.quad,
    image: data.image,
  });
}
✓ Verified

回退不会被隐藏。 LLM 阅读顺序步骤失败时,端点不会把它变成 OCR 错误,而会返回 Vision 转写。此时 data.source"vision",原因写入 data.warning。未被任何区块认领的 Vision token 也可能作为 cells[path].evidence.source: "unclaimed_tokens" 的回收区块附加,从而暴露遗漏而不是悄悄丢弃。

选纯文本还是 Markdown

全文检索、向量化、差异比较、无障碍信息流等场景,如果不需要把标题和表格保留成独立类型,纯文本更合适。需要结构时改用 POST /ocr/markdown图像转 Markdown 指南介绍了它的元素响应。坐标与复核元数据可继续阅读 OCR 原图坐标

  1. 选择阅读顺序路径
    把图像发送到 POST /ocr/text。阅读顺序重要时保留默认 useLlm:true,只有 raw Vision 顺序可接受时才设为 false。
  2. 需要来源证据时请求 blocks
    设置 includeBlocks:true,获取 values.blocks、按 path 索引的 cells 和区块级 review;只需全文时保持默认值。
  3. 处理明确的复核清单
    遍历 data.review.flagged,用 data.cells[flag.path] 取出 box 或 quad,并绘制在 data.image 所描述的图像框架上。
  4. 记录实际转写路径
    把 data.source 与正文一起保存;自动回退为 vision 时向操作者显示 data.warning。
/ocr/text 默认会修正阅读顺序吗?
会。useLlm 默认为 true,会重新排列区块并连接换行断开的内容。只有更需要 raw OCR 顺序的 Vision 转写时才设为 false。
必须请求 blocks 吗?
不必。includeBlocks 默认为 false,简单索引只读取 data.values.text 即可。需要 blocks[n] 坐标和区块级复核时再开启。
verified:true 能保证区块正确吗?
不能。它表示区块文字与链接坐标处的 Vision 文字在规范化后相符,不是准确率分数;两个读数仍可能一致地误读。
阅读顺序模型失败时会怎样?
端点会回退到 Vision 转写,把 data.source 设为 vision,并在 data.warning 中说明原因;文档级 data.review 仍会返回。
相关文章