Implement deleting

This commit is contained in:
Nicolas Mowen 2024-11-25 09:56:27 -07:00
parent c3b8110a42
commit b7877ff3f9
3 changed files with 46 additions and 9 deletions

View File

@ -2,6 +2,7 @@
import logging
import os
from pathvalidate import sanitize_filename
from fastapi import APIRouter, Request, UploadFile
from fastapi.responses import JSONResponse
@ -46,8 +47,8 @@ async def register_face(request: Request, name: str, file: UploadFile):
)
@router.delete("/faces")
def deregister_faces(request: Request, body: dict = None):
@router.post("/faces/{name}/delete")
def deregister_faces(request: Request, name: str, body: dict = None):
json: dict[str, any] = body or {}
list_of_ids = json.get("ids", "")
@ -58,7 +59,9 @@ def deregister_faces(request: Request, body: dict = None):
)
context: EmbeddingsContext = request.app.embeddings
context.delete_face_ids(list_of_ids)
context.delete_face_ids(
name, map(lambda file: sanitize_filename(file), list_of_ids)
)
return JSONResponse(
content=({"success": True, "message": "Successfully deleted faces."}),
status_code=200,

View File

@ -14,7 +14,7 @@ from setproctitle import setproctitle
from frigate.comms.embeddings_updater import EmbeddingsRequestEnum, EmbeddingsRequestor
from frigate.config import FrigateConfig
from frigate.const import CONFIG_DIR
from frigate.const import CONFIG_DIR, FACE_DIR
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
from frigate.models import Event
from frigate.util.builtin import serialize
@ -209,8 +209,13 @@ class EmbeddingsContext:
return self.db.execute_sql(sql_query).fetchall()
def delete_face_ids(self, ids: list[str]) -> None:
self.db.delete_embeddings_face(ids)
def delete_face_ids(self, face: str, ids: list[str]) -> None:
folder = os.path.join(FACE_DIR, face)
for id in ids:
file_path = os.path.join(folder, id)
if os.path.isfile(file_path):
os.unlink(file_path)
def update_description(self, event_id: str, description: str) -> None:
self.requestor.send_data(

View File

@ -3,13 +3,16 @@ import Chip from "@/components/indicators/Chip";
import { Form, FormControl, FormField, FormItem } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { Toaster } from "@/components/ui/sonner";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import useOptimisticState from "@/hooks/use-optimistic-state";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useMemo, useRef, useState } from "react";
import axios from "axios";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { isDesktop } from "react-device-detect";
import { useForm } from "react-hook-form";
import { LuTrash } from "react-icons/lu";
import { toast } from "sonner";
import useSWR from "swr";
import { z } from "zod";
@ -60,6 +63,8 @@ export default function FaceLibrary() {
return (
<div className="flex size-full flex-col p-2">
<div className="relative flex h-11 w-full items-center justify-between">
<Toaster />
<ScrollArea className="w-full whitespace-nowrap">
<div ref={tabsRef} className="flex flex-row">
<ToggleGroup
@ -108,7 +113,7 @@ export default function FaceLibrary() {
</Form>
</div>
{pageToggle && (
<div className="flex gap-2">
<div className="flex flex-wrap gap-2">
{faceImages.map((image: string) => (
<FaceImage name={pageToggle} image={image} />
))}
@ -125,6 +130,27 @@ type FaceImageProps = {
function FaceImage({ name, image }: FaceImageProps) {
const [hovered, setHovered] = useState(false);
const onDelete = useCallback(() => {
axios
.post(`/faces/${name}/delete`, { ids: [image] })
.then((resp) => {
if (resp.status == 200) {
toast.error(`Successfully deleted face.`, { position: "top-center" });
}
})
.catch((error) => {
if (error.response?.data?.message) {
toast.error(`Failed to delete: ${error.response.data.message}`, {
position: "top-center",
});
} else {
toast.error(`Failed to delete: ${error.message}`, {
position: "top-center",
});
}
});
}, [name, image]);
return (
<div
className="relative h-40"
@ -134,7 +160,10 @@ function FaceImage({ name, image }: FaceImageProps) {
>
{hovered && (
<div className="absolute right-1 top-1">
<Chip className="cursor-pointer rounded-md bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500">
<Chip
className="cursor-pointer rounded-md bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500"
onClick={() => onDelete()}
>
<LuTrash className="size-4 fill-destructive text-destructive" />
</Chip>
</div>