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:
David Bourgault 2025-02-26 21:53:21 -05:00 committed by GitHub
parent 8fbd650483
commit 4b55888d16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 63 additions and 6 deletions

2
server/src/db.d.ts vendored
View file

@ -29,7 +29,7 @@ export type JsonPrimitive = boolean | number | string | null;
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>;

View file

@ -1,6 +1,6 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
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 { PropertyLifecycle } from 'src/decorators';
import { AuthDto } from 'src/dtos/auth.dto';
@ -194,6 +194,10 @@ export class AssetFaceCreateDto extends AssetFaceUpdateItem {
@IsNotEmpty()
@IsNumber()
height!: number;
@ApiProperty({ type: 'string', enum: SourceType, enumName: 'SourceType' })
@IsEnum(SourceType)
sourceType: SourceType = SourceType.MANUAL;
}
export class AssetFaceDeleteDto {

View file

@ -228,6 +228,7 @@ export enum AssetStatus {
export enum SourceType {
MACHINE_LEARNING = 'machine-learning',
EXIF = 'exif',
MANUAL = 'manual',
}
export enum ManualJobName {

View 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;`);
}
}

View file

@ -736,6 +736,7 @@ export class PersonService extends BaseService {
boundingBoxX2: dto.x + dto.width,
boundingBoxY1: dto.y,
boundingBoxY2: dto.y + dto.height,
sourceType: dto.sourceType,
});
}