SamirDze commited on
Commit
3fc013c
ยท
verified ยท
1 Parent(s): ef436cf

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +123 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ CLIP Image Embedding API - Hosted on Streamlit Cloud
3
+ Returns 512-dimensional embeddings for image similarity search
4
+ """
5
+
6
+ import streamlit as st
7
+ import torch
8
+ from PIL import Image
9
+ from transformers import CLIPProcessor, CLIPModel
10
+ import requests
11
+ from io import BytesIO
12
+ import base64
13
+ import json
14
+
15
+ # Load model once (cached)
16
+ @st.cache_resource
17
+ def load_model():
18
+ model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
19
+ processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
20
+ return model, processor
21
+
22
+ model, processor = load_model()
23
+
24
+ def get_image_embedding(image):
25
+ """Get CLIP embedding for an image"""
26
+ inputs = processor(images=image, return_tensors="pt")
27
+ with torch.no_grad():
28
+ image_features = model.get_image_features(**inputs)
29
+ # Normalize
30
+ embedding = image_features / image_features.norm(dim=-1, keepdim=True)
31
+ return embedding[0].tolist()
32
+
33
+ def load_image_from_source(source):
34
+ """Load image from URL or base64"""
35
+ if source.startswith('http'):
36
+ response = requests.get(source, timeout=30)
37
+ return Image.open(BytesIO(response.content)).convert('RGB')
38
+ elif source.startswith('data:image'):
39
+ # Base64 data URI
40
+ base64_data = source.split(',')[1]
41
+ image_data = base64.b64decode(base64_data)
42
+ return Image.open(BytesIO(image_data)).convert('RGB')
43
+ else:
44
+ raise ValueError("Invalid image source")
45
+
46
+ # Streamlit UI
47
+ st.title("๐Ÿ–ผ๏ธ CLIP Image Embedding API")
48
+ st.write("Get 512-dimensional embeddings for image similarity search")
49
+
50
+ # API Mode - check query params
51
+ query_params = st.query_params
52
+ api_mode = query_params.get("api", "false") == "true"
53
+ image_url = query_params.get("image", None)
54
+
55
+ if api_mode and image_url:
56
+ # API mode - return JSON
57
+ try:
58
+ image = load_image_from_source(image_url)
59
+ embedding = get_image_embedding(image)
60
+ result = {
61
+ "success": True,
62
+ "embedding": embedding,
63
+ "dimensions": len(embedding),
64
+ "model": "openai/clip-vit-base-patch32"
65
+ }
66
+ st.json(result)
67
+ except Exception as e:
68
+ st.json({"success": False, "error": str(e)})
69
+ else:
70
+ # Interactive UI mode
71
+ st.markdown("---")
72
+
73
+ # Input options
74
+ tab1, tab2 = st.tabs(["๐Ÿ”— Image URL", "๐Ÿ“ค Upload Image"])
75
+
76
+ with tab1:
77
+ url_input = st.text_input("Enter image URL:", placeholder="https://example.com/image.jpg")
78
+ if st.button("Get Embedding from URL", key="url_btn"):
79
+ if url_input:
80
+ with st.spinner("Processing..."):
81
+ try:
82
+ image = load_image_from_source(url_input)
83
+ st.image(image, caption="Input Image", width=300)
84
+ embedding = get_image_embedding(image)
85
+ st.success(f"โœ… Got {len(embedding)}-dimensional embedding!")
86
+ st.json({
87
+ "embedding": embedding[:10], # Show first 10
88
+ "dimensions": len(embedding),
89
+ "note": "Showing first 10 values only"
90
+ })
91
+ # Full embedding in expander
92
+ with st.expander("๐Ÿ“‹ Full Embedding (copy this)"):
93
+ st.code(json.dumps(embedding), language="json")
94
+ except Exception as e:
95
+ st.error(f"Error: {e}")
96
+
97
+ with tab2:
98
+ uploaded_file = st.file_uploader("Upload an image", type=['jpg', 'jpeg', 'png', 'webp'])
99
+ if uploaded_file:
100
+ image = Image.open(uploaded_file).convert('RGB')
101
+ st.image(image, caption="Uploaded Image", width=300)
102
+ if st.button("Get Embedding", key="upload_btn"):
103
+ with st.spinner("Processing..."):
104
+ embedding = get_image_embedding(image)
105
+ st.success(f"โœ… Got {len(embedding)}-dimensional embedding!")
106
+ with st.expander("๐Ÿ“‹ Full Embedding (copy this)"):
107
+ st.code(json.dumps(embedding), language="json")
108
+
109
+ # API Usage instructions
110
+ st.markdown("---")
111
+ st.subheader("๐Ÿ”Œ API Usage")
112
+ st.code("""
113
+ # Call from your backend:
114
+ GET https://your-app.streamlit.app/?api=true&image=https://example.com/image.jpg
115
+
116
+ # Response:
117
+ {
118
+ "success": true,
119
+ "embedding": [0.0123, -0.0456, ...],
120
+ "dimensions": 512,
121
+ "model": "openai/clip-vit-base-patch32"
122
+ }
123
+ """, language="python")
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ streamlit>=1.28.0
2
+ gradio>=4.0.0
3
+ torch>=2.0.0
4
+ transformers>=4.35.0
5
+ Pillow>=10.0.0
6
+ requests>=2.31.0