Spaces:
Sleeping
Sleeping
| import faiss | |
| import numpy as np | |
| from PIL import Image | |
| import os | |
| import pickle | |
| class ImageVectorStore: | |
| def __init__(self): | |
| self._model = None | |
| self._preprocess = None | |
| self._device = None | |
| self.index = faiss.IndexFlatL2(512) | |
| self.metadata = [] | |
| def device(self): | |
| if self._device is None: | |
| import torch | |
| self._device = "cuda" if torch.cuda.is_available() else "cpu" | |
| return self._device | |
| def _load_clip(self): | |
| if self._model is None: | |
| import clip | |
| self._model, self._preprocess = clip.load("ViT-B/32", device=self.device) | |
| def model(self): | |
| self._load_clip() | |
| return self._model | |
| def preprocess(self): | |
| self._load_clip() | |
| return self._preprocess | |
| def add_images(self, image_paths, metadatas): | |
| import torch | |
| images = [ | |
| self.preprocess(Image.open(p)).unsqueeze(0) | |
| for p in image_paths | |
| ] | |
| images = torch.cat(images).to(self.device) | |
| with torch.no_grad(): | |
| emb = self.model.encode_image(images) | |
| self.index.add(emb.cpu().numpy().astype("float32")) | |
| for path, meta in zip(image_paths, metadatas): | |
| enriched_meta = meta.copy() | |
| enriched_meta["image_path"] = path | |
| self.metadata.append(enriched_meta) | |
| def search(self, query_text, k=5): | |
| import clip | |
| import torch | |
| if self.index.ntotal == 0: | |
| return [] | |
| k = min(k, self.index.ntotal) | |
| text_tokens = clip.tokenize([query_text]).to(self.device) | |
| with torch.no_grad(): | |
| q_emb = self.model.encode_text(text_tokens) | |
| _, idxs = self.index.search(q_emb.cpu().numpy().astype("float32"), k) | |
| return [self.metadata[i] for i in idxs[0] if 0 <= i < len(self.metadata)] | |
| def save_local(self, folder_path): | |
| os.makedirs(folder_path, exist_ok=True) | |
| faiss.write_index(self.index, os.path.join(folder_path, "index.faiss")) | |
| with open(os.path.join(folder_path, "metadata.pkl"), "wb") as f: | |
| pickle.dump(self.metadata, f) | |
| def load_local(self, folder_path): | |
| self.index = faiss.read_index(os.path.join(folder_path, "index.faiss")) | |
| with open(os.path.join(folder_path, "metadata.pkl"), "rb") as f: | |
| self.metadata = pickle.load(f) | |