ImageSearcherVitor / src /search.py
Vittav's picture
Upload folder using huggingface_hub (part 4)
9efa0c5 verified
Raw History Blame Contribute Delete
1.6 kB
import json
import sys
from pathlib import Path
import numpy as np
import open_clip
import torch
# --- Settings (must match build_index.py) ---
EMB_DIR = Path("embeddings")
MODEL_NAME = "ViT-B-32"
PRETRAINED = "laion2b_s34b_b79k"
# --- Load everything once, when the module is imported ---
model, _, _ = open_clip.create_model_and_transforms(MODEL_NAME, pretrained=PRETRAINED)
model.eval()
tokenizer = open_clip.get_tokenizer(MODEL_NAME)
embeddings = np.load(EMB_DIR / "image_embeddings.npy") # (1000, 512)
filenames = json.loads((EMB_DIR / "filenames.json").read_text()) # 1000 names
def embed_text(query: str) -> np.ndarray:
"""Turn a text query into a normalized 512-number vector."""
tokens = tokenizer([query]) # batch of 1 query
with torch.no_grad():
vec = model.encode_text(tokens) # (1, 512)
vec = vec / vec.norm(dim=-1, keepdim=True)
return vec[0].cpu().numpy() # (512,)
def search(query: str, k: int = 5) -> list[tuple[str, float]]:
"""Return the top-k (filename, score) pairs, best first."""
q = embed_text(query)
scores = embeddings @ q # (1000, 512) @ (512,) -> (1000,)
top = np.argsort(scores)[::-1][:k] # positions of the k highest scores
return [(filenames[i], float(scores[i])) for i in top]
if __name__ == "__main__":
query = " ".join(sys.argv[1:]) or "a dog running on the beach"
for rank, (name, score) in enumerate(search(query, k=5), start=1):
print(f"{rank}. {name} score={score:.3f}")