Spaces:
Sleeping
Sleeping
| import os | |
| from flask import Flask,request,jsonify,make_response | |
| from flask_bcrypt import Bcrypt | |
| from functools import wraps | |
| from flask_jwt_extended import JWTManager, create_access_token,unset_jwt_cookies, jwt_required, get_jwt_identity,decode_token | |
| from dotenv import load_dotenv | |
| from flask_cors import CORS | |
| from qdrant_client import QdrantClient | |
| from qdrant_client.http import models | |
| from datetime import datetime, timedelta | |
| from qdrant_client.models import PayloadSchemaType | |
| from supabase import create_client | |
| load_dotenv() | |
| app = Flask(__name__) | |
| app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("DATABASE_URL") | |
| db = create_client(os.getenv("DATABASE_URL"),os.getenv("SUPABASE_KEY")) | |
| qdrant=QdrantClient( | |
| url=os.getenv("Qdrant_url"), | |
| api_key=os.getenv("Qdrant_api_key"), | |
| ) | |
| qdrant.create_payload_index( | |
| collection_name="found_items", | |
| field_name="status", | |
| field_schema=PayloadSchemaType.KEYWORD | |
| ) | |
| DEFAULT_MIN_AGE_MINUTES = 60 | |
| DEFAULT_CONFIDENCE = 0.78 | |
| DEFAULT_TOP_K = 5 | |
| CORS(app, supports_credentials=True, origins=[os.getenv("CLIENT")]) | |
| print('Qdrant connected') | |
| print("Posgres Connected") | |
| def iso_now_minus(minutes): | |
| return (datetime.utcnow() - timedelta(minutes=minutes)).isoformat() | |
| def match_active_lost(): | |
| body = request.get_json(silent=True) or {} | |
| min_age_minutes = int(body.get("min_age_minutes", DEFAULT_MIN_AGE_MINUTES)) | |
| confidence_threshold = float(body.get("confidence_threshold", DEFAULT_CONFIDENCE)) | |
| top_k = int(body.get("top_k", DEFAULT_TOP_K)) | |
| cutoff = iso_now_minus(min_age_minutes) | |
| lost_rows = (db.table("lostItem").select("*").eq("status","active").execute()) | |
| lost_items = [ | |
| { | |
| "id": r.get("id"), | |
| "user_id": r.get("user_id"), | |
| "created_at": r.get("created_at") | |
| } | |
| for r in lost_rows.data | |
| ] | |
| if not lost_items: | |
| return jsonify({"message": "No eligible lost items found", "checked": 0}), 200 | |
| created_matches = [] | |
| errors = [] | |
| for lost in lost_items: | |
| lost_id=int(lost["id"]) | |
| lost_user_id=str(lost["user_id"]) | |
| try: | |
| point=qdrant.retrieve(collection_name="lost_items", ids=[lost_id], with_vectors=True) | |
| if not point: | |
| errors.append({"lost_id": lost_id, "error": "No vector found in Qdrant for this lost item"}) | |
| continue | |
| lost_vector = point[0].vector | |
| except Exception as e: | |
| errors.append({"lost_id": lost_id, "error": f"Qdrant get_point failed: {str(e)}"}) | |
| continue | |
| qfilter = models.Filter( | |
| must=[models.FieldCondition(key="status", match=models.MatchValue(value="active"))] | |
| ) | |
| try: | |
| results = qdrant.search( | |
| collection_name="found_items", | |
| query_vector=lost_vector, | |
| limit=top_k, | |
| with_payload=True, | |
| with_vectors=False, | |
| query_filter=qfilter | |
| ) | |
| except Exception as e: | |
| errors.append({"lost_id": lost_id, "error": f"Qdrant search failed: {str(e)}"}) | |
| continue | |
| for r in results: | |
| score = float(r.score) if r.score is not None else None | |
| if score is None: | |
| continue | |
| if score < confidence_threshold: | |
| continue | |
| found_point_payload = r.payload or {} | |
| found_supabase_id = found_point_payload.get("id") or r.id | |
| if lost_user_id == str(found_point_payload.get("user_id")): | |
| continue | |
| try: | |
| existing_match=db.table("matches").select("lost_item_id","found_item_id").eq("found_item_id", found_supabase_id).eq("lost_item_id", lost_id).limit(1).execute() | |
| if existing_match: | |
| continue | |
| except Exception as e: | |
| errors.append({"lost_id": lost_id, "error": f"Database query failed: {str(e)}"}) | |
| continue | |
| try: | |
| match_record = db.table("matches").insert({ | |
| "lost_item_id": lost_id, | |
| "found_item_id": found_supabase_id, | |
| "confidence_score": score | |
| }).execute() | |
| created_matches.append({"lost_id": lost_id, "found_id": found_supabase_id, "similarity": score}) | |
| except Exception as e: | |
| errors.append({"lost_id": lost_id, "found_id": found_supabase_id, "error": f"Supabase insert failed: {str(e)}"}) | |
| matches=(db.table("matches").select("id","lost_item_id","found_item_id","confidence_score").execute()) | |
| match_items = [ | |
| { | |
| "id": r.get("id"), | |
| "lost_id": int(r.get("lost_item_id")), | |
| "found_id": int(r.get("found_item_id")), | |
| "confidence_score": r.get("confidence_score") | |
| } | |
| for r in matches.data | |
| ] | |
| for match in match_items: | |
| already_exist_found=(db.table("lostItem").select("*").eq("user_id", match["lost_id"]).contains("found_items", [str(match["found_id"])]).limit(1).execute() | |
| ) | |
| if already_exist_found: | |
| continue | |
| else: | |
| res=(db.table("lostItem").select("*").eq("id", match["lost_id"]).limit(1).execute() | |
| ) | |
| if not res.data: | |
| found_item = None | |
| else: | |
| found_item = res.data[0] | |
| current_lost_items = found_item.get("found_items") or [] | |
| if match["found_id"] not in current_lost_items: | |
| current_lost_items.append(match["found_id"]) | |
| db.table("lostItem").update({"found_items": current_lost_items }).eq("id", match["lost_id"]).execute() | |
| already_exist_found=( db.table("foundItem").select("*").eq("user_id", match["found_id"]).contains("lost_items", [str(match["lost_id"])]).limit(1).execute() | |
| ) | |
| if already_exist_found: | |
| continue | |
| else: | |
| res=(db.table("foundItem").select("lost_items").eq("id", match["found_id"]).limit(1).execute() | |
| ) | |
| if not res.data: | |
| found_item = None | |
| else: | |
| found_item = res.data[0] | |
| current_lost_items = found_item.get("lost_items") or [] | |
| if match["lost_id"] not in current_lost_items: | |
| current_lost_items.append(match["lost_id"]) | |
| db.table("foundItem").update({"lost_items": current_lost_items }).eq("id", match["found_id"]).execute() | |
| return jsonify({ | |
| "checked_lost_count": len(lost_rows.data), | |
| "created_matches_count": len(created_matches), | |
| "created_matches": created_matches, | |
| "errors": errors | |
| }), 200 | |
| if __name__ == "__main__": | |
| app.run(host="0.0.0.0",port=5000) |