Coots commited on
Commit
1139b4c
Β·
verified Β·
1 Parent(s): 0616b98

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -46
app.py CHANGED
@@ -10,7 +10,7 @@ import os
10
  app = Flask(__name__, static_folder='.', static_url_path='/')
11
  CORS(app)
12
 
13
- # Load models
14
  try:
15
  rf = joblib.load("rf_model.pkl")
16
  xgb_model = xgb.Booster()
@@ -20,82 +20,85 @@ except Exception as e:
20
  print(f"❌ Error loading models: {e}")
21
  raise e
22
 
23
- # Load tile catalog and tile size data
24
  with open("tile_catalog.json", "r", encoding="utf-8") as f:
25
  tile_catalog = json.load(f)
26
-
27
  with open("tile_sizes.json", "r", encoding="utf-8") as f:
28
- tile_sizes_list = json.load(f)
29
- tile_sizes = {item["label"]: item["area_sqft"] for item in tile_sizes_list}
30
 
31
  @app.route("/")
32
  def index():
33
  return send_from_directory(".", "index.html")
34
 
35
- @app.route("/calculate", methods=["POST"])
36
- def calculate():
37
  try:
38
  data = request.get_json()
39
  tile_type = data.get("tile_type", "").lower()
40
- area = float(data.get("area", 0))
41
- tile_size_label = data.get("tile_size", "")
42
-
43
- if tile_size_label not in tile_sizes:
44
- return jsonify({"error": "Invalid tile size"}), 400
45
 
46
- per_tile_area = tile_sizes[tile_size_label]
47
- tiles_needed = math.ceil((area / per_tile_area) * 1.1)
48
- boxes = math.ceil(tiles_needed / 10)
49
 
50
- matching_products = [
51
- p for p in tile_catalog
52
- if p["type"].lower() == tile_type and p["size"] == tile_size_label
53
- ]
54
 
 
55
  return jsonify({
56
- "tile_type": tile_type,
57
- "area": area,
58
- "tile_size": tile_size_label,
59
- "tiles_needed": tiles_needed,
60
- "boxes_needed": boxes,
61
- "matching_products": matching_products[:3],
62
- "total_matches": len(matching_products)
63
  })
64
  except Exception as e:
65
- print(f"❌ Error in /calculate: {e}")
66
  return jsonify({"error": "Server error"}), 500
67
 
68
- @app.route("/recommend", methods=["POST"])
69
- def recommend():
70
  try:
71
  data = request.get_json()
72
- tile_type = data.get("tile_type", "").lower()
73
  area = float(data.get("area", 0))
74
- coverage = float(data.get("coverage", 1))
75
- price_range = data.get("price_range", [1, 100000])
76
- preferred_sizes = data.get("preferred_sizes", [])
77
 
78
- features = prepare_features(tile_type, coverage, area, price_range)
79
- xgb_pred = xgb_model.predict(xgb.DMatrix(features))[0]
80
- rf_pred = rf.predict_proba(features)[0][1]
81
- score = (xgb_pred + rf_pred) / 2
 
 
 
 
 
 
 
 
 
 
 
82
 
83
- recommended_products = filter_products(tile_type, price_range, preferred_sizes)
84
 
85
  return jsonify({
86
- "recommendation_score": round(float(score), 3),
87
- "recommended_products": recommended_products[:4],
88
- "total_matches": len(recommended_products)
 
89
  })
90
  except Exception as e:
91
- print(f"❌ Error in /recommend: {e}")
92
- return jsonify({"error": "Server error"}), 500
93
 
94
  def prepare_features(tile_type, coverage, area, price_range):
95
  tile_type_num = 0 if tile_type == "floor" else 1
96
  min_price, max_price = price_range
97
- price_per_sqft = max_price / coverage if coverage else 0
98
- efficiency = coverage / max_price if max_price else 0
99
  return np.array([[tile_type_num, area, coverage, min_price, max_price, price_per_sqft, efficiency]])
100
 
101
  def filter_products(tile_type, price_range, preferred_sizes):
@@ -110,7 +113,7 @@ def filter_products(tile_type, price_range, preferred_sizes):
110
  continue
111
 
112
  price_score = 1 - (product["price"] - min_price) / (max_price - min_price + 1e-6)
113
- size_score = 1 if not preferred_sizes else (1 if product["size"] in preferred_sizes else 0.5)
114
  score = round((price_score + size_score) / 2, 2)
115
  filtered.append({**product, "recommendation_score": score})
116
  return sorted(filtered, key=lambda x: x["recommendation_score"], reverse=True)
 
10
  app = Flask(__name__, static_folder='.', static_url_path='/')
11
  CORS(app)
12
 
13
+ # Load ML models
14
  try:
15
  rf = joblib.load("rf_model.pkl")
16
  xgb_model = xgb.Booster()
 
20
  print(f"❌ Error loading models: {e}")
21
  raise e
22
 
23
+ # Load tile data
24
  with open("tile_catalog.json", "r", encoding="utf-8") as f:
25
  tile_catalog = json.load(f)
 
26
  with open("tile_sizes.json", "r", encoding="utf-8") as f:
27
+ tile_sizes = json.load(f)
 
28
 
29
  @app.route("/")
30
  def index():
31
  return send_from_directory(".", "index.html")
32
 
33
+ @app.route("/recommend", methods=["POST"])
34
+ def recommend():
35
  try:
36
  data = request.get_json()
37
  tile_type = data.get("tile_type", "").lower()
38
+ coverage = float(data.get("coverage", 1))
39
+ area = float(data.get("area", 1))
40
+ price_range = data.get("price_range", [1, 100])
41
+ preferred_sizes = data.get("preferred_sizes", [])
 
42
 
43
+ if coverage <= 0 or area <= 0:
44
+ return jsonify({"error": "Please enter valid positive values for area and coverage."}), 400
 
45
 
46
+ features = prepare_features(tile_type, coverage, area, price_range)
47
+ xgb_pred = xgb_model.predict(xgb.DMatrix(features))[0]
48
+ rf_pred = rf.predict_proba(features)[0][1]
49
+ score = (xgb_pred + rf_pred) / 2
50
 
51
+ products = filter_products(tile_type, price_range, preferred_sizes)
52
  return jsonify({
53
+ "recommendation_score": round(float(score), 3),
54
+ "recommended_products": products[:4],
55
+ "total_matches": len(products),
 
 
 
 
56
  })
57
  except Exception as e:
58
+ print("❌ Error in /recommend:", str(e))
59
  return jsonify({"error": "Server error"}), 500
60
 
61
+ @app.route("/calculate", methods=["POST"])
62
+ def calculate():
63
  try:
64
  data = request.get_json()
65
+ tile_type = data.get("tile_type", "").strip().lower()
66
  area = float(data.get("area", 0))
67
+ tile_size = data.get("tile_size", "").strip()
 
 
68
 
69
+ if not tile_type:
70
+ return jsonify({"error": "Please select a tile type (e.g., Floor or Wall)."}), 400
71
+ if area <= 0:
72
+ return jsonify({"error": "Area must be a positive number."}), 400
73
+ if tile_size not in tile_sizes:
74
+ return jsonify({"error": f"Invalid tile size '{tile_size}'. Please select a valid size."}), 400
75
+
76
+ # Fetch tile size info
77
+ info = tile_sizes[tile_size]
78
+ per_tile_area = info["area_sqft"]
79
+ if per_tile_area <= 0:
80
+ return jsonify({"error": f"Tile size '{tile_size}' has invalid area data."}), 400
81
+
82
+ tiles_needed = math.ceil((area / per_tile_area) * 1.1)
83
+ boxes = math.ceil(tiles_needed / info.get("tiles_per_box", 10))
84
 
85
+ matches = [p for p in tile_catalog if p["type"].lower() == tile_type and p["size"] == tile_size]
86
 
87
  return jsonify({
88
+ "tiles_needed": tiles_needed,
89
+ "boxes_needed": boxes,
90
+ "matching_products": matches[:3],
91
+ "total_matches": len(matches)
92
  })
93
  except Exception as e:
94
+ print("❌ Error in /calculate:", str(e))
95
+ return jsonify({"error": "Please ensure valid tile type, size, and area are provided."}), 500
96
 
97
  def prepare_features(tile_type, coverage, area, price_range):
98
  tile_type_num = 0 if tile_type == "floor" else 1
99
  min_price, max_price = price_range
100
+ price_per_sqft = max_price / coverage
101
+ efficiency = coverage / max_price
102
  return np.array([[tile_type_num, area, coverage, min_price, max_price, price_per_sqft, efficiency]])
103
 
104
  def filter_products(tile_type, price_range, preferred_sizes):
 
113
  continue
114
 
115
  price_score = 1 - (product["price"] - min_price) / (max_price - min_price + 1e-6)
116
+ size_score = 1 if product["size"] in preferred_sizes else 0.5
117
  score = round((price_score + size_score) / 2, 2)
118
  filtered.append({**product, "recommendation_score": score})
119
  return sorted(filtered, key=lambda x: x["recommendation_score"], reverse=True)