Update app.py
Browse files
app.py
CHANGED
@@ -2,13 +2,15 @@ from flask import Flask, request, jsonify, send_from_directory
|
|
2 |
from flask_cors import CORS
|
3 |
import joblib
|
4 |
import numpy as np
|
5 |
-
import
|
6 |
import math
|
|
|
|
|
7 |
|
8 |
app = Flask(__name__, static_folder='.', static_url_path='/')
|
9 |
CORS(app)
|
10 |
|
11 |
-
# Load models
|
12 |
try:
|
13 |
rf = joblib.load("rf_model.pkl")
|
14 |
xgb_model = xgb.Booster()
|
@@ -18,7 +20,7 @@ except Exception as e:
|
|
18 |
print(f"β Error loading models: {e}")
|
19 |
raise e
|
20 |
|
21 |
-
#
|
22 |
tile_catalog = [
|
23 |
{"name": "Travertino Light Beige", "type": "Floor", "price": 780, "coverage": 15.5, "size": "1200x1200 MM", "url": "https://arqonz.ae/products/6775"},
|
24 |
{"name": "Marquina Glossy Black", "type": "Wall", "price": 620, "coverage": 12.0, "size": "600x600 MM", "url": "https://arqonz.ae/products/6776"},
|
@@ -47,26 +49,25 @@ def recommend():
|
|
47 |
tile_type = data.get("tile_type", "").strip().lower()
|
48 |
coverage = float(data.get("coverage", 1))
|
49 |
area = float(data.get("area", 1))
|
50 |
-
price_range = data.get("price_range", [
|
51 |
preferred_sizes = data.get("preferred_sizes", [])
|
52 |
|
53 |
if area <= 0 or coverage <= 0:
|
54 |
-
return jsonify({"error": "
|
55 |
|
56 |
features = prepare_features(tile_type, coverage, area, price_range)
|
57 |
xgb_pred = xgb_model.predict(xgb.DMatrix(features))[0]
|
58 |
rf_pred = rf.predict_proba(features)[0][1]
|
59 |
score = (xgb_pred + rf_pred) / 2
|
60 |
|
61 |
-
|
62 |
-
|
63 |
return jsonify({
|
64 |
"recommendation_score": round(float(score), 3),
|
65 |
-
"recommended_products":
|
66 |
-
"total_matches": len(
|
67 |
})
|
68 |
except Exception as e:
|
69 |
-
print("β /recommend
|
70 |
return jsonify({"error": "Server error"}), 500
|
71 |
|
72 |
def prepare_features(tile_type, coverage, area, price_range):
|
@@ -85,22 +86,23 @@ def filter_products(tile_type, price_range, preferred_sizes):
|
|
85 |
if not (min_price <= p["price"] <= max_price):
|
86 |
continue
|
87 |
|
88 |
-
|
89 |
-
for
|
90 |
-
if
|
91 |
-
|
92 |
break
|
93 |
-
|
|
|
94 |
continue
|
95 |
|
96 |
price_score = 1 - (p["price"] - min_price) / (max_price - min_price + 1e-6)
|
97 |
filtered.append({**p, "recommendation_score": round(price_score, 2)})
|
98 |
return sorted(filtered, key=lambda x: x["recommendation_score"], reverse=True)
|
99 |
|
100 |
-
def
|
101 |
try:
|
102 |
-
w1, h1 = map(int,
|
103 |
-
w2, h2 = map(int,
|
104 |
return abs(w1 - w2) <= tolerance and abs(h1 - h2) <= tolerance
|
105 |
except:
|
106 |
return False
|
|
|
2 |
from flask_cors import CORS
|
3 |
import joblib
|
4 |
import numpy as np
|
5 |
+
import json
|
6 |
import math
|
7 |
+
import xgboost as xgb
|
8 |
+
import re
|
9 |
|
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 |
+
# Product catalog
|
24 |
tile_catalog = [
|
25 |
{"name": "Travertino Light Beige", "type": "Floor", "price": 780, "coverage": 15.5, "size": "1200x1200 MM", "url": "https://arqonz.ae/products/6775"},
|
26 |
{"name": "Marquina Glossy Black", "type": "Wall", "price": 620, "coverage": 12.0, "size": "600x600 MM", "url": "https://arqonz.ae/products/6776"},
|
|
|
49 |
tile_type = data.get("tile_type", "").strip().lower()
|
50 |
coverage = float(data.get("coverage", 1))
|
51 |
area = float(data.get("area", 1))
|
52 |
+
price_range = data.get("price_range", [1, 10000])
|
53 |
preferred_sizes = data.get("preferred_sizes", [])
|
54 |
|
55 |
if area <= 0 or coverage <= 0:
|
56 |
+
return jsonify({"error": "Please enter valid area and coverage values."}), 400
|
57 |
|
58 |
features = prepare_features(tile_type, coverage, area, price_range)
|
59 |
xgb_pred = xgb_model.predict(xgb.DMatrix(features))[0]
|
60 |
rf_pred = rf.predict_proba(features)[0][1]
|
61 |
score = (xgb_pred + rf_pred) / 2
|
62 |
|
63 |
+
products = filter_products(tile_type, price_range, preferred_sizes)
|
|
|
64 |
return jsonify({
|
65 |
"recommendation_score": round(float(score), 3),
|
66 |
+
"recommended_products": products[:4],
|
67 |
+
"total_matches": len(products),
|
68 |
})
|
69 |
except Exception as e:
|
70 |
+
print("β Error in /recommend:", str(e))
|
71 |
return jsonify({"error": "Server error"}), 500
|
72 |
|
73 |
def prepare_features(tile_type, coverage, area, price_range):
|
|
|
86 |
if not (min_price <= p["price"] <= max_price):
|
87 |
continue
|
88 |
|
89 |
+
match_found = False
|
90 |
+
for pref in preferred_sizes:
|
91 |
+
if similar_size_mm(p["size"], pref):
|
92 |
+
match_found = True
|
93 |
break
|
94 |
+
|
95 |
+
if not match_found:
|
96 |
continue
|
97 |
|
98 |
price_score = 1 - (p["price"] - min_price) / (max_price - min_price + 1e-6)
|
99 |
filtered.append({**p, "recommendation_score": round(price_score, 2)})
|
100 |
return sorted(filtered, key=lambda x: x["recommendation_score"], reverse=True)
|
101 |
|
102 |
+
def similar_size_mm(a, b, tolerance=10):
|
103 |
try:
|
104 |
+
w1, h1 = map(int, a.lower().replace("mm", "").split("x"))
|
105 |
+
w2, h2 = map(int, b.lower().replace("mm", "").split("x"))
|
106 |
return abs(w1 - w2) <= tolerance and abs(h1 - h2) <= tolerance
|
107 |
except:
|
108 |
return False
|