從掃描件裡取出人會讀的那個順序的文字
樸素 OCR 按偵測順序回傳頁面上的所有詞,而那並不是任何人閱讀的順序。這是一份關於還原閱讀順序的純文字擷取指南——附帶逐區塊座標,以及「文字有沒有被改寫」的校驗。
「把文字給我就好」—— 聽起來是最簡單的訴求,卻是多數 OCR 整合悄悄做錯的一環。
視覺 OCR 引擎會把找到的詞按段落歸組,以 偵測順序 回傳:大致自上而下、自左而右掃過整頁。單欄便條恰好與閱讀順序一致;雙欄文章、帶側欄的發票、略有傾斜的掃描件就不是了。你會拿到左欄第一段、然後右欄第一段、再回到左欄。詞都沒錯,文件卻讀不通。
如果這些文字進入檢索索引、向量或差異比對,損害是安靜的:不報錯,只是結果慢慢變差,而沒人會追溯到 OCR 這一步。
即使不保留結構,純文字仍需要三件事
就算沒有結構要保留,可用的純文字擷取也必須回答三個問題:
- 什麼順序? 區塊要按閱讀順序出來,被換行截斷的句子要重新接上,而不是留成兩截。
- 來自哪裡? 如果你索引了一個段落,之後需要向人解釋這份文件為什麼命中,你需要那個段落的座標——頁碼不夠。
- 是不是頁面上寫的? 轉寫頁面的模型也會順手「正規化」。悄悄的改良比錯誤更糟,因為它讀起來是對的。
一次呼叫
POST /ocr/text 接收一張影像並回傳文件文字。加上 includeBlocks,還會拿到每個區塊及其座標。
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",
"includeBlocks": true
}'{
"status": "success",
"data": {
"text": "櫻花商事株式會社\n發票\n合計 1,451",
"source": "llm",
"image_size": { "width": 1654, "height": 2339 },
"review_summary": {
"unit": "block",
"total": 12,
"boxed": 12,
"text_verified": 11,
"text_mismatch": 1,
"needs_review": 1,
"flagged": [{ "path": "blocks[7]", "reason": "text_mismatch" }],
"recovered_blocks": 0,
"token_coverage": 1.0
},
"blocks": [
{
"text": "櫻花商事株式會社",
"bbox": { "xmin": 60, "ymin": 48, "xmax": 470, "ymax": 92 },
"vertices": [{ "x": 60, "y": 48 }, "…"],
"bbox_source": "token_id",
"text_verified": true,
"needs_review": false
}
]
}
}text 是整份文件拼成的一個字串(區塊以換行連接)。blocks[] 是同樣的內容,按實際定位到的單位切分,每個區塊帶 0–1000 正規化的 bbox 與 vertices。
分工值得寫清楚:字元與座標以視覺 OCR 為準,模型只被問及順序與歸組。 由它決定下一個區塊是哪個、哪些片段屬於同一塊——它無法憑空造出座標,對字元也沒有最終決定權。
text_verified,以及它為 false 的時候
每個區塊都帶 text_verified。引擎取出該區塊所主張的詞元,查出視覺 OCR 在這些座標上讀到的內容,正規化後比對。true 表示兩次判讀一致;false 表示轉寫與頁面不同——文字照樣回傳,被標記出來而不是悄悄出錯。
這不是準確率百分比。它回答的是更窄也更有用的問題:這條有沒有和像素對過,並且對上了? 對索引流程來說,一個自然的策略是全部入庫但保留標記,等到最終要展示給人時,不確定的區塊被標出來,而不是當作事實呈現。
兩種失敗被明確處理,而不是藏起來。 如果模型這一路徹底失敗(無金鑰、配額用盡、重試耗盡),端點不會報錯,而是降級為視覺轉寫並如實告知:source: "vision" 加一條 warning。另外,任何沒有被任何區塊主張的頁面詞元區間,都會作為回收區塊(bbox_source: "unclaimed_tokens")追加回來,於是掉了的段落會出現在輸出裡,而不是從輸出裡消失。
什麼時候該關掉模型
useLlm: false 給你純視覺轉寫:即時、無模型成本,代價是區塊按原始 OCR 順序。對於順序本就正確的單欄頁面,或只需判斷關鍵字是否存在的批次處理,這是划算的取捨。
當順序承載含義時就留著它——多欄排版、帶側欄的表單、有傾斜的掃描件,以及要給人看而不只是拿去比對的文字。
如果你要的是結構而不是行文(標題作為標題、表格作為表格),那是另一個端點:POST /ocr/markdown 會回傳保留版式的 Markdown,帶同樣的逐元素座標與同樣的 text_verified。