feat(server): optimize partial facial recognition (#6634)

* optimize partial facial recognition

* add tests

* use map

* bulk insert faces
This commit is contained in:
Mert
2024-01-25 01:27:39 -05:00
committed by GitHub
parent 852effa998
commit bd87eb309c
9 changed files with 77 additions and 46 deletions
@@ -607,14 +607,23 @@ describe(PersonService.name, () => {
describe('handleQueueRecognizeFaces', () => {
it('should return if machine learning is disabled', async () => {
jobMock.getJobCounts.mockResolvedValue({ active: 1, waiting: 0, paused: 0, completed: 0, failed: 0, delayed: 0 });
configMock.load.mockResolvedValue([{ key: SystemConfigKey.MACHINE_LEARNING_ENABLED, value: false }]);
await expect(sut.handleQueueRecognizeFaces({})).resolves.toBe(true);
expect(jobMock.queue).not.toHaveBeenCalled();
expect(jobMock.queueAll).not.toHaveBeenCalled();
expect(configMock.load).toHaveBeenCalled();
});
it('should return if recognition jobs are already queued', async () => {
jobMock.getJobCounts.mockResolvedValue({ active: 1, waiting: 1, paused: 0, completed: 0, failed: 0, delayed: 0 });
await expect(sut.handleQueueRecognizeFaces({})).resolves.toBe(true);
expect(jobMock.queueAll).not.toHaveBeenCalled();
});
it('should queue missing assets', async () => {
jobMock.getJobCounts.mockResolvedValue({ active: 1, waiting: 0, paused: 0, completed: 0, failed: 0, delayed: 0 });
personMock.getAllFaces.mockResolvedValue({
items: [faceStub.face1],
hasNextPage: false,
@@ -632,6 +641,7 @@ describe(PersonService.name, () => {
});
it('should queue all assets', async () => {
jobMock.getJobCounts.mockResolvedValue({ active: 1, waiting: 0, paused: 0, completed: 0, failed: 0, delayed: 0 });
personMock.getAll.mockResolvedValue({
items: [],
hasNextPage: false,
@@ -653,6 +663,7 @@ describe(PersonService.name, () => {
});
it('should delete existing people and faces if forced', async () => {
jobMock.getJobCounts.mockResolvedValue({ active: 1, waiting: 0, paused: 0, completed: 0, failed: 0, delayed: 0 });
personMock.getAll.mockResolvedValue({
items: [faceStub.face1.person],
hasNextPage: false,
@@ -727,7 +738,7 @@ describe(PersonService.name, () => {
modelName: 'buffalo_l',
},
);
expect(personMock.createFace).not.toHaveBeenCalled();
expect(personMock.createFaces).not.toHaveBeenCalled();
expect(jobMock.queue).not.toHaveBeenCalled();
expect(jobMock.queueAll).not.toHaveBeenCalled();
@@ -738,13 +749,12 @@ describe(PersonService.name, () => {
expect(assetMock.upsertJobStatus.mock.calls[0][0].facesRecognizedAt?.getTime()).toBeGreaterThan(start);
});
it('should create a face with no person', async () => {
it('should create a face with no person and queue recognition job', async () => {
personMock.createFaces.mockResolvedValue([faceStub.face1.id]);
machineLearningMock.detectFaces.mockResolvedValue([detectFaceMock]);
smartInfoMock.searchFaces.mockResolvedValue([{ face: faceStub.face1, distance: 0.7 }]);
assetMock.getByIds.mockResolvedValue([assetStub.image]);
await sut.handleDetectFaces({ id: assetStub.image.id });
expect(personMock.createFace).toHaveBeenCalledWith({
const face = {
assetId: 'asset-id',
embedding: [1, 2, 3, 4],
boundingBoxX1: 100,
@@ -753,7 +763,14 @@ describe(PersonService.name, () => {
boundingBoxY2: 200,
imageHeight: 500,
imageWidth: 400,
});
};
await sut.handleDetectFaces({ id: assetStub.image.id });
expect(personMock.createFaces).toHaveBeenCalledWith([face]);
expect(jobMock.queueAll).toHaveBeenCalledWith([
{ name: JobName.FACIAL_RECOGNITION, data: { id: faceStub.face1.id } },
]);
expect(personMock.reassignFace).not.toHaveBeenCalled();
expect(personMock.reassignFaces).not.toHaveBeenCalled();
});
@@ -767,7 +784,7 @@ describe(PersonService.name, () => {
expect(personMock.reassignFaces).not.toHaveBeenCalled();
expect(personMock.create).not.toHaveBeenCalled();
expect(personMock.createFace).not.toHaveBeenCalled();
expect(personMock.createFaces).not.toHaveBeenCalled();
});
it('should return true if face already has an assigned person', async () => {
@@ -777,7 +794,7 @@ describe(PersonService.name, () => {
expect(personMock.reassignFaces).not.toHaveBeenCalled();
expect(personMock.create).not.toHaveBeenCalled();
expect(personMock.createFace).not.toHaveBeenCalled();
expect(personMock.createFaces).not.toHaveBeenCalled();
});
it('should match existing person', async () => {