lifedebugger's picture
Update app.py
bf97313 verified
import gradio as gr
import requests
import base64
import cv2
import numpy as np
from typing import List, Union
# =========================
# CONFIG
# =========================
API_BASE = "https://lifedebugger-face-recognition-sss-beta.hf.space/api/v1"
# =========================
# UTILITIES
# =========================
def img_np_to_base64(img: np.ndarray) -> str:
"""Convert numpy image to base64 JPG"""
if img is None:
return None
success, buffer = cv2.imencode(".jpg", img)
if not success:
return None
return base64.b64encode(buffer).decode("utf-8")
def load_gallery_item(item: Union[str, dict]) -> np.ndarray:
"""
Gradio Gallery item handler (v4 compatible)
item can be:
- str (file path)
- dict with key 'name'
"""
if isinstance(item, dict) and "name" in item:
path = item["name"]
elif isinstance(item, str):
path = item
else:
return None
return cv2.imread(path)
# =========================
# VERIFY API
# =========================
def call_verify_api(img: np.ndarray, employee_id: str):
if img is None:
return "❌ No image provided", None
b64 = img_np_to_base64(img)
if b64 is None:
return "❌ Failed to encode image", None
payload = {
"employee_id": employee_id,
"image": b64,
}
try:
r = requests.post(
f"{API_BASE}/face/verify-image",
json=payload,
timeout=30,
)
r.raise_for_status()
data = r.json()
except Exception as e:
return f"❌ API error: {e}", None
if not data.get("detections"):
return "❌ No face detected", None
det = data["detections"][0]
# Draw bounding box
vis = img.copy()
x1, y1, x2, y2 = map(int, det["bbox"])
cv2.rectangle(vis, (x1, y1), (x2, y2), (0, 255, 0), 2)
text = (
f"Authorized : {det['authorized']}\n"
f"Match User : {det.get('match_user')}\n"
f"Confidence : {det['confidence']}\n"
f"Det Score : {det['det_score']}"
)
return text, vis
# =========================
# ENROLL API
# =========================
def call_enroll_api(images: List[Union[str, dict]], employee_id: str):
if not images:
return "❌ No images selected"
b64_images = []
for item in images:
img = load_gallery_item(item)
if img is None:
continue
b64 = img_np_to_base64(img)
if b64:
b64_images.append(b64)
if not b64_images:
return "❌ Failed to load images from gallery"
payload = {
"employee_id": employee_id,
"images": b64_images,
}
try:
r = requests.post(
f"{API_BASE}/face/enroll",
json=payload,
timeout=60,
)
r.raise_for_status()
data = r.json()
except Exception as e:
return f"❌ API error: {e}"
return (
"βœ… ENROLL SUCCESS\n"
f"Employee ID : {data.get('employee_id')}\n"
f"Added : {data.get('added')}\n"
f"Total Files : {data.get('total', '-')}"
)
# =========================
# GRADIO UI
# =========================
with gr.Blocks(title="Face Recognition Test (Uniface)") as demo:
gr.Markdown("""
# 🧠 Face Recognition Frontend (TEST)
**Backend:** Uniface (RetinaFace + ArcFace)
**API:** lifedebugger-face-recognition-sss-beta
""")
with gr.Tabs():
# ================= VERIFY TAB =================
with gr.Tab("πŸ” Verify Face"):
with gr.Row():
with gr.Column():
verify_employee_id = gr.Textbox(
label="Employee ID",
value="1",
)
verify_image = gr.Image(
label="Input Image (Upload / Webcam)",
sources=["upload", "webcam"],
type="numpy",
)
verify_btn = gr.Button("Verify", variant="primary")
with gr.Column():
verify_result = gr.Textbox(
label="Result",
lines=6,
)
verify_vis = gr.Image(
label="Visualization",
type="numpy",
)
verify_btn.click(
fn=call_verify_api,
inputs=[verify_image, verify_employee_id],
outputs=[verify_result, verify_vis],
)
# ================= ENROLL TAB =================
with gr.Tab("βž• Enroll Face"):
with gr.Row():
with gr.Column():
enroll_employee_id = gr.Textbox(
label="Employee ID",
value="1",
)
enroll_images = gr.Gallery(
label="Upload Face Images (Multiple)",
columns=3,
height=250,
)
enroll_btn = gr.Button("Enroll", variant="primary")
with gr.Column():
enroll_result = gr.Textbox(
label="Enroll Status",
lines=6,
)
enroll_btn.click(
fn=call_enroll_api,
inputs=[enroll_images, enroll_employee_id],
outputs=enroll_result,
)
# =========================
# RUN
# =========================
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)