SamirDze commited on
Commit
0a9b7fb
·
verified ·
1 Parent(s): 3806ba9

Upload 4 files

Browse files
Files changed (4) hide show
  1. .gitattributes +35 -35
  2. README.md +10 -43
  3. app.py +48 -107
  4. requirements.txt +4 -6
.gitattributes CHANGED
@@ -1,35 +1,35 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,43 +1,10 @@
1
- # CLIP Image Embedding API
2
-
3
- Free CLIP embeddings - two deployment options.
4
-
5
- ## Option 1: Hugging Face Spaces (Recommended - has working API!)
6
-
7
- 1. Create a new Space at https://huggingface.co/spaces
8
- 2. Choose "Gradio" as SDK
9
- 3. Upload `gradio_app.py` as `app.py`
10
- 4. Upload `requirements.txt`
11
- 5. Your API will be at: `https://your-username-your-space.hf.space/api/predict`
12
-
13
- ### API Usage (Gradio)
14
- ```javascript
15
- // From Node.js backend
16
- const response = await axios.post('https://your-space.hf.space/api/predict', {
17
- data: ['https://example.com/image.jpg']
18
- });
19
- const embedding = response.data.data[0].embedding; // 512 dimensions
20
- ```
21
-
22
- ### Environment Variable
23
- ```
24
- HF_CLIP_URL=https://your-username-your-space.hf.space
25
- ```
26
-
27
- ## Option 2: Streamlit Cloud (Web UI only - no API)
28
-
29
- 1. Push this folder to GitHub
30
- 2. Go to https://share.streamlit.io
31
- 3. Deploy `app.py`
32
-
33
- Note: Streamlit doesn't work as REST API, only for interactive web UI.
34
-
35
- ## Local Testing
36
- ```bash
37
- # Gradio (recommended)
38
- pip install -r requirements.txt
39
- python gradio_app.py
40
-
41
- # Streamlit
42
- streamlit run app.py
43
- ```
 
1
+ ---
2
+ title: alg
3
+ emoji: 🖼️
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: "4.44.0"
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,123 +1,64 @@
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")
 
1
  """
2
+ CLIP Image Embedding API - Lightweight version for HF Spaces free tier
 
3
  """
4
 
5
+ import gradio as gr
6
  import torch
7
  from PIL import Image
8
  from transformers import CLIPProcessor, CLIPModel
9
  import requests
10
  from io import BytesIO
 
 
11
 
12
+ # Use CPU and smaller memory footprint
13
+ device = "cpu"
14
+ model = None
15
+ processor = None
16
+
17
  def load_model():
18
+ global model, processor
19
+ if model is None:
20
+ model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
21
+ processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
22
+ model.eval()
23
  return model, processor
24
 
25
+ def get_embedding_from_url(image_url: str):
26
+ """Get CLIP embedding from image URL"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  try:
28
+ if not image_url or not image_url.startswith('http'):
29
+ return {"success": False, "error": "Please provide a valid image URL"}
30
+
31
+ # Load model on first use
32
+ model, processor = load_model()
33
+
34
+ # Download image
35
+ response = requests.get(image_url, timeout=30)
36
+ image = Image.open(BytesIO(response.content)).convert('RGB')
37
+
38
+ # Get embedding
39
+ inputs = processor(images=image, return_tensors="pt")
40
+ with torch.no_grad():
41
+ features = model.get_image_features(**inputs)
42
+
43
+ # Normalize
44
+ embedding = features / features.norm(dim=-1, keepdim=True)
45
+
46
+ return {
47
+ "success": True,
48
+ "embedding": embedding[0].tolist(),
49
+ "dimensions": 512
50
  }
 
51
  except Exception as e:
52
+ return {"success": False, "error": str(e)}
53
+
54
+ # Gradio interface
55
+ demo = gr.Interface(
56
+ fn=get_embedding_from_url,
57
+ inputs=gr.Textbox(label="Image URL", placeholder="https://example.com/image.jpg"),
58
+ outputs=gr.JSON(label="Result"),
59
+ title="CLIP Embedding API",
60
+ description="Get 512-dim CLIP embeddings for images"
61
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
+ if __name__ == "__main__":
64
+ demo.launch()
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,6 +1,4 @@
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
 
1
+ torch
2
+ transformers
3
+ Pillow
4
+ requests