Spaces:
Sleeping
Sleeping
| # vector/store.py — NumPy cosine index (no FAISS) | |
| from typing import List, Tuple | |
| from pathlib import Path | |
| import json, numpy as np | |
| class FaissStore: | |
| def __init__(self, dim: int, index_dir: str): | |
| self.dim = dim | |
| self.index_dir = Path(index_dir) | |
| self.index_dir.mkdir(parents=True, exist_ok=True) | |
| self.vec_path = self.index_dir / "vecs.npy" | |
| self.meta_path = self.index_dir / "meta.json" | |
| self.vecs = np.load(self.vec_path) if self.vec_path.exists() else np.zeros((0, dim), dtype="float32") | |
| self.meta = json.loads(self.meta_path.read_text()) if self.meta_path.exists() else [] | |
| def add(self, embeddings: List[List[float]], metadatas: List[dict]): | |
| arr = np.asarray(embeddings, dtype="float32") | |
| self.vecs = np.vstack([self.vecs, arr]) if self.vecs.size else arr | |
| self.meta.extend(metadatas) | |
| def save(self): | |
| np.save(self.vec_path, self.vecs) | |
| self.meta_path.write_text(json.dumps(self.meta)) | |
| def search(self, query_emb: List[float], k: int = 6) -> List[Tuple[float, dict]]: | |
| if len(self.meta) == 0: | |
| return [] | |
| q = np.asarray(query_emb, dtype="float32") | |
| q /= (np.linalg.norm(q) + 1e-9) | |
| X = self.vecs | |
| X = X / (np.linalg.norm(X, axis=1, keepdims=True) + 1e-9) | |
| sims = X @ q | |
| idx = np.argsort(-sims)[:k] | |
| return [(float(sims[i]), self.meta[i]) for i in idx] | |