はじめに
LangChainを使用して、PDF文書をベクトル化し、ローカルのベクトルストアに保存してみました。この方法により、一度ローカルに保存した後はベクトル化を再度行う必要がなくなり、回答時間を短縮することができます。LangChainを使った文書検索を開発している方におすすめです。
開発環境
- Windows 11
- Python 3.9.15
- dotenv
- LangChain
- Azure OpenAI Embeddings
- CharacterTextSplitter
- FAISS
- PyPDFLoader
実装
必要なパッケージのインストール
以下のコマンドで必要なパッケージをインストールします。
1 2 |
<span class="go">pip install langchain openai python-dotenv faiss-cpu pypdf PyPDF2 tiktoken </span> |
環境変数の設定と依存関係の読み込み
.envファイルを作成し、Azure Open AIの環境変数の設定をします。
ご自身の環境に合わせて設定してください。
1 2 3 4 5 6 7 8 9 |
# APIキー OPENAI_API_KEY = "XXXXX" # エンドポイント AZURE_OPENAI_ENDPOINT = "XXXXX" # 使用するOpenAI APIのバージョン OPENAI_API_VERSION = "XXXXX" |
必要なライブラリをインポートします。
1 2 3 4 5 6 7 8 9 10 |
<span class="kn">import</span> <span class="n">os</span> <span class="kn">from</span> <span class="n">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span> <span class="nf">load_dotenv</span><span class="p">()</span> <span class="kn">from</span> <span class="n">langchain.embeddings</span> <span class="kn">import</span> <span class="n">AzureOpenAIEmbeddings</span> <span class="kn">from</span> <span class="n">langchain.text_splitter</span> <span class="kn">import</span> <span class="n">CharacterTextSplitter</span> <span class="kn">from</span> <span class="n">langchain.vectorstores</span> <span class="kn">import</span> <span class="n">FAISS</span> <span class="kn">from</span> <span class="n">langchain.document_loaders</span> <span class="kn">import</span> <span class="n">PyPDFLoader</span> |
ベクトル化の準備
ベクトル化に使用するAzure OpenAI Embeddingsを定義します。
1 2 3 4 5 6 |
<span class="n">embeddings</span> <span class="o">=</span> <span class="nc">AzureOpenAIEmbeddings</span><span class="p">(</span> <span class="n">azure_deployment</span><span class="o">=</span><span class="sh">"</span><span class="s">text-embedding-ada-002</span><span class="sh">"</span><span class="p">,</span> <span class="n">openai_api_version</span><span class="o">=</span><span class="sh">"</span><span class="s">2023-05-15</span><span class="sh">"</span> <span class="p">)</span> |
FAISSベクトルストアの初期化
FAISSを使用して、文書を高速に検索可能な形式に変換します。
1 2 3 4 |
<span class="n">dummy_text</span><span class="p">,</span> <span class="n">dummy_id</span> <span class="o">=</span> <span class="sh">"</span><span class="s">1</span><span class="sh">"</span><span class="p">,</span> <span class="mi">1</span> <span class="n">vectorstore</span> <span class="o">=</span> <span class="n">FAISS</span><span class="p">.</span><span class="nf">from_texts</span><span class="p">([</span><span class="n">dummy_text</span><span class="p">],</span> <span class="n">embeddings</span><span class="p">,</span> <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="n">dummy_id</span><span class="p">])</span> <span class="n">vectorstore</span><span class="p">.</span><span class="nf">delete</span><span class="p">([</span><span class="n">dummy_id</span><span class="p">])</span> |
ファイルの読み込みと処理
指定されたディレクトリ内のPDFファイルを読み込み、処理します。
dirnameはご自身のディレクトリ名に合わせてください。
1 2 3 4 5 6 7 8 |
<span class="n">dirname</span> <span class="o">=</span> <span class="sh">"</span><span class="s">datasets</span><span class="sh">"</span> <span class="n">files</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">os</span><span class="p">.</span><span class="nf">listdir</span><span class="p">(</span><span class="n">dirname</span><span class="p">):</span> <span class="n">full_path</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">dirname</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span> <span class="k">if</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">isfile</span><span class="p">(</span><span class="n">full_path</span><span class="p">):</span> <span class="n">files</span><span class="p">.</span><span class="nf">append</span><span class="p">({</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">:</span> <span class="n">filename</span><span class="p">,</span> <span class="sh">"</span><span class="s">path</span><span class="sh">"</span><span class="p">:</span> <span class="n">full_path</span><span class="p">})</span> |
テキストのベクトル化とストアへの保存
読み込んだPDF文書からテキストを抽出し、ベクトル化してストアに保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<span class="k">for</span> <span class="nb">file</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span> <span class="k">if</span> <span class="nb">file</span><span class="p">[</span><span class="sh">"</span><span class="s">path</span><span class="sh">"</span><span class="p">].</span><span class="nf">endswith</span><span class="p">(</span><span class="sh">"</span><span class="s">.pdf</span><span class="sh">"</span><span class="p">):</span> <span class="n">loader</span> <span class="o">=</span> <span class="nc">PyPDFLoader</span><span class="p">(</span><span class="nb">file</span><span class="p">[</span><span class="sh">"</span><span class="s">path</span><span class="sh">"</span><span class="p">])</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Unsupported file format: </span><span class="si">{</span><span class="nb">file</span><span class="p">[</span><span class="sh">'</span><span class="s">path</span><span class="sh">'</span><span class="p">]</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span> <span class="n">pages</span> <span class="o">=</span> <span class="n">loader</span><span class="p">.</span><span class="nf">load_and_split</span><span class="p">()</span> <span class="k">for</span> <span class="n">page</span> <span class="ow">in</span> <span class="n">pages</span><span class="p">:</span> <span class="n">page</span><span class="p">.</span><span class="n">metadata</span><span class="p">[</span><span class="sh">"</span><span class="s">source</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">file</span><span class="p">[</span><span class="sh">"</span><span class="s">path</span><span class="sh">"</span><span class="p">]</span> <span class="n">page</span><span class="p">.</span><span class="n">metadata</span><span class="p">[</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">file</span><span class="p">[</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">]</span> <span class="n">text_splitter</span> <span class="o">=</span> <span class="nc">CharacterTextSplitter</span><span class="p">(</span><span class="n">chunk_size</span><span class="o">=</span><span class="mi">1000</span><span class="p">,</span> <span class="n">chunk_overlap</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="n">docs</span> <span class="o">=</span> <span class="n">text_splitter</span><span class="p">.</span><span class="nf">split_documents</span><span class="p">(</span><span class="n">pages</span><span class="p">)</span> <span class="n">vectorstore</span><span class="p">.</span><span class="nf">merge_from</span><span class="p">(</span><span class="n">FAISS</span><span class="p">.</span><span class="nf">from_documents</span><span class="p">(</span><span class="n">docs</span><span class="p">,</span> <span class="n">embeddings</span><span class="p">))</span> <span class="n">vectorstore</span><span class="p">.</span><span class="nf">save_local</span><span class="p">(</span><span class="sh">"</span><span class="s">./vectorstore</span><span class="sh">"</span><span class="p">)</span> |
これまでのPythonコードを上から順に記述し終わったら、Pythonファイルを実行します。
実行が完了すると、以下のようにvectorstoreディレクトリが作成されます。
おわりに
LangChainを使用して、PDF文書をベクトル化し、ローカルのベクトルストアに保存してみました。文書検索システム開発の際に便利です。ぜひ、試してみてください。
最後までお読みいただき、ありがとうございました! 記事に関する質問等ございましたら、コメントもしくは以下のDMにてよろしくお願いします。
https://twitter.com/t___tatsuki
参考文献
https://python.langchain.com/docs/integrations/vectorstores/faiss