import gradio as gr, pandas as pd from huggingface_hub import list_repo_files, hf_hub_download import zipfile, cloudpickle, shutil from pathlib import Path import autogluon.tabular as ag MODEL_REPO_ID = "rlogh/cheese-texture-autogluon-classifier" ZIP_CANDIDATES = ['cheese_texture_predictor_dir.zip', 'autogluon_predictor_dir.zip', 'predictor_dir.zip'] PKL_CANDIDATES = ['cheese_texture_predictor.pkl', 'autogluon_predictor.pkl', 'predictor.pkl'] CACHE_DIR = Path("hf_assets"); CACHE_DIR.mkdir(parents=True, exist_ok=True) EXTRACT_DIR = CACHE_DIR / "predictor_native" def _pick_first(files, cands): for n in cands: if n in files: return n return None def load_predictor(repo_id): files = list_repo_files(repo_id, repo_type="model") zn = _pick_first(files, ZIP_CANDIDATES) pn = _pick_first(files, PKL_CANDIDATES) if zn: zp = hf_hub_download(repo_id, filename=zn, 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, exist_ok=True) with zipfile.ZipFile(zp, "r") as zf: zf.extractall(str(EXTRACT_DIR)) kids = list(EXTRACT_DIR.iterdir()) root = kids[0] if (len(kids)==1 and kids[0].is_dir()) else EXTRACT_DIR return ag.TabularPredictor.load(str(root), require_py_version_match=False) elif pn: pp = hf_hub_download(repo_id, filename=pn, repo_type="model", local_dir=str(CACHE_DIR), local_dir_use_symlinks=False) with open(pp, "rb") as f: return cloudpickle.load(f) raise FileNotFoundError("No predictor artifact found.") PREDICTOR = load_predictor(MODEL_REPO_ID) FEATURES = ["fat","origin","holed","price","protein"] HOLED_MAP = {"Yes (has holes)":1,"No (solid)":0} COMMON_ORIGINS = ["Italy","France","USA","Switzerland","Netherlands","Spain","Greece","Mexico","Denmark","Norway","India","Cyprus"] def predict(fat, origin_pick, origin_free, holed_label, price, protein, k): origin = origin_free.strip() if origin_free and origin_free.strip() else origin_pick row = {"fat":float(fat), "origin":origin, "holed":HOLED_MAP[holed_label], "price":float(price), "protein":float(protein)} X = pd.DataFrame([row], columns=FEATURES) pred = PREDICTOR.predict(X).iloc[0] try: proba = PREDICTOR.predict_proba(X) if hasattr(proba, "to_frame"): proba = proba.to_frame().T if proba.ndim==1 else proba row0 = proba.iloc[0].to_dict() probs = {str(k): float(v) for k,v in row0.items()} probs = dict(sorted(probs.items(), key=lambda kv: kv[1], reverse=True)[:int(k)]) except Exception: probs = {} return f"**Prediction:** {pred}", probs with gr.Blocks() as demo: gr.Markdown("# Cheese Texture Classifier") fat = gr.Slider(0, 60, value=25.0, step=0.1, label="Fat (g/100g)") protein = gr.Slider(0, 40, value=22.0, step=0.1, label="Protein (g/100g)") price = gr.Slider(0, 10, value=2.50, step=0.01, label="Price") holed = gr.Radio(list(HOLED_MAP.keys()), value="No (solid)", label="Has holes?") origin_pick = gr.Dropdown(COMMON_ORIGINS, value="Italy", label="Origin (common)") origin_free = gr.Textbox(value="", placeholder="Or type a custom origin", label="Custom origin (optional)") topk = gr.Slider(1, 4, value=4, step=1, label="Top-K") summary = gr.Markdown() probs = gr.Label(num_top_classes=4, label="Class probabilities") gr.Button("Predict").click(predict, [fat, origin_pick, origin_free, holed, price, protein, topk], [summary, probs]) demo.launch()