はじめに
AzureOpenAIEmbeddingsでPDFをページごとにベクトル化して、ベクトル化したデータをローカルに保存してみました。ページ数が多いPDFをベクトル化すると、Azureのレート制限エラーが出てしまいます。各ページを個別にベクトル化することで、このエラーを回避することができます。
※レート制限のエラーとは、以下のようなエラーのことです。
openai.error.RateLimitError: Requests to the Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. Operation under Azure OpenAI API version 2023-05-15 have exceeded call rate limit of your current OpenAI S0 pricing tier. Please retry after 48 seconds.
このエラーを再現したい場合は、今回の記事で使うPDFを以下の記事のコードでベクトル化してみてください。
環境
- Python 3.11.5
- AzureOpenAI
- LangChain
- PyPDFLoader
- FAISS
実装
環境変数の設定
.envファイルを作成し、Azure Open AIの環境変数の設定をします。
ご自身の環境に合わせて設定してください。
# APIキー
OPENAI_API_KEY = "XXXXX"
# エンドポイント
AZURE_OPENAI_ENDPOINT = "XXXXX"
# 使用するOpenAI APIのバージョン
OPENAI_API_VERSION = "XXXXX"
必要なライブラリのインストール
以下のコマンドで必要なライブラリをインストールします。
pip install langchain openai python-dotenv install faiss-cpu pypdf PyPDF2 tiktoken
PDFの準備
今回実行するPythonファイルと同じ階層にdatasetsディレクトリを作成し、以下のPDF(Microsoft Fabricの概要に関するドキュメント)を追加してください。
Pythonファイルの中身は以下のとおりです。
import time
from langchain.document_loaders import PyPDFLoader
from langchain.vectorstores import FAISS
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import AzureOpenAIEmbeddings
import os
from dotenv import load_dotenv
load_dotenv()
embeddings = AzureOpenAIEmbeddings(
azure_deployment="text-embedding-ada-002",
openai_api_version="2023-05-15"
)
dummy_text, dummy_id = "1", 1
vectorstore = FAISS.from_texts([dummy_text], embeddings, ids=[dummy_id])
vectorstore.delete([dummy_id])
dirname = "datasets"
files = []
# ディレクトリ内のPDFファイルを検索
for filename in os.listdir(dirname):
full_path = os.path.join(dirname, filename)
if os.path.isfile(full_path):
files.append({"name": filename, "path": full_path})
for file in files:
if file["path"].endswith(".pdf"):
last_processed_page = 0 # 最後に処理したページ番号を記録する変数
while True:
try:
loader = PyPDFLoader(file["path"])
pages = loader.load_and_split()
for page_number, page in enumerate(pages, start=1):
if page_number <= last_processed_page:
continue # すでに処理されたページはスキップ
page.metadata["source"] = file["path"]
page.metadata["name"] = file["name"]
text_splitter = CharacterTextSplitter(
chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents([page])
vectorstore.merge_from(
FAISS.from_documents(docs, embeddings))
print(f"ベクトル化完了: {file['name']} - ページ {page_number}")
last_processed_page = page_number # 処理されたページを更新
break
except Exception as e:
print(f"エラーが発生しました: {e}")
print(
f"ファイル '{file['name']}' のページ {last_processed_page + 1} にてエラー。1分間待機してから再試行します。")
time.sleep(60) # 1分(60秒)待機してから再開
continue # エラー発生後、ループを続ける
vectorstore.save_local("./vectorstore")
コードの解説は以下のとおりです。
-
環境変数の読み込み:
dotenv
ライブラリを用いて、.env
ファイルから環境変数を読み込んでいます。 -
Azure OpenAI Embeddingsの設定: AzureのOpenAI埋め込みモデル(
AzureOpenAIEmbeddings
)を使用して、テキストをベクトル化します。 -
FAISSベクトルストアの初期化:
FAISS.from_texts
を使用して、ダミーテキストをベクトル化し、その後、vectorstore.delete
でこのダミーデータを削除しています。 -
PDFファイルの探索とリストアップ:
datasets
ディレクトリ内の全てのPDFファイルを探索し、それらのファイル名とパスをリストに追加しています。 -
PDFファイルの処理:
- 各PDFファイルに対して、
PyPDFLoader
を使用してPDFからテキストを読み込んでいます。 -
load_and_split
メソッドを用いて、PDFをページごとに分割します。 - 各ページのテキストを
CharacterTextSplitter
を使ってさらに分割し、これらの小さなテキストチャンクをベクトル化してFAISSベクトルストアに追加します。
- 各PDFファイルに対して、
- 例外処理: ファイルの読み込みやベクトル化中に例外が発生した場合、エラーメッセージを出力し、1分間待機した後に処理を再開します。
- ベクトルストアの保存: 最後に、ベクトルストアをローカルに保存します。
実行結果
以下が実行結果になります。
ベクトル化完了: microsoft-fabric.pdf - ページ 1
ベクトル化完了: microsoft-fabric.pdf - ページ 2
ベクトル化完了: microsoft-fabric.pdf - ページ 3
ベクトル化完了: microsoft-fabric.pdf - ページ 4
ベクトル化完了: microsoft-fabric.pdf - ページ 5
(中略)
ベクトル化完了: microsoft-fabric.pdf - ページ 445
処理がすべて完了すると、以下のようにvectorstoreが作成されます。
おわりに
読んでいただき、ありがとうございました!
以下のXアカウントにて、情報発信を行っています!