Spaces:
Sleeping
Sleeping
| import faiss | |
| import numpy as np | |
| import pickle | |
| import os | |
| class VectorStore: | |
| def __init__( | |
| self, | |
| index_path="data/vector.index", | |
| docs_path="data/documents.pkl" | |
| ): | |
| self.index = None | |
| self.documents = [] | |
| self.index_path = index_path | |
| self.docs_path = docs_path | |
| # Load existing database | |
| self.load() | |
| # ===================================================== | |
| # BUILD VECTOR DATABASE | |
| # ===================================================== | |
| def build( | |
| self, | |
| embeddings, | |
| documents | |
| ): | |
| """ | |
| Create FAISS vector database. | |
| embeddings: | |
| SentenceTransformer embeddings | |
| documents: | |
| text chunks | |
| """ | |
| if len(embeddings) == 0: | |
| return | |
| embeddings = np.array( | |
| embeddings | |
| ).astype("float32") | |
| # Normalize for cosine similarity | |
| faiss.normalize_L2( | |
| embeddings | |
| ) | |
| dimension = embeddings.shape[1] | |
| # Cosine similarity search | |
| self.index = faiss.IndexFlatIP( | |
| dimension | |
| ) | |
| self.index.add( | |
| embeddings | |
| ) | |
| self.documents = documents | |
| self.save() | |
| # ===================================================== | |
| # SEARCH | |
| # ===================================================== | |
| def search( | |
| self, | |
| query_embedding, | |
| k=5 | |
| ): | |
| if self.index is None: | |
| return [] | |
| query_embedding = np.array( | |
| [query_embedding] | |
| ).astype("float32") | |
| faiss.normalize_L2( | |
| query_embedding | |
| ) | |
| distances, indices = self.index.search( | |
| query_embedding, | |
| k | |
| ) | |
| results = [] | |
| for score, idx in zip( | |
| distances[0], | |
| indices[0] | |
| ): | |
| if idx != -1: | |
| results.append( | |
| self.documents[idx] | |
| ) | |
| return results | |
| # ===================================================== | |
| # SAVE DATABASE | |
| # ===================================================== | |
| def save(self): | |
| """ | |
| Save FAISS index + documents. | |
| Creates folders automatically. | |
| """ | |
| # Create directories if missing | |
| index_dir = os.path.dirname( | |
| self.index_path | |
| ) | |
| docs_dir = os.path.dirname( | |
| self.docs_path | |
| ) | |
| if index_dir: | |
| os.makedirs( | |
| index_dir, | |
| exist_ok=True | |
| ) | |
| if docs_dir: | |
| os.makedirs( | |
| docs_dir, | |
| exist_ok=True | |
| ) | |
| # Save FAISS index | |
| if self.index is not None: | |
| faiss.write_index( | |
| self.index, | |
| self.index_path | |
| ) | |
| # Save documents | |
| with open( | |
| self.docs_path, | |
| "wb" | |
| ) as f: | |
| pickle.dump( | |
| self.documents, | |
| f | |
| ) | |
| # ===================================================== | |
| # LOAD DATABASE | |
| # ===================================================== | |
| def load(self): | |
| """ | |
| Load FAISS database if available. | |
| """ | |
| if os.path.exists( | |
| self.index_path | |
| ): | |
| self.index = faiss.read_index( | |
| self.index_path | |
| ) | |
| if os.path.exists( | |
| self.docs_path | |
| ): | |
| with open( | |
| self.docs_path, | |
| "rb" | |
| ) as f: | |
| self.documents = pickle.load(f) |