From 94cbbf3c4b5c578e2634f6662c9b2bb7aecd239e Mon Sep 17 00:00:00 2001 From: GenericGuy Date: Mon, 18 Sep 2023 06:05:35 +0200 Subject: [PATCH] feat(web): add setting for minimum face count for face detection (#4128) * feat: add setting for minimum face count for face detection Adds the minimum face count setting to the web interface to circumvent detection of strangers and random background people if desired. * fix: codestyle, remove max for face count --- cli/src/api/open-api/api.ts | 6 ++++++ docs/docs/install/config-file.md | 3 ++- mobile/openapi/doc/RecognitionConfig.md | Bin 569 -> 598 bytes .../openapi/lib/model/recognition_config.dart | Bin 4291 -> 4533 bytes .../openapi/test/recognition_config_test.dart | Bin 982 -> 1080 bytes server/immich-openapi-specs.json | 4 ++++ .../facial-recognition.service.spec.ts | 1 + .../src/domain/person/person.service.spec.ts | 6 +++++- server/src/domain/person/person.service.ts | 10 ++++++++-- .../domain/smart-info/dto/model-config.dto.ts | 6 ++++++ .../system-config/system-config.core.ts | 1 + .../system-config.service.spec.ts | 1 + .../infra/entities/system-config.entity.ts | 2 ++ web/src/api/open-api/api.ts | 6 ++++++ .../machine-learning-settings.svelte | 11 +++++++++++ 15 files changed, 53 insertions(+), 4 deletions(-) diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts index f4c0315426..90e96e3998 100644 --- a/cli/src/api/open-api/api.ts +++ b/cli/src/api/open-api/api.ts @@ -2152,6 +2152,12 @@ export interface RecognitionConfig { * @memberof RecognitionConfig */ 'maxDistance': number; + /** + * + * @type {number} + * @memberof RecognitionConfig + */ + 'minFaces': number; /** * * @type {number} diff --git a/docs/docs/install/config-file.md b/docs/docs/install/config-file.md index a569df4609..195151a545 100644 --- a/docs/docs/install/config-file.md +++ b/docs/docs/install/config-file.md @@ -70,7 +70,8 @@ The default configuration looks like this: "enabled": true, "modelName": "buffalo_l", "minScore": 0.7, - "maxDistance": 0.6 + "maxDistance": 0.6, + "minFaces": 1 } }, "oauth": { diff --git a/mobile/openapi/doc/RecognitionConfig.md b/mobile/openapi/doc/RecognitionConfig.md index f1d4ae261e837a81fcf287f17b24324358704eff..f9a19c1e3d9c7fa39a5c42b7115b8fb2ecdc4c40 100644 GIT binary patch delta 22 dcmdnVa*bt!3?r*sVsdKnWJN}?%~Fi=i~vy#1_b~B delta 12 Tcmcb{vXfB}P`a#N^cC$-5a_Ags;COz}*DU_k|2TZP=rJcxn@mhVudNvyZ|!D6;5 wa9Ins&*ES)^;iX4g_4ZSVm+ALW=ZzrOi-=MIpx`*25!E { enabled: true, maxDistance: 0.6, minScore: 0.7, + minFaces: 1, modelName: 'buffalo_l', }, ); diff --git a/server/src/domain/person/person.service.spec.ts b/server/src/domain/person/person.service.spec.ts index c37abdd6d0..c403932dd8 100644 --- a/server/src/domain/person/person.service.spec.ts +++ b/server/src/domain/person/person.service.spec.ts @@ -6,11 +6,13 @@ import { newJobRepositoryMock, newPersonRepositoryMock, newStorageRepositoryMock, + newSystemConfigRepositoryMock, personStub, } from '@test'; import { BulkIdErrorReason } from '../asset'; import { IJobRepository, JobName } from '../job'; import { IStorageRepository } from '../storage'; +import { ISystemConfigRepository } from '../system-config'; import { PersonResponseDto } from './person.dto'; import { IPersonRepository } from './person.repository'; import { PersonService } from './person.service'; @@ -26,14 +28,16 @@ const responseDto: PersonResponseDto = { describe(PersonService.name, () => { let sut: PersonService; let personMock: jest.Mocked; + let configMock: jest.Mocked; let storageMock: jest.Mocked; let jobMock: jest.Mocked; beforeEach(async () => { personMock = newPersonRepositoryMock(); storageMock = newStorageRepositoryMock(); + configMock = newSystemConfigRepositoryMock(); jobMock = newJobRepositoryMock(); - sut = new PersonService(personMock, storageMock, jobMock); + sut = new PersonService(personMock, configMock, storageMock, jobMock); }); it('should be defined', () => { diff --git a/server/src/domain/person/person.service.ts b/server/src/domain/person/person.service.ts index ac814d85de..252666e22f 100644 --- a/server/src/domain/person/person.service.ts +++ b/server/src/domain/person/person.service.ts @@ -4,6 +4,7 @@ import { AuthUserDto } from '../auth'; import { mimeTypes } from '../domain.constant'; import { IJobRepository, JobName } from '../job'; import { IStorageRepository, ImmichReadStream } from '../storage'; +import { ISystemConfigRepository, SystemConfigCore } from '../system-config'; import { MergePersonDto, PeopleResponseDto, @@ -17,17 +18,22 @@ import { IPersonRepository, UpdateFacesData } from './person.repository'; @Injectable() export class PersonService { + private configCore: SystemConfigCore; readonly logger = new Logger(PersonService.name); constructor( @Inject(IPersonRepository) private repository: IPersonRepository, + @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, - ) {} + ) { + this.configCore = new SystemConfigCore(configRepository); + } async getAll(authUser: AuthUserDto, dto: PersonSearchDto): Promise { + const { machineLearning } = await this.configCore.getConfig(); const people = await this.repository.getAllForUser(authUser.id, { - minimumFaceCount: 1, + minimumFaceCount: machineLearning.facialRecognition.minFaces, withHidden: dto.withHidden || false, }); const persons: PersonResponseDto[] = people diff --git a/server/src/domain/smart-info/dto/model-config.dto.ts b/server/src/domain/smart-info/dto/model-config.dto.ts index 1fc2ef5d8f..3309ddfd93 100644 --- a/server/src/domain/smart-info/dto/model-config.dto.ts +++ b/server/src/domain/smart-info/dto/model-config.dto.ts @@ -48,4 +48,10 @@ export class RecognitionConfig extends ModelConfig { @Type(() => Number) @ApiProperty({ type: 'integer' }) maxDistance!: number; + + @IsNumber() + @Min(1) + @Type(() => Number) + @ApiProperty({ type: 'integer' }) + minFaces!: number; } diff --git a/server/src/domain/system-config/system-config.core.ts b/server/src/domain/system-config/system-config.core.ts index e33a168e8d..feefae0dda 100644 --- a/server/src/domain/system-config/system-config.core.ts +++ b/server/src/domain/system-config/system-config.core.ts @@ -72,6 +72,7 @@ export const defaults = Object.freeze({ modelName: 'buffalo_l', minScore: 0.7, maxDistance: 0.6, + minFaces: 1, }, }, map: { diff --git a/server/src/domain/system-config/system-config.service.spec.ts b/server/src/domain/system-config/system-config.service.spec.ts index 24d5914b03..6718c53f59 100644 --- a/server/src/domain/system-config/system-config.service.spec.ts +++ b/server/src/domain/system-config/system-config.service.spec.ts @@ -71,6 +71,7 @@ const updatedConfig = Object.freeze({ modelName: 'buffalo_l', minScore: 0.7, maxDistance: 0.6, + minFaces: 1, }, }, map: { diff --git a/server/src/infra/entities/system-config.entity.ts b/server/src/infra/entities/system-config.entity.ts index bd94e4d0c6..dac332564c 100644 --- a/server/src/infra/entities/system-config.entity.ts +++ b/server/src/infra/entities/system-config.entity.ts @@ -57,6 +57,7 @@ export enum SystemConfigKey { MACHINE_LEARNING_FACIAL_RECOGNITION_MODEL_NAME = 'machineLearning.facialRecognition.modelName', MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_SCORE = 'machineLearning.facialRecognition.minScore', MACHINE_LEARNING_FACIAL_RECOGNITION_MAX_DISTANCE = 'machineLearning.facialRecognition.maxDistance', + MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES = 'machineLearning.facialRecognition.minFaces', MAP_ENABLED = 'map.enabled', MAP_TILE_URL = 'map.tileUrl', @@ -164,6 +165,7 @@ export interface SystemConfig { enabled: boolean; modelName: string; minScore: number; + minFaces: number; maxDistance: number; }; }; diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index f4c0315426..90e96e3998 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -2152,6 +2152,12 @@ export interface RecognitionConfig { * @memberof RecognitionConfig */ 'maxDistance': number; + /** + * + * @type {number} + * @memberof RecognitionConfig + */ + 'minFaces': number; /** * * @type {number} diff --git a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte index af30634d25..bba0233d40 100644 --- a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte +++ b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte @@ -196,6 +196,17 @@ isEdited={machineLearningConfig.facialRecognition.maxDistance !== savedConfig.facialRecognition.maxDistance} /> + +