Reconcile 1
This commit is contained in:
@@ -3,7 +3,7 @@ import log from "@/base/log";
|
||||
import { ensure } from "@/utils/ensure";
|
||||
import { wait } from "@/utils/promise";
|
||||
import type { EnteFile } from "../../types/file";
|
||||
import { savedCGroups } from "../user-entity";
|
||||
import { savedCGroupUserEntities, type CGroupUserEntity } from "../user-entity";
|
||||
import { savedFaceClusters } from "./db";
|
||||
import {
|
||||
faceDirection,
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
type FaceIndex,
|
||||
} from "./face";
|
||||
import { dotProduct } from "./math";
|
||||
import type { CGroup } from "./people";
|
||||
|
||||
/**
|
||||
* A face cluster is an set of faces, and a nanoid to uniquely identify it.
|
||||
@@ -111,12 +112,16 @@ export const clusterFaces = async (
|
||||
let clusters: FaceCluster[] = [];
|
||||
|
||||
// Get the locally available remote cluster groups.
|
||||
const cgroups = await savedCGroups();
|
||||
// Sort them so that the latest ones are first.
|
||||
const sortedCGroups = cgroups.sort((a, b) => b.updatedAt - a.updatedAt);
|
||||
const cgroupUserEntities = await savedCGroupUserEntities();
|
||||
// Sort them so that the latest ones are first. This is not expected to be
|
||||
// needed, it is just a safety check in case a client puts a face into two
|
||||
// clusters, in which case we want to use the more recent cgroup.
|
||||
const sortedCGroupUserEntities = cgroupUserEntities.sort(
|
||||
(a, b) => b.updatedAt - a.updatedAt,
|
||||
);
|
||||
// Extract the remote clusters.
|
||||
clusters = clusters.concat(
|
||||
sortedCGroups.map((cg) => cg.data.assigned).flat(),
|
||||
sortedCGroupUserEntities.map((cg) => cg.data.assigned).flat(),
|
||||
);
|
||||
|
||||
// Add on the clusters we have available locally.
|
||||
@@ -189,19 +194,59 @@ export const clusterFaces = async (
|
||||
`Generated ${sortedClusters.length} clusters from ${faces.length} faces (${clusteredFaceCount} clustered ${faces.length - clusteredFaceCount} unclustered) (${timeTakenMs} ms)`,
|
||||
);
|
||||
|
||||
// // TODO-Cluster
|
||||
// // This isn't really part of the clustering, but help the main thread out by
|
||||
// // pre-computing temporary in-memory people, one per cluster.
|
||||
// Clustering is complete at this point. Now we want to
|
||||
// 1. Update remote cgroups that have changed.
|
||||
// 1. Update our local state.
|
||||
|
||||
// Index clusters by their ID for fast lookup.
|
||||
const clusterByID = new Map(clusters.map((c) => [c.id, c]));
|
||||
|
||||
// Map from clusters to their (remote) cgroup.
|
||||
const clusterIDToCGroupID = new Map<string, string>();
|
||||
for (const cgroup of cgroupUserEntities) {
|
||||
for (const cluster of cgroup.data.assigned)
|
||||
clusterIDToCGroupID.set(cluster.id, cgroup.id);
|
||||
}
|
||||
|
||||
// Find the cgroups that have changed since we started.
|
||||
const changedCGroupUserEntities: CGroupUserEntity[] = [];
|
||||
for (const cgroupEntity of cgroupUserEntities) {
|
||||
for (const oldCluster of cgroupEntity.data.assigned) {
|
||||
// The clustering algorithm does not remove any existing faces, it
|
||||
// can only add new ones to the cluster. So we can use the count as
|
||||
// an indication if something changed.
|
||||
if (
|
||||
oldCluster.faces.length !=
|
||||
ensure(clusterByID.get(oldCluster.id)).faces.length
|
||||
) {
|
||||
changedCGroupUserEntities.push({
|
||||
...cgroupEntity,
|
||||
data: {
|
||||
...cgroupEntity.data,
|
||||
assigned: cgroupEntity.data.assigned.map(({ id }) =>
|
||||
ensure(clusterByID.get(id)),
|
||||
),
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Should PUT remote clusters", changedCGroupUserEntities);
|
||||
|
||||
// Find clusters that are not part of a remote cgroup.
|
||||
const localClusters = clusters.filter(
|
||||
({ id }) => !clusterIDToCGroupID.has(id),
|
||||
);
|
||||
|
||||
console.log("Should save local clusters", localClusters);
|
||||
|
||||
// // For fast reverse lookup - map from face ids to the face.
|
||||
// const faceForFaceID = new Map(faces.map((f) => [f.faceID, f]));
|
||||
|
||||
// const people = toPeople(sortedClusters, localFileByID, faceForFaceID);
|
||||
|
||||
// // reconcileClusters
|
||||
// // Save local
|
||||
// // updated map -> remote - Put
|
||||
|
||||
return { clusters: sortedClusters, people: [] };
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { masterKeyFromSession } from "@/base/session-store";
|
||||
import { ensure } from "@/utils/ensure";
|
||||
import { wipClusterEnable } from ".";
|
||||
import type { EnteFile } from "../../types/file";
|
||||
import { getLocalFiles } from "../files";
|
||||
import { pullUserEntities, savedCGroups } from "../user-entity";
|
||||
import { pullUserEntities, savedCGroupUserEntities } from "../user-entity";
|
||||
import type { FaceCluster } from "./cluster";
|
||||
import { getFaceIndexes } from "./db";
|
||||
import { fileIDFromFaceID, type Face } from "./face";
|
||||
import { ensure } from "@/utils/ensure";
|
||||
|
||||
/**
|
||||
* A cgroup ("cluster group") is a group of clusters (possibly containing just a
|
||||
@@ -181,7 +181,7 @@ export const namedPeopleFromCGroups = async (): Promise<NamedPerson[]> => {
|
||||
}
|
||||
|
||||
// Convert cgroups to people.
|
||||
const cgroups = await savedCGroups();
|
||||
const cgroups = await savedCGroupUserEntities();
|
||||
return cgroups
|
||||
.map(({ id, data: cgroup }) => {
|
||||
// Hidden cgroups are clusters specifically marked so as to not be shown
|
||||
@@ -236,7 +236,6 @@ export const namedPeopleFromCGroups = async (): Promise<NamedPerson[]> => {
|
||||
.sort((a, b) => b.fileIDs.length - a.fileIDs.length);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Construct a {@link Person} object for each cluster.
|
||||
*/
|
||||
|
||||
@@ -94,7 +94,7 @@ export type CGroupUserEntity = Omit<LocalUserEntity, "data"> & {
|
||||
/**
|
||||
* Return the list of locally available cgroup user entities.
|
||||
*/
|
||||
export const savedCGroups = (): Promise<CGroupUserEntity[]> =>
|
||||
export const savedCGroupUserEntities = (): Promise<CGroupUserEntity[]> =>
|
||||
savedEntities("cgroup").then((es) =>
|
||||
es.map((e) => ({ ...e, data: RemoteCGroup.parse(e.data) })),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user