Rename and shuffle
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import DownloadManager from "@/new/photos/services/download";
|
||||
import { clearFeatureFlagSessionState } from "@/new/photos/services/feature-flags";
|
||||
import { terminateFaceWorker } from "@/new/photos/services/ml";
|
||||
import { terminateMLWorker } from "@/new/photos/services/ml";
|
||||
import { clearFaceData } from "@/new/photos/services/ml/db";
|
||||
import mlWorkManager from "@/new/photos/services/ml/mlWorkManager";
|
||||
import log from "@/next/log";
|
||||
@@ -19,11 +19,23 @@ export const photosLogout = async () => {
|
||||
const ignoreError = (label: string, e: unknown) =>
|
||||
log.error(`Ignoring error during logout (${label})`, e);
|
||||
|
||||
// - Workers
|
||||
|
||||
// Terminate any workers before clearing persistent state.
|
||||
// See: [Note: Caching IDB instances in separate execution contexts].
|
||||
|
||||
try {
|
||||
terminateMLWorker();
|
||||
} catch (e) {
|
||||
ignoreError("face", e);
|
||||
}
|
||||
|
||||
// - Remote logout and clear state
|
||||
|
||||
await accountLogout();
|
||||
|
||||
// - Photos specific logout
|
||||
|
||||
try {
|
||||
clearFeatureFlagSessionState();
|
||||
} catch (e) {
|
||||
@@ -42,11 +54,7 @@ export const photosLogout = async () => {
|
||||
ignoreError("CLIP", e);
|
||||
}
|
||||
|
||||
try {
|
||||
terminateFaceWorker();
|
||||
} catch (e) {
|
||||
ignoreError("face", e);
|
||||
}
|
||||
// - Desktop
|
||||
|
||||
const electron = globalThis.electron;
|
||||
if (electron) {
|
||||
@@ -69,7 +77,7 @@ export const photosLogout = async () => {
|
||||
}
|
||||
|
||||
try {
|
||||
await electron?.logout();
|
||||
await electron.logout();
|
||||
} catch (e) {
|
||||
ignoreError("electron", e);
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
/**
|
||||
* @file Main thread interface to {@link FaceWorker}.
|
||||
* @file Main thread interface to {@link MLWorker}.
|
||||
*/
|
||||
|
||||
import { ComlinkWorker } from "@/next/worker/comlink-worker";
|
||||
import { FaceWorker } from "./worker";
|
||||
import { MLWorker } from "./worker";
|
||||
|
||||
/** Cached instance of the {@link ComlinkWorker} that wraps our web worker. */
|
||||
let _comlinkWorker: ComlinkWorker<typeof FaceWorker> | undefined;
|
||||
let _comlinkWorker: ComlinkWorker<typeof MLWorker> | undefined;
|
||||
|
||||
/** Lazily created, cached, instance of {@link FaceWorker}. */
|
||||
export const faceWorker = async () =>
|
||||
/** Lazily created, cached, instance of {@link MLWorker}. */
|
||||
export const worker = async () =>
|
||||
(_comlinkWorker ??= createComlinkWorker()).remote;
|
||||
|
||||
const createComlinkWorker = () =>
|
||||
new ComlinkWorker<typeof FaceWorker>(
|
||||
"face",
|
||||
new ComlinkWorker<typeof MLWorker>(
|
||||
"ml",
|
||||
new Worker(new URL("worker.ts", import.meta.url)),
|
||||
);
|
||||
|
||||
/**
|
||||
* Terminate {@link faceWorker} (if any).
|
||||
* Terminate {@link worker} (if any).
|
||||
*
|
||||
* This is useful during logout to immediately stop any background face related
|
||||
* operations that are in-flight for the current user. After the user logs in
|
||||
* again, a new {@link faceWorker} will be created on demand.
|
||||
* This is useful during logout to immediately stop any background ML operations
|
||||
* that are in-flight for the current user. After the user logs in again, a new
|
||||
* {@link worker} will be created on demand for subsequent usage.
|
||||
*/
|
||||
export const terminateFaceWorker = () => {
|
||||
export const terminateMLWorker = () => {
|
||||
if (_comlinkWorker) {
|
||||
_comlinkWorker.terminate();
|
||||
_comlinkWorker = undefined;
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import { markIndexingFailed, saveFaceIndex } from "@/new/photos/services/ml/db";
|
||||
import type { FaceIndex } from "@/new/photos/services/ml/types";
|
||||
import type { EnteFile } from "@/new/photos/types/file";
|
||||
import log from "@/next/log";
|
||||
import { expose } from "comlink";
|
||||
import { pullFaceEmbeddings } from "./embedding";
|
||||
import { fileLogID } from "../../utils/file";
|
||||
import { pullFaceEmbeddings, putFaceIndex } from "./embedding";
|
||||
import { indexFaces } from "./f-index";
|
||||
|
||||
/**
|
||||
* Run operations related to face indexing and search in a Web Worker.
|
||||
* Run operations related to machine learning (e.g. indexing) in a Web Worker.
|
||||
*
|
||||
* This is a normal class that is however exposed (via comlink) as a proxy
|
||||
* running inside a Web Worker. This way, we do not bother the main thread with
|
||||
* tasks that might degrade interactivity.
|
||||
*/
|
||||
export class FaceWorker {
|
||||
export class MLWorker {
|
||||
private isSyncing = false;
|
||||
|
||||
/**
|
||||
@@ -22,4 +28,55 @@ export class FaceWorker {
|
||||
}
|
||||
}
|
||||
|
||||
expose(FaceWorker);
|
||||
expose(MLWorker);
|
||||
|
||||
/**
|
||||
* Index faces in a file, save the persist the results locally, and put them
|
||||
* on remote.
|
||||
*
|
||||
* @param enteFile The {@link EnteFile} to index.
|
||||
*
|
||||
* @param file If the file is one which is being uploaded from the current
|
||||
* client, then we will also have access to the file's content. In such
|
||||
* cases, pass a web {@link File} object to use that its data directly for
|
||||
* face indexing. If this is not provided, then the file's contents will be
|
||||
* downloaded and decrypted from remote.
|
||||
*
|
||||
* @param userAgent The UA of the client that is doing the indexing (us).
|
||||
*/
|
||||
export const index = async (
|
||||
enteFile: EnteFile,
|
||||
file: File | undefined,
|
||||
userAgent: string,
|
||||
) => {
|
||||
const f = fileLogID(enteFile);
|
||||
const startTime = Date.now();
|
||||
|
||||
let faceIndex: FaceIndex;
|
||||
try {
|
||||
faceIndex = await indexFaces(enteFile, file, userAgent);
|
||||
} catch (e) {
|
||||
// Mark indexing as having failed only if the indexing itself
|
||||
// failed, not if there were subsequent failures (like when trying
|
||||
// to put the result to remote or save it to the local face DB).
|
||||
log.error(`Failed to index faces in ${f}`, e);
|
||||
await markIndexingFailed(enteFile.id);
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
await putFaceIndex(enteFile, faceIndex);
|
||||
await saveFaceIndex(faceIndex);
|
||||
} catch (e) {
|
||||
log.error(`Failed to put/save face index for ${f}`, e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug(() => {
|
||||
const nf = faceIndex.faceEmbedding.faces.length;
|
||||
const ms = Date.now() - startTime;
|
||||
return `Indexed ${nf} faces in ${f} (${ms} ms)`;
|
||||
});
|
||||
|
||||
return faceIndex;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user