Claude3 APIを使ってPDFから情報を抽出
こんにちはkirigayaです。(・ω・)ノ
連載風で書いていこうと思います。
Claude3を使ってPDFをデータ化して
最終的にはデータウェアハウスに入れるまでの道のりを記事にしようと思います。
今回はPDFから必要な情報を抽出してDataFrameにするところまでです。
使うもの
- poetry
- Claude3 API
- pypdf
- pandas
それではさっそくやっていきましょう。
開発環境はローカルに構築したvenv使っていきます。
PCはMacです。
Claude3のAPIを何回かすぐに試してみたい!という人は
GoogleColaboratoryでAPI keyを登録して使ってみるのが一番簡単だと思います!
Claude3でPDFから情報を抽出します。
今回使うPDFは履歴書です。(中身は生成しました)
※今回はpypdfでテキストを抽出してテキストの中から該当する情報を抽出していきます
※画像とテキストのハイブリッドも試す予定
import re
import anthropic
import pandas as pd
from pypdf import PdfReader
client = anthropic.Anthropic(
# defaults to os.environ.get("ANTHROPIC_API_KEY")
)
# MODEL_NAME = "claude-3-opus-20240229"
def get_completion(client_obj, prompt_obj: str) -> str:
#メッセージを作成
return client_obj.messages.create(
model="claude-3-sonnet-20240229",
max_tokens=2048,
messages=[{
"role": 'user', "content": prompt_obj
}]
).content[0].text
def extract_text_from_pdf(file_path: str) -> str:
"""
PDFファイルからテキストコンテンツを抽出し、単一の文字列として返します
Args:
file_path (str): PDFへのパス
Returns:
str: テキストコンテンツ
"""
text_list: list[str] = []
reader = PdfReader(file_path)
number_of_pages: int = len(reader.pages)
# ページ毎にテキストを抽出
for i in range(number_of_pages):
page_data: dict = reader.pages[i]
# 改行を削除して抽出
page_text: str = page_data.extract_text(extraction_mode="layout", layout_model_space_vertically=False)
text_list.append(page_text)
combined_text: str = "".join(text_list)
# テキストの連続した空白を1つの空白に置き換える
combined_text = re.sub(r'\s+', ' ', combined_text)
return combined_text
data = extract_text_from_pdf("履歴書テストデータ.pdf")
prompt = f"""ここに履歴書があります: <curriculum vitae>{data}</curriculum vitae>
情報が抽出できない時はNoneを入力してください
以下の情報を抽出しJSON形式で生成してください:
1. 名前を抽出してください(名前キーで)
2. 名前のふりがな部分を抽出してください(ふりがなキーで)
3. 性別を抽出してください(性別キーで)
4. 年齢を抽出してください(年齢キーで)
5. 生年月日を抽出してください(生年月日キーで)
6. 電話番号を抽出してください(TELキーで)
7. 郵便番号を抽出してください(郵便番号キーで)
8. 住所を抽出してください(住所キーで)
9. 住所のふりがな部分を抽出してください(住所ふりがなキーで)
10. 学歴 職歴を順番に全て抽出してください(学歴職歴キーで)
11. 自己PR、志望動機を抽出してください(自己PR_志望動機キーで)
"""
extract_entity: str = get_completion(client, prompt)
# JSON文字列をPythonの辞書に変換
data_dict = json.loads(extract_entity)
# 辞書をDataFrameに変換
df = pd.DataFrame([data_dict])
生成されたテキストはこんな感じ
データフレームにするとこんな感じ
学歴のところとかもう少し細かく指示だして綺麗に抽出したいな...
json
で抽出するのとcsv
で抽出するのどちらがいいんだろう...
csv
の方が良い気がしてきた...
レートリミットについて
使用ティア | ティアに進むための要件 | 月間の最大使用量 |
---|---|---|
クレジット購入 | 初回購入後の待機 | |
Free | なし | 0日 |
Build ティア 1 | $5 | 0日 |
Build ティア 2 | $40 | 7日 |
Build ティア 3 | $200 | 7日 |
Build ティア 4 | $400 | 14日 |
Scale | なし | なし |
制限ティア | 分あたりのリクエスト数 (RPM) | 分あたりのトークン数 (TPM) | 1日あたりのトークン数 (TPD) |
---|---|---|---|
Free | 5 | 25,000 | 300,000 |
Build ティア 1 | 50 | 50,000 | 1,000,000 |
Build ティア 2 | 1,000 | 100,000 | 2,500,000 |
Build ティア 3 | 2,000 | 200,000 | 5,000,000 |
Build ティア 4 | 4,000 | 400,000 | 10,000,000 |
Scale | カスタム | カスタム | カスタム |
【使用制限】
各使用ティアには、カレンダー月ごとにAPIを利用できる回数に制限があります。使用ティアの使用限度に達すると、次のティアに進むまでAPIを再度利用できるのは翌月まで待つ必要があります。
次のティアに進むためには、預金要件と必須の待機期間を満たす必要があります。高いティアほど待機期間が長くなります。注意:アカウントの過剰資金調達のリスクを最小限に抑えるために、月間使用限度額を超えて入金することはできません。
【リクエスト制限】
現在のリクエスト制限は、分あたりのリクエスト数、分あたりのトークン数、および1日あたりのトークン数で計測されています。いずれかの制限を超えると、429エラーが発生します。
プロンプトエンジニアリングのコツ
技術 | 説明 |
---|---|
明確で直接的な指示 | Claudeの回答を導くために明確な指示とコンテキストを提供する |
例を使用 | プロンプトに例を含めて、目的の出力形式やスタイルを示す |
Claudeに役割を与える | Claudeに特定の役割(例:専門家)を演じさせてパフォーマンスを向上させる |
XMLタグを使用 | 明確さのためにプロンプトと回答をXMLタグで構造化する |
プロンプトを連鎖する | 複雑なタスクを管理しやすいステップに分割して結果を向上させる |
Claudeに考えさせる | ステップバイステップの思考を促して、出力の品質を向上させる |
Claudeの回答を予め埋める | 出力の方向性を導くためにClaudeの回答をいくつかの言葉で始める |
出力形式を制御する | 一貫性と可読性を確保するために目的の出力形式を指定する |
リライトを求める | ルーブリックに基づいて改訂を要求し、Claudeに反復と出力の向上を促す |
長いコンテキストウィンドウのヒント | Claudeの長いコンテキストウィンドウを活用するプロンプトを最適化する |
実験的なメタプロンプト | 提供されたガイドラインに基づいてプロンプトのバリエーションを作成するためのメタプロンプト。実験的だが、役立つ可能性がある |
どうでしょう?うまく抽出できましたか?
次回はアプリ化かな...
お疲れ様でした!
おまけ
クラウドサービスから直接PDFを読み込みたい場合
S3のPDFファイルを直接読み込む
from io import BytesIO
import boto3
from pypdf import PdfReader
s3 = boto3.client("s3")
obj = s3.get_object(Body=csv_buffer.getvalue(), Bucket="my-bucket", Key="my/doc.pdf")
reader = PdfReader(BytesIO(obj["Body"].read()))
Discussion