mirror of
https://github.com/immich-app/immich.git
synced 2024-11-30 09:47:31 +02:00
fix(server, web): reassigning faces (#9265)
* fix: reassiging faces * fix: rename
This commit is contained in:
parent
090592e5ae
commit
cf79bc9ed7
@ -5,7 +5,7 @@ import { ExifEntity } from 'src/entities/exif.entity';
|
|||||||
import { ReverseGeocodeResult } from 'src/interfaces/metadata.interface';
|
import { ReverseGeocodeResult } from 'src/interfaces/metadata.interface';
|
||||||
import { AssetSearchOptions, SearchExploreItem } from 'src/interfaces/search.interface';
|
import { AssetSearchOptions, SearchExploreItem } from 'src/interfaces/search.interface';
|
||||||
import { Paginated, PaginationOptions } from 'src/utils/pagination';
|
import { Paginated, PaginationOptions } from 'src/utils/pagination';
|
||||||
import { FindOptionsRelations, FindOptionsSelect } from 'typeorm';
|
import { FindOptionsOrder, FindOptionsRelations, FindOptionsSelect } from 'typeorm';
|
||||||
|
|
||||||
export type AssetStats = Record<AssetType, number>;
|
export type AssetStats = Record<AssetType, number>;
|
||||||
|
|
||||||
@ -162,7 +162,11 @@ export interface IAssetRepository {
|
|||||||
getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise<string | undefined>;
|
getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise<string | undefined>;
|
||||||
getByAlbumId(pagination: PaginationOptions, albumId: string): Paginated<AssetEntity>;
|
getByAlbumId(pagination: PaginationOptions, albumId: string): Paginated<AssetEntity>;
|
||||||
getByUserId(pagination: PaginationOptions, userId: string, options?: AssetSearchOptions): Paginated<AssetEntity>;
|
getByUserId(pagination: PaginationOptions, userId: string, options?: AssetSearchOptions): Paginated<AssetEntity>;
|
||||||
getById(id: string, relations?: FindOptionsRelations<AssetEntity>): Promise<AssetEntity | null>;
|
getById(
|
||||||
|
id: string,
|
||||||
|
relations?: FindOptionsRelations<AssetEntity>,
|
||||||
|
order?: FindOptionsOrder<AssetEntity>,
|
||||||
|
): Promise<AssetEntity | null>;
|
||||||
getWithout(pagination: PaginationOptions, property: WithoutProperty): Paginated<AssetEntity>;
|
getWithout(pagination: PaginationOptions, property: WithoutProperty): Paginated<AssetEntity>;
|
||||||
getWith(pagination: PaginationOptions, property: WithProperty, libraryId?: string): Paginated<AssetEntity>;
|
getWith(pagination: PaginationOptions, property: WithProperty, libraryId?: string): Paginated<AssetEntity>;
|
||||||
getRandom(userId: string, count: number): Promise<AssetEntity[]>;
|
getRandom(userId: string, count: number): Promise<AssetEntity[]>;
|
||||||
|
@ -85,6 +85,8 @@ FROM
|
|||||||
LEFT JOIN "person" "AssetFaceEntity__AssetFaceEntity_person" ON "AssetFaceEntity__AssetFaceEntity_person"."id" = "AssetFaceEntity"."personId"
|
LEFT JOIN "person" "AssetFaceEntity__AssetFaceEntity_person" ON "AssetFaceEntity__AssetFaceEntity_person"."id" = "AssetFaceEntity"."personId"
|
||||||
WHERE
|
WHERE
|
||||||
(("AssetFaceEntity"."assetId" = $1))
|
(("AssetFaceEntity"."assetId" = $1))
|
||||||
|
ORDER BY
|
||||||
|
"AssetFaceEntity"."boundingBoxX1" ASC
|
||||||
|
|
||||||
-- PersonRepository.getFaceById
|
-- PersonRepository.getFaceById
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
|
@ -36,6 +36,7 @@ import { Instrumentation } from 'src/utils/instrumentation';
|
|||||||
import { Paginated, PaginationMode, PaginationOptions, paginate, paginatedBuilder } from 'src/utils/pagination';
|
import { Paginated, PaginationMode, PaginationOptions, paginate, paginatedBuilder } from 'src/utils/pagination';
|
||||||
import {
|
import {
|
||||||
Brackets,
|
Brackets,
|
||||||
|
FindOptionsOrder,
|
||||||
FindOptionsRelations,
|
FindOptionsRelations,
|
||||||
FindOptionsSelect,
|
FindOptionsSelect,
|
||||||
FindOptionsWhere,
|
FindOptionsWhere,
|
||||||
@ -236,12 +237,17 @@ export class AssetRepository implements IAssetRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GenerateSql({ params: [DummyValue.UUID] })
|
@GenerateSql({ params: [DummyValue.UUID] })
|
||||||
getById(id: string, relations: FindOptionsRelations<AssetEntity>): Promise<AssetEntity | null> {
|
getById(
|
||||||
|
id: string,
|
||||||
|
relations: FindOptionsRelations<AssetEntity>,
|
||||||
|
order?: FindOptionsOrder<AssetEntity>,
|
||||||
|
): Promise<AssetEntity | null> {
|
||||||
return this.repository.findOne({
|
return this.repository.findOne({
|
||||||
where: { id },
|
where: { id },
|
||||||
relations,
|
relations,
|
||||||
// We are specifically asking for this asset. Return it even if it is soft deleted
|
// We are specifically asking for this asset. Return it even if it is soft deleted
|
||||||
withDeleted: true,
|
withDeleted: true,
|
||||||
|
order,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,9 @@ export class PersonRepository implements IPersonRepository {
|
|||||||
relations: {
|
relations: {
|
||||||
person: true,
|
person: true,
|
||||||
},
|
},
|
||||||
|
order: {
|
||||||
|
boundingBoxX1: 'ASC',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,21 +227,29 @@ export class AssetService {
|
|||||||
async get(auth: AuthDto, id: string): Promise<AssetResponseDto | SanitizedAssetResponseDto> {
|
async get(auth: AuthDto, id: string): Promise<AssetResponseDto | SanitizedAssetResponseDto> {
|
||||||
await this.access.requirePermission(auth, Permission.ASSET_READ, id);
|
await this.access.requirePermission(auth, Permission.ASSET_READ, id);
|
||||||
|
|
||||||
const asset = await this.assetRepository.getById(id, {
|
const asset = await this.assetRepository.getById(
|
||||||
exifInfo: true,
|
id,
|
||||||
tags: true,
|
{
|
||||||
sharedLinks: true,
|
exifInfo: true,
|
||||||
smartInfo: true,
|
tags: true,
|
||||||
owner: true,
|
sharedLinks: true,
|
||||||
faces: {
|
smartInfo: true,
|
||||||
person: true,
|
owner: true,
|
||||||
},
|
faces: {
|
||||||
stack: {
|
person: true,
|
||||||
assets: {
|
},
|
||||||
exifInfo: true,
|
stack: {
|
||||||
|
assets: {
|
||||||
|
exifInfo: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
{
|
||||||
|
faces: {
|
||||||
|
boundingBoxX1: 'ASC',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
throw new BadRequestException('Asset not found');
|
throw new BadRequestException('Asset not found');
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
let selectedPersonToReassign: Record<string, PersonResponseDto> = {};
|
let selectedPersonToReassign: Record<string, PersonResponseDto> = {};
|
||||||
let selectedPersonToCreate: Record<string, string> = {};
|
let selectedPersonToCreate: Record<string, string> = {};
|
||||||
let editedPerson: PersonResponseDto;
|
let editedPerson: PersonResponseDto;
|
||||||
|
let editedFace: AssetFaceResponseDto;
|
||||||
|
|
||||||
// loading spinners
|
// loading spinners
|
||||||
let isShowLoadingDone = false;
|
let isShowLoadingDone = false;
|
||||||
@ -155,24 +156,23 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCreatePerson = (newFeaturePhoto: string | null) => {
|
const handleCreatePerson = (newFeaturePhoto: string | null) => {
|
||||||
const personToUpdate = peopleWithFaces.find((face) => face.person?.id === editedPerson.id);
|
if (newFeaturePhoto) {
|
||||||
if (newFeaturePhoto && personToUpdate) {
|
selectedPersonToCreate[editedFace.id] = newFeaturePhoto;
|
||||||
selectedPersonToCreate[personToUpdate.id] = newFeaturePhoto;
|
|
||||||
}
|
}
|
||||||
showSelectedFaces = false;
|
showSelectedFaces = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReassignFace = (person: PersonResponseDto | null) => {
|
const handleReassignFace = (person: PersonResponseDto | null) => {
|
||||||
const personToUpdate = peopleWithFaces.find((face) => face.person?.id === editedPerson.id);
|
if (person) {
|
||||||
if (person && personToUpdate) {
|
selectedPersonToReassign[editedFace.id] = person;
|
||||||
selectedPersonToReassign[personToUpdate.id] = person;
|
|
||||||
showSelectedFaces = false;
|
|
||||||
}
|
}
|
||||||
|
showSelectedFaces = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePersonPicker = (person: PersonResponseDto | null) => {
|
const handleFacePicker = (face: AssetFaceResponseDto) => {
|
||||||
if (person) {
|
if (face.person) {
|
||||||
editedPerson = person;
|
editedFace = face;
|
||||||
|
editedPerson = face.person;
|
||||||
showSelectedFaces = true;
|
showSelectedFaces = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -285,7 +285,7 @@
|
|||||||
size="18"
|
size="18"
|
||||||
padding="1"
|
padding="1"
|
||||||
class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
||||||
on:click={() => handlePersonPicker(face.person)}
|
on:click={() => handleFacePicker(face)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user