はじめに
非構造化文書から構造化データを抽出したいというケースは、デジタル文書を扱う業務の中で広く存在すると思います。OCRや自然言語処理技術を使う手法が一般的ですが、最近ではGPTなどの大規模言語モデルを使って、より高度なデータ抽出が可能になってきています。しかし大規模言語モデルを使ってデータ抽出を行う場合、出力データの形式にばらつきがあるという課題がありました。
Open AIでは`gpt-4o-2024-08-06`というモデルから出力データの形式をJSONスキーマで定義できるようになりました。これによって、モデルの出力データを安定してプログラムで処理できるようになります。今回はこのモデルを使って、論文PDFからメタデータを抽出する方法を紹介します。
JSONスキーマとは
JSONスキーマ(JSON Schema)とは、JSONデータの構造や形式を定義するための標準的な方法です。具体的には、JSONスキーマを使用することで、いかのようなことが可能になります。
- データの構造の定義:JSONデータがどのような構造を持つべきか、例えばオブジェクトの中にどのようなキーが含まれているべきか、各キーの値がどのような型(文字列、数値、配列、オブジェクトなど)であるべきかを定義します。
- データのバリデーション:JSONスキーマに基づいて、あるJSONデータがその構造や形式に従っているかどうかを検証(バリデーション)できます。これにより、誤ったデータが処理されるのを防ぐことができます。
- データのドキュメンテーション:JSONスキーマを使用すると、JSONデータの仕様書としても機能し、開発者間でのデータ形式の理解を助けます。
出力データ形式
はじめに出力データ形式を定義する必要があります。論文にはJATS XML(Journal Article Tag Suite)という標準規格がありますので、これを参考にしてみましょう。今回はメタデータのみを抽出対象にしますが、JATS XMLでは `front` タグの中に記述されています。JATSではとても複雑なメタデータを記述することが可能ですが、ここでは簡潔なものを考えてみます。
サンプルのPDFファイルは、JATSのサイトに例として掲載されているものを使います。https://jats.nlm.nih.gov/publishing/tag-library/1.0/FullArticleSamples/bmj_sample.pdf
```xml
<article>
<front>
<journal-meta>
<journal-id>ジャーナルの識別子</journal-id>
<journal-title>ジャーナルのタイトル</journal-title>
<issn>ISSN番号</issn>
<publisher>
<publisher-name>出版社の名前</publisher-name>
</publisher>
</journal-meta>
<article-meta>
<article-id>記事の識別子</article-id>
<title-group>
<article-title>記事のタイトル</article-title>
</title-group>
<contrib-group>
<contrib contrib-type="著者の役割">
<name>
<surname>姓</surname>
<given-names>名</given-names>
</name>
</contrib>
</contrib-group>
<pub-date>
<year>公開年</year>
<month>公開月</month>
<day>公開日</day>
</pub-date>
</article-meta>
</front>
...
</article>
```
このXMLと近い構成を持つJSON形式を考えてみます。
```json
{
"article": {
"front": {
"journal-meta": {
"journal-id": "ジャーナルの識別子",
"journal-title": "ジャーナルのタイトル",
"issn": "ISSN番号",
"publisher": {
"publisher-name": "出版社の名前"
}
},
"article-meta": {
"article-id": "記事の識別子",
"title-group": {
"article-title": "記事のタイトル"
},
"contrib-group": [
{
"contrib-type": "著者の役割",
"name": {
"surname": "姓",
"given-names": "名"
}
}
],
"pub-date": {
"year": "公開年",
"month": "公開月",
"day": "公開日"
}
}
}
}
}
```
次に、このJSON形式をJSONスキーマで定義します。Open AIのGPT-4oでは、JSONスキーマを`schema` キーの中に記述します。
```json
{
"name": "paperMetadataSchema",
"strict": false,
"schema": {
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"front": {
"type": "object",
"properties": {
"journal-meta": {
"type": "object",
"properties": {
"journal-id": {
"type": "string",
"description": "ジャーナルの識別子"
},
"journal-title": {
"type": "string",
"description": "ジャーナルのタイトル"
},
"issn": {
"type": "string",
"description": "ISSN番号"
},
"publisher": {
"type": "object",
"properties": {
"publisher-name": {
"type": "string",
"description": "出版社の名前"
}
},
"required": [
"publisher-name"
]
}
},
"required": [
"journal-id",
"journal-title",
"issn",
"publisher"
]
},
"article-meta": {
"type": "object",
"properties": {
"article-id": {
"type": "string",
"description": "記事の識別子"
},
"title-group": {
"type": "object",
"properties": {
"article-title": {
"type": "string",
"description": "記事のタイトル"
}
},
"required": [
"article-title"
]
},
"contrib-group": {
"type": "array",
"items": {
"type": "object",
"properties": {
"contrib-type": {
"type": "string",
"description": "著者の役割"
},
"name": {
"type": "object",
"properties": {
"surname": {
"type": "string",
"description": "姓"
},
"given-names": {
"type": "string",
"description": "名"
}
},
"required": [
"surname",
"given-names"
]
}
},
"required": [
"contrib-type",
"name"
]
}
},
"pub-date": {
"type": "object",
"properties": {
"year": {
"type": "string",
"description": "公開年"
},
"month": {
"type": "string",
"description": "公開月"
},
"day": {
"type": "string",
"description": "公開日"
}
},
"required": [
"year",
"month",
"day"
]
}
},
"required": [
"article-id",
"title-group",
"contrib-group",
"pub-date"
]
}
},
"required": [
"journal-meta",
"article-meta"
]
}
},
"required": [
"front"
]
}
},
"required": [
"article"
]
}
}
```
実践
それでは、実際にGPT-4oを使ってPDFからメタデータを抽出してみましょう。Open AIでは様々なプログラム言語のSDKが提供されていますが、ここでは簡単に試せるように、Playground のGUIを使ってみます。
`gpt-4o-2024-08-06` モデルのPlaygroundは以下のリンクからアクセスできます。
https://platform.openai.com/playground/chat?models=gpt-4o-2024-08-06
モデルを指定せずにPlaygroundを開いた場合は、gpt-4oモデルがデフォルトで選択されているので、プルダウンから `gpt-4o-2024-08-06` に切り替える必要があります。 また、JSONスキーマでレスポンス形式を定義するため、右ペインの `Response format`で `json_schema` を選択します。すると Add response format というポップアップが表示されるので、ここに先ほど定義したJSONスキーマを貼り付けます。
Playground ではPDFをアップロードできないので、先頭のページを画像に変換してアップロードします。 プロンプトはシンプルに `Extract metadata from the image` としてみます。
結果
以下のような結果が得られました。他の論文でも同様の形式でメタデータを抽出できか確認しながら、
プロンプトを改良していくことで、より高度なデータ抽出が可能になります。
```json
{
"article": {
"front": {
"journal-meta": {
"journal-id": "bmj",
"journal-title": "BMJ",
"issn": "0959-8138",
"publisher": {
"publisher-name": "BMJ Publishing Group"
}
},
"article-meta": {
"article-id": "3247342880",
"title-group": {
"article-title": "Evolving general practice consultation in Britain: issues of length and context"
},
"contrib-group": [
{
"contrib-type": "author",
"name": {
"surname": "Freeman",
"given-names": "George K"
}
},
{
"contrib-type": "author",
"name": {
"surname": "Horder",
"given-names": "John P"
}
},
{
"contrib-type": "author",
"name": {
"surname": "Howie",
"given-names": "John G R"
}
},
{
"contrib-type": "author",
"name": {
"surname": "Hungin",
"given-names": "A Pali"
}
},
{
"contrib-type": "author",
"name": {
"surname": "Hill",
"given-names": "Alison P"
}
},
{
"contrib-type": "author",
"name": {
"surname": "Shah",
"given-names": "Nayan C"
}
},
{
"contrib-type": "author",
"name": {
"surname": "Wilson",
"given-names": "Andrew"
}
}
],
"pub-date": {
"year": "2002",
"month": "04",
"day": "13"
}
}
}
}
}
```