[desktop] Towards public beta of advanced (ML) search - Part 2/x (#2665)
This commit is contained in:
@@ -4,7 +4,6 @@ import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu";
|
||||
import { Titlebar } from "@/base/components/Titlebar";
|
||||
import {
|
||||
getLocaleInUse,
|
||||
pt,
|
||||
setLocaleInUse,
|
||||
supportedLocales,
|
||||
type SupportedLocale,
|
||||
@@ -96,7 +95,7 @@ export const Preferences: React.FC<SettingsDrawerProps> = ({
|
||||
<EnteMenuItem
|
||||
endIcon={<ChevronRight />}
|
||||
onClick={() => setOpenMLSettings(true)}
|
||||
label={pt("Face and magic search")}
|
||||
label={t("face_and_magic_search")}
|
||||
/>
|
||||
</MenuItemGroup>
|
||||
</Box>
|
||||
|
||||
@@ -264,6 +264,7 @@
|
||||
"SCAN_QR_CODE": "Scan QR code instead",
|
||||
"ENABLE_TWO_FACTOR": "Enable two-factor",
|
||||
"ENABLE": "Enable",
|
||||
"enabled": "Enabled",
|
||||
"LOST_DEVICE": "Lost two-factor device",
|
||||
"INCORRECT_CODE": "Incorrect code",
|
||||
"TWO_FACTOR_INFO": "Add an additional layer of security by requiring more than your email and password to log in to your account",
|
||||
@@ -477,6 +478,16 @@
|
||||
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "<p>You have dragged and dropped a mixture of files and folders.</p><p>Please provide either only files, or only folders when selecting option to create separate albums</p>",
|
||||
"CHOSE_THEME": "Choose theme",
|
||||
"more_details": "More details",
|
||||
"face_and_magic_search": "Face and magic search",
|
||||
"ml_search_description": "Ente supports on-device machine learning for face recognition, magic search and other advanced search features",
|
||||
"ml_search_footnote": "Magic search allows to search photos by their contents, e.g. 'car', 'red car', 'Ferrari'",
|
||||
"indexing": "Indexing",
|
||||
"processed": "Processed",
|
||||
"indexing_status_running": "Running",
|
||||
"indexing_status_scheduled": "Scheduled",
|
||||
"indexing_status_done": "Done",
|
||||
"ml_search_disable": "Disable face and magic search",
|
||||
"ml_search_disable_confirm": "Do you want to disable face and magic search on all your devices?",
|
||||
"ENABLE_FACE_SEARCH": "Enable face recognition",
|
||||
"ENABLE_FACE_SEARCH_TITLE": "Enable face recognition?",
|
||||
"ENABLE_FACE_SEARCH_DESCRIPTION": "<p>If you enable face recognition, Ente will extract face geometry from your photos. This will happen on your device, and any generated biometric data will be end-to-encrypted.</p><p><a>Please click here for more details about this feature in our privacy policy</a></p>",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { EnteDrawer } from "@/base/components/EnteDrawer";
|
||||
import { MenuItemGroup } from "@/base/components/Menu";
|
||||
import { Titlebar } from "@/base/components/Titlebar";
|
||||
import { pt } from "@/base/i18n";
|
||||
import log from "@/base/log";
|
||||
import {
|
||||
disableML,
|
||||
@@ -124,7 +123,7 @@ export const MLSettings: React.FC<MLSettingsProps> = ({
|
||||
<Stack spacing={"4px"} py={"12px"}>
|
||||
<Titlebar
|
||||
onClose={onClose}
|
||||
title={pt("Face and magic search")}
|
||||
title={t("face_and_magic_search")}
|
||||
onRootClose={onRootClose}
|
||||
/>
|
||||
{component}
|
||||
@@ -161,9 +160,7 @@ const EnableML: React.FC<EnableMLProps> = ({ onEnable }) => {
|
||||
return (
|
||||
<Stack py={"20px"} px={"16px"} spacing={"32px"}>
|
||||
<Typography color="text.muted">
|
||||
{pt(
|
||||
"Ente supports on-device machine learning for face recognition, magic search and other advanced search features",
|
||||
)}
|
||||
{t("ml_search_description")}
|
||||
</Typography>
|
||||
<Stack spacing={"8px"}>
|
||||
<Button color={"accent"} size="large" onClick={onEnable}>
|
||||
@@ -175,9 +172,7 @@ const EnableML: React.FC<EnableMLProps> = ({ onEnable }) => {
|
||||
</Button>
|
||||
</Stack>
|
||||
<Typography color="text.faint" variant="small">
|
||||
{pt(
|
||||
'Magic search allows to search photos by their contents, e.g. "car", "red car", "Ferrari"',
|
||||
)}
|
||||
{t("ml_search_footnote")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
);
|
||||
@@ -305,28 +300,26 @@ const ManageML: React.FC<ManageMLProps> = ({
|
||||
let status: string;
|
||||
switch (phase) {
|
||||
case "indexing":
|
||||
status = pt("Running");
|
||||
status = t("running");
|
||||
break;
|
||||
case "scheduled":
|
||||
status = pt("Scheduled");
|
||||
status = t("scheduled");
|
||||
break;
|
||||
// TODO: Clustering
|
||||
default:
|
||||
status = pt("Done");
|
||||
status = t("done");
|
||||
break;
|
||||
}
|
||||
const processed = `${nSyncedFiles} / ${nTotalFiles}`;
|
||||
|
||||
const confirmDisableML = () => {
|
||||
setDialogBoxAttributesV2({
|
||||
title: pt("Disable face and magic search"),
|
||||
content: pt(
|
||||
"Do you want to disable face and magic search on all your devices?",
|
||||
),
|
||||
title: t("ml_search_disable"),
|
||||
content: t("ml_search_disable_confirm"),
|
||||
close: { text: t("cancel") },
|
||||
proceed: {
|
||||
variant: "critical",
|
||||
text: pt("Disable"),
|
||||
text: t("DISABLE"),
|
||||
action: onDisableML,
|
||||
},
|
||||
buttonDirection: "row",
|
||||
@@ -338,7 +331,7 @@ const ManageML: React.FC<ManageMLProps> = ({
|
||||
<Stack gap={3}>
|
||||
<MenuItemGroup>
|
||||
<EnteMenuItem
|
||||
label={pt("Enabled")}
|
||||
label={t("enabled")}
|
||||
variant="toggle"
|
||||
checked={true}
|
||||
onClick={confirmDisableML}
|
||||
@@ -356,9 +349,11 @@ const ManageML: React.FC<ManageMLProps> = ({
|
||||
justifyContent={"space-between"}
|
||||
>
|
||||
<Typography color="text.faint">
|
||||
{pt("Indexing")}
|
||||
{t("indexing")}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{t("indexing_status", { context: status })}
|
||||
</Typography>
|
||||
<Typography>{status}</Typography>
|
||||
</Stack>
|
||||
<Divider sx={{ marginInlineStart: 2 }} />
|
||||
<Stack
|
||||
@@ -370,7 +365,7 @@ const ManageML: React.FC<ManageMLProps> = ({
|
||||
justifyContent={"space-between"}
|
||||
>
|
||||
<Typography color="text.faint">
|
||||
{pt("Processed")}
|
||||
{t("processed")}
|
||||
</Typography>
|
||||
<Typography textAlign="right">{processed}</Typography>
|
||||
</Stack>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { dotProduct } from "./math";
|
||||
*/
|
||||
export interface FaceCluster {
|
||||
/**
|
||||
* A randomly generated ID to uniquely identify this cluster.
|
||||
* A nanoid for this cluster.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ export interface FaceCluster {
|
||||
*/
|
||||
export interface Person {
|
||||
/**
|
||||
* A randomly generated ID to uniquely identify this person.
|
||||
* A nanoid for this person.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
|
||||
@@ -149,6 +149,12 @@ const deleteLegacyDB = () => {
|
||||
removeKV("embeddingSyncTime:onnx-clip"),
|
||||
removeKV("embeddingSyncTime:file-ml-clip-face"),
|
||||
]);
|
||||
|
||||
// Delete legacy ML keys.
|
||||
//
|
||||
// This code was added August 2024 (v1.7.3-beta) and can be removed at some
|
||||
// point when most clients have migrated (tag: Migration).
|
||||
localStorage.removeItem("faceIndexingEnabled");
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -160,13 +160,8 @@ export const isMLSupported = isDesktop;
|
||||
|
||||
/**
|
||||
* TODO-ML: This will not be needed when we move to a public beta.
|
||||
* Was this someone who might've enabled the beta ML? If so, show them the
|
||||
* coming back soon banner while we finalize it.
|
||||
*/
|
||||
export const canEnableML = async () =>
|
||||
// TODO-ML: The interim condition should be
|
||||
// isDevBuild || (await isInternalUser()) || (await isBetaUser());
|
||||
await isInternalUser();
|
||||
export const canEnableML = async () => await isInternalUser();
|
||||
|
||||
/**
|
||||
* Initialize the ML subsystem if the user has enabled it in preferences.
|
||||
@@ -224,6 +219,11 @@ export const disableML = async () => {
|
||||
triggerStatusUpdate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Local storage key for {@link isMLEnabledLocal}.
|
||||
*/
|
||||
const mlLocalKey = "mlEnabled";
|
||||
|
||||
/**
|
||||
* Return true if our local persistence thinks that ML is enabled.
|
||||
*
|
||||
@@ -233,17 +233,15 @@ export const disableML = async () => {
|
||||
* The remote status is tracked with a separate {@link isMLEnabledRemote} flag
|
||||
* that is synced with remote.
|
||||
*/
|
||||
const isMLEnabledLocal = () =>
|
||||
// TODO-ML: Rename this flag
|
||||
localStorage.getItem("faceIndexingEnabled") == "1";
|
||||
const isMLEnabledLocal = () => localStorage.getItem(mlLocalKey) == "1";
|
||||
|
||||
/**
|
||||
* Update the (locally stored) value of {@link isMLEnabledLocal}.
|
||||
*/
|
||||
const setIsMLEnabledLocal = (enabled: boolean) =>
|
||||
enabled
|
||||
? localStorage.setItem("faceIndexingEnabled", "1")
|
||||
: localStorage.removeItem("faceIndexingEnabled");
|
||||
? localStorage.setItem(mlLocalKey, "1")
|
||||
: localStorage.removeItem(mlLocalKey);
|
||||
|
||||
/**
|
||||
* For historical reasons, this is called "faceSearchEnabled" (it started off as
|
||||
|
||||
Reference in New Issue
Block a user