ChatGPTとPyMuPDFを使用したRAGチャットボットの作成

![py-blog-rag-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3573216/f700a83d-a520-5eaa-4c70-25e059ba0346.png)

# はじめに
検索増強生成（**RAG**）技術と**ChatGPT**の先端API、そして**PyMuPDF**の効率的な**PDF**操作機能を組み合わせることは、知的なチャットボットを作成するための新たなフロンティアを提供します。

これらのチャットボットは、**PDF**文書に保存された膨大な知識を活用し、文脈を考慮しただけでなく、情報と洞察に富んだ応答を提供することができます。

このチュートリアルでは、**ChatGPT** **API**を利用して応答を生成し、ドキュメント処理に**PyMuPDF**を利用する**RAG**チャットボットの作成方法を案内します。これにより、これらの強力なツールを統合する際の強みと簡便さが強調されます。


# **PyMuPDF**を使用したチャットボットの設定
## チャットボットの目的
私たちは、世界の国々、その首都、人口規模などについて知っているチャットボットを作成したいと考えています。私たちが利用できるデータベースは、約200行のテーブルを含む6ページの**PDF**です。各行には、国名、その国の首都の名前、首都の人口、国の人口に対する割合、およびこの情報の年齢が含まれています。

このデータに関する質問に答えるだけでなく、地理的および人口統計的な文脈が及ぶ範囲まで、できる限りさらに進んでチャットボットが応答できるようにしたいと考えています。

## チャットボットの作成
ターミナルウィンドウのコマンドラインで実行されるアプリケーションを作成します。

以下の説明の基礎は、**PyMuPDF**を使用した**RAG**（Retrieval-Augmented Generation）チャットボットの例を集めたリポジトリ[**PyMuPDF**/**RAG**: **RAG** Chatbot Examples Using **PyMuPDF**](https://github.com/PyMuPDF/RAG) 内の既存の例です。私たちの例を見るには、フォルダー「country-capitals」をご覧ください。

実際にコーディングを開始する前に、事前の手順があります：

1. **OpenAI**は、アプリケーションが**API**キーを介して認証されることを要求しています。まだ持っていない場合は、[**OpenAI**のウェブサイト](https://beta.OpenAI.com/signup)に登録し、テスト目的で**API**キーをリクエストしてください。
1. スクリプトのソースを編集し、**OpenAI**の**API**キーを入力してください。
1. 以下の**Python**パッケージをインストールまたは更新してください：

```
    python pip install -U pip
    python pip install -U **PyMuPDF**
    python pip install -U **OpenAI**
```

私たちのアプリケーションは、「**REPL**」モードで動作します。つまり、**R**ead-**E**valuate-**P**rocess **L**oop（読み取り、評価、処理のループ）で動作します。

起動すると、**PyMuPDF**を1回呼び出してテキスト情報を抽出します。このテキスト文字列は、ユーザーからのすべての後続の質問の基礎として使用されます。

すべてのチャットボットと同様に、これらのテキスト文字列のサイズに制限があります。これらの制限は、**API**キーがテスト用または本番用などの目的であるかどうかによって異なる場合があります。

いずれの場合でも、**PDF**のコンテンツを読み取るために**PyMuPDF**を呼び出す関数は、**小さなサイズに最適化**されています。つまり、テーブルの行のみを読み取ります - ページ全体のテキストは読み取りません。

[スクリプトの**Python**コード](https://github.com/PyMuPDF/RAG/blob/main/country-capitals/country-capitals.py)をご覧ください - 基本的には3つの部分で構成されています：

1. 関数`extract_text_from_pdf(pdf_path)`。 先述のように、**PDF**の完全なファイル名を一度だけ引数として呼び出されます。すべてのテーブル行からなるテキスト文字列を返します。改行文字で区切られます。
1. 関数`generate_response_with_ChatGPT(prompt)`。 この関数は、ユーザーが質問を入力した後に毎回チャットボットにアクセスします。パラメーター「prompt」は、実際の質問と**PyMuPDF**関数の初期テキストの組み合わせです。
1. ユーザーの質問を受け入れ、チャットボット関数を呼び出して応答を端末ウィンドウに出力する無限ループ（「`while True: ...`」）です。

このフローチャートは、これらの構成要素間の相互作用を示しています。

![flowchart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3573216/f439afc0-f723-dd69-de91-6ab588162214.png)

# チャットボットの使用
すべての準備ステップが成功裏に実行された場合、チャットボットは次のような振る舞いを示します。

アプリケーションが質問を受け付ける準備ができると、"```==>```"が表示され、**ENTER**キーを押して入力し、送信することができます。しばらくすると、いくつかの応答が表示され、ハイフンの行 "```----------```" で終了します。

明確さのために、<font color="cc0000">質問は赤色</font>、<font color="007aff">応答は青色</font><font color="cc0000">で色付けしています</font>。


```$ python country-capitals.py```

```ファイル 'national-capitals.pdf' から204行のテーブルが読み込まれました。```

```準備完了 - 質問するか、q/Qで終了します：```

<font color="cc0000">

```==> ドイツの首都は何ですか？```
</font>

<font color="007aff">

```応答：```

```ドイツの首都はベルリンです。```

```----------```
</font>
<font color="cc0000">

```==> ベルリンの人口、絶対数と相対数は？```
</font>
<font color="007aff">

```応答：```

```2021年時点のベルリンの人口は3,677,472人です。これはドイツの総人口の約4.4%を占めます。```

```----------```
</font>


上記の応答は、**PDF**のデータに基づいているため、驚きはありません。

しかし、以下の応答は、チャットボットが実際に人口統計および地理的な文脈を把握しており、**PDF**のデータだけでは答えられない質問に対して、インターネットで追加の情報源を積極的に検索していることを示しています。

<font color="cc0000">

```==> Vaduzはテキストの一部ではありませんか？ もしそうでなければ、それについて知っていますか？```
</font>

<font color="007aff">

```応答：```

```いいえ、Vaduzはテキストの一部ではありません。それはリヒテンシュタインの首都です。```

```----------```
</font>

**PDF**にはリヒテンシュタインとその首都ヴァドゥーツが含まれていないため、チャットボットは自動的に、「Vaduz」という単語が都市であり、リヒテンシュタインの国都であると判断しました。

別の例：**PDF**データを使用して回答**できる**質問をします：

<font color="cc0000">

```==> 人口規模で見たときの最も小さい首都10都市は何ですか？```
</font>

<font color="007aff">

```応答：```
1. バチカン市国（バチカン市国）- 453
2. ニュエルムード（パラオ）- 271
3. アダムズタウン（ピトケアン諸島）- 40
4. フナフティ（ツバル）- 6,320
5. アロフィ（ニウエ）- 597
6. ナレン（ナウル）- 747
7. サウスタラワ（キリバス）- 50,182
8. スタンリー（フォークランド諸島）- 2,460
9. フライングフィッシュコーヴ（クリスマス島）- 1,599
10. ロゾー（ドミニカ）- 14,725

```----------```

</font>

しかしながら、次の質問は、その面積（平方キロメートル）における最も小さな10の都市を尋ねると解釈されます。この情報は完全にインターネットのデータから引き出す必要があります。

<font color="cc0000">

```==> 世界で最も小さな10の首都は何ですか？```
</font>

<font color="007aff">

```応答：```
1. バチカン市国（0.44 km²）
2. モナコ（2.02 km²）
3. ナウル（21 km²）
4. ツバル（26 km²）
5. サンマリノ（61 km²）
6. リヒテンシュタイン（160 km²）
7. マーシャル諸島（181 km²）
8. セントクリストファー・ネイビス（261 km²）
9. モルディブ（298 km²）
10. マルタ（316 km²）

```----------```

</font>

# 結論
**PyMuPDF**を**RAG**フレームワークに統合することで、情報提供が豊富で文脈に即した応答を行う強力なチャットボットを構築することができます。このチュートリアルは可能性の表面をほんの一部しか触れていません。**PyMuPDF**や生成モデルにより慣れてくると、チャットボットの能力を向上させるさまざまな方法が見つかるでしょう。これにより、ユーザーと効果的にコミュニケーションを取り、彼らの問いに答えるための貴重なツールとなります。

成功する**RAG**チャットボットの鍵は、アクセスできる情報の質にあります。**PyMuPDF**は、**PDF**からこの情報を抽出することが可能であり、かつ簡単であることを保証し、ライブラリの強さと開発者向けの使いやすさを示しています。幸せなコーディングを！


# ソースコード

参照: [github.com/**PyMuPDF**/**RAG**](https://github.com/PyMuPDF/RAG)

# 関連ブログ

[RAG/LLMとPDF：PyMuPDFを使用したMarkdownテキストへの変換](https://qiita.com/jamie-lemon/items/1f2eb43f439fd28202a0)

[ChatGPT APIとPyMuPDFを使用してRAGチャットボットGUIを構築する](https://qiita.com/jamie-lemon/items/f075ae56cf56723c9409)

[RAG/LLMとPDF: テキスト抽出の強化](https://qiita.com/jamie-lemon/items/455e14f83b4f5c81034b)