diff --git a/web/apps/photos/src/pages/cluster-debug.tsx b/web/apps/photos/src/pages/cluster-debug.tsx index 2795ee5303..127133b323 100644 --- a/web/apps/photos/src/pages/cluster-debug.tsx +++ b/web/apps/photos/src/pages/cluster-debug.tsx @@ -4,10 +4,10 @@ import { faceCrop, wipClusterDebugPageContents, type ClusterDebugPageContents, - type ClusterPreviewFaceWithFile, } from "@/new/photos/services/ml"; import { type ClusteringOpts } from "@/new/photos/services/ml/cluster"; -import { faceDirection } from "@/new/photos/services/ml/face"; +import { faceDirection, type Face } from "@/new/photos/services/ml/face"; +import type { EnteFile } from "@/new/photos/types/file"; import { FlexWrapper, FluidContainer, @@ -90,7 +90,11 @@ interface ClusterListProps { const ClusterList: React.FC = ({ height, width }) => { const { startLoading, finishLoading } = useContext(AppContext); - const [clusteringOpts, setClusteringOpts] = useState(); + const [clusteringOpts, setClusteringOpts] = useState({ + method: "hdbscan", + joinThreshold: 0.7, + batchSize: 2500, + }); const [clusterRes, setClusterRes] = useState< ClusterDebugPageContents | undefined >(); @@ -158,7 +162,7 @@ const ClusterList: React.FC = ({ height, width }) => { > {!Array.isArray(item) ? ( - {`cluster size ${item.toFixed(2)}`} + {item} ) : ( item.map((f, i) => ( @@ -176,24 +180,36 @@ const ClusterList: React.FC = ({ height, width }) => { ); }; -type Item = number | ClusterPreviewFaceWithFile[]; +type Item = string | FaceWithFile[]; const itemsFromClusterRes = ( clusterRes: ClusterDebugPageContents, columns: number, ) => { - const { clusterPreviewsWithFile } = clusterRes; + const { clusterPreviewsWithFile, unclusteredFacesWithFile } = clusterRes; const result: Item[] = []; for (let index = 0; index < clusterPreviewsWithFile.length; index++) { const { clusterSize, faces } = clusterPreviewsWithFile[index]; - result.push(clusterSize); + result.push(`cluster size ${clusterSize.toFixed(2)}`); let lastIndex = 0; while (lastIndex < faces.length) { result.push(faces.slice(lastIndex, lastIndex + columns)); lastIndex += columns; } } + + if (unclusteredFacesWithFile.length) { + result.push(`•• unclustered faces ${unclusteredFacesWithFile.length}`); + let lastIndex = 0; + while (lastIndex < unclusteredFacesWithFile.length) { + result.push( + unclusteredFacesWithFile.slice(lastIndex, lastIndex + columns), + ); + lastIndex += columns; + } + } + return result; }; @@ -334,7 +350,14 @@ const Loader = () => ( ); interface FaceItemProps { - faceWithFile: ClusterPreviewFaceWithFile; + faceWithFile: FaceWithFile; +} + +interface FaceWithFile { + face: Face; + enteFile: EnteFile; + cosineSimilarity?: number; + wasMerged?: boolean; } const FaceItem: React.FC = ({ faceWithFile }) => { @@ -384,9 +407,11 @@ const FaceItem: React.FC = ({ faceWithFile }) => { {`s${face.score.toFixed(1)}`} - - {`c${cosineSimilarity.toFixed(1)}`} - + {cosineSimilarity && ( + + {`c${cosineSimilarity.toFixed(1)}`} + + )} {`d${d}`} diff --git a/web/packages/new/photos/services/ml/cluster.ts b/web/packages/new/photos/services/ml/cluster.ts index f53b8bbf03..e667884cb8 100644 --- a/web/packages/new/photos/services/ml/cluster.ts +++ b/web/packages/new/photos/services/ml/cluster.ts @@ -340,21 +340,25 @@ export const clusterFaces = ( }); } + const clusteredFaceCount = clusterIDForFaceID.size; + const unclusteredFaceCount = faces.length - clusteredFaceCount; + + const unclusteredFaces = faces.filter( + ({ faceID }) => !clusterIDForFaceID.has(faceID), + ); + const timeTakenMs = Date.now() - t; log.info( `Clustered ${faces.length} faces into ${clusters.length} clusters, with ${faces.length - clusterIDForFaceID.size} faces remaining unclustered (${timeTakenMs} ms)`, ); - const clusteredFaceCount = clusterIDForFaceID.size; - const unclusteredFaceCount = faces.length - clusteredFaceCount; - return { clusteredFaceCount, unclusteredFaceCount, clusterPreviews, clusters: sortedClusters, cgroups, - unclusteredFaces: [], + unclusteredFaces: unclusteredFaces, timeTakenMs, }; };