| | 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() |
| |
|