Skip to content

Commit

Permalink
feat(server): Import face regions from metadata (#6455)
Browse files Browse the repository at this point in the history
* feat: faces-from-metadata - Import face regions from metadata

Implements #1692.
- OpenAPI spec changes to accomodate metadata face import configs. New settings to enable the feature.
- Updates admin UI compoments
- ML faces detection/recognition & Exif/Metadata faces compatibility

Signed-off-by: BugFest <bugfest.dev@pm.me>

* chore(web): remove unused file confirm-enable-import-faces

* chore(web): format metadata-settings

* fix(server): faces-from-metadata tests and format

* fix(server): code refinements, nullable face asset sourceType

* fix(server): Add RegionInfo to ImmichTags interface

* fix(server): deleteAllFaces sourceType param can be undefined

* fix(server): exiftool-vendored 27.0.0 moves readArgs into ExifToolOptions

* fix(server): rename isImportFacesFromMetadataEnabled to isFaceImportEnabled

* fix(server): simplify sourceType conditional

* fix(server): small fixes

* fix(server): handling sourceType

* fix(server): sourceType enum

* fix(server): refactor metadata applyTaggedFaces

* fix(server): create/update signature changes

* fix(server): reduce computational cost of Person.getManyByName

* fix(server): use faceList instead of faceSet

* fix(server): Skip regions without Name defined

* fix(mobile): Update open-api (face assets feature changes)

* fix(server): Face-Person reconciliation with map/index

* fix(server): tags.RegionInfo.AppliedToDimensions must be defined to process face-region

* fix(server): fix shared-link.service.ts format

* fix(mobile): Update open-api after branch update

* simplify

* fix(server): minor fixes

* fix(server): person create/update methods type enforcement

* fix(server): style fixes

* fix(server): remove unused metadata code

* fix(server): metadata faces unit tests

* fix(server): top level config metadata category

* fix(server): rename upsertFaces to replaceFaces

* fix(server): remove sourceType when unnecessary

* fix(server): sourceType as ENUM

* fix(server): format fixes

* fix(server): fix tests after sourceType ENUM change

* fix(server): remove unnecessary JobItem cast

* fix(server): fix asset enum imports

* fix(open-api): add metadata config

* fix(mobile): update open-api after metadata open-api spec changes

* fix(web): update web/api metadata config

* fix(server): remove duplicated sourceType def

* fix(server): update generated sql queries

* fix(e2e): tests for metadata face import feature

* fix(web): Fix check:typescript

* fix(e2e): update subproject ref

* fix(server): revert format changes to pass format checks after ci

* fix(mobile): update open-api

* fix(server,movile,open-api,mobile): sourceType as DB data type

* fix(e2e): upload face asset after enabling metadata face import

* fix(web): simplify metadata admin settings and i18n keys

* Update person.repository.ts

Co-authored-by: Jason Rasmussen <jason@rasm.me>

* fix(server): asset_faces.sourceType column not nullable

* fix(server): simplified syntax

* fix(e2e): use SDK for everything except the endpoint being tested

* fix(e2e): fix test format

* chore: clean up

* chore: clean up

* chore: update e2e/test-assets

---------

Signed-off-by: BugFest <bugfest.dev@pm.me>
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
  • Loading branch information
3 people authored Sep 4, 2024
1 parent 7204126 commit 77e6a6d
Show file tree
Hide file tree
Showing 48 changed files with 1,058 additions and 96 deletions.
64 changes: 64 additions & 0 deletions e2e/src/api/specs/asset.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
LoginResponseDto,
SharedLinkType,
getAssetInfo,
getConfig,
getMyUser,
updateConfig,
} from '@immich/sdk';
import { exiftool } from 'exiftool-vendored';
import { DateTime } from 'luxon';
Expand Down Expand Up @@ -43,6 +45,9 @@ const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

const locationAssetFilepath = `${testAssetDir}/metadata/gps-position/thompson-springs.jpg`;
const ratingAssetFilepath = `${testAssetDir}/metadata/rating/mongolels.jpg`;
const facesAssetFilepath = `${testAssetDir}/metadata/faces/portrait.jpg`;

const getSystemConfig = (accessToken: string) => getConfig({ headers: asBearerAuth(accessToken) });

const readTags = async (bytes: Buffer, filename: string) => {
const filepath = join(tempDir, filename);
Expand Down Expand Up @@ -71,6 +76,7 @@ describe('/asset', () => {
let user2Assets: AssetMediaResponseDto[];
let locationAsset: AssetMediaResponseDto;
let ratingAsset: AssetMediaResponseDto;
let facesAsset: AssetMediaResponseDto;

const setupTests = async () => {
await utils.resetDatabase();
Expand Down Expand Up @@ -224,6 +230,64 @@ describe('/asset', () => {
});
});

it('should get the asset faces', async () => {
const config = await getSystemConfig(admin.accessToken);
config.metadata.faces.import = true;
await updateConfig({ systemConfigDto: config }, { headers: asBearerAuth(admin.accessToken) });

// asset faces
facesAsset = await utils.createAsset(admin.accessToken, {
assetData: {
filename: 'portrait.jpg',
bytes: await readFile(facesAssetFilepath),
},
});

await utils.waitForWebsocketEvent({ event: 'assetUpload', id: facesAsset.id });

const { status, body } = await request(app)
.get(`/assets/${facesAsset.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body.id).toEqual(facesAsset.id);
expect(body.people).toMatchObject([
{
name: 'Marie Curie',
birthDate: null,
thumbnailPath: '',
isHidden: false,
faces: [
{
imageHeight: 700,
imageWidth: 840,
boundingBoxX1: 261,
boundingBoxX2: 356,
boundingBoxY1: 146,
boundingBoxY2: 284,
sourceType: 'exif',
},
],
},
{
name: 'Pierre Curie',
birthDate: null,
thumbnailPath: '',
isHidden: false,
faces: [
{
imageHeight: 700,
imageWidth: 840,
boundingBoxX1: 536,
boundingBoxX2: 618,
boundingBoxY1: 83,
boundingBoxY2: 252,
sourceType: 'exif',
},
],
},
]);
});

it('should work with a shared link', async () => {
const sharedLink = await utils.createSharedLink(user1.accessToken, {
type: SharedLinkType.Individual,
Expand Down
1 change: 1 addition & 0 deletions e2e/src/api/specs/server-info.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ describe('/server-info', () => {
configFile: false,
duplicateDetection: false,
facialRecognition: false,
importFaces: false,
map: true,
reverseGeocoding: true,
oauth: false,
Expand Down
1 change: 1 addition & 0 deletions e2e/src/api/specs/server.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ describe('/server', () => {
facialRecognition: false,
map: true,
reverseGeocoding: true,
importFaces: false,
oauth: false,
oauthAutoLaunch: false,
passwordLogin: true,
Expand Down
2 changes: 1 addition & 1 deletion e2e/test-assets
3 changes: 3 additions & 0 deletions mobile/openapi/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions mobile/openapi/lib/api.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions mobile/openapi/lib/api_client.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions mobile/openapi/lib/api_helper.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 20 additions & 3 deletions mobile/openapi/lib/model/asset_face_response_dto.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion mobile/openapi/lib/model/server_features_dto.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 77e6a6d

Please sign in to comment.