roofeehim.com

読書記録をフォーマット化してGPTで出力させた際の課題と解決案

2024年7月22日

tags: tech GPT Python reading

概要

読書記録はブクログなど特化したアプリが市場に存在するが、Obsidianで一括管理して蓄積できれば検索もしやすくサービス依存も減らせる。

しかし、アプリのようにメタデータ込みでGUIから簡単に登録できないから手間である。

この作業の簡略化のため、GPTでweb検索させて、書籍のメタデータをフロントマターに記載してもらい、あらすじなどを含めたフォーマットで入力補助を試みた。

出力させたフォーマット

---
書籍名: "地図と拳"
著者: "小川哲"
ジャンル: "歴史小説"
出版日: "2022年6月24日"
出版社: "集英社"
ページ数: 640ページ
ISBN: 978-4-08-771801-0
評価: 4.5/5
タグ: ["書籍", "小川哲", "歴史小説", "直木賞", "山田風太郎賞"]
---

# 地図と拳

## 概要
- **著者**: 小川哲
- **ジャンル**: 歴史小説
- **出版日**: 2022年6月24日
- **出版社**: 集英社
- **ページ数**: 640ページ
- **ISBN**: 978-4-08-771801-0

## あらすじ
「地図と拳」は、第168回直木賞と第13回山田風太郎賞を受賞した小川哲の歴史小説です。物語は、日露戦争前夜から第二次世界大戦までの半世紀にわたって、満洲の架空の都市で繰り広げられる知略と殺戮のドラマを描いています。日本からの密偵に帯同して満洲に渡った通訳の細川や、ロシアの鉄道網拡大のために派遣された神父クラスニコフ、叔父に騙されて不毛の土地へと移住した孫悟空など、複数の人物の視点から物語が展開されます。

## 登場人物
- **細川**: 日本からの密偵に帯同して満洲に渡った通訳。物語の中心人物の一人。
- **クラスニコフ**: ロシアの鉄道網拡大のために派遣された神父。物語において重要な役割を果たす。
- **孫悟空**: 叔父に騙されて不毛の土地へと移住した若者。彼の視点からも物語が進行する。
- **その他の登場人物**: 満洲の様々な住民や、各国のエージェントたちが複雑に絡み合う。

## 著者紹介
小川哲(おがわ・さとし)は、1986年千葉県生まれ。東京大学大学院総合文化研究科博士課程を退学後、2015年に『ユートロニカのこちら側』で第3回ハヤカワSFコンテスト〈大賞〉を受賞してデビューしました。その後、『ゲームの王国』で第38回日本SF大賞、第31回山本周五郎賞を受賞し、『嘘と正典』で第162回直木三十五賞候補となっています。

## 特記事項
「地図と拳」は、第168回直木賞と第13回山田風太郎賞を受賞しており、その文学的価値と評価が高く、多くの読者に支持されています。物語の舞台となる満洲という地域設定は、歴史的背景を深く掘り下げ、新たな視点を提供するものとなっています。

## タグ
- #書籍 #小川哲 #歴史小説 #直木賞 #山田風太郎賞

## 引用元
- [集英社](https://www.shueisha.co.jp/books/items/contents.html?isbn=978-4-08-771801-0)
- [集英社 文芸ステーション](https://www.bungei.shueisha.co.jp)
- [読書メーター](https://bookmeter.com)
- [朝日新聞](https://book.asahi.com/article/14360259)
- [読んだ屋](https://yondaya.com)

課題と解決案

上記でGPT-4oにて、小川哲の『地図と拳』を例に、主観を省いたメタデータでmdを出力させた。

集英社のページが存在するため、概ね情報を拾えるものの、具体性が高いこともあり、細部においての正確性においては期待できない。

何冊か同様のフォーマットで出力したものの、発売日やページ数、ISBNなどで明確な誤りが見られた。

GPTsを使用して今回の出力に特化したものを作成したが、結果の正確性に変化は見られなかった。純粋にプロンプトの設定が下手なだけかもしれないが、現時点では読書記録の出力を全て任せることはできなそうだ。

ある程度、既知な情報や分野においてのみ使用した方がいい点は、ハルシネーションの対応策として依然として必要だろう。

最近、デカローグという舞台を観劇する機会があったが、その観賞記録も出力させてみた。しかしこれに関しては、俳優や演出家に対する知識がゼロなので、公式サイトを見なければ正確性は瞬時に判断できない。

そういった点も踏まえると、ある程度事実であるとすぐ判断できるコンテンツのみ記録を任せられると思う。

ただし、フォーマットを出力させるだけでも、かなり作業は簡略化された。

本に限らず、映画やアニメ、ゲームなどそれぞれに対応したフロントマターとタグ付きのフォーマットを作らせて、メタデータのみ自分で入力すれば楽そうだ。

解決案を考えるとすれば、出力が散らばるのが引用元のランダム性にあると仮定する場合、引用元を書籍を網羅的に取り扱うサイト一つに絞ると安定するだろうか。

その際にRAG的な情報検索ではなく、スクレイピングでメタデータを直接取る工程を挟めば、正確性を担保した記録が作れるかもしれない。

ただ、スクレイピングで全て引っ張ってくるなら、基本的にGPTは不要である。

しかし拾う項目が多い程コードが複雑化し、DOMが変わった時のメンテが面倒なため、比較的拾いやすそうなメタデータだけをスクレイピングでカバーしたい。

あらすじや登場人物、著者紹介やタグなどの項目に限り、引用元を絞った上で情報検索による生成ができると楽だ。

Pythonによる実装イメージ

メタデータのスクレイピング

import requests
from bs4 import BeautifulSoup

def scrape_book_metadata(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    title = soup.find('h1', {'class': 'book-title'}).text.strip()
    author = soup.find('span', {'class': 'author'}).text.strip()
    pub_date = soup.find('span', {'class': 'pub-date'}).text.strip()
    pages = soup.find('span', {'class': 'pages'}).text.strip()
    isbn = soup.find('span', {'class': 'isbn'}).text.strip()
    
    book_data = {
        'title': title,
        'author': author,
        'pub_date': pub_date,
        'pages': pages,
        'isbn': isbn
    }
    
    return book_data

# スクレイピングの実行
url = 'https://example.com/book-page'
book_metadata = scrape_book_metadata(url)

GPTを使用した詳細情報の生成

import openai

# GPT APIキーの設定
openai.api_key = 'YOUR_API_KEY'

def generate_detailed_info(book_metadata):
    prompt = f"""
    本の基本的なメタデータは以下の通りです:
    書籍名: {book_metadata['title']}
    著者: {book_metadata['author']}
    出版日: {book_metadata['pub_date']}
    ページ数: {book_metadata['pages']}
    ISBN: {book_metadata['isbn']}
    
    以下の項目について、信頼できる引用元から情報を取得し、Markdown形式で詳細情報を生成してください:
    - あらすじ
    - 登場人物
    - 著者紹介
    - タグ
    
    例えば、集英社や読書メーターのような信頼できるサイトを参照してください。
    """
    
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "あなたは書籍についての記録を記述するアシスタントです"},
            {"role": "user", "content": prompt}
        ]
    )
    
    return response.choices[0].message['content']

# 詳細情報の生成
detailed_info = generate_detailed_info(book_metadata)
print(detailed_info)