はじめに
AWSには昔からTextractというOCRサービスはあるものの、2025年8月現在でも日本語対応はされていません。日本のAWSエンジニアたちは、日本語OCRの必要がある際には、AzureやGCPなどの他のクラウドサービスを利用する等の回避策を行ってきました。中にはRekognitionのテキスト検出やTessaractを利用する強者もいらっしゃるようですが、精度や難易度の点で手を出しにくいものでした。
ところが、2025年の6月末にBedrockでもClaudeのPDFサポートが利用できるようになりました。これがなかなかの優れもので、本来の使い方とは若干異なるものの、日本語OCRにも十分使えますのでご紹介いたします。
利用ソフトウェア
以下の環境で検証を行っております。
- Python 3.10.14
- PyMuPDF 1.26.3
- boto3 1.34.162
準備
手書き文字の写真
題材は何でもよいのですが、知的財産の侵害が絶対にないように自作しました。
こちらは、レシートの裏に私が適当に書いた偽注文書のjpeg画像です。

PDF変換プログラム
今回利用するのはPDFを読む機能なので、jpeg -> PDFへの変換を行います。
複数の写真を一気にPDF化できるようにしていますが、今回は1枚だけで利用します。
他のものにも対応できるようにしておくと、汎用的に利用できそうですね。
import fitz
import os
def convert_jpeg_to_pdf(jpeg_paths, output_pdf_path):
"""
JPEG画像をPDFに変換する関数
Parameters:
jpeg_path(list): JPEGファイルのパス
output_pdf_path (str): 出力するPDFファイルのパス
"""
# 新しいPDFドキュメントを作成
doc = fitz.open()
for img_path in jpeg_paths:
# ファイルを開く
img = fitz.Pixmap(img_path)
# RGBでない場合はRGBに変換
if img.n > 4:
img = fitz.Pixmap(fitz.csRGB, img)
# PDFに変換
rect = fitz.Rect(0, 0, img.width, img.height)
page = doc.new_page(width=img.width, height=img.height)
page.insert_image(rect, pixmap=img)
# 保存して閉じる
doc.save(output_pdf_path)
doc.close()
print(f"[I] PDFに変換完了: {output_pdf_path}")
# 使用例
if __name__ == "__main__":
jpeg_paths = ["手書き注文書.jpg"]
output_pdf = "手書き注文書.pdf"
convert_jpeg_to_pdf(jpeg_paths, output_pdf)
生成AIにPDFを読ませるプログラム
変換したPDFを、boto3からClaude 4 Sonnetを利用して読ませるプログラムです。
せっかくなので、コストも計算しています。
import json
import boto3
import base64
import sys
import fitz
# Claude 4 Sonnet のモデルID(クロスリージョン推論用)
MODEL_ID = "apac.anthropic.claude-sonnet-4-20250514-v1:0"
REGION = "ap-northeast-1"
# Bedrock Runtime クライアント
client = boto3.client("bedrock-runtime", region_name=REGION)
# プロンプト
PROMPT = f'''
このPDFは手書きの注文書です。
以下の記載内容について教えてください。
・注文日
・納期
・注文内容
'''
def process_pdf(file_path):
# PDFを読み込む
doc = fitz.open(file_path)
for page_index in range(len(doc)):
# 新しいPDFを作成して1ページだけ追加
single_page_pdf = fitz.open()
single_page_pdf.insert_pdf(doc, from_page=page_index, to_page=page_index)
# バイナリとして保存(メモリ上)
pdf_bytes = single_page_pdf.write()
encoded_data = base64.b64encode(pdf_bytes).decode("utf-8")
# 各ページを読む
read_pdf(page_index, encoded_data)
single_page_pdf.close()
doc.close()
def read_pdf(page_index, encoded_pdf):
# リクエスト作成
request_body = {
"anthropic_version": "bedrock-2023-05-31",
"messages": [
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": encoded_pdf
},
"title": "注文書",
"citations": {"enabled": True},
"cache_control": {"type": "ephemeral"} # プロンプトキャッシュ有効
},
{
"type": "text",
"text": PROMPT
}
]
}
],
"max_tokens": 4096
}
# APIコール
response = client.invoke_model(
modelId=MODEL_ID,
contentType='application/json',
accept='application/json',
body=json.dumps(request_body)
)
# 結果表示
response_body = json.loads(response['body'].read())
print("[I] ===== 結果 =====")
for block in response_body.get('content', []):
if block.get('type') == 'text':
print(block.get('text', ''))
# 利用情報も出力しておく
print("[I] ===== 利用情報 =====")
usage = response_body.get('usage')
input_tokens = usage['input_tokens']
cache_create = usage['cache_creation_input_tokens']
cache_read = usage['cache_read_input_tokens']
output_tokens = usage['output_tokens']
cost = (input_tokens * 0.000003) + (output_tokens * 0.000015)
print(f'''
入力トークン数:{input_tokens}
キャッシュREAD:{cache_read}
出力トークン数:{output_tokens}
料金ドル :{cost}
''')
if __name__ == "__main__":
if len(sys.argv) > 1:
name_argument = sys.argv[1]
process_pdf(name_argument)
else:
print("[E] 引数に入力PDFを指定してください。")
結果
完璧じゃないですか!!
あの汚い文字を、単位なども含めてきちんと読んでいます。料金も良心的。
プロンプトで出力をjsonなどにしてもらえば、立派にOCRとして使えそうですし、一般的なOCRと異なり、文字情報の座標なども気にしなくてよいので、かなり活用の幅はありそうです。
$ python read_pdf.py 手書き注文書.pdf
[I] ===== 結果 =====
この手書きの注文書の内容について、以下のとおりお答えします:
**注文日:**
2025年8月12日
**納期:**
2025年8月20日
**注文内容:**
-
マダイ 12尾
-
タコ 8杯
-
エビ 25kg
この注文書は海産物の注文で、マダイ、タコ、エビの3種類の商品が記載されています。
[I] ===== 利用情報 =====
入力トークン数:51
キャッシュREAD:0
出力トークン数:212
料金ドル :0.003333
まとめ
- ClaudeのPDFサポートで日本語手書き文字が読める
- Bedrockから利用できるようになったので、AWSだけで日本語OCRが可能
- プロンプトを工夫すれば、もっと高度なことも簡単にできそう