rag-embedder / utils /retriever.py
jackenmail's picture
Upload 4 files
e6a70ac verified
Raw
History Blame Contribute Delete
3.39 kB
# ─────────────────────────────────────────────────────────────
# utils/retriever.py
# FAISS vector store β€” build, save, load, search
# ─────────────────────────────────────────────────────────────
import faiss
import numpy as np
import os
import json
class FAISSRetriever:
"""
Builds and searches a FAISS vector index
from your embedded documents.
"""
def __init__(self, index_path: str = None):
self.index_path = index_path or os.getenv("FAISS_INDEX_PATH", "vector_store/index.faiss")
self.docs_path = self.index_path.replace(".faiss", "_docs.json")
self.index = None
self.documents = []
self.dimension = None
def build(self, documents: list, embeddings: np.ndarray):
"""Build FAISS index from documents and their embeddings."""
self.documents = documents
self.dimension = embeddings.shape[1]
self.index = faiss.IndexFlatL2(self.dimension)
self.index.add(embeddings)
print(f"Index built β€” {len(documents)} documents, dimension {self.dimension}")
def save(self):
"""Save FAISS index and documents to disk."""
os.makedirs(os.path.dirname(self.index_path), exist_ok=True)
faiss.write_index(self.index, self.index_path)
with open(self.docs_path, "w") as f:
json.dump(self.documents, f)
print(f"Index saved to: {self.index_path}")
def load(self):
"""Load FAISS index and documents from disk."""
if not os.path.exists(self.index_path):
raise FileNotFoundError(f"No index at {self.index_path} β€” build first!")
self.index = faiss.read_index(self.index_path)
with open(self.docs_path) as f:
self.documents = json.load(f)
print(f"Index loaded β€” {len(self.documents)} documents")
def search(self, query_vector: np.ndarray, top_k: int = 3) -> list:
"""Return top_k most relevant documents for a query vector."""
query = query_vector.reshape(1, -1).astype(np.float32)
distances, indices = self.index.search(query, top_k)
results = []
for i, dist in zip(indices[0], distances[0]):
if i < len(self.documents):
results.append({
"text" : self.documents[i],
"distance" : float(dist),
"index" : int(i)
})
return results
def add_documents(self, new_docs: list, new_embeddings: np.ndarray):
"""Add new documents to existing index."""
self.documents.extend(new_docs)
self.index.add(new_embeddings)
print(f"Added {len(new_docs)} documents. Total: {len(self.documents)}")
# ── Quick test ────────────────────────────────────────────────
if __name__ == "__main__":
retriever = FAISSRetriever()
docs = ["Hello world", "Goodbye world"]
embeddings = np.random.rand(2, 384).astype(np.float32)
retriever.build(docs, embeddings)
retriever.save()
print("Retriever test passed!")