Spaces:
Sleeping
Sleeping
| 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 | |
| # ---------------- UI copy ---------------- | |
| TITLE = "π§± LEGO Brick Classifier" | |
| DESC = "Predicts whether a LEGO piece is Standard, Flat, or Sloped from basic dimensions." | |
| # ---------------- Settings ---------------- | |
| MODEL_REPO_ID = "Iris314/classical-automl-model" | |
| ZIP_FILENAME = "lego_predictor_dir.zip" | |
| # UI β model feature name mapping | |
| COLUMN_ALIAS = { | |
| "Length": "Max Length (cm)", | |
| "Height": "Max Height (cm)", | |
| "Width": "Width (cm)", | |
| "Studs": "Studs", | |
| } | |
| FEATURE_COLS_UI = ["Length", "Height", "Width", "Studs"] | |
| # ---------------- Load predictor ---------------- | |
| 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) | |
| # ---------------- Helpers ---------------- | |
| 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"]) | |
| # gr.Number returns float; round & cast for integer feature | |
| 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 probabilities; fall back to label | |
| 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] # ensure JSON-serializable keys | |
| 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) | |
| } | |
| # ---------------- Gradio ---------------- | |
| 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__": | |
| # In Spaces, no share=True needed | |
| demo.launch() | |