File size: 2,856 Bytes
e2e75ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""Gradio app for face detection and age estimation.

This app embeds the face-age-inference engine directly for deployment
on HuggingFace Spaces (which cannot make external HTTP calls).
"""

import cv2
import gradio as gr
import numpy as np
import spaces
from face_age_inference import (
    FaceAgeInferenceEngine,
    InferenceError,
)

# Initialize the inference engine once at startup
engine: FaceAgeInferenceEngine | None = None


def get_engine() -> FaceAgeInferenceEngine:
    """Get or create the inference engine singleton."""
    global engine
    if engine is None:
        engine = FaceAgeInferenceEngine()
    return engine


@spaces.GPU
def predict(image: np.ndarray | None) -> tuple[np.ndarray | None, str]:
    """Run face detection and age estimation on an image.

    Args:
        image: Input image as RGB numpy array from Gradio.

    Returns:
        Tuple of (annotated image, results text).
    """
    if image is None:
        return None, "Please upload an image."

    try:
        # Convert RGB to BGR for OpenCV processing
        image_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)

        # Run inference
        engine = get_engine()
        result = engine.predict(image_bgr)
        face_count = len(result.ages)

        # Convert annotated image back to RGB for Gradio
        annotated_rgb = cv2.cvtColor(result.annotated_image, cv2.COLOR_BGR2RGB)

        # Format results text
        if face_count == 0:
            results_text = "No faces detected."
        else:
            # Count minors (under 18, excluding unknown ages)
            minors_count = sum(
                1 for age in result.ages if not np.isnan(age) and age < 18
            )
            face_word = "face" if face_count == 1 else "faces"
            minor_word = "person" if minors_count == 1 else "people"
            results_text = (
                f"Detected {face_count} {face_word}.\n"
                f"Estimated {minors_count} {minor_word} under 18."
            )

        return annotated_rgb, results_text

    except InferenceError as e:
        return None, f"Error: {e}"
    except Exception as e:
        return None, f"Unexpected error: {e}"


# Create Gradio interface
demo = gr.Interface(
    fn=predict,
    inputs=gr.Image(
        label="Upload Image",
        type="numpy",
        sources=["upload", "webcam", "clipboard"],
    ),
    outputs=[
        gr.Image(label="Annotated Image", type="numpy"),
        gr.Textbox(label="Results", lines=2),
    ],
    title="Face Detection & Age Estimation",
    description=(
        "Upload an image to detect faces and estimate ages. "
        "Faces are highlighted with bounding boxes: "
        "**green** for minors (under 18), **blue** for adults."
    ),
    examples=[],
    cache_examples=False,
)

if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0")