rakibulinux commited on
Commit
add9725
·
1 Parent(s): 4935acb

Update UI

Browse files
Files changed (2) hide show
  1. api.py +14 -2
  2. ui.py +108 -47
api.py CHANGED
@@ -9,11 +9,23 @@ API_URL = os.environ.get(
9
  )
10
 
11
 
12
- def check_liveness(image: np.ndarray) -> dict:
13
  if image is None:
 
 
 
 
 
 
 
 
 
 
 
 
14
  return {"error": "No image provided"}
15
 
16
- success, img_encoded = cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, 95])
17
  if not success:
18
  return {"error": "Failed to encode image"}
19
 
 
9
  )
10
 
11
 
12
+ def _load_image(image):
13
  if image is None:
14
+ return None
15
+ if isinstance(image, str):
16
+ img = cv2.imread(image)
17
+ if img is None:
18
+ return None
19
+ return img
20
+ return image
21
+
22
+
23
+ def check_liveness(image) -> dict:
24
+ img = _load_image(image)
25
+ if img is None:
26
  return {"error": "No image provided"}
27
 
28
+ success, img_encoded = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])
29
  if not success:
30
  return {"error": "Failed to encode image"}
31
 
ui.py CHANGED
@@ -11,64 +11,117 @@ EXAMPLE_IMAGES = [
11
  ]
12
 
13
 
 
 
 
 
14
  def _format_result_html(result: dict) -> str:
15
- is_live = result.get("real", result.get("live", result.get("is_live", False)))
16
- score = result.get("score", result.get("confidence", result.get("liveness_score", 0)))
17
- message = result.get("message", result.get("msg", result.get("detail", "")))
 
 
 
 
 
 
 
 
18
 
19
- if isinstance(is_live, str):
20
- is_live = is_live.lower() in ("true", "1", "yes", "real", "live")
21
  if isinstance(score, str):
22
  try:
23
  score = float(score)
24
  except (ValueError, TypeError):
25
  score = 0
26
- if score > 1:
27
- score = score / 100
28
-
29
- pct = max(0, min(100, round(score * 100)))
30
- badge_color = "#22c55e" if is_live else "#ef4444"
31
- badge_text = "REAL / LIVE" if is_live else "SPOOF / FAKE"
32
- icon = "✅" if is_live else "❌"
33
-
34
- return f"""
35
- <div style="padding: 20px; border-radius: 12px; background: #f8fafc; border: 1px solid #e2e8f0;">
36
- <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
37
- <span style="font-size: 28px;">{icon}</span>
38
- <span style="font-size: 24px; font-weight: 700;">Liveness Result</span>
39
- </div>
40
- <div style="display: inline-block; padding: 8px 20px; border-radius: 20px;
41
- background: {badge_color}; color: white; font-weight: 700;
42
- font-size: 18px; margin-bottom: 16px;">
43
- {badge_text}
44
- </div>
45
- <div style="margin-top: 14px;">
46
- <div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
47
- <span style="font-weight: 600;">Confidence</span>
48
- <span>{pct}%</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  </div>
50
- <div style="background: #e2e8f0; border-radius: 8px; height: 12px; overflow: hidden;">
51
- <div style="width: {pct}%; height: 100%; background: {badge_color};
52
- border-radius: 8px; transition: width 0.5s;"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  </div>
54
  </div>
55
- {f"<p style='margin-top: 12px; color: #64748b;'>{message}</p>" if message else ""}
56
  </div>
57
  """
 
58
 
59
 
60
  def process_image(image):
61
  if image is None:
62
  return (
63
- '<div style="padding:20px;color:#64748b;text-align:center;">'
64
- "Upload or select an example image first</div>",
65
- {"error": "Please upload an image first"},
66
  )
67
 
68
  result = check_liveness(image)
69
  if "error" in result:
70
  return (
71
- f'<div style="padding:20px;color:#ef4444;text-align:center;">{result["error"]}</div>',
72
  result,
73
  )
74
 
@@ -76,33 +129,41 @@ def process_image(image):
76
 
77
 
78
  def create_interface():
79
- with gr.Blocks(title="MiniAiLive Face Liveness Detection", theme=gr.themes.Soft()) as demo:
 
 
 
 
 
 
 
 
 
80
  gr.Markdown(
81
  """
82
  # 🥇 MiniAiLive Face Liveness Detection
83
- **3D Passive Face Liveness Detection (Face Anti-Spoofing)**
84
 
85
  Upload a face image or click an example below to check liveness.
86
  """
87
  )
88
 
89
- with gr.Row():
90
- with gr.Column(scale=1):
91
- image_input = gr.Image(
92
- label="Upload Image",
93
- type="numpy",
94
  )
95
- submit_btn = gr.Button("🔍 Check Liveness", variant="primary", size="lg")
96
 
97
  gr.Examples(
98
  examples=EXAMPLE_IMAGES,
99
  inputs=image_input,
100
- label="📸 Example Images",
101
  )
102
 
103
- with gr.Column(scale=1):
104
  result_html = gr.HTML(label="Result")
105
- raw_json = gr.JSON(label="Raw Response", visible=True)
106
 
107
  submit_btn.click(
108
  fn=process_image,
 
11
  ]
12
 
13
 
14
+ def _normalize_keys(d: dict) -> dict:
15
+ return {k.strip().replace(" ", "_"): v for k, v in d.items()}
16
+
17
+
18
  def _format_result_html(result: dict) -> str:
19
+ r = _normalize_keys(result)
20
+
21
+ liveness_text = r.get("liveness_result", "").lower()
22
+ is_genuine = "genuine" in liveness_text
23
+
24
+ probability = r.get("probability", 0)
25
+ if isinstance(probability, str):
26
+ try:
27
+ probability = float(probability)
28
+ except (ValueError, TypeError):
29
+ probability = 0
30
 
31
+ score = r.get("score", 0)
 
32
  if isinstance(score, str):
33
  try:
34
  score = float(score)
35
  except (ValueError, TypeError):
36
  score = 0
37
+
38
+ quality = r.get("quality", 0)
39
+ if isinstance(quality, str):
40
+ try:
41
+ quality = float(quality)
42
+ except (ValueError, TypeError):
43
+ quality = 0
44
+
45
+ pct = round(max(0, min(probability, 1)) * 100)
46
+
47
+ if is_genuine:
48
+ badge_text = "✅ GENUINE / LIVE"
49
+ badge_color = "#059669"
50
+ bg_color = "#ecfdf5"
51
+ border_color = "#a7f3d0"
52
+ score_color = "#059669"
53
+ else:
54
+ badge_text = "❌ SPOOF / FAKE"
55
+ badge_color = "#dc2626"
56
+ bg_color = "#fef2f2"
57
+ border_color = "#fecaca"
58
+ score_color = "#dc2626"
59
+
60
+ html = f"""
61
+ <div style="padding: 12px 0;">
62
+ <div style="background: {bg_color}; border: 2px solid {border_color};
63
+ border-radius: 16px; padding: 24px;">
64
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;">
65
+ <span style="font-size: 22px; font-weight: 700; color: #1e293b;">
66
+ Liveness Result
67
+ </span>
68
+ </div>
69
+
70
+ <div style="display: inline-block; padding: 8px 24px; border-radius: 999px;
71
+ background: {badge_color}; color: white; font-weight: 700;
72
+ font-size: 18px; letter-spacing: 0.5px; margin-bottom: 20px;">
73
+ {badge_text}
74
+ </div>
75
+
76
+ <div style="margin-top: 16px;">
77
+ <div style="display: flex; justify-content: space-between; margin-bottom: 6px;">
78
+ <span style="font-weight: 600; color: #475569;">Confidence</span>
79
+ <span style="font-weight: 700; color: {score_color};">{pct}%</span>
80
+ </div>
81
+ <div style="background: #e2e8f0; border-radius: 999px; height: 10px; overflow: hidden;">
82
+ <div style="width: {pct}%; height: 100%; background: {badge_color};
83
+ border-radius: 999px;"></div>
84
+ </div>
85
  </div>
86
+
87
+ <div style="margin-top: 14px; display: flex; gap: 24px;">
88
+ <div>
89
+ <span style="font-size: 13px; color: #94a3b8;">Quality</span>
90
+ <div style="font-weight: 600; color: #334155;">
91
+ {round(quality * 100)}%
92
+ </div>
93
+ </div>
94
+ <div>
95
+ <span style="font-size: 13px; color: #94a3b8;">Score</span>
96
+ <div style="font-weight: 600; color: #334155;">
97
+ {score:.4f}
98
+ </div>
99
+ </div>
100
+ <div>
101
+ <span style="font-size: 13px; color: #94a3b8;">Status</span>
102
+ <div style="font-weight: 600; color: #334155;">
103
+ {r.get("state", "")}
104
+ </div>
105
+ </div>
106
  </div>
107
  </div>
 
108
  </div>
109
  """
110
+ return html
111
 
112
 
113
  def process_image(image):
114
  if image is None:
115
  return (
116
+ '<div style="padding:20px;text-align:center;color:#94a3b8;">'
117
+ "Upload or select an example image</div>",
118
+ {"error": "No image provided"},
119
  )
120
 
121
  result = check_liveness(image)
122
  if "error" in result:
123
  return (
124
+ f'<div style="padding:20px;text-align:center;color:#dc2626;">{result["error"]}</div>',
125
  result,
126
  )
127
 
 
129
 
130
 
131
  def create_interface():
132
+ with gr.Blocks(
133
+ title="MiniAiLive Face Liveness Detection",
134
+ theme=gr.themes.Soft(
135
+ primary_hue="emerald",
136
+ neutral_hue="slate",
137
+ ),
138
+ css="""
139
+ footer {display: none !important;}
140
+ """,
141
+ ) as demo:
142
  gr.Markdown(
143
  """
144
  # 🥇 MiniAiLive Face Liveness Detection
145
+ **3D Passive Face Liveness Detection · Face Anti-Spoofing**
146
 
147
  Upload a face image or click an example below to check liveness.
148
  """
149
  )
150
 
151
+ with gr.Row(equal_height=False):
152
+ with gr.Column(scale=1, min_width=400):
153
+ image_input = gr.Image(label="Upload Image")
154
+ submit_btn = gr.Button(
155
+ "Check Liveness", variant="primary", size="lg"
156
  )
 
157
 
158
  gr.Examples(
159
  examples=EXAMPLE_IMAGES,
160
  inputs=image_input,
161
+ label="Example Images",
162
  )
163
 
164
+ with gr.Column(scale=1, min_width=400):
165
  result_html = gr.HTML(label="Result")
166
+ raw_json = gr.JSON(label="Raw Response")
167
 
168
  submit_btn.click(
169
  fn=process_image,