Inline and move
This commit is contained in:
parent
2a35b0ec9c
commit
c48042546e
2 changed files with 2 additions and 115 deletions
|
@ -38,9 +38,9 @@ import arcfaceCropService from "./arcfaceCropService";
|
|||
import FaceService from "./faceService";
|
||||
import laplacianBlurDetectionService from "./laplacianBlurDetectionService";
|
||||
import mobileFaceNetEmbeddingService from "./mobileFaceNetEmbeddingService";
|
||||
import PeopleService from "./peopleService";
|
||||
|
||||
import { fetchImageBitmapForContext } from "../face/image";
|
||||
import { syncPeopleIndex } from "../face/people";
|
||||
import yoloFaceDetectionService from "./yoloFaceDetectionService";
|
||||
|
||||
/**
|
||||
|
@ -628,7 +628,7 @@ class MachineLearningService {
|
|||
public async syncIndex(syncContext: MLSyncContext) {
|
||||
await this.getMLLibraryData(syncContext);
|
||||
|
||||
await PeopleService.syncPeopleIndex(syncContext);
|
||||
await syncPeopleIndex(syncContext);
|
||||
|
||||
await this.persistMLLibraryData(syncContext);
|
||||
}
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
import log from "@/next/log";
|
||||
import mlIDbStorage from "services/face/db";
|
||||
import { Face, MLSyncContext, Person } from "services/face/types";
|
||||
import { fetchImageBitmap, getLocalFile } from "../face/image";
|
||||
import FaceService, { isDifferentOrOld } from "./faceService";
|
||||
|
||||
class PeopleService {
|
||||
async syncPeopleIndex(syncContext: MLSyncContext) {
|
||||
const filesVersion = await mlIDbStorage.getIndexVersion("files");
|
||||
if (
|
||||
filesVersion <= (await mlIDbStorage.getIndexVersion("people")) &&
|
||||
!isDifferentOrOld(syncContext.mlLibraryData?.faceClusteringMethod, {
|
||||
value: "Hdbscan",
|
||||
version: 1,
|
||||
})
|
||||
) {
|
||||
log.info(
|
||||
"[MLService] Skipping people index as already synced to latest version",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: have faces addresable through fileId + faceId
|
||||
// to avoid index based addressing, which is prone to wrong results
|
||||
// one way could be to match nearest face within threshold in the file
|
||||
const allFacesMap = await FaceService.getAllSyncedFacesMap(syncContext);
|
||||
const allFaces = getAllFacesFromMap(allFacesMap);
|
||||
|
||||
await FaceService.runFaceClustering(syncContext, allFaces);
|
||||
await this.syncPeopleFromClusters(syncContext, allFacesMap, allFaces);
|
||||
|
||||
await mlIDbStorage.setIndexVersion("people", filesVersion);
|
||||
}
|
||||
|
||||
private async syncPeopleFromClusters(
|
||||
syncContext: MLSyncContext,
|
||||
allFacesMap: Map<number, Array<Face>>,
|
||||
allFaces: Array<Face>,
|
||||
) {
|
||||
const clusters =
|
||||
syncContext.mlLibraryData.faceClusteringResults?.clusters;
|
||||
if (!clusters || clusters.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const face of allFaces) {
|
||||
face.personId = undefined;
|
||||
}
|
||||
await mlIDbStorage.clearAllPeople();
|
||||
for (const [index, cluster] of clusters.entries()) {
|
||||
const faces = cluster.map((f) => allFaces[f]).filter((f) => f);
|
||||
|
||||
// TODO: take default display face from last leaves of hdbscan clusters
|
||||
const personFace = findFirstIfSorted(
|
||||
faces,
|
||||
(a, b) => b.detection.probability - a.detection.probability,
|
||||
);
|
||||
|
||||
if (personFace && !personFace.crop?.cacheKey) {
|
||||
const file = await getLocalFile(personFace.fileId);
|
||||
const imageBitmap = await fetchImageBitmap(file);
|
||||
await FaceService.saveFaceCrop(
|
||||
imageBitmap,
|
||||
personFace,
|
||||
syncContext,
|
||||
);
|
||||
}
|
||||
|
||||
const person: Person = {
|
||||
id: index,
|
||||
files: faces.map((f) => f.fileId),
|
||||
displayFaceId: personFace?.id,
|
||||
faceCropCacheKey: personFace?.crop?.cacheKey,
|
||||
};
|
||||
|
||||
await mlIDbStorage.putPerson(person);
|
||||
|
||||
faces.forEach((face) => {
|
||||
face.personId = person.id;
|
||||
});
|
||||
// log.info("Creating person: ", person, faces);
|
||||
}
|
||||
|
||||
await mlIDbStorage.updateFaces(allFacesMap);
|
||||
}
|
||||
}
|
||||
|
||||
export default new PeopleService();
|
||||
|
||||
function findFirstIfSorted<T>(
|
||||
elements: Array<T>,
|
||||
comparator: (a: T, b: T) => number,
|
||||
) {
|
||||
if (!elements || elements.length < 1) {
|
||||
return;
|
||||
}
|
||||
let first = elements[0];
|
||||
|
||||
for (let i = 1; i < elements.length; i++) {
|
||||
const comp = comparator(elements[i], first);
|
||||
if (comp < 0) {
|
||||
first = elements[i];
|
||||
}
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
function getAllFacesFromMap(allFacesMap: Map<number, Array<Face>>) {
|
||||
const allFaces = [...allFacesMap.values()].flat();
|
||||
|
||||
return allFaces;
|
||||
}
|
Loading…
Add table
Reference in a new issue