hackerloi45 commited on
Commit
666646e
Β·
1 Parent(s): 27cddca
Files changed (1) hide show
  1. app.py +86 -75
app.py CHANGED
@@ -1,13 +1,9 @@
1
- import os
2
- import uuid
3
- import tempfile
4
  import gradio as gr
 
5
  from qdrant_client import QdrantClient
6
- from qdrant_client.models import VectorParams, Distance, PointStruct
7
  from sentence_transformers import SentenceTransformer
8
  from PIL import Image
9
- import torch
10
- import numpy as np
11
 
12
  # --------------------------
13
  # Qdrant Cloud Connection
@@ -19,7 +15,9 @@ COLLECTION_NAME = "lost_and_found"
19
  # CLIP model (text + image embeddings)
20
  MODEL_NAME = "sentence-transformers/clip-ViT-B-32"
21
  embedder = SentenceTransformer(MODEL_NAME)
22
- VECTOR_SIZE = embedder.get_sentence_embedding_dimension()
 
 
23
 
24
  # Qdrant Client (Cloud)
25
  qclient = QdrantClient(
@@ -36,106 +34,119 @@ qclient.recreate_collection(
36
  # --------------------------
37
  # Helper Functions
38
  # --------------------------
 
39
  def embed_text(text: str):
40
- """Generate embedding for text"""
41
  return embedder.encode(text).tolist()
42
 
43
- def embed_image(image: Image.Image):
44
- """Generate embedding for image"""
45
- img_tensor = embedder.encode(image, convert_to_tensor=True)
46
- return img_tensor.cpu().detach().numpy().tolist()
47
 
48
- # --------------------------
49
- # Core Functions
50
- # --------------------------
51
- def add_item(description, image):
52
- """Add a found item to Qdrant"""
53
- if not description and image is None:
54
- return "⚠️ Please provide description or image."
55
-
56
- vectors = []
57
- payload = {"description": description}
58
-
59
- if description:
60
- vectors = embed_text(description)
61
-
62
- if image:
63
- vectors = embed_image(image)
64
- # Save uploaded image
65
- with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
66
- image.save(tmp.name)
67
- payload["image_path"] = tmp.name
68
-
69
- point = PointStruct(
70
- id=str(uuid.uuid4()),
71
- vector=vectors,
72
- payload=payload
73
- )
74
- qclient.upsert(collection_name=COLLECTION_NAME, points=[point])
75
 
76
- return "βœ… Item added successfully!"
 
77
 
78
- def search_items(query_text, query_image, max_results, min_score):
79
- """Search lost items by text or image"""
80
- vectors = None
 
 
 
81
 
82
- if query_text:
83
- vectors = embed_text(query_text)
 
 
 
 
 
 
 
 
 
 
84
 
85
- elif query_image:
86
- vectors = embed_image(query_image)
 
 
87
 
 
 
 
88
  else:
89
- return ["⚠️ Provide text or image to search."]
90
 
 
91
  results = qclient.search(
92
  collection_name=COLLECTION_NAME,
93
- query_vector=vectors,
94
- limit=max_results,
95
- score_threshold=min_score,
96
  )
97
 
98
  if not results:
99
- return ["No matches found."]
100
 
101
- outputs = []
 
 
102
  for r in results:
103
  desc = r.payload.get("description", "No description")
104
- img = r.payload.get("image_path", None)
105
- score = round(r.score, 3)
106
- if img:
107
- outputs.append((img, f"{desc} (score: {score})"))
108
- else:
109
- outputs.append((None, f"{desc} (score: {score})"))
110
 
111
- return outputs
 
 
 
 
 
 
 
 
 
112
 
113
  # --------------------------
114
  # Gradio UI
115
  # --------------------------
116
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
 
 
 
117
  with gr.Tab("βž• Add Found Item"):
118
  with gr.Row():
 
119
  desc_in = gr.Textbox(label="Item Description")
120
- img_in = gr.Image(type="pil", label="Upload Image")
 
 
121
  add_btn = gr.Button("Add Item")
122
- add_out = gr.Textbox(label="Status")
123
- add_btn.click(fn=add_item, inputs=[desc_in, img_in], outputs=add_out)
124
-
125
- with gr.Tab("πŸ” Search Lost Item"):
126
- query_text = gr.Textbox(label="Search by Text (optional)")
127
- query_img = gr.Image(type="pil", label="Search by Image (optional)")
128
- max_results = gr.Slider(1, 20, step=1, value=5, label="Max Results")
129
- min_score = gr.Slider(0.0, 1.0, step=0.01, value=0.3, label="Min Similarity Score")
130
  search_btn = gr.Button("Search")
131
- results_out = gr.Gallery(label="Search Results").style(grid=2, height="auto")
132
- search_btn.click(fn=search_items, inputs=[query_text, query_img, max_results, min_score], outputs=results_out)
 
 
 
 
133
 
134
- with gr.Tab("βš™οΈ Admin"):
135
- gr.Markdown("Admin dashboard (future expansion).")
 
 
136
 
137
  # --------------------------
138
- # Run App
139
  # --------------------------
140
  if __name__ == "__main__":
141
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
1
  import gradio as gr
2
+ import uuid
3
  from qdrant_client import QdrantClient
4
+ from qdrant_client.models import PointStruct, VectorParams, Distance
5
  from sentence_transformers import SentenceTransformer
6
  from PIL import Image
 
 
7
 
8
  # --------------------------
9
  # Qdrant Cloud Connection
 
15
  # CLIP model (text + image embeddings)
16
  MODEL_NAME = "sentence-transformers/clip-ViT-B-32"
17
  embedder = SentenceTransformer(MODEL_NAME)
18
+
19
+ # CLIP ViT-B/32 always gives 512-dimensional embeddings
20
+ VECTOR_SIZE = 512
21
 
22
  # Qdrant Client (Cloud)
23
  qclient = QdrantClient(
 
34
  # --------------------------
35
  # Helper Functions
36
  # --------------------------
37
+
38
  def embed_text(text: str):
 
39
  return embedder.encode(text).tolist()
40
 
41
+ def embed_image(img: Image.Image):
42
+ return embedder.encode(img).tolist()
 
 
43
 
44
+ def add_item(image, description, finder_name, finder_phone):
45
+ """Add a found item to Qdrant database"""
46
+ if image is None or description.strip() == "":
47
+ return "❌ Please provide both an image and a description."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ # Encode image
50
+ embedding = embed_image(image)
51
 
52
+ # Store metadata
53
+ metadata = {
54
+ "description": description,
55
+ "finder_name": finder_name if finder_name.strip() else "NA",
56
+ "finder_phone": finder_phone if finder_phone.strip() else "NA",
57
+ }
58
 
59
+ # Insert into Qdrant
60
+ qclient.upsert(
61
+ collection_name=COLLECTION_NAME,
62
+ points=[
63
+ PointStruct(
64
+ id=str(uuid.uuid4()),
65
+ vector=embedding,
66
+ payload=metadata
67
+ )
68
+ ]
69
+ )
70
+ return "βœ… Item successfully added!"
71
 
72
+ def search_items(query_text, query_image):
73
+ """Search by text or image"""
74
+ if not query_text and query_image is None:
75
+ return "❌ Please enter text or upload an image to search.", []
76
 
77
+ # Use text or image embedding
78
+ if query_image:
79
+ query_vector = embed_image(query_image)
80
  else:
81
+ query_vector = embed_text(query_text)
82
 
83
+ # Search Qdrant
84
  results = qclient.search(
85
  collection_name=COLLECTION_NAME,
86
+ query_vector=query_vector,
87
+ limit=5
 
88
  )
89
 
90
  if not results:
91
+ return "❌ No matches found.", []
92
 
93
+ # Format results
94
+ gallery = []
95
+ output_text = "βœ… Found Matches:\n\n"
96
  for r in results:
97
  desc = r.payload.get("description", "No description")
98
+ name = r.payload.get("finder_name", "NA")
99
+ phone = r.payload.get("finder_phone", "NA")
100
+ output_text += f"- **{desc}** (Finder: {name}, Phone: {phone})\n"
101
+ gallery.append(Image.new("RGB", (200, 200), color="gray")) # Placeholder (no storage for images)
 
 
102
 
103
+ return output_text, gallery
104
+
105
+ def clear_database():
106
+ """Clear all stored items in Qdrant"""
107
+ qclient.delete_collection(COLLECTION_NAME)
108
+ qclient.recreate_collection(
109
+ collection_name=COLLECTION_NAME,
110
+ vectors_config=VectorParams(size=VECTOR_SIZE, distance=Distance.COSINE),
111
+ )
112
+ return "πŸ—‘οΈ Database cleared!"
113
 
114
  # --------------------------
115
  # Gradio UI
116
  # --------------------------
117
+
118
+ with gr.Blocks() as demo:
119
+ gr.Markdown("# πŸ” Lost & Found System")
120
+
121
  with gr.Tab("βž• Add Found Item"):
122
  with gr.Row():
123
+ image_in = gr.Image(type="pil", label="Upload Found Item Image")
124
  desc_in = gr.Textbox(label="Item Description")
125
+ with gr.Row():
126
+ finder_name = gr.Textbox(label="Finder's Name")
127
+ finder_phone = gr.Textbox(label="Finder's Phone Number")
128
  add_btn = gr.Button("Add Item")
129
+ add_output = gr.Textbox(label="Status")
130
+
131
+ with gr.Tab("πŸ”Ž Search Items"):
132
+ with gr.Row():
133
+ search_text = gr.Textbox(label="Search by Text")
134
+ search_image = gr.Image(type="pil", label="Or Search by Image")
 
 
135
  search_btn = gr.Button("Search")
136
+ search_output = gr.Markdown(label="Results")
137
+ gallery = gr.Gallery(label="Matched Items", show_label=True, elem_id="gallery")
138
+
139
+ with gr.Tab("⚠️ Admin"):
140
+ clear_btn = gr.Button("Clear Entire Database")
141
+ clear_output = gr.Textbox(label="Status")
142
 
143
+ # Button actions
144
+ add_btn.click(add_item, inputs=[image_in, desc_in, finder_name, finder_phone], outputs=add_output)
145
+ search_btn.click(search_items, inputs=[search_text, search_image], outputs=[search_output, gallery])
146
+ clear_btn.click(clear_database, outputs=clear_output)
147
 
148
  # --------------------------
149
+ # Launch App
150
  # --------------------------
151
  if __name__ == "__main__":
152
  demo.launch(server_name="0.0.0.0", server_port=7860)