mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-07 05:55:27 +03:00
feat: add explore model i18n keys
This commit is contained in:
parent
118ef6b2fe
commit
84ba218b1b
@ -111,6 +111,7 @@
|
|||||||
"restart": "Restart Frigate",
|
"restart": "Restart Frigate",
|
||||||
"live": "Live",
|
"live": "Live",
|
||||||
"live.allCameras": "All Cameras",
|
"live.allCameras": "All Cameras",
|
||||||
|
"live.cameras": "Cameras",
|
||||||
"review": "Review",
|
"review": "Review",
|
||||||
"explore": "Explore",
|
"explore": "Explore",
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
|
|||||||
@ -1,4 +1,32 @@
|
|||||||
{
|
{
|
||||||
|
"exploreIsUnavailable": {
|
||||||
|
"title": "Explore is Unavailable",
|
||||||
|
"embeddingsReindexing": {
|
||||||
|
"context": "Explore can be used after tracked object embeddings have finished reindexing.",
|
||||||
|
"startingUp": "Starting up...",
|
||||||
|
"estimatedTime": "Estimated time remaining:",
|
||||||
|
"finishingShortly": "Finishing shortly",
|
||||||
|
"step": {
|
||||||
|
"thumbnailsEmbedded": "Thumbnails embedded: ",
|
||||||
|
"descriptionsEmbedded": "Descriptions embedded: ",
|
||||||
|
"trackedObjectsProcessed": "Tracked objects processed: "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"downloadingModels": {
|
||||||
|
"context": "Frigate is downloading the necessary embeddings models to support the Semantic Search feature. This may take several minutes depending on the speed of your network connection.",
|
||||||
|
"setup": {
|
||||||
|
"visionModel": "Vision model",
|
||||||
|
"visionModelFeatureExtractor": "Vision model feature extractor",
|
||||||
|
"textModel": "Text model",
|
||||||
|
"textTokenizer": "Text tokenizer"
|
||||||
|
},
|
||||||
|
"tips": {
|
||||||
|
"context": "You may want to reindex the embeddings of your tracked objects once the models are downloaded.",
|
||||||
|
"documentation": "Read the documentation"
|
||||||
|
},
|
||||||
|
"error": "An error has occurred. Check Frigate logs."
|
||||||
|
}
|
||||||
|
},
|
||||||
"trackedObjectDetails": "Tracked Object Details",
|
"trackedObjectDetails": "Tracked Object Details",
|
||||||
"type": {
|
"type": {
|
||||||
"details": "details",
|
"details": "details",
|
||||||
|
|||||||
@ -69,6 +69,7 @@
|
|||||||
"stats": {
|
"stats": {
|
||||||
"ffmpegHighCpuUsage": "{{camera}} has high FFMPEG CPU usage ({{ffmpegAvg}}%)",
|
"ffmpegHighCpuUsage": "{{camera}} has high FFMPEG CPU usage ({{ffmpegAvg}}%)",
|
||||||
"detectHighCpuUsage": "{{camera}} has high detect CPU usage ({{detectAvg}}%)",
|
"detectHighCpuUsage": "{{camera}} has high detect CPU usage ({{detectAvg}}%)",
|
||||||
"healthy": "System is healthy"
|
"healthy": "System is healthy",
|
||||||
|
"reindexingEmbeddings": "Reindexing embeddings ({{processed}}% complete)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,6 +110,7 @@
|
|||||||
"documentation": "文档",
|
"documentation": "文档",
|
||||||
"live": "实时监控",
|
"live": "实时监控",
|
||||||
"live.allCameras": "所有摄像头",
|
"live.allCameras": "所有摄像头",
|
||||||
|
"live.cameras": "摄像头",
|
||||||
"review": "回放",
|
"review": "回放",
|
||||||
"explore": "探测",
|
"explore": "探测",
|
||||||
"export": "导出",
|
"export": "导出",
|
||||||
|
|||||||
@ -1,4 +1,32 @@
|
|||||||
{
|
{
|
||||||
|
"exploreIsUnavailable": {
|
||||||
|
"title": "探索功能不可用",
|
||||||
|
"embeddingsReindexing": {
|
||||||
|
"context": "跟踪对象嵌入重新索引完成后,可以使用探索功能。",
|
||||||
|
"startingUp": "启动中...",
|
||||||
|
"estimatedTime": "预计剩余时间:",
|
||||||
|
"finishingShortly": "即将完成",
|
||||||
|
"step": {
|
||||||
|
"thumbnailsEmbedded": "缩略图嵌入:",
|
||||||
|
"descriptionsEmbedded": "描述嵌入:",
|
||||||
|
"trackedObjectsProcessed": "跟踪对象已处理:"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"downloadingModels": {
|
||||||
|
"context": "Frigate正在下载支持语义搜索功能所需的嵌入模型。根据网络连接速度,这可能需要几分钟。",
|
||||||
|
"setup": {
|
||||||
|
"visionModel": "视觉模型",
|
||||||
|
"visionModelFeatureExtractor": "视觉模型特征提取器",
|
||||||
|
"textModel": "文本模型",
|
||||||
|
"textTokenizer": "文本分词器"
|
||||||
|
},
|
||||||
|
"tips": {
|
||||||
|
"context": "模型下载完成后,您可能需要重新索引跟踪对象的嵌入。",
|
||||||
|
"documentation": "阅读文档(英文)"
|
||||||
|
},
|
||||||
|
"error": "发生错误。请检查Frigate日志。"
|
||||||
|
}
|
||||||
|
},
|
||||||
"trackedObjectDetails": "探测对象详情",
|
"trackedObjectDetails": "探测对象详情",
|
||||||
"type": {
|
"type": {
|
||||||
"details": "详情",
|
"details": "详情",
|
||||||
|
|||||||
@ -69,6 +69,7 @@
|
|||||||
"stats": {
|
"stats": {
|
||||||
"ffmpegHighCpuUsage": "{{camera}} 的 FFMPEG CPU 使用率较高({{ffmpegAvg}}%)",
|
"ffmpegHighCpuUsage": "{{camera}} 的 FFMPEG CPU 使用率较高({{ffmpegAvg}}%)",
|
||||||
"detectHighCpuUsage": "{{camera}} 的 探测 CPU 使用率较高({{detectAvg}}%)",
|
"detectHighCpuUsage": "{{camera}} 的 探测 CPU 使用率较高({{detectAvg}}%)",
|
||||||
"healthy": "系统运行正常"
|
"healthy": "系统运行正常",
|
||||||
|
"reindexingEmbeddings": "正在重新索引嵌入(已完成 {{processed}}%)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,14 +54,19 @@ export default function Statusbar() {
|
|||||||
clearMessages("embeddings-reindex");
|
clearMessages("embeddings-reindex");
|
||||||
addMessage(
|
addMessage(
|
||||||
"embeddings-reindex",
|
"embeddings-reindex",
|
||||||
`Reindexing embeddings (${Math.floor((reindexState.processed_objects / reindexState.total_objects) * 100)}% complete)`,
|
t("stats.reindexingEmbeddings", {
|
||||||
|
processed: Math.floor(
|
||||||
|
(reindexState.processed_objects / reindexState.total_objects) *
|
||||||
|
100,
|
||||||
|
),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (reindexState.status === "completed") {
|
if (reindexState.status === "completed") {
|
||||||
clearMessages("embeddings-reindex");
|
clearMessages("embeddings-reindex");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [reindexState, addMessage, clearMessages]);
|
}, [reindexState, addMessage, clearMessages, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute bottom-0 left-0 right-0 z-10 flex h-8 w-full items-center justify-between border-t border-secondary-highlight bg-background_alt px-4 dark:text-secondary-foreground">
|
<div className="absolute bottom-0 left-0 right-0 z-10 flex h-8 w-full items-center justify-between border-t border-secondary-highlight bg-background_alt px-4 dark:text-secondary-foreground">
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export function CamerasFilterButton({
|
|||||||
|
|
||||||
const buttonText = useMemo(() => {
|
const buttonText = useMemo(() => {
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
return "Cameras";
|
return t("menu.live.cameras", { ns: "common" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selectedCameras || selectedCameras.length == 0) {
|
if (!selectedCameras || selectedCameras.length == 0) {
|
||||||
|
|||||||
@ -109,7 +109,7 @@ export default function AccountSettings({ className }: AccountSettingsProps) {
|
|||||||
{t("menu.user.current", {
|
{t("menu.user.current", {
|
||||||
user: profile?.username || t("menu.user.anonymous"),
|
user: profile?.username || t("menu.user.anonymous"),
|
||||||
})}{" "}
|
})}{" "}
|
||||||
{t("role." + profile?.role) && `(${t("role." + profile.role)})`}
|
{t("role." + profile?.role) && `(${t("role." + profile?.role)})`}
|
||||||
</DropdownMenuLabel>
|
</DropdownMenuLabel>
|
||||||
<DropdownMenuSeparator className={isDesktop ? "mt-3" : "mt-1"} />
|
<DropdownMenuSeparator className={isDesktop ? "mt-3" : "mt-1"} />
|
||||||
{profile?.username && profile.username !== "anonymous" && (
|
{profile?.username && profile.username !== "anonymous" && (
|
||||||
|
|||||||
@ -170,7 +170,7 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
|||||||
user: profile?.username || t("menu.user.anonymous"),
|
user: profile?.username || t("menu.user.anonymous"),
|
||||||
})}{" "}
|
})}{" "}
|
||||||
{t("role." + profile?.role) &&
|
{t("role." + profile?.role) &&
|
||||||
`(${t("role." + profile.role)})`}
|
`(${t("role." + profile?.role)})`}
|
||||||
</DropdownMenuLabel>
|
</DropdownMenuLabel>
|
||||||
<DropdownMenuSeparator
|
<DropdownMenuSeparator
|
||||||
className={isDesktop ? "mt-3" : "mt-1"}
|
className={isDesktop ? "mt-3" : "mt-1"}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { formatSecondsToDuration } from "@/utils/dateUtil";
|
|||||||
import SearchView from "@/views/search/SearchView";
|
import SearchView from "@/views/search/SearchView";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { isMobileOnly } from "react-device-detect";
|
import { isMobileOnly } from "react-device-detect";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { LuCheck, LuExternalLink, LuX } from "react-icons/lu";
|
import { LuCheck, LuExternalLink, LuX } from "react-icons/lu";
|
||||||
import { TbExclamationCircle } from "react-icons/tb";
|
import { TbExclamationCircle } from "react-icons/tb";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
@ -27,6 +28,8 @@ const API_LIMIT = 25;
|
|||||||
export default function Explore() {
|
export default function Explore() {
|
||||||
// search field handler
|
// search field handler
|
||||||
|
|
||||||
|
const { t } = useTranslation(["views/explore"]);
|
||||||
|
|
||||||
const { data: config } = useSWR<FrigateConfig>("config", {
|
const { data: config } = useSWR<FrigateConfig>("config", {
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
});
|
});
|
||||||
@ -353,13 +356,12 @@ export default function Explore() {
|
|||||||
<div className="flex max-w-96 flex-col items-center justify-center space-y-3 rounded-lg bg-background/50 p-5">
|
<div className="flex max-w-96 flex-col items-center justify-center space-y-3 rounded-lg bg-background/50 p-5">
|
||||||
<div className="my-5 flex flex-col items-center gap-2 text-xl">
|
<div className="my-5 flex flex-col items-center gap-2 text-xl">
|
||||||
<TbExclamationCircle className="mb-3 size-10" />
|
<TbExclamationCircle className="mb-3 size-10" />
|
||||||
<div>Explore is Unavailable</div>
|
<div>{t("exploreIsUnavailable.title")}</div>
|
||||||
</div>
|
</div>
|
||||||
{embeddingsReindexing && allModelsLoaded && (
|
{embeddingsReindexing && allModelsLoaded && (
|
||||||
<>
|
<>
|
||||||
<div className="text-center text-primary-variant">
|
<div className="text-center text-primary-variant">
|
||||||
Explore can be used after tracked object embeddings have
|
{t("exploreIsUnavailable.embeddingsReindexing.context")}
|
||||||
finished reindexing.
|
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-5 text-center">
|
<div className="pt-5 text-center">
|
||||||
<AnimatedCircularProgressBar
|
<AnimatedCircularProgressBar
|
||||||
@ -375,29 +377,35 @@ export default function Explore() {
|
|||||||
<div className="mb-3 flex flex-col items-center justify-center gap-1">
|
<div className="mb-3 flex flex-col items-center justify-center gap-1">
|
||||||
<div className="text-primary-variant">
|
<div className="text-primary-variant">
|
||||||
{reindexState.time_remaining === -1
|
{reindexState.time_remaining === -1
|
||||||
? "Starting up..."
|
? t(
|
||||||
: "Estimated time remaining:"}
|
"exploreIsUnavailable.embeddingsReindexing.startingUp",
|
||||||
|
)
|
||||||
|
: t(
|
||||||
|
"exploreIsUnavailable.embeddingsReindexing.estimatedTime",
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{reindexState.time_remaining >= 0 &&
|
{reindexState.time_remaining >= 0 &&
|
||||||
(formatSecondsToDuration(reindexState.time_remaining) ||
|
(formatSecondsToDuration(reindexState.time_remaining) ||
|
||||||
"Finishing shortly")}
|
t(
|
||||||
|
"exploreIsUnavailable.embeddingsReindexing.finishingShortly",
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-row items-center justify-center gap-3">
|
<div className="flex flex-row items-center justify-center gap-3">
|
||||||
<span className="text-primary-variant">
|
<span className="text-primary-variant">
|
||||||
Thumbnails embedded:
|
t("exploreIsUnavailable.embeddingsReindexing.step.thumbnailsEmbedded")
|
||||||
</span>
|
</span>
|
||||||
{reindexState.thumbnails}
|
{reindexState.thumbnails}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center justify-center gap-3">
|
<div className="flex flex-row items-center justify-center gap-3">
|
||||||
<span className="text-primary-variant">
|
<span className="text-primary-variant">
|
||||||
Descriptions embedded:
|
t("exploreIsUnavailable.embeddingsReindexing.step.descriptionsEmbedded")
|
||||||
</span>
|
</span>
|
||||||
{reindexState.descriptions}
|
{reindexState.descriptions}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center justify-center gap-3">
|
<div className="flex flex-row items-center justify-center gap-3">
|
||||||
<span className="text-primary-variant">
|
<span className="text-primary-variant">
|
||||||
Tracked objects processed:
|
t("exploreIsUnavailable.embeddingsReindexing.step.trackedObjectsProcessed")
|
||||||
</span>
|
</span>
|
||||||
{reindexState.processed_objects} /{" "}
|
{reindexState.processed_objects} /{" "}
|
||||||
{reindexState.total_objects}
|
{reindexState.total_objects}
|
||||||
@ -408,26 +416,32 @@ export default function Explore() {
|
|||||||
{!allModelsLoaded && (
|
{!allModelsLoaded && (
|
||||||
<>
|
<>
|
||||||
<div className="text-center text-primary-variant">
|
<div className="text-center text-primary-variant">
|
||||||
Frigate is downloading the necessary embeddings models to
|
{t("exploreIsUnavailable.downloadingModels.context")}
|
||||||
support the Semantic Search feature. This may take several
|
|
||||||
minutes depending on the speed of your network connection.
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-96 flex-col gap-2 py-5">
|
<div className="flex w-96 flex-col gap-2 py-5">
|
||||||
<div className="flex flex-row items-center justify-center gap-2">
|
<div className="flex flex-row items-center justify-center gap-2">
|
||||||
{renderModelStateIcon(visionModelState)}
|
{renderModelStateIcon(visionModelState)}
|
||||||
Vision model
|
{t(
|
||||||
|
"exploreIsUnavailable.downloadingModels.setup.visionModel",
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center justify-center gap-2">
|
<div className="flex flex-row items-center justify-center gap-2">
|
||||||
{renderModelStateIcon(visionFeatureExtractorState)}
|
{renderModelStateIcon(visionFeatureExtractorState)}
|
||||||
Vision model feature extractor
|
{t(
|
||||||
|
"exploreIsUnavailable.downloadingModels.setup.visionModelFeatureExtractor",
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center justify-center gap-2">
|
<div className="flex flex-row items-center justify-center gap-2">
|
||||||
{renderModelStateIcon(textModelState)}
|
{renderModelStateIcon(textModelState)}
|
||||||
Text model
|
{t(
|
||||||
|
"exploreIsUnavailable.downloadingModels.setup.textModel",
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center justify-center gap-2">
|
<div className="flex flex-row items-center justify-center gap-2">
|
||||||
{renderModelStateIcon(textTokenizerState)}
|
{renderModelStateIcon(textTokenizerState)}
|
||||||
Text tokenizer
|
{t(
|
||||||
|
"exploreIsUnavailable.downloadingModels.setup.textTokenizer",
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{(textModelState === "error" ||
|
{(textModelState === "error" ||
|
||||||
@ -435,12 +449,11 @@ export default function Explore() {
|
|||||||
visionModelState === "error" ||
|
visionModelState === "error" ||
|
||||||
visionFeatureExtractorState === "error") && (
|
visionFeatureExtractorState === "error") && (
|
||||||
<div className="my-3 max-w-96 text-center text-danger">
|
<div className="my-3 max-w-96 text-center text-danger">
|
||||||
An error has occurred. Check Frigate logs.
|
{t("exploreIsUnavailable.downloadingModels.error")}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="text-center text-primary-variant">
|
<div className="text-center text-primary-variant">
|
||||||
You may want to reindex the embeddings of your tracked objects
|
{t("exploreIsUnavailable.downloadingModels.tips.context")}
|
||||||
once the models are downloaded.
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center text-primary-variant">
|
<div className="flex items-center text-primary-variant">
|
||||||
<Link
|
<Link
|
||||||
@ -449,7 +462,9 @@ export default function Explore() {
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="inline"
|
className="inline"
|
||||||
>
|
>
|
||||||
Read the documentation{" "}
|
{t(
|
||||||
|
"exploreIsUnavailable.downloadingModels.tips.documentation",
|
||||||
|
)}{" "}
|
||||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user