Reclassification (#22603)

* add ability to reclassify images

* add ability to reclassify faces

* work around radix pointer events issue again
This commit is contained in:
Josh Hawkins
2026-03-24 07:18:06 -06:00
committed by GitHub
parent 91ef3b2ceb
commit 854ef320de
7 changed files with 324 additions and 13 deletions
@@ -304,6 +304,37 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
[pageToggle, model, refreshTrain, refreshDataset, t],
);
const onReclassify = useCallback(
(image: string, newCategory: string) => {
axios
.post(
`/classification/${model.name}/dataset/${pageToggle}/reclassify`,
{
id: image,
new_category: newCategory,
},
)
.then((resp) => {
if (resp.status == 200) {
toast.success(t("toast.success.reclassifiedImage"), {
position: "top-center",
});
refreshDataset();
}
})
.catch((error) => {
const errorMessage =
error.response?.data?.message ||
error.response?.data?.detail ||
"Unknown error";
toast.error(t("toast.error.reclassifyFailed", { errorMessage }), {
position: "top-center",
});
});
},
[pageToggle, model, refreshDataset, t],
);
// keyboard
const contentRef = useRef<HTMLDivElement | null>(null);
@@ -535,10 +566,12 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
contentRef={contentRef}
modelName={model.name}
categoryName={pageToggle}
classes={Object.keys(dataset || {})}
images={dataset?.[pageToggle] || []}
selectedImages={selectedImages}
onClickImages={onClickImages}
onDelete={onDelete}
onReclassify={onReclassify}
/>
)}
</div>
@@ -776,19 +809,23 @@ type DatasetGridProps = {
contentRef: MutableRefObject<HTMLDivElement | null>;
modelName: string;
categoryName: string;
classes: string[];
images: string[];
selectedImages: string[];
onClickImages: (images: string[], ctrl: boolean) => void;
onDelete: (ids: string[]) => void;
onReclassify: (image: string, newCategory: string) => void;
};
function DatasetGrid({
contentRef,
modelName,
categoryName,
classes,
images,
selectedImages,
onClickImages,
onDelete,
onReclassify,
}: DatasetGridProps) {
const { t } = useTranslation(["views/classificationModel"]);
@@ -816,10 +853,23 @@ function DatasetGrid({
i18nLibrary="views/classificationModel"
onClick={(data, _) => onClickImages([data.filename], true)}
>
<ClassificationSelectionDialog
classes={classes}
modelName={modelName}
image={image}
excludeCategory={categoryName}
dialogLabel={t("reclassifyImageAs")}
tooltipLabel={t("reclassifyImage")}
onCategorize={(newCat) => onReclassify(image, newCat)}
>
<BlurredIconButton>
<TbCategoryPlus className="size-5" />
</BlurredIconButton>
</ClassificationSelectionDialog>
<Tooltip>
<TooltipTrigger>
<LuTrash2
className="size-5 cursor-pointer text-primary-variant hover:text-danger"
className="size-5 cursor-pointer text-gray-200 hover:text-danger"
onClick={(e) => {
e.stopPropagation();
onDelete([image]);