YomiTokuは日本語に特化して学習したAI OCRです。Pythonパッケージとして公開されており、インストールすればCLIで簡単にOCR解析が可能です。APIもありますので、Pythonからの操作も可能です。
YomiTokuのOCR精度は十分に高いですが、自動化する際には異なるOCR処理と組み合わせることで、検証が行えます。今回はOpenAIのAPIを使って、YomiTokuのOCR結果を検証する流れを解説します。
今回検証する帳票
今回は、以下のような帳票を対象としています。
YomiTokuのインストール
YomiTokuのインストールは、 pip
コマンドで行います。
pip install yomitoku
APIを利用する
今回は自動処理なので、YomiTokuのAPIを利用します。CLIも提供しているので、解析結果だけが欲しい場合には、そちらを利用してください。
yomitoku -o /path/to/results -f md /path/to/dir
インポートする
まずは、YomiTokuをインポートします。
from yomitoku import DocumentAnalyzer
from yomitoku.data.functions import load_pdf
DocumentAnalyzerを初期化する
DocumentAnalyzerを初期化します。このとき、GPUを使う場合は device="cuda"
を指定します。
analyzer = DocumentAnalyzer(visualize=True, device="cuda")
ドキュメントを読み込む
ドキュメントを読み込みます。PDFファイルを読み込む場合は、 load_pdf
を使います。
imgs = load_pdf("/path/to/invoice.pdf")
今回利用したドキュメントは1ページしかないので、 imgs
には1つの要素が入ります。複数ある場合にはループ処理を行ってください。今回は1ページ目を取り出しています。
img = imgs[0]
OCRを実行する
OCR処理を行う analyzer
は非同期処理なので、 await
を使います。
results, ocr_vis, layout_vis = await analyzer.run(img=img)
結果を出力する
解析結果を取得します。
yomitoku_results = results.to_json("", img=img)
この時、 json
にOCR処理の結果が入ります。以下はその一部です。たとえば検証として、請求金額の合計を使います。明細やフッターなども取得できていますが、今回は省略しています。
{
:,
"paragraphs": [
:
{
"box": [
449,
500,
707,
542
],
"contents": "¥2,855,600-",
"direction": "horizontal",
"order": 5,
"role": null
},
:
],
:
}
OpenAIのAPIを利用する
次に、OpenAIのAPIを利用して処理をします。OpenAIのAPIは、APIキーを取得して利用します。APIキーは、OpenAIのサイトから取得できます。なお、OpenAIでは画像ファイルのみ対象なので、PDFは画像(PNGなど)にしてから処理します。
import argparse
import os
import sys
import json
import openai
import base64
from typing import Optional, Dict, Any
def main():
"""メイン関数"""
# OpenAI APIクライアントの初期化
client = initialize_openai_client(os.environ.get("OPENAI_API_KEY"))
# ファイルの内容に対して、解析を行う
openai_results = analyse_file(client, "/path/to/invoice.png")
if openai_results:
print("\n=== ファイル解析結果 ===")
print(json.dumps(openai_results, indent=2, ensure_ascii=False))
print("=== 解析完了 ===")
else:
print("ファイルの解析に失敗しました。")
if __name__ == "__main__":
main()
OpenAIのクライアントを初期化する関数です。キーは環境変数で設定しておくと便利です。
def initialize_openai_client(api_key: str) -> openai.OpenAI:
"""OpenAI APIクライアントを初期化する関数"""
return openai.OpenAI(api_key=api_key)
analyse_file
関数は、ファイルを読み込んでOpenAIに送信し、結果を取得する関数です。
def analyse_file(client: openai.OpenAI, file_path: str) -> Dict[str, Any]:
"""OpenAIを使って、ファイルを解析する
Args:
client: OpenAI APIクライアント
file_path: 解析対象のファイルパス
Returns:
Dict[str, Any]: ヘッダー、明細、フッターを含むJSON形式のデータ
"""
try:
# ファイルが存在するか確認
if not os.path.exists(file_path):
print(f"エラー: ファイル '{file_path}' が見つかりません。", file=sys.stderr)
return None
# ファイル名から拡張子を取得
_, file_extension = os.path.splitext(file_path)
file_extension = file_extension.lower()
# ファイル解析のためのプロンプト
prompt = """
このファイルを解析して、以下の3つの部分に分けてください:
1. ヘッダー部分
2. 明細部分
3. フッター部分
それぞれの部分について、構造と内容を詳細に説明してください。
結果はJSON形式で返してください。
"""
# ファイルの種類に応じた処理
image_content = None
if file_extension in ['.jpg', '.jpeg', '.png']:
# 画像ファイルを直接読み込む
with open(file_path, 'rb') as file:
image_content = file.read()
mime_type = f"image/{file_extension[1:]}"
else:
print(f"サポートされていないファイル形式です: {file_extension}", file=sys.stderr)
return None
if not image_content:
print("画像データの取得に失敗しました。", file=sys.stderr)
return None
# OpenAI APIを使用してファイルを解析
print("OpenAI APIを使用してファイルを解析しています...")
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": "あなたはファイル解析の専門家です。アップロードされたファイルを解析し、ヘッダー、明細、フッターに分けて情報を抽出してください。"
},
{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:{mime_type};base64,{base64.b64encode(image_content).decode('utf-8')}"
}
}
]
}
],
response_format={"type": "json_object"}
)
# 解析結果を取得
raw_content = response.choices[0].message.content
try:
analysis_result = json.loads(raw_content)
# 結果を整形
result = {
"header": analysis_result.get("ヘッダー部分", analysis_result.get("header", {})),
"details": analysis_result.get("明細部分", analysis_result.get("details", {})),
"footer": analysis_result.get("フッター部分", analysis_result.get("footer", {}))
}
# 結果が空の場合は、元のレスポンスをそのまま返す
if all(not v for v in result.values()):
print("解析結果が空のため、元のレスポンスを使用します。")
openai_results = analysis_result
except json.JSONDecodeError as e:
print(f"JSONの解析に失敗しました: {e}")
return None
return openai_results
except Exception as e:
print(f"エラー: ファイルの解析中に問題が発生しました: {e}", file=sys.stderr)
return None
結果として、以下のようなJSON形式のデータが得られます。なお、この結果を確実に受け取るには、プロンプトにて明示的に指定する必要があります。
{
"header": {
"title": "請求書",
"recipient_info": {
"name": "合名会社小田部石材商会 東京支社 御中",
"address": "〒919-5359 福井県南条群日野2-4-4",
"department": "営業部",
"contact_person": "担当者:北岡 崇典 様"
},
"issuer_info": {
"name": "株式会社ナカヤマ",
"address": {
"postal_code": "〒456-0029",
"prefecture_area": "愛知県日井市胡瓜町",
"office": "4-1-10 東城ビレ1F"
},
"phone": [
"0531-50-0067",
"0531-50-0058"
],
"email": "sato_415@example.org"
},
"invoice_info": {
"number": "123456-123",
"date": "令和13年12月21日"
},
"seal": "株式会社ナカヤマ"
},
"details": {
"request_statement": "下記の通りご請求申し上げます。",
"total_amount_due": "¥2,855,600",
"items": [
{
"no": 1,
"name": "ノートパソコン",
"quantity": "5台",
"unit_price": "120,000",
"amount": "600,000"
},
:
{
"no": 9,
"name": "モニター",
"quantity": "4台",
"unit_price": "30,000",
"amount": "120,000"
}
],
"sub_total": "¥2,596,000",
"tax": {
"rate": "10%",
"amount": "¥259,600"
},
"grand_total": "¥2,855,600"
},
"footer": {
"notes": "備考欄:",
"bank_info": {
"bank_name": "あおぞら銀行",
"branch": "夕立支店",
"account_type": "普通口座",
"account_number": "No 0123456",
"account_holder": "カ)ナカヤマ"
},
"payment_due_date": "お支払い期限:令和13年12月31日",
"payment_note": "(※お振込み手数料は御社ご負担にてお願い致します)"
}
}
この結果から、 results["details"]["grand_total"]
に請求金額が入っています。これを使って、YomiTokuの結果と比較します。
# 正規表現で、数値でないものは除去
yomitoku_total = re.sub(r"[^0-9]", "", yomitoku_results["paragraphs"][5]["contents"]) # 2855600
openai_total = re.sub(r"[^0-9]", "", openai_results["details"]["grand_total"]) # 2855600
assert int(yomitoku_total) == int(openai_total)
このようにして、YomiTokuの結果とOpenAI APIによる結果を検証できます。
検証のメリット・デメリット
OpenAIのAPIは、有料です。また、ネットワークを使うので、結果が返ってくるのに時間を要する場合があります。そのため、常時検証するのではなく、定期的にテストするなどでも十分でしょう。
YomiTokuは商用では有償ですが、実行回数などによる課金は発生しません。また、データを自社内に留めて利用できますので、セキュリティ的にも安心して利用できます。さらに、同様の帳票であれば同じように結果が得られるので、システム自動化しやすいのがメリットです。
こうした複数のAIによる検証により、信頼性や精度の向上を図れるでしょう。AIによる業務フロー自動化を行う際には、こうした検証・テスト工程をフローに含めることをお勧めします。
ライセンス
YomiTokuのライセンスはコモンズ証 - 表示 - 非営利 - 継承 4.0 国際 - Creative Commonsです。非商用での個人利用、研究目的においては、ご自由に利用できます。商用目的での利用に関しては、商用ライセンスが必要です。
まとめ
YomiTokuの精度を検証する際には、他のOCR処理が可能なAIと比較してみると良いでしょう。OpenAI APIは有名なLLMであり、検証に用いるのにちょうど良いかと思います。
YomiTokuは日本語に特化しており、日本語のOCR処理には最適です。また、Pythonパッケージとして提供されているため、簡単に利用できます。ぜひ、AI OCRを使って業務効率化を実現してください。