🦉

Claude3 APIを使ってPDFから情報を抽出

2024/03/21に公開

こんにちは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の方が良い気がしてきた...

レートリミットについて

https://docs.anthropic.com/claude/reference/rate-limits

使用ティア ティアに進むための要件 月間の最大使用量
クレジット購入 初回購入後の待機
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エラーが発生します。

プロンプトエンジニアリングのコツ

https://docs.anthropic.com/claude/docs/prompt-engineering#prompt-engineering-techniques

技術 説明
明確で直接的な指示 Claudeの回答を導くために明確な指示とコンテキストを提供する
例を使用 プロンプトに例を含めて、目的の出力形式やスタイルを示す
Claudeに役割を与える Claudeに特定の役割(例:専門家)を演じさせてパフォーマンスを向上させる
XMLタグを使用 明確さのためにプロンプトと回答をXMLタグで構造化する
プロンプトを連鎖する 複雑なタスクを管理しやすいステップに分割して結果を向上させる
Claudeに考えさせる ステップバイステップの思考を促して、出力の品質を向上させる
Claudeの回答を予め埋める 出力の方向性を導くためにClaudeの回答をいくつかの言葉で始める
出力形式を制御する 一貫性と可読性を確保するために目的の出力形式を指定する
リライトを求める ルーブリックに基づいて改訂を要求し、Claudeに反復と出力の向上を促す
長いコンテキストウィンドウのヒント Claudeの長いコンテキストウィンドウを活用するプロンプトを最適化する
実験的なメタプロンプト 提供されたガイドラインに基づいてプロンプトのバリエーションを作成するためのメタプロンプト。実験的だが、役立つ可能性がある

どうでしょう?うまく抽出できましたか?
次回はアプリ化かな...
お疲れ様でした!

おまけ
クラウドサービスから直接PDFを読み込みたい場合
S3のPDFファイルを直接読み込む

https://pypdf.readthedocs.io/en/stable/user/streaming-data.html#reading-pdfs-directly-from-cloud-services

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