Classification fixes

This commit is contained in:
Nicolas Mowen 2026-01-21 08:04:14 -07:00
parent 722497ba0b
commit 28b8ef18b2
2 changed files with 41 additions and 8 deletions

View File

@ -759,15 +759,28 @@ def delete_classification_dataset_images(
CLIPS_DIR, sanitize_filename(name), "dataset", sanitize_filename(category) CLIPS_DIR, sanitize_filename(name), "dataset", sanitize_filename(category)
) )
deleted_count = 0
for id in list_of_ids: for id in list_of_ids:
file_path = os.path.join(folder, sanitize_filename(id)) file_path = os.path.join(folder, sanitize_filename(id))
if os.path.isfile(file_path): if os.path.isfile(file_path):
os.unlink(file_path) os.unlink(file_path)
deleted_count += 1
if os.path.exists(folder) and not os.listdir(folder) and category.lower() != "none": if os.path.exists(folder) and not os.listdir(folder) and category.lower() != "none":
os.rmdir(folder) 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( return JSONResponse(
content=({"success": True, "message": "Successfully deleted images."}), content=({"success": True, "message": "Successfully deleted images."}),
status_code=200, status_code=200,

View File

@ -141,16 +141,36 @@ export default function ClassificationModelEditDialog({
}); });
// Fetch dataset to get current classes for state models // Fetch dataset to get current classes for state models
const { data: dataset } = useSWR<ClassificationDatasetResponse>( const { data: dataset, mutate: mutateDataset } =
isStateModel ? `classification/${model.name}/dataset` : null, useSWR<ClassificationDatasetResponse>(
{ isStateModel && open ? `classification/${model.name}/dataset` : null,
revalidateOnFocus: false, { 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 // Update form with classes from dataset when loaded
useEffect(() => { useEffect(() => {
if (isStateModel && dataset?.categories) { if (isStateModel && open && dataset?.categories) {
const classes = Object.keys(dataset.categories).filter( const classes = Object.keys(dataset.categories).filter(
(key) => key !== "none", (key) => key !== "none",
); );
@ -161,7 +181,7 @@ export default function ClassificationModelEditDialog({
); );
} }
} }
}, [dataset, isStateModel, form]); }, [dataset, isStateModel, open, form]);
const watchedClasses = isStateModel const watchedClasses = isStateModel
? (form as ReturnType<typeof useForm<StateFormData>>).watch("classes") ? (form as ReturnType<typeof useForm<StateFormData>>).watch("classes")