OCR と書類の認識
受け口の読み取りの設定、状態と理由のコード、結果の API、書類の種類と項目(認識)。
このページの見出し
スキャン・FAX・フォルダ(PC)と API(スマートフォンの写真など。20.12)から受け口に届いた書類を、OCR の処理で読み、品目といっしょに保管する。
20.2 受け口の設定
パネルの「受け口」→「OCR」で、受け口ごとに決める(所有者・管理者)。API キーでは変えられない(送信先と同じく、パネルだけ)。
API の GET /api/v1/inboxes で読める(ocr: {mode, lang, deliver, capture})。
| 項目 | 値 | 既定 | 意味 |
|---|---|---|---|
mode(読み取り) | off(しない)・text(文字)・text+tables(文字と表)・text+tables+recognize(文字と表と項目) | off | text は OCR の kind=plain、text+tables は kind=document(表・見出しを含む)、text+tables+recognize は kind=recognize(書類の種類の判定と項目の抜き出しまで。20.9) |
lang(言語) | ja・en・zh・ko・auto | ja | OCR へのヒント |
capture(撮り方) | scan(スキャン・FAX・PDF)・photo(紙・名刺を撮った写真)・sheet(名刺を並べたスキャン) | scan | 画像のときだけ OCR の処理 の capture に渡す(PDF・scan は渡さない)。photo は紙の領域をホモグラフィで正面に直し、sheet は名刺ごとにページを分けて(傾き・90° 回しを直した約 91×55 mm の画像を、上の行から左から右へ。1 ページ = 1 枚の名刺)読む。結果の pages[i] が i 番目の名刺で、bbox はその名刺の画像のもの。領域が見つからなければ元のまま読む。ページの向き(90・180・270°)は、ワーカーが名刺ごとに自動で直す(rotation)。scan のスキャン・FAX の傾きは、OCR の処理 が自動で直す(deskew。設定は不要) |
deliver(知らせ) | immediate(すぐ)・after_ocr(読み取りのあと) | immediate | 下の 20.5 |
- 有効にするには、サーバーに OCR の接続先(20.8)があり、契約の
ocr_pages_monthが 1 以上であること。どちらかが無ければ保存できない。 - 設定を変えると
inbox.ocrを記録する。変えたあとに届いた書類から効く。 - 書類の種類の判定と項目の抜き出しは
text+tables+recognize(20.9)。
20.3 状態
品目の OCR の状態(API の ocr.status・status):
none(OCR をしない受け口)
queued ──渡した──▶ running ──▶ done | partial | unreadable | failed
│ │
│ └─(上限を超えた)──▶ skipped
├─(渡せないまま 30 分)──▶ failed(ocr_unavailable)
└─(上限・契約)──▶ skipped
最初から: skipped(quota_exceeded・plan_disabled)・failed(ocr_unavailable)
status | 画面 | 意味 |
|---|---|---|
none | — | OCR をしない受け口(OCR の行が無い) |
queued | 待ち | 渡す順番を待っている(混雑・接続の失敗のやり直し中も) |
running | 処理中 | OCR の処理 に渡した |
done | 完了 | 全ページ読めた |
partial | 一部 | 一部のページが読めなかった(ページごとの状態は pages[]) |
unreadable | 読めませんでした | どのページも読めなかった・書類を受け付けてもらえなかった |
failed | 失敗 | 処理の失敗・時間切れ・OCR が使えない |
skipped | 上限超え・契約外 | 契約の都合で読まなかった(書類は届ける) |
ページごとの状態(pages[].status): done(読めた)・unreadable(読めなかった。message は「読めませんでした」、detail に理由)。
時刻: created_at(受け取り)・started_at(渡した)・finished_at(終わった)。数: pages_total・pages_done(読めたページ)・tables_count。
20.4 理由のコード
終わりの状態には、決まったコードが付く(code・message)。読めない(中身)・処理の失敗・契約の都合は、コードも出来事も分ける。
code | status | 出来事 | message | 起きるとき |
|---|---|---|---|---|
unreadable | unreadable | item.ocr.failed | 読めませんでした | どのページも読めなかった。書類を受け付けてもらえなかった(pdf_rejected・image_rejected・形式違い) |
ocr_failed | failed | item.ocr.failed | 読み取りに失敗しました | OCR のジョブの失敗、51 ページ以上(「ページが多すぎます」を添える)、結果が大きすぎる、結果が読めない |
ocr_timeout | failed | item.ocr.failed | 時間内に終わりませんでした | 受け取りから 30 分で終わらない。OCR 側の期限切れを出し直しても、また期限切れ |
ocr_unavailable | failed | item.ocr.failed | OCR を使えませんでした | 30 分のあいだ一度も渡せなかった(止まっている・混み続けている・鍵の誤り)。OCR の接続先の設定が無い |
quota_exceeded | skipped | item.ocr.skipped | 今月の OCR の上限を超えました | 今月の使用量が契約の ocr_pages_month に達している・この書類を足すと超える |
plan_disabled | skipped | item.ocr.skipped | 契約に OCR がありません | 契約の ocr_pages_month が 0 |
unsupported_document | failed | item.ocr.failed | 対応していない書類です | text+tables+recognize で、マイナンバーカードと判定された(20.9)。文字も項目も残さない |
done・partialにはコードが無い(partialの読めなかったページはpages[].code = unreadable)。- 上限で断る API の呼び出しは無い(受け取りは上限でも通し、
skippedにする)。
20.5 知らせ(Webhook)
送信先で、出来事を選ぶ(パネルの「送信先」。Webhook)。どれも書類の出来事なので、item.received と同じく、受け口で届け先を絞る。
| 出来事 | いつ | 既定 |
|---|---|---|
item.received | 届いた(immediate: すぐ。after_ocr: OCR が終わってから) | 選ぶ |
item.ocr.started | OCR の処理 に渡した | 選ばない |
item.ocr.done | 読めた(ocr_status: done・partial) | 選ばない |
item.ocr.failed | 読めなかった・失敗した(unreadable・ocr_failed・ocr_timeout・ocr_unavailable) | 選ばない |
item.ocr.skipped | 契約の都合で読まなかった(quota_exceeded・plan_disabled) | 選ばない |
item.recognized | 書類の種類が決まり、項目を抜き出した(text+tables+recognize の受け口だけ。20.9) | 選ばない |
immediate(既定)
item.received(すぐ。ocr: {status: "queued", …}を含む)item.ocr.started(選んだときだけ)item.ocr.done・item.ocr.failed・item.ocr.skippedのどれか
after_ocr
OCR が終わる(失敗・時間切れ・上限を含む)まで item.received を待たせ、ocr に結果の要約を入れて 1 回で知らせる。
1 回だけ受け取りたいときは、item.received だけを選ぶ。OCR の出来事も選べば、item.received のあとに届く。
OCR が最初から終わっている(上限・契約に無い・接続先が無い)ときは、待たせずにすぐ知らせる。
本文
本文は小さくする(書類・文字は入れない)。結果は API で読む。
{"event":"item.ocr.done","tenant":"acme","delivery_id":"dlv_01JA…",
"inbox":"受付","item_id":"itm_01JA…","ocr_id":"ocr_01JA…","ocr_status":"partial",
"pages_total":3,"pages_done":2,"tables":1,"at":1760000000,
"ocr_url":"https://acme.cloudpaper.appz.jp/api/v1/items/itm_01JA…/ocr"}
item.ocr.failed・item.ocr.skipped には code・message も入る。item.ocr.started の ocr_status は running。
OCR の出来事には download_url・ack_url は入らない(item.received だけ)。
item.received の ocr(OCR をする受け口だけ):
"ocr":{"ocr_id":"ocr_01JA…","status":"done","pages_total":2,"pages_done":2,"tables":1,"url":"https://…/api/v1/items/itm_…/ocr"}
- 送る順: 同じ送信先には、積んだ順に送る(
item.received→item.ocr.*)。ただし再送があると前後しうる。状態は API のstatusで確かめること。 - 署名・再送・
delivery_idでの重複の除き方は、ほかの出来事と同じ(Webhook)。
20.6 API
scope は inbox(full でも可)。API リファレンス の 5.8。
| メソッド | パス | 内容 |
|---|---|---|
| GET | /items/{id} | 品目 1 件(未確認・確認済み・履歴)と ocr の要約 |
| GET | /items/{id}/ocr | OCR の状態と結果 |
| GET | /items/{id}/ocr/tables.csv | 表の CSV |
| GET | /items/{id}/fields | 認識の結果(書類の種類と項目。20.9) |
品目の一覧(/inboxes/{name}/items)・履歴(/history・/history/{id})の各行にも ocr(status・code・pages_total・pages_done・tables・url)が入る。OCR をしない品目は {"status":"none"}。
GET /items/{id}/ocr
{"item_id":"itm_…","ocr_id":"ocr_…","status":"partial","mode":"text+tables","lang":"ja","deliver":"immediate",
"pages_total":2,"pages_done":1,"tables_count":1,"attempt":1,"created_at":…,"started_at":…,"finished_at":…,
"engine":"paddle","model":"PaddleOCR-VL-…",
"text":"…","markdown":"…",
"tables":[{"page":0,"index":0,"rows":[["品名","金額"],["紙","1,000"]]}],
"pages":[
{"index":0,"width":1654,"height":2339,"status":"done","text":"…","markdown":"…",
"blocks":[{"label":"text","text":"請求書","bbox":[120,400,900,520],"confidence":0.98}]},
{"index":1,"width":1654,"height":2339,"status":"unreadable","code":"unreadable","message":"読めませんでした","detail":"空","text":"","markdown":""}]}
- 終わっていないときは、
statusとページの状態(分かっていれば)だけ。code・messageは終わりの理由があるとき。 page・indexは 0 から。bboxはページの画像(PDF は 200 dpi で描いた画像)の画素[x0, y0, x1, y1]。PDF のポイントには × 72 / 200。confidenceは、モデルが出すときだけ入る。- 表は、
text+tablesの受け口だけ。ブロックのlabelがtableのもの(無ければページの Markdown)から取り出す。 pages[].rotation(0 のときは無い): OCR の処理 が向き(90・180・270°)を直すために、画像を時計回りに回した角度。その場合、width・height・blocksのbboxは回したあとの画像のもの(90・270 は縦横が入れ替わる)。元の画像に重ねるときは、逆に回してから使う。text_corrected(とブロックのcorrected・corrections): OCR の処理 が、辞書(IPA 辞書と SudachiDict の名詞)と前後の文字で読み違いを直した文字(直したときだけ。textは読んだまま)。パネルの書類の画面は、両方を並べて出す。仕組みは- 結果が大きすぎて位置を保管しなかったときは
blocks_dropped: true(blocksが無い)。 - 品目が無い・消えた・別のテナント・形の違う ID は 404。OCR をしない品目は
{"status":"none"}。
GET /items/{id}/ocr/tables.csv
text/csv; charset=utf-8・BOM つき・attachment。表が複数なら、空の行で区切る。
=・+・-・@・タブで始まるマスは、表計算ソフトで式にならないよう先頭に ' を付ける(書類の中身は信用しない)。
結果が無ければ 404。
20.9 認識(書類の種類の判定と項目の抜き出し)
受け口の mode = text+tables+recognize。OCR の処理 の kind=recognize(OCR → 種類の判定 → 種類別の項目の抜き出し → Go での確かめ。
に渡す。本人確認(eKYC)ではない(券が本物か・本人かは確かめない)。
対象は名刺(並べたスキャンは 1 枚ずつ)・見積書・請求書・納品書・学生証・運転免許証(表だけ)・在留カード(項目の構造だけ)。種類のヒントは付けない(自動)。
状態は OCR の状態(20.3)に足さない。 OCR 自体は今までどおり running → done|partial|unreadable|failed で、
認識の結果は別の欄(recognition)に持つ。認識だけが失敗しても、文字・表の結果は done のまま読める。
recognition.status | 意味 |
|---|---|
(recognition が無い) | 認識をしない受け口・OCR が終わっていない・OCR が失敗した |
recognized | 種類が決まり、項目を 1 つ以上抜き出した |
unrecognized | 種類が分からない・other(項目は抜き出さない) |
failed | 項目の抜き出しだけが失敗した。code: llm_unavailable(使えない)・llm_failed(出力が読めない)・llm_quota_exceeded(OCR の処理 側の 1 日の上限) |
recognition:status・document_type(business_card・estimate・invoice・delivery_note・student_id・driver_license・residence_card・other)・fields(値のある項目の数)・needs_review・code/message(失敗のとき)。GET /items/{id}・一覧・GET /items/{id}/ocrのocr.recognitionに入る。- マイナンバーカードは対応しない。OCR の処理 が判定して断ると、OCR は
failed(code: unsupported_document)になり、 文字も項目も保管しない(結果の API は何も返さない)。個人番号を読み取る・保管する機能は無い。 - 出来事
item.recognized(recognizedになったときだけ。item.ocr.doneのあと)。本文はinbox・item_id・ocr_id・document_type・fields・needs_review・at・fields_url。項目の値は入れない。 - 契約の
ocr_pages_monthの数え方は変えない(ページ数)。
GET /items/{id}/fields
認識の結果。scope は inbox。認識の結果が無い(認識をしない・失敗・マイナンバーカード・まだ)品目は 404。
{"item_id":"itm_…","ocr_id":"ocr_…","status":"recognized","document_type":"business_card","fields_count":3,"needs_review":true,
"version":"recognition-v1","state":"done","doc_type":"business_card","doc_type_source":"rules","needs_review_fields":1,
"business_card":{"company":{"value":"株式会社…","confidence":0.97,"needs_review":false,
"source":{"page":0,"block":0,"text":"…","bbox":[…]}},
"tel":{"value":"078-…","confidence":0.5,"needs_review":true,"checks":["invalid_phone"]}}}
- 種類に合う 1 つだけが入る:
business_card・cards(並べた名刺)・quote(見積書・請求書・納品書。区分・明細・税率ごとの対象額と消費税・合計)・id_card(学生証・免許証・在留カード)。 項目の形(value・raw・computed・source・confidence・checks・needs_review)は 読み取りの仕様。 - LLM が返した元の出力(
llm_output)は保管も返しもしない(確かめる前の値を使わせない)。 - どの値も、人が確かめる前提。パネルの書類の画面は、項目を 1 つずつ並べ、
needs_reviewを「要確認」と目立たせる。誤り・低い確からしさのまま自動で他のシステムへ流さない。 - 書類と同じ置き場の
ocr/<品目 ID>.fields.json(20.11)。品目を消すと消える。
20.10 上限
| 項目 | 値 |
|---|---|
| 1 品目のページ | OCR の処理 の max_pages_per_job(既定 50)。超えると ocr_failed |
| 渡せないまま・終わらないまま | 受け取りから 30 分 |
| 問い合わせ | 渡してから 10 分後から、1 分ごと |
| 出し直し(OCR 側の期限切れ) | 1 回 |
| 読む結果 | 64 MiB |
| 保管する結果 | 16 MiB。超えたら位置(blocks)を落とし、それでも超えたら ocr_failed |
| 表 | 1 品目 200 個・1 つの表 2 万マス |
| 知らせの本文・時刻のずれ・覚える期間 | 64 KiB・5 分・48 時間 |
20.12 API で受け取る写真
スマートフォンで撮った写真(帳票・名刺・注文書など)は、PC を通さずに API(POST /api/v1/inboxes/{name}/items。API リファレンス の 5.8)で受け口に入れられる。
受け口の「API から受け取る」(accept_api。パネルだけ・既定 切)を入れたときだけ。入ったあとは PC からの書類と同じ流れ(20.1)。
- 写真の受け口は、
mode=text+tables+recognize・capture=photoを勧める(紙の領域を見つけて正面に直してから読む。名刺・帳票の種類の判定と項目の抜き出しまで)。 - 画像は保管の前に読んで書き直す。EXIF の向き(Orientation)は画素に反映してから EXIF を落とすので、OCR に渡る画像は正面の向き。
そのうえで 90・180・270° の向きは OCR の処理 も直す(
rotation)。EXIF・XMP・ICC・PNG の文字のチャンクは残らない(位置情報は保管しない)。 - 品目は
source=api・kind=photo(PDF はfile)・uploaded_by= 入れた者。 - HEIC は受け付けない(415)。サーバーには HEIC を読む部品が無い(足すと、信用しない画像を C の部品で読むことになる)。送る側(アプリ)で JPEG にする。
- OCR の契約・上限は PC からの書類と同じ(契約に OCR が無ければ受け取って
skipped)。
ご不明な点はお問い合わせください。