Merge branch 'embeddings-ui' of github.com:blakeblackshear/frigate into embeddings-ui

This commit is contained in:
Nicolas Mowen 2024-10-15 16:10:00 -06:00
commit e48f3c5236
3 changed files with 95 additions and 88 deletions

View File

@ -10,8 +10,6 @@ import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { import {
@ -24,13 +22,7 @@ import {
AlertDialogHeader, AlertDialogHeader,
AlertDialogTitle, AlertDialogTitle,
} from "../ui/alert-dialog"; } from "../ui/alert-dialog";
import { import { LuCamera, LuDownload, LuMoreVertical, LuTrash2 } from "react-icons/lu";
LuCamera,
LuCheck,
LuDownload,
LuMoreVertical,
LuTrash2,
} from "react-icons/lu";
import FrigatePlusIcon from "@/components/icons/FrigatePlusIcon"; import FrigatePlusIcon from "@/components/icons/FrigatePlusIcon";
import { FrigatePlusDialog } from "../overlay/dialog/FrigatePlusDialog"; import { FrigatePlusDialog } from "../overlay/dialog/FrigatePlusDialog";
import { Event } from "@/types/event"; import { Event } from "@/types/event";
@ -39,6 +31,7 @@ import { baseUrl } from "@/api/baseUrl";
import axios from "axios"; import axios from "axios";
import { toast } from "sonner"; import { toast } from "sonner";
import { MdImageSearch } from "react-icons/md"; import { MdImageSearch } from "react-icons/md";
import { isMobileOnly } from "react-device-detect";
type SearchThumbnailProps = { type SearchThumbnailProps = {
searchResult: SearchResult; searchResult: SearchResult;
@ -130,18 +123,12 @@ export default function SearchThumbnailFooter({
)} )}
{formattedDate} {formattedDate}
</div> </div>
<div className="flex flex-row items-center justify-end gap-8 md:gap-4"> <div className="flex flex-row items-center justify-end gap-6 md:gap-4">
{config?.plus?.enabled && {!isMobileOnly &&
config?.plus?.enabled &&
searchResult.has_snapshot && searchResult.has_snapshot &&
searchResult.end_time && searchResult.end_time &&
(searchResult.plus_id ? ( !searchResult.plus_id && (
<Tooltip>
<TooltipTrigger>
<LuCheck className="size-5 cursor-pointer text-primary text-success" />
</TooltipTrigger>
<TooltipContent>Submitted to Frigate+</TooltipContent>
</Tooltip>
) : (
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<FrigatePlusIcon <FrigatePlusIcon
@ -151,7 +138,7 @@ export default function SearchThumbnailFooter({
</TooltipTrigger> </TooltipTrigger>
<TooltipContent>Submit to Frigate+</TooltipContent> <TooltipContent>Submit to Frigate+</TooltipContent>
</Tooltip> </Tooltip>
))} )}
{config?.semantic_search?.enabled && ( {config?.semantic_search?.enabled && (
<Tooltip> <Tooltip>
@ -170,10 +157,6 @@ export default function SearchThumbnailFooter({
<LuMoreVertical className="size-5 cursor-pointer text-primary" /> <LuMoreVertical className="size-5 cursor-pointer text-primary" />
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align={"end"}> <DropdownMenuContent align={"end"}>
<DropdownMenuLabel className="mt-0.5">
Tracked Object Actions
</DropdownMenuLabel>
<DropdownMenuSeparator className="mt-1" />
{searchResult.has_clip && ( {searchResult.has_clip && (
<DropdownMenuItem> <DropdownMenuItem>
<a <a
@ -205,6 +188,20 @@ export default function SearchThumbnailFooter({
<FaArrowsRotate className="mr-2 size-4" /> <FaArrowsRotate className="mr-2 size-4" />
<span>View object lifecycle</span> <span>View object lifecycle</span>
</DropdownMenuItem> </DropdownMenuItem>
{isMobileOnly &&
config?.plus?.enabled &&
searchResult.has_snapshot &&
searchResult.end_time &&
!searchResult.plus_id && (
<DropdownMenuItem
className="cursor-pointer"
onClick={() => setShowFrigatePlus(true)}
>
<FrigatePlusIcon className="mr-1 size-5 cursor-pointer text-primary" />
<span>Submit to Frigate+</span>
</DropdownMenuItem>
)}
<DropdownMenuItem <DropdownMenuItem
className="cursor-pointer" className="cursor-pointer"
onClick={() => setDeleteDialogOpen(true)} onClick={() => setDeleteDialogOpen(true)}

View File

@ -73,13 +73,16 @@ export default function SearchView({
const [columnCount, setColumnCount] = usePersistence("exploreGridColumns", 4); const [columnCount, setColumnCount] = usePersistence("exploreGridColumns", 4);
const effectiveColumnCount = useMemo(() => columnCount ?? 4, [columnCount]); const effectiveColumnCount = useMemo(() => columnCount ?? 4, [columnCount]);
const gridClassName = cn("grid w-full gap-2 px-1 gap-2 lg:gap-4 md:mx-2", { const gridClassName = cn(
"sm:grid-cols-2": effectiveColumnCount <= 2, "grid w-full gap-2 px-1 gap-2 lg:gap-4 md:mx-2 grid-cols-2",
"sm:grid-cols-3": effectiveColumnCount === 3, {
"sm:grid-cols-4": effectiveColumnCount === 4, "sm:grid-cols-2": effectiveColumnCount <= 2,
"sm:grid-cols-5": effectiveColumnCount === 5, "sm:grid-cols-3": effectiveColumnCount === 3,
"sm:grid-cols-6": effectiveColumnCount === 6, "sm:grid-cols-4": effectiveColumnCount === 4,
}); "sm:grid-cols-5": effectiveColumnCount === 5,
"sm:grid-cols-6": effectiveColumnCount === 6,
},
);
// suggestions values // suggestions values

View File

@ -125,7 +125,7 @@ export default function SearchSettingsView({
if (changedValue) { if (changedValue) {
addMessage( addMessage(
"search_settings", "search_settings",
`Unsaved search settings changes)`, `Unsaved search settings changes`,
undefined, undefined,
"search_settings", "search_settings",
); );
@ -151,31 +151,37 @@ export default function SearchSettingsView({
<Heading as="h3" className="my-2"> <Heading as="h3" className="my-2">
Search Settings Search Settings
</Heading> </Heading>
<div className="my-3 space-y-3 text-sm text-muted-foreground"> <Separator className="my-2 flex bg-secondary" />
<p> <Heading as="h4" className="my-2">
Semantic Search in Frigate allows you to find tracked objects within Semantic Search
your review items using either the image itself, a user-defined text </Heading>
description, or an automatically generated one. This feature works <div className="max-w-6xl">
by creating embeddings numerical vector representations for both <div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 text-sm text-primary-variant">
the images and text descriptions of your tracked objects. By <p>
comparing these embeddings, Frigate assesses their similarities to Semantic Search in Frigate allows you to find tracked objects
deliver relevant search results. within your review items using either the image itself, a
</p> user-defined text description, or an automatically generated one.
This feature works by creating embeddings numerical vector
representations for both the images and text descriptions of
your tracked objects. By comparing these embeddings, Frigate
assesses their similarities to deliver relevant search results.
</p>
<div className="flex items-center text-primary"> <div className="flex items-center text-primary">
<Link <Link
to="https://docs.frigate.video/configuration/semantic_search" to="https://docs.frigate.video/configuration/semantic_search"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="inline" className="inline"
> >
Read the semantic search docs Read the Documentation
<LuExternalLink className="ml-2 inline-flex size-3" /> <LuExternalLink className="ml-2 inline-flex size-3" />
</Link> </Link>
</div>
</div> </div>
</div> </div>
<Separator className="my-2 flex bg-secondary" />
<div className="flex w-full flex-col space-y-6"> <div className="flex w-full max-w-lg flex-col space-y-6">
<div className="flex flex-row items-center justify-between"> <div className="flex flex-row items-center justify-between">
<div className="space-y-0.5"> <div className="space-y-0.5">
<Label htmlFor="improve-contrast">Enabled</Label> <Label htmlFor="improve-contrast">Enabled</Label>
@ -210,23 +216,24 @@ export default function SearchSettingsView({
/> />
</div> </div>
<Separator className="my-2 flex bg-secondary" /> <Separator className="my-2 flex bg-secondary" />
<div className="mt-2 space-y-3"> <div className="mt-2 flex flex-row space-x-5 space-y-3">
<div className="space-y-0.5"> <div className="space-y-0.5">
<div className="text-md">Model Size</div> <div className="text-sm">Model Size</div>
<div className="my-2 space-y-1 text-sm text-muted-foreground"> <div className="my-2 space-y-1 text-sm text-muted-foreground">
<p> <p>
Configure the size of the model used for semantic search The size of the model used for semantic search embeddings.
embeddings:
</p>
<p>
Configuring the <em>small</em> model employs a quantized
version of the model that uses much less RAM and runs faster
on CPU with a very negligible difference in embedding quality.
</p>
<p>
Configuring the <em>large</em> model employs the full Jina
model and will automatically run on the GPU if applicable.
</p> </p>
<ul className="list-disc pl-5 text-sm">
<li>
Using <em>small</em> employs a quantized version of the
model that uses much less RAM and runs faster on CPU with a
very negligible difference in embedding quality.
</li>
<li>
Using <em>large</em> employs the full Jina model and will
automatically run on the GPU if applicable.
</li>
</ul>
</div> </div>
</div> </div>
<Select <Select
@ -256,27 +263,27 @@ export default function SearchSettingsView({
</Select> </Select>
</div> </div>
</div> </div>
<div className="flex flex-1 flex-col justify-end"> <Separator className="my-2 flex bg-secondary" />
<div className="flex flex-row gap-2 pt-5">
<Button className="flex flex-1" onClick={onCancel}> <div className="flex w-full flex-row items-center gap-2 pt-2 md:w-[25%]">
Reset <Button className="flex flex-1" onClick={onCancel}>
</Button> Reset
<Button </Button>
variant="select" <Button
disabled={!changedValue || isLoading} variant="select"
className="flex flex-1" disabled={!changedValue || isLoading}
onClick={saveToConfig} className="flex flex-1"
> onClick={saveToConfig}
{isLoading ? ( >
<div className="flex flex-row items-center gap-2"> {isLoading ? (
<ActivityIndicator /> <div className="flex flex-row items-center gap-2">
<span>Saving...</span> <ActivityIndicator />
</div> <span>Saving...</span>
) : ( </div>
"Save" ) : (
)} "Save"
</Button> )}
</div> </Button>
</div> </div>
</div> </div>
</div> </div>