diff --git a/web/src/pages/FaceLibrary.tsx b/web/src/pages/FaceLibrary.tsx index 167dd9325..cbcb7c7de 100644 --- a/web/src/pages/FaceLibrary.tsx +++ b/web/src/pages/FaceLibrary.tsx @@ -416,6 +416,86 @@ export default function FaceLibrary() { )} + {pageToggle === "train" && ( + { + // Batch train all selected faces + let successCount = 0; + let failCount = 0; + const totalCount = selectedFaces.length; + + selectedFaces.forEach((filename, index) => { + axios + .post(`/faces/train/${name}/classify`, { + training_file: filename, + }) + .then((resp) => { + if (resp.status == 200) { + successCount++; + } else { + failCount++; + } + + // Show final toast after all requests complete + if (index === totalCount - 1) { + if (successCount === totalCount) { + toast.success( + t("toast.success.batchTrainedFaces", { + count: successCount, + }), + { + position: "top-center", + }, + ); + } else if (successCount > 0) { + toast.warning( + t("toast.warning.partialBatchTrained", { + success: successCount, + total: totalCount, + }), + { + position: "top-center", + }, + ); + } else { + toast.error( + t("toast.error.batchTrainFailed", { + count: totalCount, + }), + { + position: "top-center", + }, + ); + } + setSelectedFaces([]); + refreshFaces(); + } + }) + .catch(() => { + failCount++; + if (index === totalCount - 1) { + toast.error( + t("toast.error.batchTrainFailed", { + count: totalCount, + }), + { + position: "top-center", + }, + ); + setSelectedFaces([]); + refreshFaces(); + } + }); + }); + }} + > + + + )}