sohamnk commited on
Commit
7a4305a
Β·
verified Β·
1 Parent(s): 276d537
Files changed (1) hide show
  1. pipeline/routes.py +127 -0
pipeline/routes.py CHANGED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # pipeline/routes.py
2
+ import traceback
3
+ import numpy as np
4
+ import cv2
5
+ from flask import request, jsonify
6
+
7
+ # Import app, models, and logic functions
8
+ from pipeline import app, models, logic
9
+
10
+ @app.route('/process', methods=['POST'])
11
+ def process_item():
12
+ print("\n" + "="*50)
13
+ print("➑ [Request] Received new request to /process")
14
+ try:
15
+ data = request.get_json()
16
+ if not data: return jsonify({"error": "Invalid JSON payload"}), 400
17
+
18
+ object_name = data.get('objectName')
19
+ description = data.get('objectDescription')
20
+ image_url = data.get('objectImage')
21
+
22
+ if not all([object_name, description]):
23
+ return jsonify({"error": "objectName and objectDescription are required."}), 400
24
+
25
+ canonical_label = logic.get_canonical_label(object_name)
26
+ text_embedding = logic.get_text_embedding(description, models)
27
+
28
+ response_data = {
29
+ "canonicalLabel": canonical_label,
30
+ "text_embedding": text_embedding,
31
+ }
32
+
33
+ if image_url:
34
+ print("--- Image URL provided, processing visual features... ---")
35
+ image = logic.download_image_from_url(image_url)
36
+ object_crop = logic.detect_and_crop(image, canonical_label, models)
37
+ visual_features = logic.extract_features(object_crop)
38
+ response_data.update(visual_features)
39
+ else:
40
+ print("--- No image URL provided, skipping visual feature extraction. ---")
41
+
42
+ print("βœ… Successfully processed item.")
43
+ print("="*50)
44
+ return jsonify(response_data), 200
45
+
46
+ except Exception as e:
47
+ print(f"❌ Error in /process: {e}")
48
+ traceback.print_exc()
49
+ return jsonify({"error": str(e)}), 500
50
+
51
+ @app.route('/compare', methods=['POST'])
52
+ def compare_items():
53
+ print("\n" + "="*50)
54
+ print("➑ [Request] Received new request to /compare")
55
+ try:
56
+ data = request.get_json()
57
+ if not data: return jsonify({"error": "Invalid JSON payload"}), 400
58
+
59
+ query_item = data.get('queryItem')
60
+ search_list = data.get('searchList')
61
+
62
+ if not all([query_item, search_list]):
63
+ return jsonify({"error": "queryItem and searchList are required."}), 400
64
+
65
+ query_text_emb = np.array(query_item['text_embedding'])
66
+ results = []
67
+ print(f"--- Comparing 1 query item against {len(search_list)} items ---")
68
+
69
+ for item in search_list:
70
+ item_id = item.get('_id')
71
+ print(f"\n [Checking] Item ID: {item_id}")
72
+ try:
73
+ text_emb_found = np.array(item['text_embedding'])
74
+ text_score = logic.cosine_similarity(query_text_emb, text_emb_found)
75
+ print(f" - Text Score: {text_score:.4f}")
76
+
77
+ has_query_image = 'shape_features' in query_item and query_item['shape_features']
78
+ has_item_image = 'shape_features' in item and item['shape_features']
79
+
80
+ if has_query_image and has_item_image:
81
+ print(" - Both items have images. Performing visual comparison.")
82
+ from pipeline import FEATURE_WEIGHTS # Import constant
83
+ query_shape = np.array(query_item['shape_features'])
84
+ query_color = np.array(query_item['color_features']).astype("float32")
85
+ query_texture = np.array(query_item['texture_features']).astype("float32")
86
+ found_shape = np.array(item['shape_features'])
87
+ found_color = np.array(item['color_features']).astype("float32")
88
+ found_texture = np.array(item['texture_features']).astype("float32")
89
+ shape_dist = cv2.matchShapes(query_shape, found_shape, cv2.CONTOURS_MATCH_I1, 0.0)
90
+ shape_score = 1.0 / (1.0 + shape_dist)
91
+ color_score = cv2.compareHist(query_color, found_color, cv2.HISTCMP_CORREL)
92
+ texture_score = cv2.compareHist(query_texture, found_texture, cv2.HISTCMP_CORREL)
93
+ raw_image_score = (FEATURE_WEIGHTS["shape"] * shape_score +
94
+ FEATURE_WEIGHTS["color"] * color_score +
95
+ FEATURE_WEIGHTS["texture"] * texture_score)
96
+ image_score = logic.stretch_image_score(raw_image_score)
97
+ final_score = 0.4 * image_score + 0.6 * text_score
98
+ print(f" - Image Score: {image_score:.4f} | Final Score: {final_score:.4f}")
99
+ else:
100
+ print(" - One or both items missing image. Using text score only.")
101
+ final_score = text_score
102
+
103
+ from pipeline import FINAL_SCORE_THRESHOLD # Import constant
104
+ if final_score >= FINAL_SCORE_THRESHOLD:
105
+ print(f" - βœ… ACCEPTED (Score >= {FINAL_SCORE_THRESHOLD})")
106
+ results.append({
107
+ "_id": item_id,
108
+ "score": round(final_score, 4),
109
+ "objectName": item.get("objectName"),
110
+ "objectDescription": item.get("objectDescription"),
111
+ "objectImage": item.get("objectImage"),
112
+ })
113
+ else:
114
+ print(f" - ❌ REJECTED (Score < {FINAL_SCORE_THRESHOLD})")
115
+ except Exception as e:
116
+ print(f" [Skipping] Item {item_id} due to processing error: {e}")
117
+ continue
118
+
119
+ results.sort(key=lambda x: x["score"], reverse=True)
120
+ print(f"\nβœ… Search complete. Found {len(results)} potential matches.")
121
+ print("="*50)
122
+ return jsonify({"matches": results}), 200
123
+
124
+ except Exception as e:
125
+ print(f"❌ Error in /compare: {e}")
126
+ traceback.print_exc()
127
+ return jsonify({"error": str(e)}), 500