Implement best practices

This commit is contained in:
Weitheng Haw 2025-01-28 09:24:39 +00:00
parent 70f46fae28
commit aa5f7721b6
2 changed files with 105 additions and 54 deletions

View File

@ -24,6 +24,10 @@ logger = logging.getLogger(__name__)
MIN_MATCHING_FACES = 2
MIN_FACE_SCORE = 0.8
NMS_THRESHOLD = 0.3
FACE_INPUT_SIZE = (320, 320)
FACE_QUALITY = 100
class FaceProcessor(RealTimeProcessorApi):
@ -358,11 +362,18 @@ class FaceProcessor(RealTimeProcessorApi):
if topic == EmbeddingsRequestEnum.clear_face_classifier.value:
self.__clear_classifier()
elif topic == EmbeddingsRequestEnum.register_face.value:
face_name = request_data.get("face_name")
if not self.__validate_face_name(face_name):
return {
"message": "Invalid face name",
"success": False,
}
try:
rand_id = "".join(
random.choices(string.ascii_lowercase + string.digits, k=6)
)
label = request_data["face_name"]
id = f"{label}-{rand_id}"
id = f"{face_name}-{rand_id}"
if request_data.get("cropped"):
thumbnail = request_data["image"]
@ -387,7 +398,7 @@ class FaceProcessor(RealTimeProcessorApi):
)
# write face to library
folder = os.path.join(FACE_DIR, label)
folder = os.path.join(FACE_DIR, face_name)
file = os.path.join(folder, f"{id}.webp")
os.makedirs(folder, exist_ok=True)
@ -400,7 +411,34 @@ class FaceProcessor(RealTimeProcessorApi):
"message": "Successfully registered face.",
"success": True,
}
except cv2.error as e:
return {
"message": f"Failed to process image: {str(e)}",
"success": False,
}
except Exception as e:
logger.error(f"Unexpected error registering face: {str(e)}")
return {
"message": "Internal server error",
"success": False,
}
def expire_object(self, object_id: str):
if object_id in self.detected_faces:
self.detected_faces.pop(object_id)
def __validate_face_name(self, name: str) -> bool:
"""Validate face name meets requirements."""
if not name or not isinstance(name, str):
return False
# Add any other validation rules (e.g., no special chars)
return True
def cleanup(self):
"""Cleanup resources when shutting down."""
if self.face_detector:
self.face_detector = None
if self.landmark_detector:
self.landmark_detector = None
if self.face_recognizer:
self.face_recognizer = None

View File

@ -116,29 +116,38 @@ export default function FaceLibrary() {
);
const [newFaceDialog, setNewFaceDialog] = useState(false);
const [isCreatingFace, setIsCreatingFace] = useState(false);
const [newFaceName, setNewFaceName] = useState("");
const createNewFace = useCallback(() => {
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
createNewFace();
}
};
const createNewFace = useCallback(async () => {
if (!newFaceName.trim()) {
toast.error("Face name cannot be empty", { position: "top-center" });
return;
}
axios
.post(`/faces/${newFaceName}`)
.then((resp) => {
if (resp.status == 200) {
setIsCreatingFace(true);
try {
const resp = await axios.post(`/faces/${newFaceName}`);
if (resp.status === 200) {
setNewFaceDialog(false);
setNewFaceName("");
refreshFaces();
toast.success("Successfully created new face", { position: "top-center" });
}
})
.catch((error) => {
toast.error(`Failed to create face: ${error.response?.data?.message || error.message}`, {
position: "top-center",
});
});
} catch (error) {
toast.error(
`Failed to create face: ${error.response?.data?.message || error.message}`,
{ position: "top-center" }
);
} finally {
setIsCreatingFace(false);
}
}, [newFaceName, refreshFaces]);
if (!config) {
@ -159,8 +168,12 @@ export default function FaceLibrary() {
placeholder="Enter face name"
value={newFaceName}
onChange={(e) => setNewFaceName(e.target.value)}
onKeyPress={handleKeyPress}
disabled={isCreatingFace}
/>
<Button onClick={createNewFace}>Create</Button>
<Button onClick={createNewFace} disabled={isCreatingFace}>
{isCreatingFace ? "Creating..." : "Create"}
</Button>
</div>
</DialogContent>
</Dialog>