rakibulinux commited on
Commit
d02862c
·
1 Parent(s): ba3f67e

Fixed API error

Browse files
Files changed (2) hide show
  1. api.py +3 -1
  2. ui.py +66 -21
api.py CHANGED
@@ -20,7 +20,7 @@ def _load_image(image):
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"}
@@ -43,3 +43,5 @@ def check_liveness(image) -> dict:
43
  return {"error": "Request timed out"}
44
  except requests.exceptions.RequestException as e:
45
  return {"error": f"API request failed: {str(e)}"}
 
 
 
20
  return image
21
 
22
 
23
+ def check_liveness(image):
24
  img = _load_image(image)
25
  if img is None:
26
  return {"error": "No image provided"}
 
43
  return {"error": "Request timed out"}
44
  except requests.exceptions.RequestException as e:
45
  return {"error": f"API request failed: {str(e)}"}
46
+ except ValueError as e:
47
+ return {"error": f"Invalid response from server (not JSON): {str(e)}"}
ui.py CHANGED
@@ -3,38 +3,74 @@ from api import check_liveness
3
 
4
  EXAMPLE_IMAGES = [[f"assets/{i}.jpg"] for i in range(1, 4)]
5
 
 
6
 
7
- def _format_result_html(result: dict) -> str:
8
- if not result or "error" in result:
9
- return ""
10
 
11
- liveness_text = result.get("liveness result", result.get("liveness_result", "")).lower()
12
- is_genuine = "genuine" in liveness_text or "live" in liveness_text
13
- score = result.get("score", result.get("probability", 0))
14
- if isinstance(score, str):
15
- try:
16
- score = float(score)
17
- except (ValueError, TypeError):
18
- score = 0
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  if is_genuine:
21
  badge_text = "✅ GENUINE / LIVE"
22
  badge_color = "#059669"
23
  bg_color = "#ecfdf5"
24
  border_color = "#a7f3d0"
25
  else:
26
- badge_text = "❌ SPOOF / FAKE"
27
  badge_color = "#dc2626"
28
  bg_color = "#fef2f2"
29
  border_color = "#fecaca"
30
 
31
- detail_rows = "".join(
32
- f'<tr><td style="padding:6px 12px;font-weight:600;color:#64748b;'
33
- f'border-bottom:1px solid #f1f5f9;">{k}</td>'
34
- f'<td style="padding:6px 12px;color:#334155;border-bottom:1px solid #f1f5f9;">{v}</td></tr>'
35
- for k, v in result.items()
36
- )
37
-
38
  return f"""
39
  <div style="padding:12px 0;">
40
  <div style="background:{bg_color};border:2px solid {border_color};
@@ -49,7 +85,16 @@ def _format_result_html(result: dict) -> str:
49
  </div>
50
  <div style="margin-top:16px;background:white;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;">
51
  <table style="width:100%;border-collapse:collapse;">
52
- {detail_rows}
 
 
 
 
 
 
 
 
 
53
  </table>
54
  </div>
55
  </div>
@@ -66,7 +111,7 @@ def process_image(image):
66
  )
67
 
68
  result = check_liveness(image)
69
- if "error" in result:
70
  return (
71
  f'<div style="padding:20px;text-align:center;color:#dc2626;">{result["error"]}</div>',
72
  result,
 
3
 
4
  EXAMPLE_IMAGES = [[f"assets/{i}.jpg"] for i in range(1, 4)]
5
 
6
+ THRESHOLD = 0.5
7
 
 
 
 
8
 
9
+ def _normalize(d: dict) -> dict:
10
+ return {k.strip().replace(" ", "_"): v for k, v in d.items()}
11
+
 
 
 
 
 
12
 
13
+ def _format_result_html(results: list) -> str:
14
+ if not results or (isinstance(results, dict) and "error" in results):
15
+ return ""
16
+
17
+ if isinstance(results, dict):
18
+ results = [results]
19
+
20
+ max_prob = 0
21
+ max_attack = ""
22
+ rows = ""
23
+ for item in results:
24
+ r = _normalize(item)
25
+ attack = r.get("attack_method", "Unknown")
26
+ prob = r.get("liveness_probability", 0)
27
+ score = r.get("liveness_score", 0)
28
+ quality = r.get("quality_score", 0)
29
+ state = r.get("state", "")
30
+
31
+ if isinstance(prob, str):
32
+ try:
33
+ prob = float(prob)
34
+ except (ValueError, TypeError):
35
+ prob = 0
36
+
37
+ if prob > max_prob:
38
+ max_prob = prob
39
+ max_attack = attack
40
+
41
+ pct = round(max(0, min(prob, 1)) * 100)
42
+ bar_color = "#059669" if prob < THRESHOLD else "#dc2626"
43
+
44
+ rows += f"""
45
+ <tr>
46
+ <td style="padding:8px 12px;font-weight:600;color:#334155;border-bottom:1px solid #f1f5f9;">
47
+ {attack}
48
+ </td>
49
+ <td style="padding:8px 12px;border-bottom:1px solid #f1f5f9;">
50
+ <div style="display:flex;align-items:center;gap:8px;">
51
+ <div style="flex:1;background:#e2e8f0;border-radius:999px;height:8px;overflow:hidden;">
52
+ <div style="width:{pct}%;height:100%;background:{bar_color};border-radius:999px;"></div>
53
+ </div>
54
+ <span style="font-weight:700;color:{bar_color};min-width:40px;text-align:right;">{pct}%</span>
55
+ </div>
56
+ </td>
57
+ <td style="padding:8px 12px;color:#64748b;border-bottom:1px solid #f1f5f9;text-align:center;">
58
+ {state}
59
+ </td>
60
+ </tr>"""
61
+
62
+ is_genuine = max_prob < THRESHOLD
63
  if is_genuine:
64
  badge_text = "✅ GENUINE / LIVE"
65
  badge_color = "#059669"
66
  bg_color = "#ecfdf5"
67
  border_color = "#a7f3d0"
68
  else:
69
+ badge_text = f"❌ SPOOF / FAKE — {max_attack}"
70
  badge_color = "#dc2626"
71
  bg_color = "#fef2f2"
72
  border_color = "#fecaca"
73
 
 
 
 
 
 
 
 
74
  return f"""
75
  <div style="padding:12px 0;">
76
  <div style="background:{bg_color};border:2px solid {border_color};
 
85
  </div>
86
  <div style="margin-top:16px;background:white;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;">
87
  <table style="width:100%;border-collapse:collapse;">
88
+ <thead>
89
+ <tr style="background:#f8fafc;">
90
+ <th style="padding:8px 12px;text-align:left;font-weight:600;color:#64748b;">Attack Method</th>
91
+ <th style="padding:8px 12px;text-align:left;font-weight:600;color:#64748b;">Probability</th>
92
+ <th style="padding:8px 12px;text-align:center;font-weight:600;color:#64748b;">Status</th>
93
+ </tr>
94
+ </thead>
95
+ <tbody>
96
+ {rows}
97
+ </tbody>
98
  </table>
99
  </div>
100
  </div>
 
111
  )
112
 
113
  result = check_liveness(image)
114
+ if isinstance(result, dict) and "error" in result:
115
  return (
116
  f'<div style="padding:20px;text-align:center;color:#dc2626;">{result["error"]}</div>',
117
  result,