Humanly / app.py
jatinkarma's picture
Update app.py
2f4c841 verified
Raw History Blame Contribute Delete
7.19 kB
import os
import sys
import numpy as np
from PIL import Image
import keras
import gradio as gr
import spaces
# 1. Dummy GPU function to satisfy HuggingFace ZeroGPU startup check
@spaces.GPU
def _dummy_startup():
pass
# 2. Load trained MobileNetV2 model once at startup
MODEL_PATH = os.getenv("MODEL_PATH", "models/human_face_v1.keras")
model = keras.models.load_model(MODEL_PATH)
CLASS_NAMES = ["human", "non_human"]
THRESHOLD = 0.5
# 3. CPU prediction function (runs cleanly in ~30ms without ZeroGPU hang)
def predict_face(img):
if img is None:
return """
<div style="background: #f8fafc; border: 2px dashed #cbd5e1; border-radius: 20px; padding: 40px 20px; text-align: center; color: #94a3b8; font-weight: 600;">
Upload an image on the left to see the AI decision!
</div>
"""
# Preprocess image
image = img.convert("RGB").resize((224, 224))
pixels = np.asarray(image, dtype=np.float32)[None, ...]
p_non_human = float(model.predict(pixels, verbose=0)[0][0])
p_human = 1.0 - p_non_human
if p_human >= THRESHOLD:
pct = round(p_human * 100, 1)
return f"""
<div style="background: white; border: 2px solid #10b981; border-radius: 20px; padding: 24px; box-shadow: 0 10px 30px rgba(16,185,129,0.12);">
<div style="display: flex; align-items: center; gap: 14px; margin-bottom: 12px;">
<div style="width: 44px; height: 44px; border-radius: 50%; background: #10b981; color: white; display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 900;">βœ“</div>
<div>
<h2 style="font-size: 24px; font-weight: 800; color: #1e293b; margin: 0;">It's a Human!</h2>
<p style="color: #64748b; font-weight: 600; margin: 0; font-size: 15px;">Confidence: <span style="color: #10b981; font-weight: 800;">{pct}%</span></p>
</div>
</div>
<div style="background: #f1f5f9; border-radius: 9999px; height: 10px; overflow: hidden; margin: 16px 0;">
<div style="background: #10b981; height: 100%; width: {pct}%; border-radius: 9999px;"></div>
</div>
<div style="font-family: 'Caveat', cursive, sans-serif; font-size: 24px; color: #1e293b; text-align: right; margin-top: 10px;">
Looks like a human! 😊
</div>
</div>
"""
else:
pct = round(p_non_human * 100, 1)
return f"""
<div style="background: white; border: 2px solid #ef4444; border-radius: 20px; padding: 24px; box-shadow: 0 10px 30px rgba(239,68,68,0.12);">
<div style="display: flex; align-items: center; gap: 14px; margin-bottom: 12px;">
<div style="width: 44px; height: 44px; border-radius: 50%; background: #ef4444; color: white; display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 900;">βœ—</div>
<div>
<h2 style="font-size: 24px; font-weight: 800; color: #1e293b; margin: 0;">Not a Human!</h2>
<p style="color: #64748b; font-weight: 600; margin: 0; font-size: 15px;">Confidence: <span style="color: #ef4444; font-weight: 800;">{pct}%</span></p>
</div>
</div>
<div style="background: #f1f5f9; border-radius: 9999px; height: 10px; overflow: hidden; margin: 16px 0;">
<div style="background: #ef4444; height: 100%; width: {pct}%; border-radius: 9999px;"></div>
</div>
<div style="font-family: 'Caveat', cursive, sans-serif; font-size: 22px; color: #1e293b; text-align: right; margin-top: 10px;">
Looks like AI or synthetic! πŸ€–
</div>
</div>
"""
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Caveat:wght@600;700&family=Outfit:wght@600;700;800&family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap');
.gradio-container {
max-width: 1080px !important;
margin: 0 auto !important;
font-family: 'Plus Jakarta Sans', sans-serif !important;
background: #f8faff !important;
}
"""
with gr.Blocks(title="Humanly - Human or Not?") as demo:
# 1. Top Navbar
gr.HTML("""
<div style="display: flex; justify-content: space-between; align-items: center; padding: 16px 0; border-bottom: 1px solid #e2e8f0; margin-bottom: 24px;">
<div style="display: flex; align-items: center; gap: 8px; font-family: 'Outfit', sans-serif; font-size: 22px; font-weight: 800; color: #1e293b;">
<span style="color: #5c54e5;">✦</span> VisionMind
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<a href="https://github.com/jatin-karma/Humanly" target="_blank" style="text-decoration: none; color: #64748b; font-weight: 600; font-size: 14px;">GitHub</a>
<div style="display: flex; align-items: center; gap: 6px; background: #dcfce7; color: #15803d; padding: 6px 14px; border-radius: 9999px; font-size: 13px; font-weight: 700;">
<span style="width: 8px; height: 8px; border-radius: 50%; background: #16a34a;"></span> Model Online
</div>
</div>
</div>
""")
# 2. Hero Section with Mascot & Title
gr.HTML("""
<div style="text-align: center; margin-bottom: 32px;">
<div style="font-size: 54px; margin-bottom: 8px;">πŸ€–</div>
<h1 style="font-family: 'Outfit', sans-serif; font-size: 42px; font-weight: 800; color: #4338ca; margin: 0 0 6px 0;">
Human <span style="color: #6366f1;">or</span> Not?
</h1>
<p style="color: #64748b; font-size: 17px; font-weight: 500; margin: 0;">Upload an image and let AI decide!</p>
</div>
""")
# 3. Main Two-Column Card Layout
with gr.Row():
with gr.Column(scale=1):
image_input = gr.Image(
type="pil",
label="Upload Face Image (JPG, PNG, JPEG)",
sources=["upload", "clipboard"],
)
classify_btn = gr.Button("πŸ” Classify Face", variant="primary", size="lg")
with gr.Column(scale=1):
result_output = gr.HTML(
value="""
<div style="background: #f8fafc; border: 2px dashed #cbd5e1; border-radius: 20px; padding: 50px 20px; text-align: center; color: #94a3b8; font-weight: 600; min-height: 180px; display: flex; align-items: center; justify-content: center;">
Upload an image on the left and click Classify!
</div>
"""
)
# 4. Triggers: Auto on upload + manual on button click
image_input.change(fn=predict_face, inputs=image_input, outputs=result_output)
classify_btn.click(fn=predict_face, inputs=image_input, outputs=result_output)
# 5. Footer
gr.HTML("""
<div style="text-align: center; padding: 32px 0 16px 0; color: #94a3b8; font-size: 14px; font-weight: 500; border-top: 1px solid #e2e8f0; margin-top: 40px;">
Built by <strong>Jatin Karma ❀️</strong>
</div>
""")
if __name__ == "__main__":
demo.launch(css=custom_css, ssr_mode=False)