hackerloi45 commited on
Commit
f77c4c2
Β·
1 Parent(s): dc0c9d5
Files changed (1) hide show
  1. app.py +28 -22
app.py CHANGED
@@ -7,31 +7,21 @@ from PIL import Image
7
  import gradio as gr
8
  import numpy as np
9
 
10
- # CLIP via Sentence-Transformers
11
  from sentence_transformers import SentenceTransformer
12
-
13
- # Gemini (Google) client
14
  from google import genai
15
-
16
- # Qdrant client & helpers
17
  from qdrant_client import QdrantClient
18
  from qdrant_client.http.models import VectorParams, Distance, PointStruct
19
 
20
  # -------------------------
21
- # CONFIG (reads env vars)
22
  # -------------------------
23
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "").strip()
24
  QDRANT_URL = os.environ.get("QDRANT_URL", "").strip()
25
  QDRANT_API_KEY = os.environ.get("QDRANT_API_KEY", "").strip()
26
 
27
- # -------------------------
28
- # Initialize clients/models
29
- # -------------------------
30
  print("Loading CLIP model (this may take 20-60s the first time)...")
31
  MODEL_ID = "sentence-transformers/clip-ViT-B-32-multilingual-v1"
32
  clip_model = SentenceTransformer(MODEL_ID)
33
-
34
- # Dynamically detect vector size
35
  VECTOR_SIZE = clip_model.get_sentence_embedding_dimension()
36
 
37
  genai_client = genai.Client(api_key=GEMINI_API_KEY) if GEMINI_API_KEY else None
@@ -42,7 +32,6 @@ if not QDRANT_URL:
42
  qclient = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
43
  COLLECTION = "lost_found_items"
44
 
45
- # Ensure collection exists with correct vector size
46
  try:
47
  if not qclient.collection_exists(COLLECTION):
48
  qclient.create_collection(
@@ -70,8 +59,7 @@ def gen_tags_from_image_file(image_bytes: io.BytesIO) -> str:
70
  file_obj = genai_client.files.upload(file=image_bytes)
71
  prompt_text = (
72
  "Give 4 short tags (comma-separated) describing this item in the image. "
73
- "Tags should be short single words or two-word phrases (e.g. 'black backpack', 'water bottle'). "
74
- "Respond only with tags, no extra explanation."
75
  )
76
  response = genai_client.models.generate_content(
77
  model="gemini-2.5-flash",
@@ -90,12 +78,17 @@ def decode_image_from_b64(b64_str: str):
90
  return None
91
 
92
  # -------------------------
93
- # App logic: add item
94
  # -------------------------
95
- def add_item(mode: str, uploaded_image, text_description: str):
96
  item_id = str(uuid.uuid4())
97
  payload = {"mode": mode, "text": text_description}
98
 
 
 
 
 
 
99
  try:
100
  if uploaded_image is not None:
101
  img_bytes = io.BytesIO()
@@ -121,7 +114,6 @@ def add_item(mode: str, uploaded_image, text_description: str):
121
  else:
122
  payload["tags"] = ""
123
 
124
- # Upsert into Qdrant
125
  point = PointStruct(id=item_id, vector=vec, payload=payload)
126
  qclient.upsert(collection_name=COLLECTION, points=[point], wait=True)
127
 
@@ -130,7 +122,7 @@ def add_item(mode: str, uploaded_image, text_description: str):
130
  return f"❌ Error saving to Qdrant: {e}"
131
 
132
  # -------------------------
133
- # App logic: search
134
  # -------------------------
135
  def search_items(query_image, query_text, limit: int = 5, min_score: float = 0.90):
136
  if query_image is not None:
@@ -156,6 +148,11 @@ def search_items(query_image, query_text, limit: int = 5, min_score: float = 0.9
156
 
157
  payload = h.payload or {}
158
  caption = f"ID: {h.id}\nScore: {score:.4f}\nMode: {payload.get('mode','')}\nTags: {payload.get('tags','')}\nText: {payload.get('text','')}"
 
 
 
 
 
159
  captions.append(caption)
160
 
161
  if payload.get("has_image") and payload.get("image_b64"):
@@ -165,7 +162,6 @@ def search_items(query_image, query_text, limit: int = 5, min_score: float = 0.9
165
  else:
166
  images.append(Image.new("RGB", (200,200), color="gray"))
167
  else:
168
- # Placeholder for text-only entries
169
  img = Image.new("RGB", (200,200), color="lightblue")
170
  images.append(img)
171
 
@@ -183,7 +179,9 @@ with gr.Blocks(title="Lost & Found β€” Simple Helper") as demo:
183
  with gr.Column():
184
  mode = gr.Radio(choices=["lost", "found"], value="lost", label="Add as")
185
  upload_img = gr.Image(type="pil", label="Item photo (optional)")
186
- text_desc = gr.Textbox(lines=2, placeholder="Short description (e.g. 'black backpack with blue zipper')", label="Description (optional)")
 
 
187
  add_btn = gr.Button("βž• Add item")
188
  add_out = gr.Textbox(label="Add result", interactive=False)
189
  with gr.Column():
@@ -202,8 +200,16 @@ with gr.Blocks(title="Lost & Found β€” Simple Helper") as demo:
202
  )
203
  search_msg = gr.Textbox(label="Message", interactive=False)
204
 
205
- add_btn.click(add_item, inputs=[mode, upload_img, text_desc], outputs=[add_out])
206
- search_btn.click(search_items, inputs=[query_img, query_text, limit_slider, score_slider], outputs=[gallery, search_msg])
 
 
 
 
 
 
 
 
207
 
208
  if __name__ == "__main__":
209
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
7
  import gradio as gr
8
  import numpy as np
9
 
 
10
  from sentence_transformers import SentenceTransformer
 
 
11
  from google import genai
 
 
12
  from qdrant_client import QdrantClient
13
  from qdrant_client.http.models import VectorParams, Distance, PointStruct
14
 
15
  # -------------------------
16
+ # CONFIG
17
  # -------------------------
18
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "").strip()
19
  QDRANT_URL = os.environ.get("QDRANT_URL", "").strip()
20
  QDRANT_API_KEY = os.environ.get("QDRANT_API_KEY", "").strip()
21
 
 
 
 
22
  print("Loading CLIP model (this may take 20-60s the first time)...")
23
  MODEL_ID = "sentence-transformers/clip-ViT-B-32-multilingual-v1"
24
  clip_model = SentenceTransformer(MODEL_ID)
 
 
25
  VECTOR_SIZE = clip_model.get_sentence_embedding_dimension()
26
 
27
  genai_client = genai.Client(api_key=GEMINI_API_KEY) if GEMINI_API_KEY else None
 
32
  qclient = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
33
  COLLECTION = "lost_found_items"
34
 
 
35
  try:
36
  if not qclient.collection_exists(COLLECTION):
37
  qclient.create_collection(
 
59
  file_obj = genai_client.files.upload(file=image_bytes)
60
  prompt_text = (
61
  "Give 4 short tags (comma-separated) describing this item in the image. "
62
+ "Tags should be short single words or two-word phrases. Respond only with tags."
 
63
  )
64
  response = genai_client.models.generate_content(
65
  model="gemini-2.5-flash",
 
78
  return None
79
 
80
  # -------------------------
81
+ # Add item
82
  # -------------------------
83
+ def add_item(mode: str, uploaded_image, text_description: str, finder_name: str, finder_phone: str):
84
  item_id = str(uuid.uuid4())
85
  payload = {"mode": mode, "text": text_description}
86
 
87
+ # If "found", save finder info
88
+ if mode == "found":
89
+ payload["finder_name"] = finder_name
90
+ payload["finder_phone"] = finder_phone
91
+
92
  try:
93
  if uploaded_image is not None:
94
  img_bytes = io.BytesIO()
 
114
  else:
115
  payload["tags"] = ""
116
 
 
117
  point = PointStruct(id=item_id, vector=vec, payload=payload)
118
  qclient.upsert(collection_name=COLLECTION, points=[point], wait=True)
119
 
 
122
  return f"❌ Error saving to Qdrant: {e}"
123
 
124
  # -------------------------
125
+ # Search
126
  # -------------------------
127
  def search_items(query_image, query_text, limit: int = 5, min_score: float = 0.90):
128
  if query_image is not None:
 
148
 
149
  payload = h.payload or {}
150
  caption = f"ID: {h.id}\nScore: {score:.4f}\nMode: {payload.get('mode','')}\nTags: {payload.get('tags','')}\nText: {payload.get('text','')}"
151
+
152
+ # If it's a found item, show finder details
153
+ if payload.get("mode") == "found":
154
+ caption += f"\nπŸ‘€ Finder: {payload.get('finder_name','N/A')} | πŸ“ž {payload.get('finder_phone','N/A')}"
155
+
156
  captions.append(caption)
157
 
158
  if payload.get("has_image") and payload.get("image_b64"):
 
162
  else:
163
  images.append(Image.new("RGB", (200,200), color="gray"))
164
  else:
 
165
  img = Image.new("RGB", (200,200), color="lightblue")
166
  images.append(img)
167
 
 
179
  with gr.Column():
180
  mode = gr.Radio(choices=["lost", "found"], value="lost", label="Add as")
181
  upload_img = gr.Image(type="pil", label="Item photo (optional)")
182
+ text_desc = gr.Textbox(lines=2, placeholder="Short description", label="Description (optional)")
183
+ finder_name = gr.Textbox(lines=1, placeholder="Finder name (only if found)", label="Finder Name")
184
+ finder_phone = gr.Textbox(lines=1, placeholder="Finder phone (only if found)", label="Finder Phone")
185
  add_btn = gr.Button("βž• Add item")
186
  add_out = gr.Textbox(label="Add result", interactive=False)
187
  with gr.Column():
 
200
  )
201
  search_msg = gr.Textbox(label="Message", interactive=False)
202
 
203
+ add_btn.click(
204
+ add_item,
205
+ inputs=[mode, upload_img, text_desc, finder_name, finder_phone],
206
+ outputs=[add_out]
207
+ )
208
+ search_btn.click(
209
+ search_items,
210
+ inputs=[query_img, query_text, limit_slider, score_slider],
211
+ outputs=[gallery, search_msg]
212
+ )
213
 
214
  if __name__ == "__main__":
215
  demo.launch(server_name="0.0.0.0", server_port=7860)