lostfound-hack / app.py
hackerloi45's picture
fixed V
c65ef6e
raw
history blame
5.95 kB
import os
import uuid
import gradio as gr
import qdrant_client
from qdrant_client import models
from sentence_transformers import SentenceTransformer
from PIL import Image
# ===============================
# Setup
# ===============================
UPLOAD_DIR = "uploaded_images"
os.makedirs(UPLOAD_DIR, exist_ok=True)
COLLECTION = "lost_and_found"
# Qdrant client (in-memory for Hugging Face)
qclient = qdrant_client.QdrantClient(":memory:")
encoder = SentenceTransformer("clip-ViT-B-32")
# Create collection if not exists
if not qclient.collection_exists(COLLECTION):
qclient.create_collection(
collection_name=COLLECTION,
vectors_config=models.VectorParams(size=512, distance=models.Distance.COSINE),
)
# ===============================
# Encode Function (Text or Image)
# ===============================
def encode_data(text=None, image=None):
if isinstance(image, Image.Image): # Image is already PIL
return encoder.encode(image.convert("RGB"))
elif isinstance(image, str): # Path to image
return encoder.encode(Image.open(image).convert("RGB"))
elif text:
return encoder.encode([text])[0]
else:
return None
# ===============================
# Add Item
# ===============================
def add_item(text, image, uploader_name, uploader_phone):
try:
img_path = None
vector = None
if isinstance(image, Image.Image): # PIL image
img_id = str(uuid.uuid4())
img_path = os.path.join(UPLOAD_DIR, f"{img_id}.png")
image.save(img_path)
vector = encode_data(image=image)
elif text:
vector = encode_data(text=text)
if vector is None:
return "❌ Please provide an image or text."
qclient.upsert(
collection_name=COLLECTION,
points=[
models.PointStruct(
id=str(uuid.uuid4()),
vector=vector.tolist(),
payload={
"text": text or "",
"uploader_name": uploader_name or "N/A",
"uploader_phone": uploader_phone or "N/A",
"image_path": img_path,
},
)
],
)
return "βœ… Item added to database!"
except Exception as e:
return f"❌ Error: {e}"
# ===============================
# Search Function
# ===============================
def search_items(text, image, max_results, min_score):
try:
vector = None
if isinstance(image, Image.Image): # Search with PIL
vector = encode_data(image=image)
elif text:
vector = encode_data(text=text)
if vector is None:
return "❌ Please provide an image or text.", []
results = qclient.search(
collection_name=COLLECTION,
query_vector=vector.tolist(),
limit=max_results,
score_threshold=min_score,
)
if not results:
return "No matches found.", []
# Format results
result_texts, result_imgs = [], []
for r in results:
payload = r.payload
result_texts.append(
f"id:{r.id} | score:{r.score:.3f} | "
f"text:{payload.get('text','')} | "
f"finder:{payload.get('uploader_name','N/A')} "
f"({payload.get('uploader_phone','N/A')})"
)
if payload.get("image_path") and os.path.exists(payload["image_path"]):
result_imgs.append(payload["image_path"])
return "\n".join(result_texts), result_imgs
except Exception as e:
return f"❌ Error: {e}", []
# ===============================
# Delete All
# ===============================
def clear_database():
qclient.delete_collection(COLLECTION)
qclient.create_collection(
collection_name=COLLECTION,
vectors_config=models.VectorParams(size=512, distance=models.Distance.COSINE),
)
return "πŸ—‘οΈ Database cleared!"
# ===============================
# Gradio UI
# ===============================
with gr.Blocks() as demo:
gr.Markdown("## πŸ—οΈ Lost & Found - Database")
# --- Add Item Tab ---
with gr.Tab("βž• Add Item"):
with gr.Row():
text_input = gr.Textbox(label="Description (optional)")
img_input = gr.Image(type="pil", label="Upload Image")
with gr.Row():
uploader_name = gr.Textbox(label="Finder Name")
uploader_phone = gr.Textbox(label="Finder Phone")
add_btn = gr.Button("Add to Database")
add_output = gr.Textbox(label="Status")
add_btn.click(
add_item,
inputs=[text_input, img_input, uploader_name, uploader_phone],
outputs=add_output,
)
# --- Search Tab ---
with gr.Tab("πŸ” Search"):
with gr.Row():
search_text = gr.Textbox(label="Search by text (optional)")
search_img = gr.Image(type="pil", label="Search by image (optional)")
with gr.Row():
max_results = gr.Slider(1, 10, value=5, step=1, label="Max results")
min_score = gr.Slider(0.5, 1.0, value=0.8, step=0.01, label="Min similarity threshold")
search_btn = gr.Button("Search")
search_text_out = gr.Textbox(label="Search results (text)")
search_gallery = gr.Gallery(label="Search Results", columns=2, height="auto")
search_btn.click(
search_items,
inputs=[search_text, search_img, max_results, min_score],
outputs=[search_text_out, search_gallery],
)
# --- Admin Tab ---
with gr.Tab("πŸ—‘οΈ Admin"):
clear_btn = gr.Button("Clear Database")
clear_out = gr.Textbox(label="Status")
clear_btn.click(clear_database, outputs=clear_out)
demo.launch()