From b7a45b432725db95cd21a254396912175016b744 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 18 Sep 2024 12:03:54 +0530 Subject: [PATCH] Match server schema --- .../new/photos/services/ml/cluster.ts | 27 +++++++------------ web/packages/new/photos/services/ml/index.ts | 2 +- .../new/photos/services/user-entity.ts | 12 ++++----- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index 919e602aee..bb26c386f6 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -8,12 +8,9 @@ import { faceDirection, type Face, type FaceIndex } from "./face"; import { dotProduct } from "./math"; /** - * A face cluster is an set of faces. + * A face cluster is an set of faces, and a nanoid to uniquely identify it. * - * Each cluster has an id so that a {@link CGroup} can refer to it. - * - * The cluster is not directly synced to remote. Only clusters that the user - * interacts with get synced to remote, as part of a {@link CGroup}. + * A cluster may be local only, or synced to remote as part of a {@link CGroup}. */ export interface FaceCluster { /** @@ -26,7 +23,7 @@ export interface FaceCluster { * For ergonomics of transportation and persistence this is an array, but it * should conceptually be thought of as a set. */ - faceIDs: string[]; + faces: string[]; } export interface ClusteringOpts { @@ -164,11 +161,11 @@ export const clusterFaces = ( // Prune clusters that are smaller than the threshold. const validClusters = clusters.filter( - (cs) => cs.faceIDs.length > minClusterSize, + (cs) => cs.faces.length > minClusterSize, ); const sortedClusters = validClusters.sort( - (a, b) => b.faceIDs.length - a.faceIDs.length, + (a, b) => b.faces.length - a.faces.length, ); // Convert into the data structure we're using to debug/visualize. @@ -177,9 +174,7 @@ export const clusterFaces = ( ? sortedClusters : sortedClusters.slice(0, 30).concat(sortedClusters.slice(-30)); const clusterPreviews = clusterPreviewClusters.map((cluster) => { - const faces = cluster.faceIDs.map((id) => - ensure(faceForFaceID.get(id)), - ); + const faces = cluster.faces.map((id) => ensure(faceForFaceID.get(id))); const topFace = faces.reduce((top, face) => top.score > face.score ? top : face, ); @@ -188,7 +183,7 @@ export const clusterFaces = ( return { face, cosineSimilarity: csim, wasMerged: false }; }); return { - clusterSize: cluster.faceIDs.length, + clusterSize: cluster.faces.length, faces: previewFaces .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) .slice(0, 50), @@ -201,9 +196,7 @@ export const clusterFaces = ( const cgroups: AnnotatedCGroup[] = []; for (const cluster of sortedClusters) { - const faces = cluster.faceIDs.map((id) => - ensure(faceForFaceID.get(id)), - ); + const faces = cluster.faces.map((id) => ensure(faceForFaceID.get(id))); const topFace = faces.reduce((top, face) => top.score > face.score ? top : face, ); @@ -377,12 +370,12 @@ const clusterBatchLinear = ( state.clusterIDForFaceID.set(fi.faceID, nnCluster.id); state.clusterIndexForFaceID.set(fi.faceID, nnClusterIndex); - nnCluster.faceIDs.push(fi.faceID); + nnCluster.faces.push(fi.faceID); } else { // No neighbour within the threshold. Create a new cluster. const clusterID = newClusterID(); const clusterIndex = state.clusters.length; - const cluster = { id: clusterID, faceIDs: [fi.faceID] }; + const cluster = { id: clusterID, faces: [fi.faceID] }; state.clusterIDForFaceID.set(fi.faceID, cluster.id); state.clusterIndexForFaceID.set(fi.faceID, clusterIndex); diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index a4862b158a..d7ac134b7e 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -429,7 +429,7 @@ export const wipClusterDebugPageContents = async ( const faceIDs = cgroup.clusterIDs .map((id) => ensure(clusterByID.get(id))) - .flatMap((cluster) => cluster.faceIDs); + .flatMap((cluster) => cluster.faces); const fileIDs = faceIDs .map((faceID) => fileIDFromFaceID(faceID)) .filter((fileID) => fileID !== undefined); diff --git a/web/packages/new/photos/services/user-entity.ts b/web/packages/new/photos/services/user-entity.ts index 731a39d565..fab3f731ea 100644 --- a/web/packages/new/photos/services/user-entity.ts +++ b/web/packages/new/photos/services/user-entity.ts @@ -132,14 +132,14 @@ export const pullCGroups = (masterKey: Uint8Array) => { return pullUserEntities("cgroup", masterKey, processBatch); }; +const RemoteFaceCluster = z.object({ + id: z.string(), + faces: z.string().array(), +}); + const RemoteCGroup = z.object({ name: z.string().nullish().transform(nullToUndefined), - assigned: z.array( - z.object({ - id: z.string(), - faces: z.string().array(), - }), - ), + assigned: z.array(RemoteFaceCluster), // The remote cgroup also has a "rejected" property, but that is not // currently used by any of the clients. isHidden: z.boolean(),