|
|
|
|
@ -1,5 +1,4 @@
|
|
|
|
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
|
|
|
|
import { AssetFace } from 'src/database';
|
|
|
|
|
import { BulkIdErrorReason } from 'src/dtos/asset-ids.response.dto';
|
|
|
|
|
import { mapFaces, mapPerson, PersonResponseDto } from 'src/dtos/person.dto';
|
|
|
|
|
import { CacheControl, Colorspace, ImageFormat, JobName, JobStatus, SourceType, SystemMetadataKey } from 'src/enum';
|
|
|
|
|
@ -719,24 +718,7 @@ describe(PersonService.name, () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should skip when no resize path', async () => {
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([assetStub.noResizePath]);
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.noResizePath.id });
|
|
|
|
|
expect(mocks.machineLearning.detectFaces).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should skip it the asset has already been processed', async () => {
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([
|
|
|
|
|
{
|
|
|
|
|
...assetStub.noResizePath,
|
|
|
|
|
faces: [
|
|
|
|
|
{
|
|
|
|
|
id: 'asset-face-1',
|
|
|
|
|
assetId: assetStub.noResizePath.id,
|
|
|
|
|
personId: faceStub.face1.personId,
|
|
|
|
|
} as AssetFace,
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
]);
|
|
|
|
|
mocks.assetJob.getForDetectFacesJob.mockResolvedValue({ ...assetStub.noResizePath, files: [] });
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.noResizePath.id });
|
|
|
|
|
expect(mocks.machineLearning.detectFaces).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
@ -745,7 +727,7 @@ describe(PersonService.name, () => {
|
|
|
|
|
const start = Date.now();
|
|
|
|
|
|
|
|
|
|
mocks.machineLearning.detectFaces.mockResolvedValue({ imageHeight: 500, imageWidth: 400, faces: [] });
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([assetStub.image]);
|
|
|
|
|
mocks.assetJob.getForDetectFacesJob.mockResolvedValue({ ...assetStub.image, files: [assetStub.image.files[1]] });
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.image.id });
|
|
|
|
|
expect(mocks.machineLearning.detectFaces).toHaveBeenCalledWith(
|
|
|
|
|
['http://immich-machine-learning:3003'],
|
|
|
|
|
@ -766,7 +748,7 @@ describe(PersonService.name, () => {
|
|
|
|
|
it('should create a face with no person and queue recognition job', async () => {
|
|
|
|
|
mocks.machineLearning.detectFaces.mockResolvedValue(detectFaceMock);
|
|
|
|
|
mocks.search.searchFaces.mockResolvedValue([{ ...faceStub.face1, distance: 0.7 }]);
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([assetStub.image]);
|
|
|
|
|
mocks.assetJob.getForDetectFacesJob.mockResolvedValue({ ...assetStub.image, files: [assetStub.image.files[1]] });
|
|
|
|
|
mocks.person.refreshFaces.mockResolvedValue();
|
|
|
|
|
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.image.id });
|
|
|
|
|
@ -782,7 +764,11 @@ describe(PersonService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should delete an existing face not among the new detected faces', async () => {
|
|
|
|
|
mocks.machineLearning.detectFaces.mockResolvedValue({ faces: [], imageHeight: 500, imageWidth: 400 });
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([{ ...assetStub.image, faces: [faceStub.primaryFace1] }]);
|
|
|
|
|
mocks.assetJob.getForDetectFacesJob.mockResolvedValue({
|
|
|
|
|
...assetStub.image,
|
|
|
|
|
faces: [faceStub.primaryFace1],
|
|
|
|
|
files: [assetStub.image.files[1]],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.image.id });
|
|
|
|
|
|
|
|
|
|
@ -794,7 +780,11 @@ describe(PersonService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should add new face and delete an existing face not among the new detected faces', async () => {
|
|
|
|
|
mocks.machineLearning.detectFaces.mockResolvedValue(detectFaceMock);
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([{ ...assetStub.image, faces: [faceStub.primaryFace1] }]);
|
|
|
|
|
mocks.assetJob.getForDetectFacesJob.mockResolvedValue({
|
|
|
|
|
...assetStub.image,
|
|
|
|
|
faces: [faceStub.primaryFace1],
|
|
|
|
|
files: [assetStub.image.files[1]],
|
|
|
|
|
});
|
|
|
|
|
mocks.person.refreshFaces.mockResolvedValue();
|
|
|
|
|
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.image.id });
|
|
|
|
|
@ -810,7 +800,11 @@ describe(PersonService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should add embedding to matching metadata face', async () => {
|
|
|
|
|
mocks.machineLearning.detectFaces.mockResolvedValue(detectFaceMock);
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([{ ...assetStub.image, faces: [faceStub.fromExif1] }]);
|
|
|
|
|
mocks.assetJob.getForDetectFacesJob.mockResolvedValue({
|
|
|
|
|
...assetStub.image,
|
|
|
|
|
faces: [faceStub.fromExif1],
|
|
|
|
|
files: [assetStub.image.files[1]],
|
|
|
|
|
});
|
|
|
|
|
mocks.person.refreshFaces.mockResolvedValue();
|
|
|
|
|
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.image.id });
|
|
|
|
|
@ -827,7 +821,11 @@ describe(PersonService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should not add embedding to non-matching metadata face', async () => {
|
|
|
|
|
mocks.machineLearning.detectFaces.mockResolvedValue(detectFaceMock);
|
|
|
|
|
mocks.asset.getByIds.mockResolvedValue([{ ...assetStub.image, faces: [faceStub.fromExif2] }]);
|
|
|
|
|
mocks.assetJob.getForDetectFacesJob.mockResolvedValue({
|
|
|
|
|
...assetStub.image,
|
|
|
|
|
faces: [faceStub.fromExif2],
|
|
|
|
|
files: [assetStub.image.files[1]],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await sut.handleDetectFaces({ id: assetStub.image.id });
|
|
|
|
|
|
|
|
|
|
|