| import pathlib, shutil, zipfile, os, traceback |
| import pandas as pd |
| import gradio as gr |
|
|
| from huggingface_hub import hf_hub_download |
| from autogluon.tabular import TabularPredictor |
|
|
| |
| TITLE = "🧱 LEGO Brick Classifier" |
| DESC = "Predicts whether a LEGO piece is Standard, Flat, or Sloped from basic dimensions." |
|
|
| |
| MODEL_REPO_ID = "Iris314/classical-automl-model" |
| ZIP_FILENAME = "lego_predictor_dir.zip" |
|
|
| |
| COLUMN_ALIAS = { |
| "Length": "Max Length (cm)", |
| "Height": "Max Height (cm)", |
| "Width": "Width (cm)", |
| "Studs": "Studs", |
| } |
| FEATURE_COLS_UI = ["Length", "Height", "Width", "Studs"] |
|
|
| |
| CACHE_DIR = pathlib.Path("hf_cache"); EXTRACT_DIR = CACHE_DIR / "predictor" |
| CACHE_DIR.mkdir(exist_ok=True, parents=True) |
|
|
| def load_predictor(): |
| local_zip = hf_hub_download( |
| repo_id=MODEL_REPO_ID, |
| filename=ZIP_FILENAME, |
| repo_type="model", |
| local_dir=str(CACHE_DIR), |
| local_dir_use_symlinks=False, |
| ) |
| if EXTRACT_DIR.exists(): |
| shutil.rmtree(EXTRACT_DIR) |
| EXTRACT_DIR.mkdir(parents=True) |
| with zipfile.ZipFile(local_zip, "r") as zf: |
| zf.extractall(EXTRACT_DIR) |
| kids = list(EXTRACT_DIR.iterdir()) |
| path = kids[0] if len(kids) == 1 and kids[0].is_dir() else EXTRACT_DIR |
| return TabularPredictor.load(str(path), require_py_version_match=False) |
|
|
| try: |
| PREDICTOR = load_predictor() |
| except Exception as e: |
| PREDICTOR = None |
| print("Failed to load predictor:", e) |
|
|
| |
| def _cast_and_rename(row_dict): |
| row = dict(row_dict) |
| row["Length"] = float(row["Length"]) |
| row["Height"] = float(row["Height"]) |
| row["Width"] = float(row["Width"]) |
| |
| row["Studs"] = int(round(float(row["Studs"]))) |
| X_ui = pd.DataFrame([row], columns=FEATURE_COLS_UI) |
| X_model = X_ui.rename(columns=COLUMN_ALIAS) |
| return X_model |
|
|
| def classify_brick(length, height, width, studs): |
| try: |
| if PREDICTOR is None: |
| raise RuntimeError("Model failed to load on startup. Check model artifact path & runtime deps.") |
|
|
| X = _cast_and_rename({ |
| "Length": length, "Height": height, "Width": width, "Studs": studs |
| }) |
|
|
| |
| try: |
| proba = PREDICTOR.predict_proba(X) |
| s = proba.iloc[0] if hasattr(proba, "iloc") else proba |
| s = s.sort_values(ascending=False) |
| s.index = [str(k) for k in s.index] |
| return {k: float(v) for k, v in s.items()} |
| except Exception: |
| pred = PREDICTOR.predict(X) |
| pred_val = pred.iloc[0] if hasattr(pred, "iloc") else pred |
| return {"prediction": str(pred_val)} |
| except Exception as e: |
| return { |
| "error": f"{type(e).__name__}: {e}", |
| "traceback": traceback.format_exc(limit=1) |
| } |
|
|
| |
| demo = gr.Interface( |
| fn=classify_brick, |
| inputs=[ |
| gr.Slider(1, 10, step=0.1, value=4, label="Length"), |
| gr.Slider(0.2, 5, step=0.1, value=1.2, label="Height"), |
| gr.Slider(1, 10, step=0.1, value=2, label="Width"), |
| gr.Number(value=4, precision=0, label="Studs"), |
| ], |
| outputs=gr.Label(num_top_classes=3, label="Predicted Class / Probabilities"), |
| examples=[[4, 1.2, 2, 4], [2, 0.6, 2, 2], [3, 2.0, 2, 2]], |
| title=TITLE, |
| description=DESC |
| ) |
|
|
| if __name__ == "__main__": |
| |
| demo.launch() |
|
|