feat: add number of unassigned faces

This commit is contained in:
martabal 2023-10-24 23:34:55 +02:00
parent f42cf33605
commit c8d173697f
No known key found for this signature in database
GPG key ID: C00196E3148A52BD
19 changed files with 536 additions and 22 deletions

View file

@ -819,10 +819,10 @@ export interface AssetResponseDto {
'ownerId': string;
/**
*
* @type {Array<PersonResponseDto>}
* @type {Array<PeopleAssetResponseDto>}
* @memberof AssetResponseDto
*/
'people'?: Array<PersonResponseDto>;
'people'?: Array<PeopleAssetResponseDto>;
/**
*
* @type {boolean}
@ -871,6 +871,12 @@ export interface AssetResponseDto {
* @memberof AssetResponseDto
*/
'type': AssetTypeEnum;
/**
*
* @type {Array<UnassignedFacesResponseDto>}
* @memberof AssetResponseDto
*/
'unassignedPeople'?: Array<UnassignedFacesResponseDto>;
/**
*
* @type {string}
@ -2390,6 +2396,25 @@ export const PathType = {
export type PathType = typeof PathType[keyof typeof PathType];
/**
*
* @export
* @interface PeopleAssetResponseDto
*/
export interface PeopleAssetResponseDto {
/**
*
* @type {string}
* @memberof PeopleAssetResponseDto
*/
'assetFaceId': string;
/**
*
* @type {PersonResponseDto}
* @memberof PeopleAssetResponseDto
*/
'person': PersonResponseDto;
}
/**
*
* @export
@ -4024,6 +4049,25 @@ export const TranscodePolicy = {
export type TranscodePolicy = typeof TranscodePolicy[keyof typeof TranscodePolicy];
/**
*
* @export
* @interface UnassignedFacesResponseDto
*/
export interface UnassignedFacesResponseDto {
/**
*
* @type {string}
* @memberof UnassignedFacesResponseDto
*/
'assetFaceId': string;
/**
*
* @type {AssetFaceBoxDto}
* @memberof UnassignedFacesResponseDto
*/
'boudinxBox': AssetFaceBoxDto;
}
/**
*
* @export

View file

@ -92,6 +92,7 @@ doc/OAuthConfigResponseDto.md
doc/PartnerApi.md
doc/PathEntityType.md
doc/PathType.md
doc/PeopleAssetResponseDto.md
doc/PeopleResponseDto.md
doc/PeopleUpdateDto.md
doc/PeopleUpdateItem.md
@ -150,6 +151,7 @@ doc/TimeBucketSize.md
doc/ToneMapping.md
doc/TranscodeHWAccel.md
doc/TranscodePolicy.md
doc/UnassignedFacesResponseDto.md
doc/UpdateAlbumDto.md
doc/UpdateAssetDto.md
doc/UpdateLibraryDto.md
@ -268,6 +270,7 @@ lib/model/o_auth_config_dto.dart
lib/model/o_auth_config_response_dto.dart
lib/model/path_entity_type.dart
lib/model/path_type.dart
lib/model/people_asset_response_dto.dart
lib/model/people_response_dto.dart
lib/model/people_update_dto.dart
lib/model/people_update_item.dart
@ -320,6 +323,7 @@ lib/model/time_bucket_size.dart
lib/model/tone_mapping.dart
lib/model/transcode_hw_accel.dart
lib/model/transcode_policy.dart
lib/model/unassigned_faces_response_dto.dart
lib/model/update_album_dto.dart
lib/model/update_asset_dto.dart
lib/model/update_library_dto.dart
@ -421,6 +425,7 @@ test/o_auth_config_response_dto_test.dart
test/partner_api_test.dart
test/path_entity_type_test.dart
test/path_type_test.dart
test/people_asset_response_dto_test.dart
test/people_response_dto_test.dart
test/people_update_dto_test.dart
test/people_update_item_test.dart
@ -479,6 +484,7 @@ test/time_bucket_size_test.dart
test/tone_mapping_test.dart
test/transcode_hw_accel_test.dart
test/transcode_policy_test.dart
test/unassigned_faces_response_dto_test.dart
test/update_album_dto_test.dart
test/update_asset_dto_test.dart
test/update_library_dto_test.dart

View file

@ -283,6 +283,7 @@ Class | Method | HTTP request | Description
- [OAuthConfigResponseDto](doc//OAuthConfigResponseDto.md)
- [PathEntityType](doc//PathEntityType.md)
- [PathType](doc//PathType.md)
- [PeopleAssetResponseDto](doc//PeopleAssetResponseDto.md)
- [PeopleResponseDto](doc//PeopleResponseDto.md)
- [PeopleUpdateDto](doc//PeopleUpdateDto.md)
- [PeopleUpdateItem](doc//PeopleUpdateItem.md)
@ -335,6 +336,7 @@ Class | Method | HTTP request | Description
- [ToneMapping](doc//ToneMapping.md)
- [TranscodeHWAccel](doc//TranscodeHWAccel.md)
- [TranscodePolicy](doc//TranscodePolicy.md)
- [UnassignedFacesResponseDto](doc//UnassignedFacesResponseDto.md)
- [UpdateAlbumDto](doc//UpdateAlbumDto.md)
- [UpdateAssetDto](doc//UpdateAssetDto.md)
- [UpdateLibraryDto](doc//UpdateLibraryDto.md)

View file

@ -30,7 +30,7 @@ Name | Type | Description | Notes
**originalPath** | **String** | |
**owner** | [**UserResponseDto**](UserResponseDto.md) | | [optional]
**ownerId** | **String** | |
**people** | [**List<PersonResponseDto>**](PersonResponseDto.md) | | [optional] [default to const []]
**people** | [**List<PeopleAssetResponseDto>**](PeopleAssetResponseDto.md) | | [optional] [default to const []]
**resized** | **bool** | |
**smartInfo** | [**SmartInfoResponseDto**](SmartInfoResponseDto.md) | | [optional]
**stack** | [**List<AssetResponseDto>**](AssetResponseDto.md) | | [optional] [default to const []]
@ -39,6 +39,7 @@ Name | Type | Description | Notes
**tags** | [**List<TagResponseDto>**](TagResponseDto.md) | | [optional] [default to const []]
**thumbhash** | **String** | |
**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | |
**unassignedPeople** | [**List<UnassignedFacesResponseDto>**](UnassignedFacesResponseDto.md) | | [optional] [default to const []]
**updatedAt** | [**DateTime**](DateTime.md) | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View file

@ -0,0 +1,16 @@
# openapi.model.PeopleAssetResponseDto
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**assetFaceId** | **String** | |
**person** | [**PersonResponseDto**](PersonResponseDto.md) | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View file

@ -0,0 +1,16 @@
# openapi.model.UnassignedFacesResponseDto
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**assetFaceId** | **String** | |
**boudinxBox** | [**AssetFaceBoxDto**](AssetFaceBoxDto.md) | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View file

@ -125,6 +125,7 @@ part 'model/o_auth_config_dto.dart';
part 'model/o_auth_config_response_dto.dart';
part 'model/path_entity_type.dart';
part 'model/path_type.dart';
part 'model/people_asset_response_dto.dart';
part 'model/people_response_dto.dart';
part 'model/people_update_dto.dart';
part 'model/people_update_item.dart';
@ -177,6 +178,7 @@ part 'model/time_bucket_size.dart';
part 'model/tone_mapping.dart';
part 'model/transcode_hw_accel.dart';
part 'model/transcode_policy.dart';
part 'model/unassigned_faces_response_dto.dart';
part 'model/update_album_dto.dart';
part 'model/update_asset_dto.dart';
part 'model/update_library_dto.dart';

View file

@ -341,6 +341,8 @@ class ApiClient {
return PathEntityTypeTypeTransformer().decode(value);
case 'PathType':
return PathTypeTypeTransformer().decode(value);
case 'PeopleAssetResponseDto':
return PeopleAssetResponseDto.fromJson(value);
case 'PeopleResponseDto':
return PeopleResponseDto.fromJson(value);
case 'PeopleUpdateDto':
@ -445,6 +447,8 @@ class ApiClient {
return TranscodeHWAccelTypeTransformer().decode(value);
case 'TranscodePolicy':
return TranscodePolicyTypeTransformer().decode(value);
case 'UnassignedFacesResponseDto':
return UnassignedFacesResponseDto.fromJson(value);
case 'UpdateAlbumDto':
return UpdateAlbumDto.fromJson(value);
case 'UpdateAssetDto':

View file

@ -44,6 +44,7 @@ class AssetResponseDto {
this.tags = const [],
required this.thumbhash,
required this.type,
this.unassignedPeople = const [],
required this.updatedAt,
});
@ -104,7 +105,7 @@ class AssetResponseDto {
String ownerId;
List<PersonResponseDto> people;
List<PeopleAssetResponseDto> people;
bool resized;
@ -128,6 +129,8 @@ class AssetResponseDto {
AssetTypeEnum type;
List<UnassignedFacesResponseDto> unassignedPeople;
DateTime updatedAt;
@override
@ -163,6 +166,7 @@ class AssetResponseDto {
other.tags == tags &&
other.thumbhash == thumbhash &&
other.type == type &&
other.unassignedPeople == unassignedPeople &&
other.updatedAt == updatedAt;
@override
@ -199,10 +203,11 @@ class AssetResponseDto {
(tags.hashCode) +
(thumbhash == null ? 0 : thumbhash!.hashCode) +
(type.hashCode) +
(unassignedPeople.hashCode) +
(updatedAt.hashCode);
@override
String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, isReadOnly=$isReadOnly, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, stack=$stack, stackCount=$stackCount, stackParentId=$stackParentId, tags=$tags, thumbhash=$thumbhash, type=$type, updatedAt=$updatedAt]';
String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, isReadOnly=$isReadOnly, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, stack=$stack, stackCount=$stackCount, stackParentId=$stackParentId, tags=$tags, thumbhash=$thumbhash, type=$type, unassignedPeople=$unassignedPeople, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@ -261,6 +266,7 @@ class AssetResponseDto {
// json[r'thumbhash'] = null;
}
json[r'type'] = this.type;
json[r'unassignedPeople'] = this.unassignedPeople;
json[r'updatedAt'] = this.updatedAt.toUtc().toIso8601String();
return json;
}
@ -295,7 +301,7 @@ class AssetResponseDto {
originalPath: mapValueOfType<String>(json, r'originalPath')!,
owner: UserResponseDto.fromJson(json[r'owner']),
ownerId: mapValueOfType<String>(json, r'ownerId')!,
people: PersonResponseDto.listFromJson(json[r'people']),
people: PeopleAssetResponseDto.listFromJson(json[r'people']),
resized: mapValueOfType<bool>(json, r'resized')!,
smartInfo: SmartInfoResponseDto.fromJson(json[r'smartInfo']),
stack: AssetResponseDto.listFromJson(json[r'stack']),
@ -304,6 +310,7 @@ class AssetResponseDto {
tags: TagResponseDto.listFromJson(json[r'tags']),
thumbhash: mapValueOfType<String>(json, r'thumbhash'),
type: AssetTypeEnum.fromJson(json[r'type'])!,
unassignedPeople: UnassignedFacesResponseDto.listFromJson(json[r'unassignedPeople']),
updatedAt: mapDateTime(json, r'updatedAt', '')!,
);
}

View file

@ -0,0 +1,106 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class PeopleAssetResponseDto {
/// Returns a new [PeopleAssetResponseDto] instance.
PeopleAssetResponseDto({
required this.assetFaceId,
required this.person,
});
String assetFaceId;
PersonResponseDto person;
@override
bool operator ==(Object other) => identical(this, other) || other is PeopleAssetResponseDto &&
other.assetFaceId == assetFaceId &&
other.person == person;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(assetFaceId.hashCode) +
(person.hashCode);
@override
String toString() => 'PeopleAssetResponseDto[assetFaceId=$assetFaceId, person=$person]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'assetFaceId'] = this.assetFaceId;
json[r'person'] = this.person;
return json;
}
/// Returns a new [PeopleAssetResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static PeopleAssetResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return PeopleAssetResponseDto(
assetFaceId: mapValueOfType<String>(json, r'assetFaceId')!,
person: PersonResponseDto.fromJson(json[r'person'])!,
);
}
return null;
}
static List<PeopleAssetResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <PeopleAssetResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = PeopleAssetResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, PeopleAssetResponseDto> mapFromJson(dynamic json) {
final map = <String, PeopleAssetResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PeopleAssetResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of PeopleAssetResponseDto-objects as value to a dart map
static Map<String, List<PeopleAssetResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<PeopleAssetResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = PeopleAssetResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'assetFaceId',
'person',
};
}

View file

@ -0,0 +1,106 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class UnassignedFacesResponseDto {
/// Returns a new [UnassignedFacesResponseDto] instance.
UnassignedFacesResponseDto({
required this.assetFaceId,
required this.boudinxBox,
});
String assetFaceId;
AssetFaceBoxDto boudinxBox;
@override
bool operator ==(Object other) => identical(this, other) || other is UnassignedFacesResponseDto &&
other.assetFaceId == assetFaceId &&
other.boudinxBox == boudinxBox;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(assetFaceId.hashCode) +
(boudinxBox.hashCode);
@override
String toString() => 'UnassignedFacesResponseDto[assetFaceId=$assetFaceId, boudinxBox=$boudinxBox]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'assetFaceId'] = this.assetFaceId;
json[r'boudinxBox'] = this.boudinxBox;
return json;
}
/// Returns a new [UnassignedFacesResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UnassignedFacesResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return UnassignedFacesResponseDto(
assetFaceId: mapValueOfType<String>(json, r'assetFaceId')!,
boudinxBox: AssetFaceBoxDto.fromJson(json[r'boudinxBox'])!,
);
}
return null;
}
static List<UnassignedFacesResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UnassignedFacesResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UnassignedFacesResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, UnassignedFacesResponseDto> mapFromJson(dynamic json) {
final map = <String, UnassignedFacesResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UnassignedFacesResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of UnassignedFacesResponseDto-objects as value to a dart map
static Map<String, List<UnassignedFacesResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UnassignedFacesResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = UnassignedFacesResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'assetFaceId',
'boudinxBox',
};
}

View file

@ -127,7 +127,7 @@ void main() {
// TODO
});
// List<PersonResponseDto> people (default value: const [])
// List<PeopleAssetResponseDto> people (default value: const [])
test('to test the property `people`', () async {
// TODO
});
@ -172,6 +172,11 @@ void main() {
// TODO
});
// List<UnassignedFacesResponseDto> unassignedPeople (default value: const [])
test('to test the property `unassignedPeople`', () async {
// TODO
});
// DateTime updatedAt
test('to test the property `updatedAt`', () async {
// TODO

View file

@ -0,0 +1,32 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for PeopleAssetResponseDto
void main() {
// final instance = PeopleAssetResponseDto();
group('test PeopleAssetResponseDto', () {
// String assetFaceId
test('to test the property `assetFaceId`', () async {
// TODO
});
// PersonResponseDto person
test('to test the property `person`', () async {
// TODO
});
});
}

View file

@ -0,0 +1,32 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for UnassignedFacesResponseDto
void main() {
// final instance = UnassignedFacesResponseDto();
group('test UnassignedFacesResponseDto', () {
// String assetFaceId
test('to test the property `assetFaceId`', () async {
// TODO
});
// AssetFaceBoxDto boudinxBox
test('to test the property `boudinxBox`', () async {
// TODO
});
});
}

View file

@ -6176,7 +6176,7 @@
},
"people": {
"items": {
"$ref": "#/components/schemas/PersonResponseDto"
"$ref": "#/components/schemas/PeopleAssetResponseDto"
},
"type": "array"
},
@ -6212,6 +6212,12 @@
"type": {
"$ref": "#/components/schemas/AssetTypeEnum"
},
"unassignedPeople": {
"items": {
"$ref": "#/components/schemas/UnassignedFacesResponseDto"
},
"type": "array"
},
"updatedAt": {
"format": "date-time",
"type": "string"
@ -7480,6 +7486,21 @@
],
"type": "string"
},
"PeopleAssetResponseDto": {
"properties": {
"assetFaceId": {
"type": "string"
},
"person": {
"$ref": "#/components/schemas/PersonResponseDto"
}
},
"required": [
"assetFaceId",
"person"
],
"type": "object"
},
"PeopleResponseDto": {
"properties": {
"people": {
@ -8744,6 +8765,21 @@
],
"type": "string"
},
"UnassignedFacesResponseDto": {
"properties": {
"assetFaceId": {
"type": "string"
},
"boudinxBox": {
"$ref": "#/components/schemas/AssetFaceBoxDto"
}
},
"required": [
"assetFaceId",
"boudinxBox"
],
"type": "object"
},
"UpdateAlbumDto": {
"properties": {
"albumName": {

View file

@ -1,6 +1,11 @@
import { AssetEntity, AssetType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
import { PersonResponseDto, mapFace } from '../../person/person.dto';
import {
PeopleAssetResponseDto,
UnassignedFacesResponseDto,
mapFace,
mapUnassignedFace,
} from '../../person/person.dto';
import { TagResponseDto, mapTag } from '../../tag';
import { UserResponseDto, mapUser } from '../../user/response-dto/user-response.dto';
import { ExifResponseDto, mapExif } from './exif-response.dto';
@ -39,7 +44,8 @@ export class AssetResponseDto extends SanitizedAssetResponseDto {
exifInfo?: ExifResponseDto;
smartInfo?: SmartInfoResponseDto;
tags?: TagResponseDto[];
people?: PersonResponseDto[];
unassignedPeople?: UnassignedFacesResponseDto[];
people?: PeopleAssetResponseDto[];
/**base64 encoded sha1 hash */
checksum!: string;
stackParentId?: string | null;
@ -96,9 +102,12 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As
smartInfo: entity.smartInfo ? mapSmartInfo(entity.smartInfo) : undefined,
livePhotoVideoId: entity.livePhotoVideoId,
tags: entity.tags?.map(mapTag),
unassignedPeople: entity.faces
?.map(mapUnassignedFace)
.filter((assetFace) => assetFace) as UnassignedFacesResponseDto[],
people: entity.faces
?.map(mapFace)
.filter((person): person is PersonResponseDto => person !== null && !person.isHidden),
.filter((assetFace) => assetFace && !assetFace.person.isHidden) as PeopleAssetResponseDto[],
checksum: entity.checksum.toString('base64'),
stackParentId: entity.stackParentId,
stack: withStack ? entity.stack?.map((a) => mapAsset(a, { stripMetadata })) ?? undefined : undefined,

View file

@ -110,6 +110,16 @@ export class PersonResponseDto {
isHidden!: boolean;
}
export class PeopleAssetResponseDto {
assetFaceId!: string;
person!: PersonResponseDto;
}
export class UnassignedFacesResponseDto {
assetFaceId!: string;
boudinxBox!: AssetFaceBoxDto;
}
export class PersonStatisticsResponseDto {
@ApiProperty({ type: 'integer' })
assets!: number;
@ -135,10 +145,31 @@ export function mapPerson(person: PersonEntity): PersonResponseDto {
};
}
export function mapFace(face: AssetFaceEntity): PersonResponseDto | null {
export function mapFace(face: AssetFaceEntity): PeopleAssetResponseDto | null {
if (face.person) {
return mapPerson(face.person);
return {
assetFaceId: face.id,
person: face.person,
};
} else {
return null;
}
}
export function mapUnassignedFace(face: AssetFaceEntity): UnassignedFacesResponseDto | null {
if (face.person !== null) {
return null;
} else {
return {
assetFaceId: face.id,
boudinxBox: {
imageWidth: face.imageWidth,
imageHeight: face.imageHeight,
boundingBoxX1: face.boundingBoxX1,
boundingBoxY1: face.boundingBoxY1,
boundingBoxX2: face.boundingBoxX2,
boundingBoxY2: face.boundingBoxY2,
},
};
}
return null;
}

View file

@ -819,10 +819,10 @@ export interface AssetResponseDto {
'ownerId': string;
/**
*
* @type {Array<PersonResponseDto>}
* @type {Array<PeopleAssetResponseDto>}
* @memberof AssetResponseDto
*/
'people'?: Array<PersonResponseDto>;
'people'?: Array<PeopleAssetResponseDto>;
/**
*
* @type {boolean}
@ -871,6 +871,12 @@ export interface AssetResponseDto {
* @memberof AssetResponseDto
*/
'type': AssetTypeEnum;
/**
*
* @type {Array<UnassignedFacesResponseDto>}
* @memberof AssetResponseDto
*/
'unassignedPeople'?: Array<UnassignedFacesResponseDto>;
/**
*
* @type {string}
@ -2390,6 +2396,25 @@ export const PathType = {
export type PathType = typeof PathType[keyof typeof PathType];
/**
*
* @export
* @interface PeopleAssetResponseDto
*/
export interface PeopleAssetResponseDto {
/**
*
* @type {string}
* @memberof PeopleAssetResponseDto
*/
'assetFaceId': string;
/**
*
* @type {PersonResponseDto}
* @memberof PeopleAssetResponseDto
*/
'person': PersonResponseDto;
}
/**
*
* @export
@ -4024,6 +4049,25 @@ export const TranscodePolicy = {
export type TranscodePolicy = typeof TranscodePolicy[keyof typeof TranscodePolicy];
/**
*
* @export
* @interface UnassignedFacesResponseDto
*/
export interface UnassignedFacesResponseDto {
/**
*
* @type {string}
* @memberof UnassignedFacesResponseDto
*/
'assetFaceId': string;
/**
*
* @type {AssetFaceBoxDto}
* @memberof UnassignedFacesResponseDto
*/
'boudinxBox': AssetFaceBoxDto;
}
/**
*
* @export

View file

@ -3,7 +3,14 @@
import { locale } from '$lib/stores/preferences.store';
import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
import { getAssetFilename } from '$lib/utils/asset-utils';
import { AlbumResponseDto, AssetResponseDto, ThumbnailFormat, api } from '@api';
import {
AlbumResponseDto,
AssetResponseDto,
PersonResponseDto,
ThumbnailFormat,
UnassignedFacesResponseDto,
api,
} from '@api';
import type { LatLngTuple } from 'leaflet';
import { DateTime } from 'luxon';
import { createEventDispatcher } from 'svelte';
@ -20,6 +27,8 @@
export let asset: AssetResponseDto;
export let albums: AlbumResponseDto[] = [];
let unassignedFaces: UnassignedFacesResponseDto[] = [];
let people: PersonResponseDto[] = [];
let customFeaturePhoto = new Array<PersonToCreate | null>(asset.people?.length || 0);
@ -46,7 +55,13 @@
// Get latest description from server
if (asset.id && !api.isSharedLink && !showEditFaces) {
api.assetApi.getAssetById({ id: asset.id }).then((res) => {
people = res.data?.people || [];
if (res.data && res.data.people) {
unassignedFaces = res.data?.unassignedPeople || [];
people = (res.data?.people || [])
.map((peopleAsset) => peopleAsset.person)
.filter((person): person is PersonResponseDto => person !== null);
}
textarea.value = res.data?.exifInfo?.description || '';
});
}
@ -64,8 +79,6 @@
$: lat = latlng ? latlng[0] : undefined;
$: lng = latlng ? latlng[1] : undefined;
let people = asset.people || [];
const dispatch = createEventDispatcher();
const getMegapixel = (width: number, height: number): number | undefined => {
@ -148,10 +161,12 @@
<section class="px-4 py-4 text-sm">
<div class="grid grid-cols-2 items-center">
<h2 class="justify-self-start uppercase">People</h2>
<button class="justify-self-end" on:click={() => (showEditFaces = true)}>
<Pencil size={18} />
</button>
{#if unassignedFaces.length > 0}
<p>{`${unassignedFaces.length} face${unassignedFaces.length > 1 ? 's' : ''} available to add`}</p>
{/if}
</div>
{#if people.length > 0}
<div class="mt-4 flex flex-wrap gap-2">