🙌

FAISS

2025/02/14に公開
src/FAISS/faiss.py
import faiss
import openai
import numpy as np
import os

class FAISSWrapper:

    def __init__(self, embedding_model: str = "text-embedding-3-small"):
        """
        コンストラクタ。OpenAI APIキーと埋め込みモデルを初期化します。
        """
        self.embedding_model = embedding_model
        self.index = None  # FAISSインデックスを格納
        self.corpus = []  # オリジナルのテキストをキャッシュ

    def _get_embeddings(self, texts: list[str]) -> np.ndarray:
        """
        OpenAIの埋め込みモデルを使用してテキストをベクトル化します。
        """
        client = openai.AzureOpenAI(
            azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"),
            api_key=os.environ.get("AZURE_OPENAI_API_KEY"),
            api_version=os.environ.get("OPENAI_API_VERSION")
        )
        response = client.embeddings.create(
            model=self.embedding_model,  # OpenAIの埋め込みモデル
            input=texts
        )
        
        embeddings = [d.embedding for d in response.data]
        return np.array(embeddings, dtype='float32')

    def embedding_corpus(self, corpus: list[str]) -> np.ndarray:
        """
        コーパス全体をベクトル化し、FAISSインデックスを構築します。
        """
        self.corpus = corpus
        embeddings = self._get_embeddings(corpus)

        # ベクトル次元を取得し、FAISSインデックスを初期化
        dimension = embeddings.shape[1]
        self.index = faiss.IndexFlatL2(dimension)
        self.index.add(embeddings)  # インデックスにベクトルを追加
        return embeddings

    def rank_documents(self, query: str, top_k: int = 10) -> tuple[np.ndarray, np.ndarray]:
        """
        クエリに対して類似度の高い文書をランキングする。
        """
        if self.index is None:
            raise ValueError("FAISSインデックスが初期化されていません。embedding_corpus()を呼び出してください。")
        
        # クエリをベクトル化
        query_embedding = self._get_embeddings([query])

        # 類似度検索を実行
        distances, indices = self.index.search(query_embedding, top_k)
        return indices[0], distances[0]

    def get_original_texts(self, indices: list[int]) -> list[str]:
        """
        インデックスからオリジナルのテキストを取得する。
        """
        return [self.corpus[i] for i in indices]

# 使用例
if __name__ == "__main__":
    # 環境変数からOpenAI APIキーを取得(手動で設定も可)
    OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "YOUR_API_KEY_HERE")

    # テキストコーパス
    texts = [
        "This is a test sentence.",
        "I love programming.",
        "Artificial Intelligence is fascinating.",
        "FAISS is a library for similarity search.",
        "Python is great for data science."
    ]

    # クラスの初期化
    faiss_wrapper = FAISSWrapper(openai_api_key=OPENAI_API_KEY)

    # コーパスをベクトル化してFAISSに登録
    faiss_wrapper.embedding_corpus(texts)

    # クエリを実行
    query = "I like machine learning."
    distances, indices = faiss_wrapper.rank_documents(query)

    # 結果を表示
    print("\nクエリ:", query)
    print("\n類似したテキスト:")
    for i, idx in enumerate(indices):
        print(f"{i+1}: {faiss_wrapper.corpus[idx]} (距離: {distances[i]:.4f})")

Discussion