Compare commits

...

2 Commits

Author SHA1 Message Date
Nicolas Mowen
a22e24f24b Fix process name 2025-06-23 15:55:57 -06:00
Nicolas Mowen
23cc1803a1
Classification model cover images (#18843)
* Move to separate component

* Add cover images for clssification models
2025-06-23 08:40:28 -06:00
2 changed files with 57 additions and 23 deletions

View File

@ -55,7 +55,7 @@ from frigate.util.process import FrigateProcess
logger = logging.getLogger(__name__)
def stop_ffmpeg(ffmpeg_process, logger):
def stop_ffmpeg(ffmpeg_process: sp.Popen[Any], logger: logging.Logger):
logger.info("Terminating the existing ffmpeg process...")
ffmpeg_process.terminate()
try:
@ -441,7 +441,7 @@ class CameraCapture(FrigateProcess):
def __init__(
self, config: CameraConfig, shm_frame_count: int, camera_metrics: CameraMetrics
) -> None:
super().__init__(name=f"camera_capture:{config.name}", daemon=True)
super().__init__(name=f"frigate.capture:{config.name}", daemon=True)
self.config = config
self.shm_frame_count = shm_frame_count
self.camera_metrics = camera_metrics
@ -473,7 +473,7 @@ class CameraTracker(FrigateProcess):
ptz_metrics: PTZMetrics,
region_grid: list[list[dict[str, Any]]],
) -> None:
super().__init__(name=f"camera_processor:{config.name}", daemon=True)
super().__init__(name=f"frigate.process:{config.name}", daemon=True)
self.config = config
self.model_config = model_config
self.labelmap = labelmap

View File

@ -1,3 +1,4 @@
import { baseUrl } from "@/api/baseUrl";
import ActivityIndicator from "@/components/indicators/activity-indicator";
import { cn } from "@/lib/utils";
import {
@ -37,27 +38,60 @@ export default function ModelSelectionView({
return (
<div className="flex size-full gap-2 p-2">
{classificationConfigs.map((config) => (
<div
key={config.name}
className={cn(
"flex h-52 cursor-pointer flex-col gap-2 rounded-lg bg-card p-2 outline outline-[3px]",
"outline-transparent duration-500",
isMobile && "w-full",
)}
onClick={() => onClick(config)}
onContextMenu={() => {
// e.stopPropagation();
// e.preventDefault();
// handleClickEvent(true);
}}
>
<div className="size-48"></div>
<div className="smart-capitalize">
{config.name} ({config.state_config != null ? "State" : "Object"}{" "}
Classification)
</div>
</div>
<ModelCard config={config} onClick={() => onClick(config)} />
))}
</div>
);
}
type ModelCardProps = {
config: CustomClassificationModelConfig;
onClick: () => void;
};
function ModelCard({ config, onClick }: ModelCardProps) {
const { data: dataset } = useSWR<{
[id: string]: string[];
}>(`classification/${config.name}/dataset`, { revalidateOnFocus: false });
const coverImages = useMemo(() => {
if (!dataset) {
return {};
}
const imageMap: { [key: string]: string } = {};
for (const [key, imageList] of Object.entries(dataset)) {
if (imageList.length > 0) {
imageMap[key] = imageList[0];
}
}
return imageMap;
}, [dataset]);
return (
<div
key={config.name}
className={cn(
"flex h-60 cursor-pointer flex-col items-center gap-2 rounded-lg bg-card p-2 outline outline-[3px]",
"outline-transparent duration-500",
isMobile && "w-full",
)}
onClick={() => onClick()}
>
<div className="grid size-48 grid-cols-2 gap-2">
{Object.entries(coverImages).map(([key, image]) => (
<img
key={key}
className=""
src={`${baseUrl}clips/${config.name}/dataset/${key}/${image}`}
/>
))}
</div>
<div className="smart-capitalize">
{config.name} ({config.state_config != null ? "State" : "Object"}{" "}
Classification)
</div>
</div>
);
}