| import gradio as gr |
| from api import check_liveness |
|
|
| EXAMPLE_IMAGES = [ |
| ["assets/1.jpg"], |
| ["assets/2.jpg"], |
| ["assets/3.jpg"], |
| ["assets/4.jpg"], |
| ["assets/5.jpg"], |
| ["assets/6.jpg"], |
| ] |
|
|
|
|
| def _normalize_keys(d: dict) -> dict: |
| return {k.strip().replace(" ", "_"): v for k, v in d.items()} |
|
|
|
|
| def _format_result_html(result: dict) -> str: |
| r = _normalize_keys(result) |
|
|
| liveness_text = r.get("liveness_result", "").lower() |
| is_genuine = "genuine" in liveness_text |
|
|
| probability = r.get("probability", 0) |
| if isinstance(probability, str): |
| try: |
| probability = float(probability) |
| except (ValueError, TypeError): |
| probability = 0 |
|
|
| score = r.get("score", 0) |
| if isinstance(score, str): |
| try: |
| score = float(score) |
| except (ValueError, TypeError): |
| score = 0 |
|
|
| quality = r.get("quality", 0) |
| if isinstance(quality, str): |
| try: |
| quality = float(quality) |
| except (ValueError, TypeError): |
| quality = 0 |
|
|
| pct = round(max(0, min(probability, 1)) * 100) |
|
|
| if is_genuine: |
| badge_text = "✅ GENUINE / LIVE" |
| badge_color = "#059669" |
| bg_color = "#ecfdf5" |
| border_color = "#a7f3d0" |
| score_color = "#059669" |
| else: |
| badge_text = "❌ SPOOF / FAKE" |
| badge_color = "#dc2626" |
| bg_color = "#fef2f2" |
| border_color = "#fecaca" |
| score_color = "#dc2626" |
|
|
| html = f""" |
| <div style="padding: 12px 0;"> |
| <div style="background: {bg_color}; border: 2px solid {border_color}; |
| border-radius: 16px; padding: 24px;"> |
| <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;"> |
| <span style="font-size: 22px; font-weight: 700; color: #1e293b;"> |
| Liveness Result |
| </span> |
| </div> |
| |
| <div style="display: inline-block; padding: 8px 24px; border-radius: 999px; |
| background: {badge_color}; color: white; font-weight: 700; |
| font-size: 18px; letter-spacing: 0.5px; margin-bottom: 20px;"> |
| {badge_text} |
| </div> |
| |
| <div style="margin-top: 16px;"> |
| <div style="display: flex; justify-content: space-between; margin-bottom: 6px;"> |
| <span style="font-weight: 600; color: #475569;">Confidence</span> |
| <span style="font-weight: 700; color: {score_color};">{pct}%</span> |
| </div> |
| <div style="background: #e2e8f0; border-radius: 999px; height: 10px; overflow: hidden;"> |
| <div style="width: {pct}%; height: 100%; background: {badge_color}; |
| border-radius: 999px;"></div> |
| </div> |
| </div> |
| |
| <div style="margin-top: 14px; display: flex; gap: 24px;"> |
| <div> |
| <span style="font-size: 13px; color: #94a3b8;">Quality</span> |
| <div style="font-weight: 600; color: #334155;"> |
| {round(quality * 100)}% |
| </div> |
| </div> |
| <div> |
| <span style="font-size: 13px; color: #94a3b8;">Score</span> |
| <div style="font-weight: 600; color: #334155;"> |
| {score:.4f} |
| </div> |
| </div> |
| <div> |
| <span style="font-size: 13px; color: #94a3b8;">Status</span> |
| <div style="font-weight: 600; color: #334155;"> |
| {r.get("state", "")} |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| """ |
| return html |
|
|
|
|
| def process_image(image): |
| if image is None: |
| return ( |
| '<div style="padding:20px;text-align:center;color:#94a3b8;">' |
| "Upload or select an example image</div>", |
| {"error": "No image provided"}, |
| ) |
|
|
| result = check_liveness(image) |
| if "error" in result: |
| return ( |
| f'<div style="padding:20px;text-align:center;color:#dc2626;">{result["error"]}</div>', |
| result, |
| ) |
|
|
| return _format_result_html(result), result |
|
|
|
|
| def create_interface(): |
| with gr.Blocks( |
| title="MiniAiLive Face Liveness Detection", |
| theme=gr.themes.Soft( |
| primary_hue="emerald", |
| neutral_hue="slate", |
| ), |
| css=""" |
| footer {display: none !important;} |
| """, |
| ) as demo: |
| gr.Markdown( |
| """ |
| # 🥇 MiniAiLive Face Liveness Detection |
| **3D Passive Face Liveness Detection · Face Anti-Spoofing** · |
| <a href="https://miniai.live/face-liveness-detection/">For more details: please visit our website</a> |
| |
| Upload a face image or click an example below to check liveness. |
| """ |
| ) |
|
|
| with gr.Row(equal_height=False): |
| with gr.Column(scale=1, min_width=400): |
| image_input = gr.Image(label="Upload Image") |
| submit_btn = gr.Button( |
| "Check Liveness", variant="primary", size="lg" |
| ) |
|
|
| gr.Examples( |
| examples=EXAMPLE_IMAGES, |
| inputs=image_input, |
| label="Example Images", |
| ) |
|
|
| with gr.Column(scale=1, min_width=400): |
| result_html = gr.HTML(label="Result") |
| raw_json = gr.JSON(label="Raw Response") |
|
|
| submit_btn.click( |
| fn=process_image, |
| inputs=image_input, |
| outputs=[result_html, raw_json], |
| ) |
|
|
| return demo |
|
|