| from __future__ import annotations
|
|
|
| import os
|
| import sys
|
| from functools import lru_cache
|
| from pathlib import Path
|
| from typing import Dict, List
|
|
|
| import gradio as gr
|
| from PIL import Image
|
|
|
| ROOT = Path(__file__).resolve().parent
|
| if str(ROOT) not in sys.path:
|
| sys.path.insert(0, str(ROOT))
|
|
|
| from src.inference import ClipPredictor, CustomModelPredictor, OpenAIVisionPredictor
|
|
|
|
|
| labels = ["charizard", "charmander", "charmeleon", "ditto", "eevee", "ekans"]
|
|
|
|
|
| @lru_cache(maxsize=1)
|
| def get_predictors() -> tuple[CustomModelPredictor, ClipPredictor, OpenAIVisionPredictor]:
|
| custom = CustomModelPredictor(str(ROOT / "models" / "custom_resnet18.pth"))
|
| predictor_labels = custom.labels if custom.available() else labels
|
| clip_model = ClipPredictor(predictor_labels)
|
| openai_model = OpenAIVisionPredictor(predictor_labels)
|
| return custom, clip_model, openai_model
|
|
|
|
|
| def _format_preds(result: Dict[str, object]) -> str:
|
| if not result.get("available", False):
|
| return f"Unavailable: {result.get('error', 'unknown error')}"
|
|
|
| lines: List[str] = []
|
| top = result.get("top_prediction", {})
|
| label = top.get("label", "-")
|
| confidence = float(top.get("confidence", 0.0))
|
| lines.append(f"Top prediction: {label} ({confidence:.2%})")
|
|
|
| for pred in result.get("predictions", []):
|
| lines.append(f"- {pred['label']}: {pred['confidence']:.2%}")
|
|
|
| raw_response = result.get("raw_response")
|
| if isinstance(raw_response, dict) and raw_response.get("reason"):
|
| lines.append(f"Reason: {raw_response['reason']}")
|
|
|
| return "\n".join(lines)
|
|
|
|
|
| def classify_image(image: Image.Image):
|
| if image is None:
|
| return "No image provided.", "No image provided.", "No image provided."
|
|
|
| custom, clip_model, openai_model = get_predictors()
|
| custom_pred = custom.predict(image)
|
| clip_pred = clip_model.predict(image)
|
| openai_pred = openai_model.predict(image)
|
|
|
| return _format_preds(custom_pred), _format_preds(clip_pred), _format_preds(openai_pred)
|
|
|
|
|
| def get_examples() -> List[List[str]]:
|
| examples_dir = ROOT / "app" / "examples"
|
| if not examples_dir.exists():
|
| return []
|
| image_paths = sorted(
|
| [p for p in examples_dir.iterdir() if p.suffix.lower() in {".jpg", ".jpeg", ".png", ".webp"}]
|
| )
|
| return [[str(p)] for p in image_paths]
|
|
|
|
|
| description = """
|
| Upload an image and compare predictions from three models:
|
| 1) Custom transfer learning model (ResNet18)
|
| 2) Open-source CLIP model
|
| 3) Closed-source OpenAI vision model
|
|
|
| If OPENAI_API_KEY is not set, OpenAI predictions are shown as unavailable.
|
| """
|
|
|
| with gr.Blocks(title="Computer Vision Model Comparison") as demo:
|
| gr.Markdown("# Computer Vision Classification & Model Comparison")
|
| gr.Markdown(description)
|
|
|
| with gr.Row():
|
| image_input = gr.Image(type="pil", label="Upload image")
|
|
|
| classify_button = gr.Button("Classify")
|
|
|
| with gr.Row():
|
| custom_output = gr.Textbox(label="Custom Transfer Learning", lines=8)
|
| clip_output = gr.Textbox(label="Open-Source CLIP", lines=8)
|
| openai_output = gr.Textbox(label="Closed-Source OpenAI Vision", lines=8)
|
|
|
| classify_button.click(classify_image, inputs=[image_input], outputs=[custom_output, clip_output, openai_output])
|
|
|
| gr.Examples(examples=get_examples(), inputs=image_input, label="Example images")
|
|
|
| if __name__ == "__main__":
|
| in_space = bool(os.getenv("SPACE_ID"))
|
| if in_space:
|
| demo.launch(ssr_mode=False)
|
| else:
|
| print("Launching local app on http://127.0.0.1:7860")
|
| demo.launch(server_name="127.0.0.1", server_port=7860, share=False, ssr_mode=False)
|
|
|