visual-search / app.py
FayssalJ's picture
Upload app.py
ec0ee7c verified
Raw
History Blame
2.03 kB
"""
Visual Search API - HuggingFace Space
Returns embedding vector for external Pinecone queries
"""
import os
import gradio as gr
import torch
import numpy as np
from PIL import Image
import json
# Model (loaded on first use)
model = None
def load_model():
"""Load Jina CLIP v2 model."""
global model
if model is None:
print("Loading Jina CLIP v2...")
from transformers import AutoModel
model = AutoModel.from_pretrained(
"jinaai/jina-clip-v2",
trust_remote_code=True
)
model.eval()
print("Model loaded!")
return model
def get_embedding(image: Image.Image) -> list:
"""Generate 512-dim embedding for an image."""
m = load_model()
with torch.no_grad():
emb = m.encode_image(image)
if hasattr(emb, 'cpu'):
emb = emb.cpu().numpy()
emb = emb.flatten()
emb = emb / np.linalg.norm(emb)
if len(emb) > 512:
emb = emb[:512]
return emb.tolist()
def search(image):
"""Return embedding vector as JSON."""
if image is None:
return json.dumps({"error": "No image provided"})
try:
print("Generating embedding...")
embedding = get_embedding(image)
print(f"Embedding generated: {len(embedding)} dimensions")
# Return embedding as JSON
result = {
"embedding": embedding,
"dimensions": len(embedding)
}
return json.dumps(result, indent=2)
except Exception as e:
import traceback
traceback.print_exc()
return json.dumps({"error": str(e)})
# Gradio interface - returns embedding as JSON
demo = gr.Interface(
fn=search,
inputs=gr.Image(type="pil", label="Upload Image"),
outputs=gr.Textbox(label="Embedding Vector (JSON)", lines=15),
title="Visual Search - Embedding Generator",
description="Upload an image to get its 512-dimensional CLIP embedding as JSON."
)
if __name__ == "__main__":
demo.queue().launch()