space ocr
ガイド記事料金ドキュメント

監査証跡つきのドキュメントOCR

ほとんどのOCRは、信じるしかないテキストを返すだけ。space-ocr は抽出したすべての値に出所を添えて返します——data.cells[path] の box と quad の座標、照合の根拠である evidence、そして人が見るべきパスをまとめた data.review.flagged です。

ドキュメントからデータを抽出するのは、デモで見せるのは簡単でも、信用するのは難しいものです。モデルが請求書を読み取り、total: 2,045 と返してきても、どんな信頼度スコアでも本当には答えてくれない疑問が残ります。それはページに実際に印字されている数字なのか、それともモデルが生成したものなのか? その場限りの照会ならそれで構いません。しかし、経理、保険金支払、コンプライアンス、あるいは監査の対象になりうる業務では、「モデルを信じる」というのは管理体制とは言えません。

監査証跡がこれを解決します。むき出しの値ではなく、すべてのフィールドがページ上の検証済みの位置情報とともに返ってくる——だから人(あるいは別のシステム)が、値を読み取った正確なピクセルへ一足飛びに移動して、それを確認できます。これが、単なる答えと、根拠を示して説明できる答えとの違いです。

実際に見てみる:どの値も元の位置にさかのぼれる

下のフィールドにカーソルを合わせてみてください。レシート上のボックスが、その値を読み取った場所です——そして各フィールドは、その位置情報とあわせて自身の検証状態を持っています。

Receipts with extracted-field bounding boxes
Verified fields
KINSHO · 合計 2,045
ライフ · 合計 4,286

Each value with a box carries a verified on-page location — in data.cells[path], that is box + 4-point quad + evidence.match_ratio — on a 0–1000 normalized grid (0,0 top-left → 1000,1000 bottom-right), the same shape the live API returns. Hover a field to trace it back to the pixels it came from.

「検証済みの値」が実際に持っているもの

根拠を示せる結果とは、数値ひとつにスコアをひとつ添えたものではありません。POST /ocr/fields は、答えを別々に保存・照会・引用できる層に分けて返します。

  1. data.values — 何を読んだか。リクエストしたスキーマそのままで、予約キーが混ざらないので、そのままデータベースへ入れられます。
  2. data.cells[path].box と .quad — どこから読んだか。box は { xmin, ymin, xmax, ymax } の軸に沿った矩形で、0–1000 正規化のグリッド上(0,0 = 左上、1000,1000 = 右下)にあります。quad は順序づけられた4点で、傾き補正を一切行わないためページの傾きにそのまま追従します。パスの文法は全体で共通です(total、items[0].price)。
  3. data.cells[path].evidence — どんな根拠があったか。text_match が文字照合そのもの、source が座標の解決経路、match_ratio はその値の文字のうちページ上で位置を特定できた割合(0.85 以上で確信を持ったマッチ)です。printed_text はその座標で OCR が読み取った文字なので、values と完全一致で突合したいときに使えます。
  4. data.cells[path].verified と .review — 人手を介さずに受け入れてよいか。verified は文字スコアではなく判定です。review に理由がひとつでも載れば false、照合が走って何も立たなければ true、何も立たないが照合する相手が無ければ null になります(行ユニオンは幾何情報だけを持ちます)。review.reasons は常に配列で、ランキング順、先頭が代表理由です。
  5. data.review.flagged — 人が見る作業リスト。各要素は { path, reasons } の組で、確認すべき件数は flagged.length そのものです。
  6. data.normalized — 印字された表記と、計算に使う値の分離。スカラー型(あるいは pattern・enum を付けた string)を宣言したフィールドがあるときだけ付き、同じ読みをその型に解釈した値を values に触れずに並べます。

位置情報と根拠が値と一緒に付いてくるので、結果はブラックボックスではありません。ボックスを描画したり、パスと座標を引用したり、フラグの立ったフィールドをOCRを再実行せずに再確認したりできます。

✓ Verified

座標はモデルの言い分を鵜呑みにしたものではありません。 言語モデルが返すのは各値のテキスト——そしてどの単語トークンを使ったかのヒント——だけで、ボックスそのものは決して返しません。エンジンはそのうえで、そのテキストを、ビジョンOCRがページ上で実際に検出したシンボルと文字単位で照合します。だからボックスは、それらの文字が見つかった本物のピクセルに着地し、各値にはマッチ率——その文字のうち実際に位置を特定できた割合——が付きます。モデルのトークンヒントはノイズを含みうる(繰り返し行のあいだで取り違えることもある)ため、列・行の一貫性チェックによって、鵜呑みにせず検証されます。要点は、AIが間違えないということではなく、ページと食い違う値が黙って通らず、要確認として表に出てくるということです。照合する相手が無かった項目——行ユニオンは幾何情報だけを持ちます——は、合格を騙らずに verified: null とだけ報告します。

値をクリックすれば、そのピクセルにたどり着く

アプリ上では、これがインタラクションになります。任意のセルをクリックすると、元画像上でその値が読み取られた正確なボックスがハイライトされ、拡大したクロップと接続線が表示されます。バッチをざっと検査するのにこれ以上速い方法はありません——ドキュメント全体を見渡すのではなく、視線がそのまま該当箇所に向かいます。

任意のセルをクリック → 対応する領域が元画像上で点灯します。

修正もまた監査可能

監査証跡は、機械の出力だけの話ではありません——人が何を変更したかも含みます。セルを編集すると、space-ocr はあなたの修正を元のOCR値とは別に保存します。Original ツールチップが、エンジンが最初に読み取った内容を常に示すので、レビュアーは機械の値と人による上書きの両方を並べて確認できます。

セルを編集すると、元のOCR値が Original ツールチップの下に保持されます。

APIにも、すべての値に備わっている

これはUIだけの機能ではありません。POST /ocr/fields が返す data.cells は、total・items[0].price のようなパスをキーにしたフラットなマップで、各エントリが box、quad、verified、review、evidence を持ちます。data.review.flagged[].path も同じ文法なので、要確認の項目からその座標へ直接引けます。GET /view で保存済みのシートを照会すると、このマップはデフォルトで一緒に付いてきます——boxes=0 を付けて落ちるのは行の cells マップだけで、values・review・image はそのまま返ります。

POST /ocr/fields → レスポンス(抜粋)
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
{
  "status": "success",
  "data": {
    "values": {
      "total": "2,045",
      "items": [
        { "qty": "2", "price": "780" }
      ]
    },
    "cells": {
      "total": {
        "box": { "xmin": 595, "ymin": 974, "xmax": 781, "ymax": 1000 },
        "quad": [
          { "x": 594, "y": 975 }, { "x": 781, "y": 972 },
          { "x": 781, "y": 998 }, { "x": 595, "y": 1000 }
        ],
        "verified": true,
        "review": null,
        "evidence": {
          "text_match": true,
          "source": "vision_symbol_match",
          "match_ratio": 1.0,
          "printed_text": "2,045"
        }
      },
      "items[0].price": {
        "box": { "xmin": 693, "ymin": 640, "xmax": 781, "ymax": 668 },
        "quad": [
          { "x": 693, "y": 641 }, { "x": 781, "y": 640 },
          { "x": 781, "y": 667 }, { "x": 693, "y": 668 }
        ],
        "verified": false,
        "review": { "reasons": ["text_mismatch"] },
        "evidence": {
          "text_match": false,
          "source": "vision_symbol_match",
          "match_ratio": 0.67,
          "printed_text": "180"
        }
      }
    },
    "review": {
      "unit": "field",
      "flagged": [
        { "path": "items[0].price", "reasons": ["text_mismatch"] }
      ],
      "by_reason": { "text_mismatch": 1 }
    },
    "normalized": { "total": 2045 },
    "image": { "width": 1654, "height": 2339 }
  }
}

evidence.source は、各座標がどのように解決されたかを教えてくれます——vision_symbol_match は通常の文字照合パスで、その match_ratio を伴います。token_id は単語トークンのヒントが使われたことを意味します。ログに残したり、フィルタリングしたり、レビュアーに提示したりできるメタデータです。弱いマッチはこのキーの中に隠れるのではなく、review.reasons に low_ratio・weak_source・low_ocr_confidence といったコードとして表れ、同じパスが data.review.flagged にも並びます。理由コードはAPI契約の語彙です——コードで分岐し、まだ知らないコードには汎用の文言を出す作りにしてください。

実際に値を検証する手順

  1. 抽出結果を開く
    シートを開くか GET /view を呼び出します——各値はパスで指定でき、data.cells[path] が box、quad、review、evidence を持っています。
  2. 値をクリックする
    セルをクリックすると、その値が読み取られた元画像上の正確な領域がハイライトされます。
  3. 根拠と要確認リストを読む
    match_ratio が 1.0 ならすべての文字の位置が特定できたことを意味し、0.85 以上で確信を持ったマッチとみなされます。エンジンが決めきれなかったものは、low_ratio や text_mismatch といった理由とともに data.review.flagged に並びます。
  4. 必要なら修正する
    セルを編集して上書きします——元のOCR値は監査証跡のために Original ツールチップの下に保持されます。
OCRの監査証跡とは何ですか?
監査証跡とは、抽出されたすべての値を、元のドキュメント上の正確な位置までさかのぼってたどれることを意味します。space-ocr では、各値がパスで data.cells から引け、そこに box、ページの傾きに追従する4点の quad、そして照合の根拠である evidence が入っています。だから結果を信用任せにするのではなく、引用したり再確認したりできます。
AIがバウンディングボックスを勝手にでっち上げることはありませんか?
モデルは座標を一切返しません——返すのは値のテキストと、どの単語を使ったかのヒントだけです。エンジンはそのテキストを、ビジョンOCRがページ上で実際に検出したシンボルと文字単位で照合し、どれだけ見つかったかを match_ratio として報告します。モデルのトークンヒントも鵜呑みにはされず、列と行の一貫性と照合されます。だからボックスは、値の文字が本当に見つかった場所を反映します。この照合が捉えるのは食い違いです——ページと合わない値は、黙って通らずに data.review.flagged に上がります。ただし正しさの証明ではありません。二つのエンジンが同じ誤読で一致することはあり得るので、required・enum・pattern といった宣言したルールを併せて走らせてください。
座標はピクセル単位で返されますか?
APIは 0–1000 正規化のグリッドで返します(0,0 が左上、1000,1000 が右下)。画像の解像度には依存しません。ピクセルへの変換は pixel_x = box.xmin / 1000 × data.image.width で行えます。data.image は EXIF の向きを立て、必要なら縮小したうえで実際に読み取ったページの寸法なので、送ったファイルではなくこちらを基準にしてください。
検証に追加料金はかかりますか? OCRを再実行しますか?
いいえ。座標は標準レスポンスの一部であり、GET /view で保存済みのシートを照会してもOCRが再実行されることはなく、料金も発生しません。boxes=0 を付けて落ちるのは行の cells マップだけで、values・review・image はそのまま返ります。

自分のドキュメントで試してみる

無料プラン——月100クレジット、クレジットカード不要。すべての値が、ページ上の位置情報とともに返ってきます。

関連