File size: 3,975 Bytes
416ce05
211aa18
a1626c0
fc55797
a1626c0
 
4067998
416ce05
211aa18
416ce05
 
a1626c0
416ce05
211aa18
 
 
 
416ce05
211aa18
416ce05
211aa18
389dccc
211aa18
a1626c0
 
 
 
 
416ce05
 
 
 
 
fc55797
a1626c0
fc55797
416ce05
 
 
 
 
211aa18
416ce05
211aa18
 
416ce05
211aa18
416ce05
 
 
 
 
 
4ca754d
416ce05
 
fc55797
416ce05
fc55797
 
 
416ce05
 
 
211aa18
416ce05
fc55797
211aa18
416ce05
 
 
 
211aa18
416ce05
211aa18
fc55797
211aa18
416ce05
 
 
fc55797
 
416ce05
 
 
 
 
 
 
 
 
 
 
 
fc55797
 
416ce05
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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 os

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 data
with open("tile_catalog.json", "r", encoding="utf-8") as f:
    tile_catalog = json.load(f)
with open("tile_sizes.json", "r", encoding="utf-8") as f:
    tile_sizes = 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", "").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", [])

        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", "").lower()
        area = float(data.get("area", 0))
        tile_size = data.get("tile_size", "")

        if tile_size not in tile_sizes:
            return jsonify({"error": "Invalid tile size"}), 400

        info = tile_sizes[tile_size]
        per_tile_area = info["length"] * info["width"]
        tiles_needed = math.ceil((area / per_tile_area) * 1.1)
        boxes = math.ceil(tiles_needed / info.get("tiles_per_box", 10))

        matches = [p for p in tile_catalog if p["type"].lower() == tile_type and p["size"] == tile_size]

        return jsonify({
            "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": "Server error"}), 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)