image_app_duo / app.py
ddecosmo's picture
Update app.py
eb02742 verified
# -*- coding: utf-8 -*-
"""image_model.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1SRq7ZIsAwqDYyV4UWM9SZJuRYJvQe59o
"""
import os # For reading environment variables
import shutil # For directory cleanup
import zipfile # For extracting model archives
import pathlib # For path manipulations
import tempfile # For creating temporary files/directories
import gradio # For interactive UI
import pandas # For tabular data handling
import PIL.Image # For image I/O
import huggingface_hub # For downloading model assets
import autogluon.multimodal # For loading AutoGluon image classifier
# Hardcoded Hub model (native zip)
MODEL_REPO_ID = "SebastianAndreu/2025-24679-HW1-Part2-image-autogluon-predictor"
ZIP_FILENAME = "autogluon_image_predictor_dir.zip"
HF_TOKEN = os.getenv("HF_TOKEN", None)
# Local cache/extract dirs
CACHE_DIR = pathlib.Path("hf_assets")
EXTRACT_DIR = CACHE_DIR / "predictor_native"
# Download & load the native predictor
def _prepare_predictor_dir() -> str:
CACHE_DIR.mkdir(parents=True, exist_ok=True)
local_zip = huggingface_hub.hf_hub_download(
repo_id=MODEL_REPO_ID,
filename=ZIP_FILENAME,
repo_type="model",
token=HF_TOKEN,
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(local_zip, "r") as zf:
zf.extractall(str(EXTRACT_DIR))
contents = list(EXTRACT_DIR.iterdir())
predictor_root = contents[0] if (len(contents) == 1 and contents[0].is_dir()) else EXTRACT_DIR
return str(predictor_root)
PREDICTOR_DIR = _prepare_predictor_dir()
PREDICTOR = autogluon.multimodal.MultiModalPredictor.load(PREDICTOR_DIR)
# Explicit class labels (edit copy as desired)
CLASS_LABELS = {0: "No Duo :(", 1: "DUO :-)"}
# Helper to map model class -> human label
def _human_label(c):
try:
ci = int(c)
return CLASS_LABELS.get(ci, str(c))
except Exception:
return CLASS_LABELS.get(c, str(c))
# Do the prediction!
def do_predict(pil_img: PIL.Image.Image):
# Make sure there's actually an image to work with
if pil_img is None:
return "No image provided.", {}, pandas.DataFrame(columns=["Predicted label", "Confidence (%)"])
# IF we have something to work with, save it and prepare the input
tmpdir = pathlib.Path(tempfile.mkdtemp())
img_path = tmpdir / "input.png"
pil_img.save(img_path)
df = pandas.DataFrame({"image": [str(img_path)]}) # For AutoGluon expected input format
# For class probabilities
proba_df = PREDICTOR.predict_proba(df)
# For user-friendly column names
proba_df = proba_df.rename(columns={0: "No Duo :(", 1: "DUO :-)"})
row = proba_df.iloc[0]
# For pretty ranked dict expected by gr.Label
pretty_dict = {
"No Duo :(": float(row.get("No Duo :(", 0.0)),
"DUO :-)": float(row.get("DUO :-)", 0.0)),
}
# Calculate confidence interval (a simple representation for demonstration)
# This is not a statistically rigorous CI, but rather a representation of the probability spread.
confidence_info = f"No Duo Probability: {pretty_dict['No Duo :(']:.2f}, DUO Probability: {pretty_dict['DUO :-)']:.2f}"
return pretty_dict, confidence_info
EXAMPLES = [
["duo_1.jpg"],
["duo_2.jpg"],
["no_duo_1.jpg"],
["no_duo_2.jpg"]
]
# Gradio UI
with gradio.Blocks() as demo:
# Provide an introduction
gradio.Markdown("# Is Duo Here?")
gradio.Markdown("""
This is an app that demonstrates a binary classifier using SebastianAndreu/2025-24679-HW1-Part2-image-autogluon-predictor model
based on the scottymcgee/duo-image-dataset imageset. This performs binary classification of outdoor images to see
if the bird from Duolingo is in them. It has an accuracy of 80% based on the model so can have errors.
""")
# Interface for the incoming image
image_in = gradio.Image(type="pil", label="Input image", sources=["upload", "webcam"])
# Interface elements to show htte result and probabilities
proba_pretty = gradio.Label(num_top_classes=2, label="Class probabilities")
# Whenever a new image is uploaded, update the result
image_in.change(fn=do_predict, inputs=[image_in], outputs=[proba_pretty])
# For clickable example images
gradio.Examples(
examples=EXAMPLES,
inputs=[image_in],
label="Representative examples",
examples_per_page=8,
cache_examples=False,
)
# Gradio UI
with gradio.Blocks() as demo:
# Provide an introduction
gradio.Markdown("# Is Duo Here?")
gradio.Markdown("""
This is a simple app that demonstrates how to use an autogluon multimodal
predictor in a gradio space to predict the contents of a picture. To use,
just upload a photo. The result should be generated automatically.
""")
# Interface for the incoming image
image_in = gradio.Image(type="pil", label="Input image", sources=["upload", "webcam"])
# Interface elements to show htte result and probabilities
proba_pretty = gradio.Label(num_top_classes=2, label="Class probabilities")
confidence_output = gradio.Textbox(label="Confidence Information")
# Whenever a new image is uploaded, update the result
image_in.change(fn=do_predict, inputs=[image_in], outputs=[proba_pretty, confidence_output])
# For clickable example images
gradio.Examples(
examples=EXAMPLES,
inputs=[image_in],
label="Representative examples",
examples_per_page=8,
cache_examples=False,
)
# Launch here
if __name__ == "__main__":
demo.launch()