diff --git a/frigate/stats/util.py b/frigate/stats/util.py index cfc5ae42b..17b45d1d4 100644 --- a/frigate/stats/util.py +++ b/frigate/stats/util.py @@ -362,7 +362,7 @@ def stats_snapshot( stats["embeddings"]["review_description_speed"] = round( embeddings_metrics.review_desc_speed.value * 1000, 2 ) - stats["embeddings"]["review_descriptions"] = round( + stats["embeddings"]["review_description_events_per_second"] = round( embeddings_metrics.review_desc_dps.value, 2 ) @@ -370,7 +370,7 @@ def stats_snapshot( stats["embeddings"]["object_description_speed"] = round( embeddings_metrics.object_desc_speed.value * 1000, 2 ) - stats["embeddings"]["object_descriptions"] = round( + stats["embeddings"]["object_description_events_per_second"] = round( embeddings_metrics.object_desc_dps.value, 2 ) @@ -378,7 +378,7 @@ def stats_snapshot( stats["embeddings"][f"{key}_classification_speed"] = round( embeddings_metrics.classification_speeds[key].value * 1000, 2 ) - stats["embeddings"][f"{key}_classification"] = round( + stats["embeddings"][f"{key}_classification_events_per_second"] = round( embeddings_metrics.classification_cps[key].value, 2 ) diff --git a/web/public/locales/en/views/system.json b/web/public/locales/en/views/system.json index c4c6fd4f6..e72b993cb 100644 --- a/web/public/locales/en/views/system.json +++ b/web/public/locales/en/views/system.json @@ -169,6 +169,7 @@ "enrichments": { "title": "Enrichments", "infPerSecond": "Inferences Per Second", + "averageInf": "Average Inference Time", "embeddings": { "image_embedding": "Image Embedding", "text_embedding": "Text Embedding", @@ -180,7 +181,13 @@ "plate_recognition_speed": "Plate Recognition Speed", "text_embedding_speed": "Text Embedding Speed", "yolov9_plate_detection_speed": "YOLOv9 Plate Detection Speed", - "yolov9_plate_detection": "YOLOv9 Plate Detection" + "yolov9_plate_detection": "YOLOv9 Plate Detection", + "review_description": "Review Description", + "review_description_speed": "Review Description Speed", + "review_description_events_per_second": "Review Description", + "object_description": "Object Description", + "object_description_speed": "Object Description Speed", + "object_description_events_per_second": "Object Description" } } } diff --git a/web/src/views/system/EnrichmentMetrics.tsx b/web/src/views/system/EnrichmentMetrics.tsx index b762f6a7f..75ab593a0 100644 --- a/web/src/views/system/EnrichmentMetrics.tsx +++ b/web/src/views/system/EnrichmentMetrics.tsx @@ -67,13 +67,14 @@ export default function EnrichmentMetrics({ // features stats - const embeddingInferenceTimeSeries = useMemo(() => { + const groupedEnrichmentMetrics = useMemo(() => { if (!statsHistory) { return []; } const series: { [key: string]: { + rawKey: string; name: string; metrics: Threshold; data: { x: number; y: number }[]; @@ -90,6 +91,7 @@ export default function EnrichmentMetrics({ if (!(key in series)) { series[key] = { + rawKey, name: t("enrichments.embeddings." + rawKey), metrics: getThreshold(rawKey), data: [], @@ -99,7 +101,57 @@ export default function EnrichmentMetrics({ series[key].data.push({ x: statsIdx + 1, y: stat }); }); }); - return Object.values(series); + + // Group series by category (extract base name from raw key) + const grouped: { + [category: string]: { + categoryName: string; + speedSeries?: { + name: string; + metrics: Threshold; + data: { x: number; y: number }[]; + }; + eventsSeries?: { + name: string; + metrics: Threshold; + data: { x: number; y: number }[]; + }; + }; + } = {}; + + Object.values(series).forEach((s) => { + // Extract base category name from raw key + // All metrics follow the pattern: {base}_speed and {base}_events_per_second + let categoryKey = s.rawKey; + let isSpeed = false; + + if (s.rawKey.endsWith("_speed")) { + categoryKey = s.rawKey.replace("_speed", ""); + isSpeed = true; + } else if (s.rawKey.endsWith("_events_per_second")) { + categoryKey = s.rawKey.replace("_events_per_second", ""); + isSpeed = false; + } + + // Get translated category name + const categoryName = t("enrichments.embeddings." + categoryKey); + + if (!(categoryKey in grouped)) { + grouped[categoryKey] = { + categoryName, + speedSeries: undefined, + eventsSeries: undefined, + }; + } + + if (isSpeed) { + grouped[categoryKey].speedSeries = s; + } else { + grouped[categoryKey].eventsSeries = s; + } + }); + + return Object.values(grouped); }, [statsHistory, t, getThreshold]); return ( @@ -110,35 +162,42 @@ export default function EnrichmentMetrics({
{statsHistory.length != 0 ? ( <> - {embeddingInferenceTimeSeries.map((series) => ( -
-
{series.name}
- {series.name.endsWith("Speed") ? ( - - ) : ( - - )} + {groupedEnrichmentMetrics.map((group) => ( +
+
+ {group.categoryName} +
+
+ {group.speedSeries && ( + + )} + {group.eventsSeries && ( + + )} +
))}