diff --git a/mobile/openapi/doc/AllJobStatusResponseDto.md b/mobile/openapi/doc/AllJobStatusResponseDto.md index a904aac12..587fa0b8a 100644 --- a/mobile/openapi/doc/AllJobStatusResponseDto.md +++ b/mobile/openapi/doc/AllJobStatusResponseDto.md @@ -9,6 +9,7 @@ import 'package:openapi/api.dart'; Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **backgroundTask** | [**JobStatusDto**](JobStatusDto.md) | | +**duplicateDetection** | [**JobStatusDto**](JobStatusDto.md) | | **faceDetection** | [**JobStatusDto**](JobStatusDto.md) | | **facialRecognition** | [**JobStatusDto**](JobStatusDto.md) | | **library_** | [**JobStatusDto**](JobStatusDto.md) | | diff --git a/mobile/openapi/doc/CLIPConfig.md b/mobile/openapi/doc/CLIPConfig.md index 13c2d56ae..f013daef3 100644 --- a/mobile/openapi/doc/CLIPConfig.md +++ b/mobile/openapi/doc/CLIPConfig.md @@ -8,6 +8,7 @@ import 'package:openapi/api.dart'; ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**duplicateThreshold** | **double** | | **enabled** | **bool** | | **mode** | [**CLIPMode**](CLIPMode.md) | | [optional] **modelName** | **String** | | diff --git a/mobile/openapi/doc/SystemConfigJobDto.md b/mobile/openapi/doc/SystemConfigJobDto.md index cb989e7d8..f1d53a7bf 100644 --- a/mobile/openapi/doc/SystemConfigJobDto.md +++ b/mobile/openapi/doc/SystemConfigJobDto.md @@ -9,6 +9,7 @@ import 'package:openapi/api.dart'; Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **backgroundTask** | [**JobSettingsDto**](JobSettingsDto.md) | | +**duplicateDetection** | [**JobSettingsDto**](JobSettingsDto.md) | | **faceDetection** | [**JobSettingsDto**](JobSettingsDto.md) | | **library_** | [**JobSettingsDto**](JobSettingsDto.md) | | **metadataExtraction** | [**JobSettingsDto**](JobSettingsDto.md) | | diff --git a/mobile/openapi/lib/model/all_job_status_response_dto.dart b/mobile/openapi/lib/model/all_job_status_response_dto.dart index 917bf9cb4..9d637d4e4 100644 --- a/mobile/openapi/lib/model/all_job_status_response_dto.dart +++ b/mobile/openapi/lib/model/all_job_status_response_dto.dart @@ -14,6 +14,7 @@ class AllJobStatusResponseDto { /// Returns a new [AllJobStatusResponseDto] instance. AllJobStatusResponseDto({ required this.backgroundTask, + required this.duplicateDetection, required this.faceDetection, required this.facialRecognition, required this.library_, @@ -29,6 +30,8 @@ class AllJobStatusResponseDto { JobStatusDto backgroundTask; + JobStatusDto duplicateDetection; + JobStatusDto faceDetection; JobStatusDto facialRecognition; @@ -54,6 +57,7 @@ class AllJobStatusResponseDto { @override bool operator ==(Object other) => identical(this, other) || other is AllJobStatusResponseDto && other.backgroundTask == backgroundTask && + other.duplicateDetection == duplicateDetection && other.faceDetection == faceDetection && other.facialRecognition == facialRecognition && other.library_ == library_ && @@ -70,6 +74,7 @@ class AllJobStatusResponseDto { int get hashCode => // ignore: unnecessary_parenthesis (backgroundTask.hashCode) + + (duplicateDetection.hashCode) + (faceDetection.hashCode) + (facialRecognition.hashCode) + (library_.hashCode) + @@ -83,11 +88,12 @@ class AllJobStatusResponseDto { (videoConversion.hashCode); @override - String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, faceDetection=$faceDetection, facialRecognition=$facialRecognition, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]'; + String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, duplicateDetection=$duplicateDetection, faceDetection=$faceDetection, facialRecognition=$facialRecognition, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]'; Map toJson() { final json = {}; json[r'backgroundTask'] = this.backgroundTask; + json[r'duplicateDetection'] = this.duplicateDetection; json[r'faceDetection'] = this.faceDetection; json[r'facialRecognition'] = this.facialRecognition; json[r'library'] = this.library_; @@ -111,6 +117,7 @@ class AllJobStatusResponseDto { return AllJobStatusResponseDto( backgroundTask: JobStatusDto.fromJson(json[r'backgroundTask'])!, + duplicateDetection: JobStatusDto.fromJson(json[r'duplicateDetection'])!, faceDetection: JobStatusDto.fromJson(json[r'faceDetection'])!, facialRecognition: JobStatusDto.fromJson(json[r'facialRecognition'])!, library_: JobStatusDto.fromJson(json[r'library'])!, @@ -170,6 +177,7 @@ class AllJobStatusResponseDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'backgroundTask', + 'duplicateDetection', 'faceDetection', 'facialRecognition', 'library', diff --git a/mobile/openapi/lib/model/clip_config.dart b/mobile/openapi/lib/model/clip_config.dart index 367102f3e..053f21cf1 100644 --- a/mobile/openapi/lib/model/clip_config.dart +++ b/mobile/openapi/lib/model/clip_config.dart @@ -13,12 +13,15 @@ part of openapi.api; class CLIPConfig { /// Returns a new [CLIPConfig] instance. CLIPConfig({ + required this.duplicateThreshold, required this.enabled, this.mode, required this.modelName, this.modelType, }); + double duplicateThreshold; + bool enabled; /// @@ -41,6 +44,7 @@ class CLIPConfig { @override bool operator ==(Object other) => identical(this, other) || other is CLIPConfig && + other.duplicateThreshold == duplicateThreshold && other.enabled == enabled && other.mode == mode && other.modelName == modelName && @@ -49,16 +53,18 @@ class CLIPConfig { @override int get hashCode => // ignore: unnecessary_parenthesis + (duplicateThreshold.hashCode) + (enabled.hashCode) + (mode == null ? 0 : mode!.hashCode) + (modelName.hashCode) + (modelType == null ? 0 : modelType!.hashCode); @override - String toString() => 'CLIPConfig[enabled=$enabled, mode=$mode, modelName=$modelName, modelType=$modelType]'; + String toString() => 'CLIPConfig[duplicateThreshold=$duplicateThreshold, enabled=$enabled, mode=$mode, modelName=$modelName, modelType=$modelType]'; Map toJson() { final json = {}; + json[r'duplicateThreshold'] = this.duplicateThreshold; json[r'enabled'] = this.enabled; if (this.mode != null) { json[r'mode'] = this.mode; @@ -82,6 +88,7 @@ class CLIPConfig { final json = value.cast(); return CLIPConfig( + duplicateThreshold: mapValueOfType(json, r'duplicateThreshold')!, enabled: mapValueOfType(json, r'enabled')!, mode: CLIPMode.fromJson(json[r'mode']), modelName: mapValueOfType(json, r'modelName')!, @@ -133,6 +140,7 @@ class CLIPConfig { /// The list of required keys that must be present in a JSON. static const requiredKeys = { + 'duplicateThreshold', 'enabled', 'modelName', }; diff --git a/mobile/openapi/lib/model/job_name.dart b/mobile/openapi/lib/model/job_name.dart index e3b6b380a..85cf2d2c3 100644 --- a/mobile/openapi/lib/model/job_name.dart +++ b/mobile/openapi/lib/model/job_name.dart @@ -29,6 +29,7 @@ class JobName { static const faceDetection = JobName._(r'faceDetection'); static const facialRecognition = JobName._(r'facialRecognition'); static const smartSearch = JobName._(r'smartSearch'); + static const duplicateDetection = JobName._(r'duplicateDetection'); static const backgroundTask = JobName._(r'backgroundTask'); static const storageTemplateMigration = JobName._(r'storageTemplateMigration'); static const migration = JobName._(r'migration'); @@ -44,6 +45,7 @@ class JobName { faceDetection, facialRecognition, smartSearch, + duplicateDetection, backgroundTask, storageTemplateMigration, migration, @@ -94,6 +96,7 @@ class JobNameTypeTransformer { case r'faceDetection': return JobName.faceDetection; case r'facialRecognition': return JobName.facialRecognition; case r'smartSearch': return JobName.smartSearch; + case r'duplicateDetection': return JobName.duplicateDetection; case r'backgroundTask': return JobName.backgroundTask; case r'storageTemplateMigration': return JobName.storageTemplateMigration; case r'migration': return JobName.migration; diff --git a/mobile/openapi/lib/model/system_config_job_dto.dart b/mobile/openapi/lib/model/system_config_job_dto.dart index 3a23f1975..032d91372 100644 --- a/mobile/openapi/lib/model/system_config_job_dto.dart +++ b/mobile/openapi/lib/model/system_config_job_dto.dart @@ -14,6 +14,7 @@ class SystemConfigJobDto { /// Returns a new [SystemConfigJobDto] instance. SystemConfigJobDto({ required this.backgroundTask, + required this.duplicateDetection, required this.faceDetection, required this.library_, required this.metadataExtraction, @@ -27,6 +28,8 @@ class SystemConfigJobDto { JobSettingsDto backgroundTask; + JobSettingsDto duplicateDetection; + JobSettingsDto faceDetection; JobSettingsDto library_; @@ -48,6 +51,7 @@ class SystemConfigJobDto { @override bool operator ==(Object other) => identical(this, other) || other is SystemConfigJobDto && other.backgroundTask == backgroundTask && + other.duplicateDetection == duplicateDetection && other.faceDetection == faceDetection && other.library_ == library_ && other.metadataExtraction == metadataExtraction && @@ -62,6 +66,7 @@ class SystemConfigJobDto { int get hashCode => // ignore: unnecessary_parenthesis (backgroundTask.hashCode) + + (duplicateDetection.hashCode) + (faceDetection.hashCode) + (library_.hashCode) + (metadataExtraction.hashCode) + @@ -73,11 +78,12 @@ class SystemConfigJobDto { (videoConversion.hashCode); @override - String toString() => 'SystemConfigJobDto[backgroundTask=$backgroundTask, faceDetection=$faceDetection, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]'; + String toString() => 'SystemConfigJobDto[backgroundTask=$backgroundTask, duplicateDetection=$duplicateDetection, faceDetection=$faceDetection, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]'; Map toJson() { final json = {}; json[r'backgroundTask'] = this.backgroundTask; + json[r'duplicateDetection'] = this.duplicateDetection; json[r'faceDetection'] = this.faceDetection; json[r'library'] = this.library_; json[r'metadataExtraction'] = this.metadataExtraction; @@ -99,6 +105,7 @@ class SystemConfigJobDto { return SystemConfigJobDto( backgroundTask: JobSettingsDto.fromJson(json[r'backgroundTask'])!, + duplicateDetection: JobSettingsDto.fromJson(json[r'duplicateDetection'])!, faceDetection: JobSettingsDto.fromJson(json[r'faceDetection'])!, library_: JobSettingsDto.fromJson(json[r'library'])!, metadataExtraction: JobSettingsDto.fromJson(json[r'metadataExtraction'])!, @@ -156,6 +163,7 @@ class SystemConfigJobDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'backgroundTask', + 'duplicateDetection', 'faceDetection', 'library', 'metadataExtraction', diff --git a/mobile/openapi/test/all_job_status_response_dto_test.dart b/mobile/openapi/test/all_job_status_response_dto_test.dart index e0709378d..88d50085f 100644 --- a/mobile/openapi/test/all_job_status_response_dto_test.dart +++ b/mobile/openapi/test/all_job_status_response_dto_test.dart @@ -21,6 +21,11 @@ void main() { // TODO }); + // JobStatusDto duplicateDetection + test('to test the property `duplicateDetection`', () async { + // TODO + }); + // JobStatusDto faceDetection test('to test the property `faceDetection`', () async { // TODO diff --git a/mobile/openapi/test/clip_config_test.dart b/mobile/openapi/test/clip_config_test.dart index 77069e5b9..86889704a 100644 --- a/mobile/openapi/test/clip_config_test.dart +++ b/mobile/openapi/test/clip_config_test.dart @@ -16,6 +16,11 @@ void main() { // final instance = CLIPConfig(); group('test CLIPConfig', () { + // double duplicateThreshold + test('to test the property `duplicateThreshold`', () async { + // TODO + }); + // bool enabled test('to test the property `enabled`', () async { // TODO diff --git a/mobile/openapi/test/system_config_job_dto_test.dart b/mobile/openapi/test/system_config_job_dto_test.dart index 4da78453e..9e52d5752 100644 --- a/mobile/openapi/test/system_config_job_dto_test.dart +++ b/mobile/openapi/test/system_config_job_dto_test.dart @@ -21,6 +21,11 @@ void main() { // TODO }); + // JobSettingsDto duplicateDetection + test('to test the property `duplicateDetection`', () async { + // TODO + }); + // JobSettingsDto faceDetection test('to test the property `faceDetection`', () async { // TODO diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index a2aae92c4..9cf3396b2 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -6831,6 +6831,9 @@ "backgroundTask": { "$ref": "#/components/schemas/JobStatusDto" }, + "duplicateDetection": { + "$ref": "#/components/schemas/JobStatusDto" + }, "faceDetection": { "$ref": "#/components/schemas/JobStatusDto" }, @@ -6867,6 +6870,7 @@ }, "required": [ "backgroundTask", + "duplicateDetection", "faceDetection", "facialRecognition", "library", @@ -7479,6 +7483,10 @@ }, "CLIPConfig": { "properties": { + "duplicateThreshold": { + "format": "float", + "type": "number" + }, "enabled": { "type": "boolean" }, @@ -7493,6 +7501,7 @@ } }, "required": [ + "duplicateThreshold", "enabled", "modelName" ], @@ -8178,6 +8187,7 @@ "faceDetection", "facialRecognition", "smartSearch", + "duplicateDetection", "backgroundTask", "storageTemplateMigration", "migration", @@ -9907,6 +9917,9 @@ "backgroundTask": { "$ref": "#/components/schemas/JobSettingsDto" }, + "duplicateDetection": { + "$ref": "#/components/schemas/JobSettingsDto" + }, "faceDetection": { "$ref": "#/components/schemas/JobSettingsDto" }, @@ -9937,6 +9950,7 @@ }, "required": [ "backgroundTask", + "duplicateDetection", "faceDetection", "library", "metadataExtraction", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index b9b4978a9..c582a21c8 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -429,6 +429,7 @@ export type JobStatusDto = { }; export type AllJobStatusResponseDto = { backgroundTask: JobStatusDto; + duplicateDetection: JobStatusDto; faceDetection: JobStatusDto; facialRecognition: JobStatusDto; library: JobStatusDto; @@ -832,6 +833,7 @@ export type JobSettingsDto = { }; export type SystemConfigJobDto = { backgroundTask: JobSettingsDto; + duplicateDetection: JobSettingsDto; faceDetection: JobSettingsDto; library: JobSettingsDto; metadataExtraction: JobSettingsDto; @@ -858,6 +860,7 @@ export type SystemConfigLoggingDto = { level: LogLevel; }; export type ClipConfig = { + duplicateThreshold: number; enabled: boolean; mode?: CLIPMode; modelName: string; @@ -2816,6 +2819,7 @@ export enum JobName { FaceDetection = "faceDetection", FacialRecognition = "facialRecognition", SmartSearch = "smartSearch", + DuplicateDetection = "duplicateDetection", BackgroundTask = "backgroundTask", StorageTemplateMigration = "storageTemplateMigration", Migration = "migration", diff --git a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte index 15b91c98b..694a9e3b0 100644 --- a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte +++ b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte @@ -88,6 +88,12 @@ subtitle: 'Run machine learning on assets to support smart search', disabled: !$featureFlags.smartSearch, }, + [JobName.DuplicateDetection]: { + icon: mdiImageSearch, + title: getJobName(JobName.DuplicateDetection), + subtitle: 'Run machine learning on assets to detect near-duplicate images', + disabled: !$featureFlags.smartSearch, + }, [JobName.FaceDetection]: { icon: mdiFaceRecognition, title: getJobName(JobName.FaceDetection), diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 299f04505..0ff5d660d 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -115,6 +115,7 @@ export const getJobName = (jobName: JobName) => { [JobName.MetadataExtraction]: 'Extract Metadata', [JobName.Sidecar]: 'Sidecar Metadata', [JobName.SmartSearch]: 'Smart Search', + [JobName.DuplicateDetection]: 'Duplicate Detection', [JobName.FaceDetection]: 'Face Detection', [JobName.FacialRecognition]: 'Facial Recognition', [JobName.VideoConversion]: 'Transcode Videos',