From 890ea6c8d16f683140685b1c6300710147b7be32 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Fri, 9 Aug 2024 12:22:55 +0530 Subject: [PATCH] Closer --- web/apps/photos/src/services/searchService.ts | 4 ++- .../new/photos/services/ml/cluster-new.ts | 32 +++++++++++-------- web/packages/new/photos/services/ml/index.ts | 4 +-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/web/apps/photos/src/services/searchService.ts b/web/apps/photos/src/services/searchService.ts index 8488462aba..c697c34575 100644 --- a/web/apps/photos/src/services/searchService.ts +++ b/web/apps/photos/src/services/searchService.ts @@ -421,7 +421,9 @@ async function getAllPeople(limit: number = undefined) { // people.push(person); // }); people = people ?? []; - return people + const result = people .sort((p1, p2) => p2.files.length - p1.files.length) .slice(0, limit); + // log.debug(() => ["getAllPeople", result]); + return result; } diff --git a/web/packages/new/photos/services/ml/cluster-new.ts b/web/packages/new/photos/services/ml/cluster-new.ts index bee7c2fee8..3a615471d4 100644 --- a/web/packages/new/photos/services/ml/cluster-new.ts +++ b/web/packages/new/photos/services/ml/cluster-new.ts @@ -81,34 +81,40 @@ export const clusterFaces = (faceIndexes: FaceIndex[]) => { const clusters: FaceCluster[] = []; const clusterIndexByFaceID = new Map(); for (const [i, { faceID, embedding }] of faces.entries()) { - let j = 0; - for (; j < i; j++) { - // Can't find a better way for avoiding the null assertion. + // Find the nearest neighbour from among the faces we have already seen. + let nnIndex: number | undefined; + let nnCosineSimilarity = 0; + for (let j = 0; j < i; j++) { + // Can't find a way of avoiding the null assertion. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const n = faces[j]!; - // TODO-ML: The distance metric and the thresholds are placeholders. - // The vectors are already normalized, so we can directly use their // dot product as their cosine similarity. const csim = dotProduct(embedding, n.embedding); - if (csim > 0.5) { - // Found a neighbour near enough. Add this face to the - // neighbour's cluster and call it a day. - const ci = ensure(clusterIndexByFaceID.get(n.faceID)); - clusters[ci]?.faceIDs.push(faceID); - clusterIndexByFaceID.set(faceID, ci); - break; + if (csim > 0.76 && csim > nnCosineSimilarity) { + nnIndex = j; + nnCosineSimilarity = csim; } } - if (j == i) { + if (nnIndex === undefined) { // We didn't find a neighbour. Create a new cluster with this face. + const cluster = { id: newNonSecureID("cluster_"), faceIDs: [faceID], }; clusters.push(cluster); clusterIndexByFaceID.set(faceID, clusters.length); + } else { + // Found a neighbour near enough. Add this face to the neighbour's + // cluster. + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const nn = faces[nnIndex]!; + const nnClusterIndex = ensure(clusterIndexByFaceID.get(nn.faceID)); + clusters[nnClusterIndex]?.faceIDs.push(faceID); + clusterIndexByFaceID.set(faceID, nnClusterIndex); } } diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index 434568e22f..bee9291563 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -309,7 +309,7 @@ export const indexNewUpload = (enteFile: EnteFile, uploadItem: UploadItem) => { void worker().then((w) => w.onUpload(enteFile, uploadItem)); }; -let last: Person[] = []; +let last: Person[] | undefined; /** * WIP! Don't enable, dragon eggs are hatching here. @@ -318,7 +318,7 @@ export const wipCluster = async () => { if (!isDevBuild || !(await isInternalUser())) return; if (!process.env.NEXT_PUBLIC_ENTE_WIP_CL) return; - if (last.length) return last; + if (last) return last; const clusters = clusterFaces(await faceIndexes());