feat(server,ml): remove image tagging (#5903)

* remove image tagging

* updated lock

* fixed tests, improved logging

* be nice

* fixed tests
This commit is contained in:
Mert
2023-12-20 20:47:56 -05:00
committed by GitHub
parent 154292242f
commit 092a23fd7f
65 changed files with 988 additions and 2930 deletions

View File

@@ -29,12 +29,6 @@ export class SystemConfigJobDto implements Record<QueueName, JobSettingsDto> {
@Type(() => JobSettingsDto)
[QueueName.VIDEO_CONVERSION]!: JobSettingsDto;
@ApiProperty({ type: JobSettingsDto })
@ValidateNested()
@IsObject()
@Type(() => JobSettingsDto)
[QueueName.OBJECT_TAGGING]!: JobSettingsDto;
@ApiProperty({ type: JobSettingsDto })
@ValidateNested()
@IsObject()

View File

@@ -1,4 +1,4 @@
import { ClassificationConfig, CLIPConfig, RecognitionConfig } from '@app/domain';
import { CLIPConfig, RecognitionConfig } from '@app/domain';
import { Type } from 'class-transformer';
import { IsBoolean, IsObject, IsUrl, ValidateIf, ValidateNested } from 'class-validator';
@@ -10,11 +10,6 @@ export class SystemConfigMachineLearningDto {
@ValidateIf((dto) => dto.enabled)
url!: string;
@Type(() => ClassificationConfig)
@ValidateNested()
@IsObject()
classification!: ClassificationConfig;
@Type(() => CLIPConfig)
@ValidateNested()
@IsObject()

View File

@@ -49,7 +49,6 @@ export const defaults = Object.freeze<SystemConfig>({
[QueueName.BACKGROUND_TASK]: { concurrency: 5 },
[QueueName.SMART_SEARCH]: { concurrency: 2 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 5 },
[QueueName.OBJECT_TAGGING]: { concurrency: 2 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 2 },
[QueueName.SEARCH]: { concurrency: 5 },
[QueueName.SIDECAR]: { concurrency: 5 },
@@ -66,11 +65,6 @@ export const defaults = Object.freeze<SystemConfig>({
machineLearning: {
enabled: process.env.IMMICH_MACHINE_LEARNING_ENABLED !== 'false',
url: process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003',
classification: {
enabled: false,
modelName: 'microsoft/resnet-50',
minScore: 0.9,
},
clip: {
enabled: true,
modelName: 'ViT-B-32__openai',
@@ -137,7 +131,6 @@ export const defaults = Object.freeze<SystemConfig>({
export enum FeatureFlag {
CLIP_ENCODE = 'clipEncode',
FACIAL_RECOGNITION = 'facialRecognition',
TAG_IMAGE = 'tagImage',
MAP = 'map',
REVERSE_GEOCODING = 'reverseGeocoding',
SIDECAR = 'sidecar',
@@ -182,8 +175,6 @@ export class SystemConfigCore {
throw new BadRequestException('Clip encoding is not enabled');
case FeatureFlag.FACIAL_RECOGNITION:
throw new BadRequestException('Facial recognition is not enabled');
case FeatureFlag.TAG_IMAGE:
throw new BadRequestException('Image tagging is not enabled');
case FeatureFlag.SIDECAR:
throw new BadRequestException('Sidecar is not enabled');
case FeatureFlag.SEARCH:
@@ -212,7 +203,6 @@ export class SystemConfigCore {
return {
[FeatureFlag.CLIP_ENCODE]: mlEnabled && config.machineLearning.clip.enabled,
[FeatureFlag.FACIAL_RECOGNITION]: mlEnabled && config.machineLearning.facialRecognition.enabled,
[FeatureFlag.TAG_IMAGE]: mlEnabled && config.machineLearning.classification.enabled,
[FeatureFlag.MAP]: config.map.enabled,
[FeatureFlag.REVERSE_GEOCODING]: config.reverseGeocoding.enabled,
[FeatureFlag.SIDECAR]: true,
@@ -245,10 +235,7 @@ export class SystemConfigCore {
_.set(config, key, value);
}
const errors = await validate(plainToInstance(SystemConfigDto, config), {
forbidNonWhitelisted: true,
forbidUnknownValues: true,
});
const errors = await validate(plainToInstance(SystemConfigDto, config));
if (errors.length > 0) {
this.logger.error('Validation error', errors);
if (configFilePath) {
@@ -334,13 +321,13 @@ export class SystemConfigCore {
}
if (!_.isEmpty(file)) {
throw new Error(`Unknown keys found: ${JSON.stringify(file)}`);
this.logger.warn(`Unknown keys found: ${JSON.stringify(file, null, 2)}`);
}
this.configCache = overrides;
} catch (error: Error | any) {
this.logger.error(`Unable to load configuration file: ${filepath} due to ${error}`, error?.stack);
throw new Error('Invalid configuration file');
this.logger.error(`Unable to load configuration file: ${filepath}`);
throw error;
}
}

View File

@@ -11,6 +11,7 @@ import {
TranscodePolicy,
VideoCodec,
} from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException } from '@nestjs/common';
import { newCommunicationRepositoryMock, newSystemConfigRepositoryMock } from '@test';
import { QueueName } from '../job';
@@ -29,7 +30,6 @@ const updatedConfig = Object.freeze<SystemConfig>({
[QueueName.BACKGROUND_TASK]: { concurrency: 5 },
[QueueName.SMART_SEARCH]: { concurrency: 2 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 5 },
[QueueName.OBJECT_TAGGING]: { concurrency: 2 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 2 },
[QueueName.SEARCH]: { concurrency: 5 },
[QueueName.SIDECAR]: { concurrency: 5 },
@@ -65,11 +65,6 @@ const updatedConfig = Object.freeze<SystemConfig>({
machineLearning: {
enabled: true,
url: 'http://immich-machine-learning:3003',
classification: {
enabled: false,
modelName: 'microsoft/resnet-50',
minScore: 0.9,
},
clip: {
enabled: true,
modelName: 'ViT-B-32__openai',
@@ -169,6 +164,16 @@ describe(SystemConfigService.name, () => {
});
describe('getConfig', () => {
let warnLog: jest.SpyInstance;
beforeEach(() => {
warnLog = jest.spyOn(ImmichLogger.prototype, 'warn');
});
afterEach(() => {
warnLog.mockRestore();
});
it('should return the default config', async () => {
configMock.load.mockResolvedValue([]);
@@ -217,9 +222,9 @@ describe(SystemConfigService.name, () => {
{ should: 'validate numbers', config: { ffmpeg: { crf: 'not-a-number' } } },
{ should: 'validate booleans', config: { oauth: { enabled: 'invalid' } } },
{ should: 'validate enums', config: { ffmpeg: { transcode: 'unknown' } } },
{ should: 'validate top level unknown options', config: { unknownOption: true } },
{ should: 'validate nested unknown options', config: { ffmpeg: { unknownOption: true } } },
{ should: 'validate required oauth fields', config: { oauth: { enabled: true } } },
{ should: 'warn for top level unknown options', warn: true, config: { unknownOption: true } },
{ should: 'warn for nested unknown options', warn: true, config: { ffmpeg: { unknownOption: true } } },
];
for (const test of tests) {
@@ -227,7 +232,12 @@ describe(SystemConfigService.name, () => {
process.env.IMMICH_CONFIG_FILE = 'immich-config.json';
configMock.readFile.mockResolvedValue(JSON.stringify(test.config));
await expect(sut.getConfig()).rejects.toBeInstanceOf(Error);
if (test.warn) {
await sut.getConfig();
expect(warnLog).toHaveBeenCalled();
} else {
await expect(sut.getConfig()).rejects.toBeInstanceOf(Error);
}
});
}
});