mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
fix: ensure manually tagged faces have proper source type (#16364)
immich-app/immich#16062 added manual face tagging and deletion, but did not add a new 'SourceType'. The create faces would default to 'machine-learning' which is incorrect, and has the annoying downside that they will be wiped when the 'Refresh Faces' job is run. Handling of non-machine-learning faces was previously added in immich-app/immich#6455. This PR simply extends it to the new manually tagged faces.
This commit is contained in:
parent
8fbd650483
commit
4b55888d16
10 changed files with 51 additions and 5 deletions
BIN
mobile/openapi/lib/model/asset_face_create_dto.dart
generated
BIN
mobile/openapi/lib/model/asset_face_create_dto.dart
generated
Binary file not shown.
BIN
mobile/openapi/lib/model/source_type.dart
generated
BIN
mobile/openapi/lib/model/source_type.dart
generated
Binary file not shown.
|
|
@ -8301,6 +8301,14 @@
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"sourceType": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/SourceType"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": "manual"
|
||||||
|
},
|
||||||
"width": {
|
"width": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -8317,6 +8325,7 @@
|
||||||
"imageHeight",
|
"imageHeight",
|
||||||
"imageWidth",
|
"imageWidth",
|
||||||
"personId",
|
"personId",
|
||||||
|
"sourceType",
|
||||||
"width",
|
"width",
|
||||||
"x",
|
"x",
|
||||||
"y"
|
"y"
|
||||||
|
|
@ -11952,7 +11961,8 @@
|
||||||
"SourceType": {
|
"SourceType": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"machine-learning",
|
"machine-learning",
|
||||||
"exif"
|
"exif",
|
||||||
|
"manual"
|
||||||
],
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -529,6 +529,7 @@ export type AssetFaceCreateDto = {
|
||||||
imageHeight: number;
|
imageHeight: number;
|
||||||
imageWidth: number;
|
imageWidth: number;
|
||||||
personId: string;
|
personId: string;
|
||||||
|
sourceType: SourceType;
|
||||||
width: number;
|
width: number;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
|
@ -3453,7 +3454,8 @@ export enum AlbumUserRole {
|
||||||
}
|
}
|
||||||
export enum SourceType {
|
export enum SourceType {
|
||||||
MachineLearning = "machine-learning",
|
MachineLearning = "machine-learning",
|
||||||
Exif = "exif"
|
Exif = "exif",
|
||||||
|
Manual = "manual"
|
||||||
}
|
}
|
||||||
export enum AssetTypeEnum {
|
export enum AssetTypeEnum {
|
||||||
Image = "IMAGE",
|
Image = "IMAGE",
|
||||||
|
|
|
||||||
2
server/src/db.d.ts
vendored
2
server/src/db.d.ts
vendored
|
|
@ -29,7 +29,7 @@ export type JsonPrimitive = boolean | number | string | null;
|
||||||
|
|
||||||
export type JsonValue = JsonArray | JsonObject | JsonPrimitive;
|
export type JsonValue = JsonArray | JsonObject | JsonPrimitive;
|
||||||
|
|
||||||
export type Sourcetype = 'exif' | 'machine-learning';
|
export type Sourcetype = 'exif' | 'machine-learning' | 'manual';
|
||||||
|
|
||||||
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { IsArray, IsInt, IsNotEmpty, IsNumber, IsString, Max, Min, ValidateNested } from 'class-validator';
|
import { IsArray, IsEnum, IsInt, IsNotEmpty, IsNumber, IsString, Max, Min, ValidateNested } from 'class-validator';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { PropertyLifecycle } from 'src/decorators';
|
import { PropertyLifecycle } from 'src/decorators';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
|
|
@ -194,6 +194,10 @@ export class AssetFaceCreateDto extends AssetFaceUpdateItem {
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
height!: number;
|
height!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'string', enum: SourceType, enumName: 'SourceType' })
|
||||||
|
@IsEnum(SourceType)
|
||||||
|
sourceType: SourceType = SourceType.MANUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AssetFaceDeleteDto {
|
export class AssetFaceDeleteDto {
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,7 @@ export enum AssetStatus {
|
||||||
export enum SourceType {
|
export enum SourceType {
|
||||||
MACHINE_LEARNING = 'machine-learning',
|
MACHINE_LEARNING = 'machine-learning',
|
||||||
EXIF = 'exif',
|
EXIF = 'exif',
|
||||||
|
MANUAL = 'manual',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ManualJobName {
|
export enum ManualJobName {
|
||||||
|
|
|
||||||
27
server/src/migrations/1740619600996-AddManualSourceType.ts
Normal file
27
server/src/migrations/1740619600996-AddManualSourceType.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class AddManualSourceType1740619600996 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TYPE sourceType ADD VALUE 'manual'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Prior to this migration, manually tagged pictures had the 'machine-learning' type
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "asset_faces" SET "sourceType" = 'machine-learning' WHERE "sourceType" = 'manual';`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Postgres doesn't allow removing values from enums, we have to recreate the type
|
||||||
|
await queryRunner.query(`ALTER TYPE sourceType RENAME TO oldSourceType`);
|
||||||
|
await queryRunner.query(`CREATE TYPE sourceType AS ENUM ('machine-learning', 'exif');`);
|
||||||
|
|
||||||
|
await queryRunner.query(`ALTER TABLE "asset_faces" ALTER COLUMN "sourceType" DROP DEFAULT;`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "asset_faces" ALTER COLUMN "sourceType" TYPE sourceType USING "sourceType"::text::sourceType;`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "asset_faces" ALTER COLUMN "sourceType" SET DEFAULT 'machine-learning'::sourceType;`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`DROP TYPE oldSourceType;`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -736,6 +736,7 @@ export class PersonService extends BaseService {
|
||||||
boundingBoxX2: dto.x + dto.width,
|
boundingBoxX2: dto.x + dto.width,
|
||||||
boundingBoxY1: dto.y,
|
boundingBoxY1: dto.y,
|
||||||
boundingBoxY2: dto.y + dto.height,
|
boundingBoxY2: dto.y + dto.height,
|
||||||
|
sourceType: dto.sourceType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
import { notificationController } from '$lib/components/shared-components/notification/notification';
|
import { notificationController } from '$lib/components/shared-components/notification/notification';
|
||||||
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
|
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
|
||||||
import { getPeopleThumbnailUrl } from '$lib/utils';
|
import { getPeopleThumbnailUrl } from '$lib/utils';
|
||||||
import { getAllPeople, createFace, type PersonResponseDto } from '@immich/sdk';
|
import { getAllPeople, createFace, type PersonResponseDto, SourceType } from '@immich/sdk';
|
||||||
import { Button } from '@immich/ui';
|
import { Button } from '@immich/ui';
|
||||||
import { Canvas, InteractiveFabricObject, Rect } from 'fabric';
|
import { Canvas, InteractiveFabricObject, Rect } from 'fabric';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
@ -288,6 +288,7 @@
|
||||||
assetFaceCreateDto: {
|
assetFaceCreateDto: {
|
||||||
assetId,
|
assetId,
|
||||||
personId: person.id,
|
personId: person.id,
|
||||||
|
sourceType: SourceType.Manual,
|
||||||
...data,
|
...data,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue