File size: 4,907 Bytes
5d5165f a43c45a e09d218 61ffb8e 0616b98 5d5165f d12096d 1139b4c 61ffb8e 5d5165f 61ffb8e 0616b98 61ffb8e 0616b98 5d5165f 61ffb8e e09d218 5d5165f 14765ac 5d5165f 0616b98 5d5165f 1139b4c 857baf5 e09d218 1139b4c 857baf5 e09d218 857baf5 1139b4c 857baf5 1139b4c 857baf5 1139b4c 857baf5 0616b98 1139b4c 0616b98 1139b4c 0616b98 1139b4c 0616b98 e09d218 857baf5 1139b4c e09d218 1139b4c e09d218 1139b4c e09d218 1139b4c e09d218 0616b98 e09d218 0616b98 e09d218 1139b4c 0616b98 857baf5 1139b4c e09d218 0616b98 1139b4c 0616b98 5d5165f a43c45a 0616b98 1139b4c 0616b98 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
import joblib
import numpy as np
import json
import math
import xgboost as xgb
import re
app = Flask(__name__, static_folder='.', static_url_path='/')
CORS(app)
# Load ML models
try:
rf = joblib.load("rf_model.pkl")
xgb_model = xgb.Booster()
xgb_model.load_model("xgb_model.json")
print("β
Models loaded successfully.")
except Exception as e:
print(f"β Error loading models: {e}")
raise e
# Load tile catalog
with open("tile_catalog.json", "r", encoding="utf-8") as f:
tile_catalog = json.load(f)
@app.route("/")
def index():
return send_from_directory(".", "index.html")
@app.route("/recommend", methods=["POST"])
def recommend():
try:
data = request.get_json()
tile_type = data.get("tile_type", "").strip().lower()
coverage = float(data.get("coverage", 1))
area = float(data.get("area", 1))
price_range = data.get("price_range", [1, 100])
preferred_sizes = data.get("preferred_sizes", [])
if area <= 0 or coverage <= 0:
return jsonify({"error": "Please enter valid area and coverage values."}), 400
features = prepare_features(tile_type, coverage, area, price_range)
xgb_pred = xgb_model.predict(xgb.DMatrix(features))[0]
rf_pred = rf.predict_proba(features)[0][1]
score = (xgb_pred + rf_pred) / 2
products = filter_products(tile_type, price_range, preferred_sizes)
return jsonify({
"recommendation_score": round(float(score), 3),
"recommended_products": products[:4],
"total_matches": len(products),
})
except Exception as e:
print("β Error in /recommend:", str(e))
return jsonify({"error": "Server error"}), 500
@app.route("/calculate", methods=["POST"])
def calculate():
try:
data = request.get_json()
tile_type = data.get("tile_type", "").strip().lower()
area = float(data.get("area", 0))
tile_size_raw = data.get("tile_size", "").strip()
if not tile_type:
return jsonify({"error": "Please select a tile type (e.g., floor, wall)."}), 400
if area <= 0:
return jsonify({"error": "Area must be greater than 0."}), 400
# Extract tile length and width in feet using regex
match = re.match(r"(\d+(\.\d+)?)\s*(ft|feet)?\s*[xXΓ*]\s*(\d+(\.\d+)?)\s*(ft|feet)?", tile_size_raw)
if not match:
return jsonify({"error": f"Invalid tile size format: '{tile_size_raw}'. Please enter like '2 x 2 ft'."}), 400
length_ft = float(match.group(1))
width_ft = float(match.group(4))
if length_ft <= 0 or width_ft <= 0:
return jsonify({"error": "Tile dimensions must be greater than 0."}), 400
tile_area = length_ft * width_ft # in sq.ft
tiles_needed = math.ceil((area / tile_area) * 1.1) # +10% buffer
boxes = math.ceil(tiles_needed / 10) # assuming 10 tiles per box
# Filter matching products by type and approximate size
matches = [
p for p in tile_catalog
if p["type"].lower() == tile_type
]
return jsonify({
"tile_type": tile_type,
"area_sqft": area,
"tile_size": f"{length_ft:.2f} ft x {width_ft:.2f} ft",
"tiles_needed": tiles_needed,
"boxes_needed": boxes,
"matching_products": matches[:3],
"total_matches": len(matches)
})
except Exception as e:
print("β Error in /calculate:", str(e))
return jsonify({"error": "An error occurred. Please check your input values."}), 500
def prepare_features(tile_type, coverage, area, price_range):
tile_type_num = 0 if tile_type == "floor" else 1
min_price, max_price = price_range
price_per_sqft = max_price / coverage
efficiency = coverage / max_price
return np.array([[tile_type_num, area, coverage, min_price, max_price, price_per_sqft, efficiency]])
def filter_products(tile_type, price_range, preferred_sizes):
min_price, max_price = price_range
filtered = []
for product in tile_catalog:
if product["type"].lower() != tile_type:
continue
if not (min_price <= product["price"] <= max_price):
continue
if preferred_sizes and product["size"] not in preferred_sizes:
continue
price_score = 1 - (product["price"] - min_price) / (max_price - min_price + 1e-6)
size_score = 1 if product["size"] in preferred_sizes else 0.5
score = round((price_score + size_score) / 2, 2)
filtered.append({**product, "recommendation_score": score})
return sorted(filtered, key=lambda x: x["recommendation_score"], reverse=True)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860)
|