Spaces:
Runtime error
Runtime error
File size: 5,473 Bytes
7c5c440 7a8dd54 7116b90 7a8dd54 c559bc7 294389b afa5ea3 7a8dd54 226d235 27514c1 7a8dd54 109869f 7a8dd54 109869f 7a8dd54 afa5ea3 7a8dd54 afa5ea3 7a8dd54 afa5ea3 7a8dd54 7fae8fb 666646e 7a8dd54 666646e 7a8dd54 afa5ea3 7a8dd54 7c5c440 7a8dd54 afa5ea3 7a8dd54 666646e 7a8dd54 226d235 7a8dd54 47edb75 7a8dd54 47edb75 666646e 7a8dd54 666646e 7a8dd54 666646e 7a8dd54 7116b90 7a8dd54 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
import gradio as gr
import uuid
import base64
import io
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, VectorParams, Distance
from sentence_transformers import SentenceTransformer
from PIL import Image
# --------------------------
# Qdrant Cloud Connection
# --------------------------
QDRANT_URL = "https://ff4da494-27b1-413c-ba58-d5ea14932fe1.europe-west3-0.gcp.cloud.qdrant.io:6333"
QDRANT_API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.jjeB1JgnUSlb1hOOKMdRpVvMrUER57-udT-X1AWXT1E"
COLLECTION_NAME = "lost_and_found"
# CLIP model (text + image embeddings)
MODEL_NAME = "sentence-transformers/clip-ViT-B-32"
embedder = SentenceTransformer(MODEL_NAME)
# CLIP ViT-B/32 always gives 512-dimensional embeddings
VECTOR_SIZE = 512
# Qdrant Client (Cloud)
qclient = QdrantClient(
url=QDRANT_URL,
api_key=QDRANT_API_KEY
)
# Ensure collection exists
qclient.recreate_collection(
collection_name=COLLECTION_NAME,
vectors_config=VectorParams(size=VECTOR_SIZE, distance=Distance.COSINE),
)
# --------------------------
# Helper Functions
# --------------------------
def image_to_base64(img: Image.Image) -> str:
buf = io.BytesIO()
img.save(buf, format="PNG")
return base64.b64encode(buf.getvalue()).decode("utf-8")
def base64_to_image(b64_str: str) -> Image.Image:
img_bytes = base64.b64decode(b64_str)
return Image.open(io.BytesIO(img_bytes))
def embed_text(text: str):
return embedder.encode(text).tolist()
def embed_image(img: Image.Image):
return embedder.encode(img).tolist()
def add_item(image, description, finder_name, finder_phone):
if image is None or description.strip() == "":
return "Please provide both an image and a description."
embedding = embed_image(image)
img_b64 = image_to_base64(image)
metadata = {
"description": description,
"finder_name": finder_name if finder_name.strip() else "NA",
"finder_phone": finder_phone if finder_phone.strip() else "NA",
"image_b64": img_b64
}
qclient.upsert(
collection_name=COLLECTION_NAME,
points=[
PointStruct(
id=str(uuid.uuid4()),
vector=embedding,
payload=metadata
)
]
)
return "Item successfully added!"
def search_items(query_text, query_image):
if not query_text and query_image is None:
return "Please enter text or upload an image to search.", []
if query_image:
query_vector = embed_image(query_image)
else:
query_vector = embed_text(query_text)
results = qclient.search(
collection_name=COLLECTION_NAME,
query_vector=query_vector,
limit=5
)
if not results:
return "No matches found.", []
gallery = []
output_text = "### Matches Found\n\n"
for r in results:
desc = r.payload.get("description", "No description")
name = r.payload.get("finder_name", "NA")
phone = r.payload.get("finder_phone", "NA")
output_text += f"- **{desc}** — Finder: {name}, Phone: {phone}\n"
if "image_b64" in r.payload:
try:
img = base64_to_image(r.payload["image_b64"])
gallery.append(img)
except Exception:
pass
return output_text, gallery
def clear_database():
qclient.delete_collection(COLLECTION_NAME)
qclient.recreate_collection(
collection_name=COLLECTION_NAME,
vectors_config=VectorParams(size=VECTOR_SIZE, distance=Distance.COSINE),
)
return "Database cleared successfully."
# --------------------------
# Gradio UI
# --------------------------
with gr.Blocks() as demo:
gr.Markdown(
"""
# Lost & Found System
A simple platform to add and search lost items.
"""
)
with gr.Tab("Add Item"):
gr.Markdown("### Add a Found Item")
with gr.Row():
image_in = gr.Image(type="pil", label="Upload Image")
desc_in = gr.Textbox(label="Item Description")
with gr.Row():
finder_name = gr.Textbox(label="Finder's Name (optional)")
finder_phone = gr.Textbox(label="Finder's Phone Number (optional)")
add_btn = gr.Button("Submit Item", variant="primary")
add_output = gr.Textbox(label="Status", interactive=False)
with gr.Tab("Search"):
gr.Markdown("### Search Lost Items")
with gr.Row():
search_text = gr.Textbox(label="Search by Text")
search_image = gr.Image(type="pil", label="Or Upload Image")
search_btn = gr.Button("Search", variant="primary")
search_output = gr.Markdown()
gallery = gr.Gallery(label="Matched Items", show_label=True, elem_id="gallery")
with gr.Tab("Admin"):
gr.Markdown("### Admin Controls")
clear_btn = gr.Button("Clear Database", variant="stop")
clear_output = gr.Textbox(label="Status", interactive=False)
# Button actions
add_btn.click(add_item, inputs=[image_in, desc_in, finder_name, finder_phone], outputs=add_output)
search_btn.click(search_items, inputs=[search_text, search_image], outputs=[search_output, gallery])
clear_btn.click(clear_database, outputs=clear_output)
# --------------------------
# Launch App
# --------------------------
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)
|