diff --git a/frigate/api/classification.py b/frigate/api/classification.py index f60cfd3c3..ed1e7b317 100644 --- a/frigate/api/classification.py +++ b/frigate/api/classification.py @@ -759,15 +759,28 @@ def delete_classification_dataset_images( CLIPS_DIR, sanitize_filename(name), "dataset", sanitize_filename(category) ) + deleted_count = 0 for id in list_of_ids: file_path = os.path.join(folder, sanitize_filename(id)) if os.path.isfile(file_path): os.unlink(file_path) + deleted_count += 1 if os.path.exists(folder) and not os.listdir(folder) and category.lower() != "none": os.rmdir(folder) + # Update training metadata to reflect deleted images + # This ensures the dataset is marked as changed after deletion + # (even if the total count happens to be the same after adding and deleting) + if deleted_count > 0: + sanitized_name = sanitize_filename(name) + metadata = read_training_metadata(sanitized_name) + if metadata: + last_count = metadata.get("last_training_image_count", 0) + updated_count = max(0, last_count - deleted_count) + write_training_metadata(sanitized_name, updated_count) + return JSONResponse( content=({"success": True, "message": "Successfully deleted images."}), status_code=200, diff --git a/web/src/components/classification/ClassificationModelEditDialog.tsx b/web/src/components/classification/ClassificationModelEditDialog.tsx index a3ff2df8a..77b0780f7 100644 --- a/web/src/components/classification/ClassificationModelEditDialog.tsx +++ b/web/src/components/classification/ClassificationModelEditDialog.tsx @@ -141,16 +141,36 @@ export default function ClassificationModelEditDialog({ }); // Fetch dataset to get current classes for state models - const { data: dataset } = useSWR( - isStateModel ? `classification/${model.name}/dataset` : null, - { - revalidateOnFocus: false, - }, - ); + const { data: dataset, mutate: mutateDataset } = + useSWR( + isStateModel && open ? `classification/${model.name}/dataset` : null, + { revalidateOnFocus: false }, + ); + + useEffect(() => { + if (open) { + if (isObjectModel) { + form.reset({ + objectLabel: model.object_config?.objects?.[0] || "", + objectType: + (model.object_config + ?.classification_type as ObjectClassificationType) || "sub_label", + } as ObjectFormData); + } else { + form.reset({ + classes: [""], + } as StateFormData); + } + + if (isStateModel) { + mutateDataset(); + } + } + }, [open, isObjectModel, isStateModel, model, form, mutateDataset]); // Update form with classes from dataset when loaded useEffect(() => { - if (isStateModel && dataset?.categories) { + if (isStateModel && open && dataset?.categories) { const classes = Object.keys(dataset.categories).filter( (key) => key !== "none", ); @@ -161,7 +181,7 @@ export default function ClassificationModelEditDialog({ ); } } - }, [dataset, isStateModel, form]); + }, [dataset, isStateModel, open, form]); const watchedClasses = isStateModel ? (form as ReturnType>).watch("classes")