mirror of
https://github.com/immich-app/immich.git
synced 2025-01-07 00:50:23 -05:00
feat(server): optimize face re-queueing (#6961)
* do not defer faces with no matches * move comment
This commit is contained in:
parent
479fca8f02
commit
b31c7681ae
2 changed files with 34 additions and 7 deletions
|
@ -866,11 +866,29 @@ describe(PersonService.name, () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should defer non-core faces to end of queue', async () => {
|
it('should not queue face with no matches', async () => {
|
||||||
const faces = [{ face: faceStub.noPerson1, distance: 0 }] as FaceSearchResult[];
|
const faces = [{ face: faceStub.noPerson1, distance: 0 }] as FaceSearchResult[];
|
||||||
|
|
||||||
|
smartInfoMock.searchFaces.mockResolvedValue(faces);
|
||||||
|
personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1);
|
||||||
|
personMock.create.mockResolvedValue(personStub.withName);
|
||||||
|
|
||||||
|
await sut.handleRecognizeFaces({ id: faceStub.noPerson1.id });
|
||||||
|
|
||||||
|
expect(jobMock.queue).not.toHaveBeenCalled();
|
||||||
|
expect(smartInfoMock.searchFaces).toHaveBeenCalledTimes(1);
|
||||||
|
expect(personMock.create).not.toHaveBeenCalled();
|
||||||
|
expect(personMock.reassignFaces).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should defer non-core faces to end of queue', async () => {
|
||||||
|
const faces = [
|
||||||
|
{ face: faceStub.noPerson1, distance: 0 },
|
||||||
|
{ face: faceStub.noPerson2, distance: 0.4 },
|
||||||
|
] as FaceSearchResult[];
|
||||||
|
|
||||||
configMock.load.mockResolvedValue([
|
configMock.load.mockResolvedValue([
|
||||||
{ key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 2 },
|
{ key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 3 },
|
||||||
]);
|
]);
|
||||||
smartInfoMock.searchFaces.mockResolvedValue(faces);
|
smartInfoMock.searchFaces.mockResolvedValue(faces);
|
||||||
personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1);
|
personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1);
|
||||||
|
@ -887,11 +905,14 @@ describe(PersonService.name, () => {
|
||||||
expect(personMock.reassignFaces).not.toHaveBeenCalled();
|
expect(personMock.reassignFaces).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not assign person to non-core face with no matching person', async () => {
|
it('should not assign person to deferred non-core face with no matching person', async () => {
|
||||||
const faces = [{ face: faceStub.noPerson1, distance: 0 }] as FaceSearchResult[];
|
const faces = [
|
||||||
|
{ face: faceStub.noPerson1, distance: 0 },
|
||||||
|
{ face: faceStub.noPerson2, distance: 0.4 },
|
||||||
|
] as FaceSearchResult[];
|
||||||
|
|
||||||
configMock.load.mockResolvedValue([
|
configMock.load.mockResolvedValue([
|
||||||
{ key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 2 },
|
{ key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 3 },
|
||||||
]);
|
]);
|
||||||
smartInfoMock.searchFaces.mockResolvedValueOnce(faces).mockResolvedValueOnce([]);
|
smartInfoMock.searchFaces.mockResolvedValueOnce(faces).mockResolvedValueOnce([]);
|
||||||
personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1);
|
personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1);
|
||||||
|
|
|
@ -417,7 +417,13 @@ export class PersonService {
|
||||||
numResults: machineLearning.facialRecognition.minFaces,
|
numResults: machineLearning.facialRecognition.minFaces,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.debug(`Face ${id} has ${matches.length} match${matches.length == 1 ? '' : 'es'}`);
|
// `matches` also includes the face itself
|
||||||
|
if (matches.length <= 1) {
|
||||||
|
this.logger.debug(`Face ${id} has no matches`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.debug(`Face ${id} has ${matches.length} matches`);
|
||||||
|
|
||||||
const isCore = matches.length >= machineLearning.facialRecognition.minFaces;
|
const isCore = matches.length >= machineLearning.facialRecognition.minFaces;
|
||||||
if (!isCore && !deferred) {
|
if (!isCore && !deferred) {
|
||||||
|
@ -426,7 +432,7 @@ export class PersonService {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let personId = matches.find((match) => match.face.personId)?.face.personId; // `matches` also includes the face itself
|
let personId = matches.find((match) => match.face.personId)?.face.personId;
|
||||||
if (!personId) {
|
if (!personId) {
|
||||||
const matchWithPerson = await this.smartInfoRepository.searchFaces({
|
const matchWithPerson = await this.smartInfoRepository.searchFaces({
|
||||||
userIds: [face.asset.ownerId],
|
userIds: [face.asset.ownerId],
|
||||||
|
|
Loading…
Reference in a new issue