Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| import onnxruntime as ort | |
| from PIL import Image | |
| from torchvision import transforms | |
| from torchvision.transforms import functional as F | |
| MODEL_PATH = "oink0.onnx" | |
| NSFW_THRESHOLD = 0.30 # adjust if needed | |
| class Letterbox224: | |
| def __call__(self, img): | |
| w, h = img.size | |
| scale = 224 / max(w, h) | |
| nw, nh = int(w * scale), int(h * scale) | |
| img = img.resize((nw, nh)) | |
| pad_w, pad_h = 224 - nw, 224 - nh | |
| return F.pad( | |
| img, | |
| (pad_w // 2, pad_h // 2, pad_w - pad_w // 2, pad_h - pad_h // 2), | |
| fill=0 | |
| ) | |
| transform = transforms.Compose([ | |
| Letterbox224(), | |
| transforms.ToTensor(), | |
| ]) | |
| session = ort.InferenceSession( | |
| MODEL_PATH, | |
| providers=["CPUExecutionProvider"] | |
| ) | |
| def predict(image: Image.Image): | |
| if image is None: | |
| return "No image", 0.0 | |
| img = image.convert("RGB") | |
| x = transform(img).unsqueeze(0).numpy() | |
| logits = session.run(None, {"input": x})[0] | |
| probs = np.exp(logits) / np.exp(logits).sum(axis=1, keepdims=True) | |
| nsfw_prob = float(probs[0, 1]) | |
| if nsfw_prob > NSFW_THRESHOLD: | |
| decision = "NSFW (block)" | |
| elif nsfw_prob > 0.20: | |
| decision = "Borderline (review)" | |
| else: | |
| decision = "Safe" | |
| return decision, nsfw_prob | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# Oink0 Demo (ONNX)") | |
| gr.Markdown( | |
| "Upload a Roblox avatar image. " | |
| "Model outputs an NSFW probability and a moderation decision." | |
| ) | |
| with gr.Row(): | |
| image_input = gr.Image(type="pil", label="Avatar Image") | |
| label_output = gr.Label(label="Result", num_top_classes=1) | |
| prob_output = gr.Number(label="NSFW probability", precision=4) | |
| image_input.change( | |
| fn=predict, | |
| inputs=image_input, | |
| outputs=[label_output, prob_output], | |
| ) | |
| demo.launch() | |