diff --git a/web/public/locales/en/views/explore.json b/web/public/locales/en/views/explore.json index 541b90e7b..43db9bda4 100644 --- a/web/public/locales/en/views/explore.json +++ b/web/public/locales/en/views/explore.json @@ -62,7 +62,10 @@ "zones": "Zones", "ratio": "Ratio", "area": "Area", - "score": "Score" + "score": "Score", + "computedScore": "Computed Score", + "topScore": "Top Score", + "toggleAdvancedScores": "Toggle advanced scores" } }, "annotationSettings": { diff --git a/web/src/components/overlay/detail/TrackingDetails.tsx b/web/src/components/overlay/detail/TrackingDetails.tsx index 00d09ec4f..026c0a1b6 100644 --- a/web/src/components/overlay/detail/TrackingDetails.tsx +++ b/web/src/components/overlay/detail/TrackingDetails.tsx @@ -9,7 +9,12 @@ import { FrigateConfig } from "@/types/frigateConfig"; import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import { use24HourTime } from "@/hooks/use-date-utils"; import { getIconForLabel } from "@/utils/iconUtil"; -import { LuCircle, LuFolderX } from "react-icons/lu"; +import { + LuChevronDown, + LuChevronRight, + LuCircle, + LuFolderX, +} from "react-icons/lu"; import { cn } from "@/lib/utils"; import HlsVideoPlayer from "@/components/player/HlsVideoPlayer"; import { baseUrl } from "@/api/baseUrl"; @@ -899,6 +904,7 @@ function LifecycleIconRow({ const { t } = useTranslation(["views/explore", "components/player"]); const { data: config } = useSWR("config"); const [isOpen, setIsOpen] = useState(false); + const [showAdvancedScores, setShowAdvancedScores] = useState(false); const navigate = useNavigate(); const isAdmin = useIsAdmin(); @@ -993,12 +999,31 @@ function LifecycleIconRow({ [item.data.box], ); - const score = useMemo(() => { - if (item.data.score !== undefined) { - return (item.data.score * 100).toFixed(0) + "%"; - } - return "N/A"; - }, [item.data.score]); + const currentScore = useMemo( + () => + item.data.score !== undefined + ? (item.data.score * 100).toFixed(0) + "%" + : null, + [item.data.score], + ); + const computedScore = useMemo( + () => + item.data.computed_score !== undefined && + item.data.computed_score !== null && + item.data.computed_score > 0 + ? (item.data.computed_score * 100).toFixed(0) + "%" + : null, + [item.data.computed_score], + ); + const topScore = useMemo( + () => + item.data.top_score !== undefined && + item.data.top_score !== null && + item.data.top_score > 0 + ? (item.data.top_score * 100).toFixed(0) + "%" + : null, + [item.data.top_score], + ); return (
{t("trackingDetails.lifecycleItemDesc.header.score")} - {score} + + {currentScore ?? "N/A"} + + {(computedScore || topScore) && ( + + )}
+ {showAdvancedScores && computedScore && ( +
+ + {t( + "trackingDetails.lifecycleItemDesc.header.computedScore", + )} + + + {computedScore} + +
+ )} + {showAdvancedScores && topScore && ( +
+ + {t("trackingDetails.lifecycleItemDesc.header.topScore")} + + {topScore} +
+ )}
{t("trackingDetails.lifecycleItemDesc.header.ratio")} diff --git a/web/src/types/timeline.ts b/web/src/types/timeline.ts index 0de067406..273952fb7 100644 --- a/web/src/types/timeline.ts +++ b/web/src/types/timeline.ts @@ -17,6 +17,8 @@ export type TrackingDetailsSequence = { camera: string; label: string; score: number; + computed_score?: number; + top_score?: number; sub_label: string; box?: [number, number, number, number]; region: [number, number, number, number];