mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-06 05:24:11 +03:00
Miscellaneous Fixes (#21033)
* catch failed image embedding in triggers * move scrollbar to edge on platform aware dialog drawers * add i18n key * show negotiated mse codecs in console on error * try changing rocm * Improve toast consistency * add attribute area and score to detail stream tooltip --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
parent
2a9c028f55
commit
3bbe24f5f8
@ -2,7 +2,7 @@ variable "AMDGPU" {
|
|||||||
default = "gfx900"
|
default = "gfx900"
|
||||||
}
|
}
|
||||||
variable "ROCM" {
|
variable "ROCM" {
|
||||||
default = "7.1"
|
default = "7.1.0"
|
||||||
}
|
}
|
||||||
variable "HSA_OVERRIDE_GFX_VERSION" {
|
variable "HSA_OVERRIDE_GFX_VERSION" {
|
||||||
default = ""
|
default = ""
|
||||||
|
|||||||
@ -232,7 +232,7 @@ When your browser runs into problems playing back your camera streams, it will l
|
|||||||
- **mse-decode**
|
- **mse-decode**
|
||||||
|
|
||||||
- What it means: The browser reported a decoding error while trying to play the stream, which usually is a result of a codec incompatibility or corrupted frames.
|
- What it means: The browser reported a decoding error while trying to play the stream, which usually is a result of a codec incompatibility or corrupted frames.
|
||||||
- What to try: Ensure your camera/restream is using H.264 video and AAC audio (these are the most compatible). If your camera uses a non-standard audio codec, configure `go2rtc` to transcode the stream to AAC. Try another browser (some browsers have stricter MSE/codec support) and, for iPhone, ensure you're on iOS 17.1 or newer.
|
- What to try: Check the browser console for the supported and negotiated codecs. Ensure your camera/restream is using H.264 video and AAC audio (these are the most compatible). If your camera uses a non-standard audio codec, configure `go2rtc` to transcode the stream to AAC. Try another browser (some browsers have stricter MSE/codec support) and, for iPhone, ensure you're on iOS 17.1 or newer.
|
||||||
|
|
||||||
- Possible console messages from the player code:
|
- Possible console messages from the player code:
|
||||||
|
|
||||||
|
|||||||
@ -1753,7 +1753,7 @@ def create_trigger_embedding(
|
|||||||
body.data, (base64.b64encode(thumbnail).decode("ASCII"))
|
body.data, (base64.b64encode(thumbnail).decode("ASCII"))
|
||||||
)
|
)
|
||||||
|
|
||||||
if embedding is None:
|
if not embedding:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={
|
content={
|
||||||
"success": False,
|
"success": False,
|
||||||
@ -1888,7 +1888,7 @@ def update_trigger_embedding(
|
|||||||
body.data, (base64.b64encode(thumbnail).decode("ASCII"))
|
body.data, (base64.b64encode(thumbnail).decode("ASCII"))
|
||||||
)
|
)
|
||||||
|
|
||||||
if embedding is None:
|
if not embedding:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={
|
content={
|
||||||
"success": False,
|
"success": False,
|
||||||
|
|||||||
@ -53,6 +53,7 @@
|
|||||||
"selectOrExport": "Select or Export",
|
"selectOrExport": "Select or Export",
|
||||||
"toast": {
|
"toast": {
|
||||||
"success": "Successfully started export. View the file in the exports page.",
|
"success": "Successfully started export. View the file in the exports page.",
|
||||||
|
"view": "View",
|
||||||
"error": {
|
"error": {
|
||||||
"failed": "Failed to start export: {{error}}",
|
"failed": "Failed to start export: {{error}}",
|
||||||
"endTimeMustAfterStartTime": "End time must be after start time",
|
"endTimeMustAfterStartTime": "End time must be after start time",
|
||||||
|
|||||||
@ -61,7 +61,8 @@
|
|||||||
"header": {
|
"header": {
|
||||||
"zones": "Zones",
|
"zones": "Zones",
|
||||||
"ratio": "Ratio",
|
"ratio": "Ratio",
|
||||||
"area": "Area"
|
"area": "Area",
|
||||||
|
"score": "Score"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"annotationSettings": {
|
"annotationSettings": {
|
||||||
|
|||||||
@ -87,7 +87,7 @@ export default function ReviewCard({
|
|||||||
position: "top-center",
|
position: "top-center",
|
||||||
action: (
|
action: (
|
||||||
<a href="/export" target="_blank" rel="noopener noreferrer">
|
<a href="/export" target="_blank" rel="noopener noreferrer">
|
||||||
<Button>View</Button>
|
<Button>{t("export.toast.view")}</Button>
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -148,7 +148,9 @@ export default function Step3ChooseExamples({
|
|||||||
// Step 3: Kick off training
|
// Step 3: Kick off training
|
||||||
await axios.post(`/classification/${step1Data.modelName}/train`);
|
await axios.post(`/classification/${step1Data.modelName}/train`);
|
||||||
|
|
||||||
toast.success(t("wizard.step3.trainingStarted"));
|
toast.success(t("wizard.step3.trainingStarted"), {
|
||||||
|
closeButton: true,
|
||||||
|
});
|
||||||
setIsTraining(true);
|
setIsTraining(true);
|
||||||
},
|
},
|
||||||
[step1Data, step2Data, t],
|
[step1Data, step2Data, t],
|
||||||
|
|||||||
@ -314,11 +314,10 @@ function GeneralFilterButton({
|
|||||||
<PlatformAwareDialog
|
<PlatformAwareDialog
|
||||||
trigger={trigger}
|
trigger={trigger}
|
||||||
content={content}
|
content={content}
|
||||||
contentClassName={
|
contentClassName={cn(
|
||||||
isDesktop
|
"scrollbar-container h-auto overflow-y-auto",
|
||||||
? "scrollbar-container h-auto max-h-[80dvh] overflow-y-auto"
|
isDesktop ? "max-h-[80dvh]" : "px-4",
|
||||||
: "max-h-[75dvh] overflow-hidden p-4"
|
)}
|
||||||
}
|
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
@ -510,11 +509,10 @@ function SortTypeButton({
|
|||||||
<PlatformAwareDialog
|
<PlatformAwareDialog
|
||||||
trigger={trigger}
|
trigger={trigger}
|
||||||
content={content}
|
content={content}
|
||||||
contentClassName={
|
contentClassName={cn(
|
||||||
isDesktop
|
"scrollbar-container h-auto overflow-y-auto",
|
||||||
? "scrollbar-container h-auto max-h-[80dvh] overflow-y-auto"
|
isDesktop ? "max-h-[80dvh]" : "px-4",
|
||||||
: "max-h-[75dvh] overflow-hidden p-4"
|
)}
|
||||||
}
|
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
|
|||||||
@ -97,7 +97,7 @@ export default function ExportDialog({
|
|||||||
position: "top-center",
|
position: "top-center",
|
||||||
action: (
|
action: (
|
||||||
<a href="/export" target="_blank" rel="noopener noreferrer">
|
<a href="/export" target="_blank" rel="noopener noreferrer">
|
||||||
<Button>View</Button>
|
<Button>{t("export.toast.view")}</Button>
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -106,7 +106,9 @@ export default function MobileReviewSettingsDrawer({
|
|||||||
position: "top-center",
|
position: "top-center",
|
||||||
action: (
|
action: (
|
||||||
<a href="/export" target="_blank" rel="noopener noreferrer">
|
<a href="/export" target="_blank" rel="noopener noreferrer">
|
||||||
<Button>View</Button>
|
<Button>
|
||||||
|
{t("export.toast.view", { ns: "components/dialog" })}
|
||||||
|
</Button>
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -44,8 +44,8 @@ export default function PlatformAwareDialog({
|
|||||||
return (
|
return (
|
||||||
<Drawer open={open} onOpenChange={onOpenChange}>
|
<Drawer open={open} onOpenChange={onOpenChange}>
|
||||||
<DrawerTrigger asChild>{trigger}</DrawerTrigger>
|
<DrawerTrigger asChild>{trigger}</DrawerTrigger>
|
||||||
<DrawerContent className="max-h-[75dvh] overflow-hidden px-4">
|
<DrawerContent className="max-h-[75dvh] overflow-hidden">
|
||||||
{content}
|
<div className={contentClassName}>{content}</div>
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -94,12 +94,19 @@ function MSEPlayer({
|
|||||||
console.error(
|
console.error(
|
||||||
`${camera} - MSE error '${error}': ${description} See the documentation: https://docs.frigate.video/configuration/live/#live-player-error-messages`,
|
`${camera} - MSE error '${error}': ${description} See the documentation: https://docs.frigate.video/configuration/live/#live-player-error-messages`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mseCodecRef.current) {
|
if (mseCodecRef.current) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(`${camera} - MSE codec in use: ${mseCodecRef.current}`);
|
console.error(
|
||||||
|
`${camera} - Browser negotiated codecs: ${mseCodecRef.current}`,
|
||||||
|
);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(`${camera} - Supported codecs: ${CODECS.join(", ")}`);
|
||||||
}
|
}
|
||||||
onError?.(error);
|
onError?.(error);
|
||||||
},
|
},
|
||||||
|
// we know that these deps are correct
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[camera, onError],
|
[camera, onError],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -136,11 +136,10 @@ export default function ExploreSettings({
|
|||||||
<PlatformAwareDialog
|
<PlatformAwareDialog
|
||||||
trigger={trigger}
|
trigger={trigger}
|
||||||
content={content}
|
content={content}
|
||||||
contentClassName={
|
contentClassName={cn(
|
||||||
isDesktop
|
"scrollbar-container h-auto overflow-y-auto",
|
||||||
? "scrollbar-container h-auto max-h-[80dvh] overflow-y-auto"
|
isDesktop ? "max-h-[80dvh]" : "px-4",
|
||||||
: "max-h-[75dvh] overflow-hidden p-4"
|
)}
|
||||||
}
|
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
setOpen(open);
|
setOpen(open);
|
||||||
|
|||||||
@ -681,22 +681,62 @@ function LifecycleItem({
|
|||||||
})
|
})
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const ratio =
|
const ratio = useMemo(
|
||||||
Array.isArray(item?.data.box) && item?.data.box.length >= 4
|
() =>
|
||||||
? (aspectRatio * (item?.data.box[2] / item?.data.box[3])).toFixed(2)
|
Array.isArray(item?.data.box) && item?.data.box.length >= 4
|
||||||
: "N/A";
|
? (aspectRatio * (item?.data.box[2] / item?.data.box[3])).toFixed(2)
|
||||||
const areaPx =
|
: "N/A",
|
||||||
Array.isArray(item?.data.box) && item?.data.box.length >= 4
|
[aspectRatio, item],
|
||||||
? Math.round(
|
);
|
||||||
(config?.cameras[item?.camera]?.detect?.width ?? 0) *
|
|
||||||
(config?.cameras[item?.camera]?.detect?.height ?? 0) *
|
const areaPx = useMemo(
|
||||||
(item?.data.box[2] * item?.data.box[3]),
|
() =>
|
||||||
)
|
Array.isArray(item?.data.box) && item?.data.box.length >= 4
|
||||||
: undefined;
|
? Math.round(
|
||||||
const areaPct =
|
(config?.cameras[item?.camera]?.detect?.width ?? 0) *
|
||||||
Array.isArray(item?.data.box) && item?.data.box.length >= 4
|
(config?.cameras[item?.camera]?.detect?.height ?? 0) *
|
||||||
? (item?.data.box[2] * item?.data.box[3]).toFixed(4)
|
(item?.data.box[2] * item?.data.box[3]),
|
||||||
: undefined;
|
)
|
||||||
|
: undefined,
|
||||||
|
[config, item],
|
||||||
|
);
|
||||||
|
|
||||||
|
const areaPct = useMemo(
|
||||||
|
() =>
|
||||||
|
Array.isArray(item?.data.box) && item?.data.box.length >= 4
|
||||||
|
? (item?.data.box[2] * item?.data.box[3]).toFixed(4)
|
||||||
|
: undefined,
|
||||||
|
[item],
|
||||||
|
);
|
||||||
|
|
||||||
|
const attributeAreaPx = useMemo(
|
||||||
|
() =>
|
||||||
|
Array.isArray(item?.data.attribute_box) &&
|
||||||
|
item?.data.attribute_box.length >= 4
|
||||||
|
? Math.round(
|
||||||
|
(config?.cameras[item?.camera]?.detect?.width ?? 0) *
|
||||||
|
(config?.cameras[item?.camera]?.detect?.height ?? 0) *
|
||||||
|
(item?.data.attribute_box[2] * item?.data.attribute_box[3]),
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
[config, item],
|
||||||
|
);
|
||||||
|
|
||||||
|
const attributeAreaPct = useMemo(
|
||||||
|
() =>
|
||||||
|
Array.isArray(item?.data.attribute_box) &&
|
||||||
|
item?.data.attribute_box.length >= 4
|
||||||
|
? (item?.data.attribute_box[2] * item?.data.attribute_box[3]).toFixed(4)
|
||||||
|
: undefined,
|
||||||
|
[item],
|
||||||
|
);
|
||||||
|
|
||||||
|
const score = useMemo(() => {
|
||||||
|
if (item?.data?.score !== undefined) {
|
||||||
|
return (item.data.score * 100).toFixed(0) + "%";
|
||||||
|
}
|
||||||
|
return "N/A";
|
||||||
|
}, [item?.data?.score]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -733,6 +773,13 @@ function LifecycleItem({
|
|||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<div className="mt-1 flex flex-wrap items-start gap-3 text-sm text-secondary-foreground">
|
<div className="mt-1 flex flex-wrap items-start gap-3 text-sm text-secondary-foreground">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
|
<div className="flex items-start gap-1">
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
{t("trackingDetails.lifecycleItemDesc.header.score")}
|
||||||
|
</span>
|
||||||
|
<span className="font-medium text-foreground">{score}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex items-start gap-1">
|
<div className="flex items-start gap-1">
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">
|
||||||
{t("trackingDetails.lifecycleItemDesc.header.ratio")}
|
{t("trackingDetails.lifecycleItemDesc.header.ratio")}
|
||||||
@ -742,7 +789,13 @@ function LifecycleItem({
|
|||||||
|
|
||||||
<div className="flex items-start gap-1">
|
<div className="flex items-start gap-1">
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">
|
||||||
{t("trackingDetails.lifecycleItemDesc.header.area")}
|
{t("trackingDetails.lifecycleItemDesc.header.area")}{" "}
|
||||||
|
{attributeAreaPx !== undefined &&
|
||||||
|
attributeAreaPct !== undefined && (
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
({getTranslatedLabel(item.data.label)})
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
{areaPx !== undefined && areaPct !== undefined ? (
|
{areaPx !== undefined && areaPct !== undefined ? (
|
||||||
<span className="font-medium text-foreground">
|
<span className="font-medium text-foreground">
|
||||||
@ -754,6 +807,26 @@ function LifecycleItem({
|
|||||||
<span>N/A</span>
|
<span>N/A</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{attributeAreaPx !== undefined &&
|
||||||
|
attributeAreaPct !== undefined && (
|
||||||
|
<div className="flex items-start gap-1">
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
{t("trackingDetails.lifecycleItemDesc.header.area")}{" "}
|
||||||
|
{attributeAreaPx !== undefined &&
|
||||||
|
attributeAreaPct !== undefined && (
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
({getTranslatedLabel(item.data.attribute)})
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span className="font-medium text-foreground">
|
||||||
|
{attributeAreaPx} {t("pixels", { ns: "common" })}{" "}
|
||||||
|
<span className="text-secondary-foreground">·</span>{" "}
|
||||||
|
{attributeAreaPct}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
@ -820,7 +893,7 @@ function ObjectTimeline({
|
|||||||
}, [config, fullTimeline, review]);
|
}, [config, fullTimeline, review]);
|
||||||
|
|
||||||
if (isValidating && (!timeline || timeline.length === 0)) {
|
if (isValidating && (!timeline || timeline.length === 0)) {
|
||||||
return <ActivityIndicator className="ml-2 size-3" />;
|
return <ActivityIndicator className="ml-2.5 size-3" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!timeline || timeline.length === 0) {
|
if (!timeline || timeline.length === 0) {
|
||||||
|
|||||||
@ -808,6 +808,7 @@ function FaceAttemptGroup({
|
|||||||
if (resp.status == 200) {
|
if (resp.status == 200) {
|
||||||
toast.success(t("toast.success.trainedFace"), {
|
toast.success(t("toast.success.trainedFace"), {
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
|
closeButton: true,
|
||||||
});
|
});
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,12 +104,14 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
|||||||
if (modelState == "complete") {
|
if (modelState == "complete") {
|
||||||
toast.success(t("toast.success.trainedModel"), {
|
toast.success(t("toast.success.trainedModel"), {
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
|
closeButton: true,
|
||||||
});
|
});
|
||||||
setWasTraining(false);
|
setWasTraining(false);
|
||||||
refreshDataset();
|
refreshDataset();
|
||||||
} else if (modelState == "failed") {
|
} else if (modelState == "failed") {
|
||||||
toast.error(t("toast.error.trainingFailed"), {
|
toast.error(t("toast.error.trainingFailed"), {
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
|
closeButton: true,
|
||||||
});
|
});
|
||||||
setWasTraining(false);
|
setWasTraining(false);
|
||||||
}
|
}
|
||||||
@ -182,6 +184,7 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
|||||||
setWasTraining(true);
|
setWasTraining(true);
|
||||||
toast.success(t("toast.success.trainingModel"), {
|
toast.success(t("toast.success.trainingModel"), {
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
|
closeButton: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -193,6 +196,7 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
|||||||
|
|
||||||
toast.error(t("toast.error.trainingFailedToStart", { errorMessage }), {
|
toast.error(t("toast.error.trainingFailedToStart", { errorMessage }), {
|
||||||
position: "top-center",
|
position: "top-center",
|
||||||
|
closeButton: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [model, t]);
|
}, [model, t]);
|
||||||
|
|||||||
@ -219,7 +219,9 @@ export default function EventView({
|
|||||||
position: "top-center",
|
position: "top-center",
|
||||||
action: (
|
action: (
|
||||||
<a href="/export" target="_blank" rel="noopener noreferrer">
|
<a href="/export" target="_blank" rel="noopener noreferrer">
|
||||||
<Button>View</Button>
|
<Button>
|
||||||
|
{t("export.toast.view", { ns: "components/dialog" })}
|
||||||
|
</Button>
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user