mirror of
https://github.com/xuthus83/pigallery2.git
synced 2024-11-03 21:04:03 +08:00
improving faces sample photo selection
This commit is contained in:
parent
46aa9710ee
commit
da6c77678f
@ -45,10 +45,10 @@ export class PersonMWs {
|
||||
}
|
||||
try {
|
||||
const persons = (req.resultPipe as PersonWithPhoto[]);
|
||||
for (let i = 0; i < persons.length; i++) {
|
||||
persons[i].samplePhoto = await ObjectManagers.getInstance()
|
||||
.PersonManager.getSamplePhoto(persons[i].name);
|
||||
}
|
||||
const photoMap = await ObjectManagers.getInstance()
|
||||
.PersonManager.getSamplePhotos(persons.map(p => p.name));
|
||||
persons.forEach(p => p.samplePhoto = photoMap[p.name]);
|
||||
|
||||
req.resultPipe = persons;
|
||||
return next();
|
||||
|
||||
|
@ -10,6 +10,7 @@ import {ThumbnailSourceType} from '../../model/threading/PhotoWorker';
|
||||
import {MediaDTO} from '../../../common/entities/MediaDTO';
|
||||
import {PersonWithPhoto} from '../PersonMWs';
|
||||
import {PhotoProcessing} from '../../model/fileprocessing/PhotoProcessing';
|
||||
import {PhotoDTO} from '../../../common/entities/PhotoDTO';
|
||||
|
||||
|
||||
export class ThumbnailGeneratorMWs {
|
||||
@ -75,12 +76,14 @@ export class ThumbnailGeneratorMWs {
|
||||
if (!req.resultPipe) {
|
||||
return next();
|
||||
}
|
||||
const photo: PhotoDTO = req.resultPipe;
|
||||
try {
|
||||
req.resultPipe = await PhotoProcessing.generatePersonThumbnail(req.resultPipe);
|
||||
req.resultPipe = await PhotoProcessing.generatePersonThumbnail(photo);
|
||||
return next();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return next(new ErrorDTO(ErrorCodes.THUMBNAIL_GENERATION_ERROR,
|
||||
'Error during generating face thumbnail: ' + req.resultPipe, error.toString()));
|
||||
'Error during generating face thumbnail: ' + photo.name, error.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ export interface IPersonManager {
|
||||
|
||||
getSamplePhoto(name: string): Promise<PhotoDTO>;
|
||||
|
||||
getSamplePhotos(names: string[]): Promise<{ [key: string]: PhotoDTO }>;
|
||||
|
||||
get(name: string): Promise<PersonEntry>;
|
||||
|
||||
saveAll(names: string[]): Promise<void>;
|
||||
|
@ -6,6 +6,7 @@ import {MediaEntity} from './enitites/MediaEntity';
|
||||
import {FaceRegionEntry} from './enitites/FaceRegionEntry';
|
||||
import {PersonDTO} from '../../../../common/entities/PersonDTO';
|
||||
import {Utils} from '../../../../common/Utils';
|
||||
import {SelectQueryBuilder} from 'typeorm';
|
||||
|
||||
const LOG_TAG = '[PersonManager]';
|
||||
|
||||
@ -35,28 +36,39 @@ export class PersonManager implements IPersonManager {
|
||||
}
|
||||
|
||||
async getSamplePhoto(name: string): Promise<PhotoDTO> {
|
||||
if (!this.samplePhotos[name]) {
|
||||
return (await this.getSamplePhotos([name]))[name];
|
||||
}
|
||||
|
||||
|
||||
async getSamplePhotos(names: string[]): Promise<{ [key: string]: PhotoDTO }> {
|
||||
const hasAll = names.reduce((prev, name) => prev && !!this.samplePhotos[name], true);
|
||||
if (!hasAll) {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
const rawAndEntities = await connection.getRepository(MediaEntity).createQueryBuilder('media')
|
||||
.limit(1)
|
||||
.leftJoinAndSelect('media.directory', 'directory')
|
||||
const rawAndEntities = await (connection
|
||||
.getRepository(MediaEntity)
|
||||
.createQueryBuilder('media') as SelectQueryBuilder<MediaEntity>)
|
||||
.select(['media.name', 'media.id', 'person.name', 'directory.name',
|
||||
'directory.path', 'media.metadata.size.width', 'media.metadata.size.height'])
|
||||
.leftJoin('media.directory', 'directory')
|
||||
.leftJoinAndSelect('media.metadata.faces', 'faces')
|
||||
.leftJoin('faces.person', 'person')
|
||||
.where('person.name LIKE :name COLLATE utf8_general_ci', {name: name}).getRawAndEntities();
|
||||
.groupBy('person.name')
|
||||
.orWhere(`person.name IN (:...names) COLLATE utf8_general_ci`, {names: names}).getRawAndEntities();
|
||||
|
||||
if (rawAndEntities.entities.length === 0) {
|
||||
return null;
|
||||
|
||||
for (let i = 0; i < rawAndEntities.raw.length; ++i) {
|
||||
this.samplePhotos[rawAndEntities.raw[i].person_name] =
|
||||
Utils.clone(rawAndEntities.entities.find(m => m.name === rawAndEntities.raw[i].media_name));
|
||||
this.samplePhotos[rawAndEntities.raw[i].person_name].metadata.faces = [FaceRegionEntry.fromRawToDTO(rawAndEntities.raw[i])];
|
||||
}
|
||||
const media: PhotoDTO = Utils.clone(rawAndEntities.entities[0]);
|
||||
|
||||
media.metadata.faces = [FaceRegionEntry.fromRawToDTO(rawAndEntities.raw[0])];
|
||||
|
||||
this.samplePhotos[name] = media;
|
||||
}
|
||||
|
||||
return this.samplePhotos[name];
|
||||
const photoMap: { [key: string]: PhotoDTO } = {};
|
||||
names.forEach(n => photoMap[n] = this.samplePhotos[n]);
|
||||
return photoMap;
|
||||
}
|
||||
|
||||
|
||||
async loadAll(): Promise<void> {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
const personRepository = connection.getRepository(PersonEntry);
|
||||
|
@ -6,6 +6,7 @@ import {PersonDTO} from '../../../../../common/entities/PersonDTO';
|
||||
@Entity()
|
||||
@Unique(['name'])
|
||||
export class PersonEntry implements PersonDTO {
|
||||
|
||||
@Index()
|
||||
@PrimaryGeneratedColumn({unsigned: true})
|
||||
id: number;
|
||||
|
@ -1,4 +1,14 @@
|
||||
import {expect} from 'chai';
|
||||
import {PersonManager} from '../../../../../src/backend/model/database/sql/PersonManager';
|
||||
import {SQLTestHelper} from '../../../SQLTestHelper';
|
||||
import {TestHelper} from './TestHelper';
|
||||
import {PhotoDTO} from '../../../../../src/common/entities/PhotoDTO';
|
||||
import {PersonEntry} from '../../../../../src/backend/model/database/sql/enitites/PersonEntry';
|
||||
import {FaceRegionEntry} from '../../../../../src/backend/model/database/sql/enitites/FaceRegionEntry';
|
||||
import {SQLConnection} from '../../../../../src/backend/model/database/sql/SQLConnection';
|
||||
import {PhotoEntity} from '../../../../../src/backend/model/database/sql/enitites/PhotoEntity';
|
||||
import {DirectoryEntity} from '../../../../../src/backend/model/database/sql/enitites/DirectoryEntity';
|
||||
import {VideoEntity} from '../../../../../src/backend/model/database/sql/enitites/VideoEntity';
|
||||
|
||||
|
||||
// to help WebStorm to handle the test cases
|
||||
@ -7,7 +17,78 @@ declare const after: any;
|
||||
declare const it: any;
|
||||
|
||||
|
||||
describe('PersonManager', () => {
|
||||
describe = SQLTestHelper.describe;
|
||||
|
||||
describe('PersonManager', (sqlHelper: SQLTestHelper) => {
|
||||
|
||||
|
||||
const dir = TestHelper.getDirectoryEntry();
|
||||
const p = TestHelper.getPhotoEntry1(dir);
|
||||
const p2 = TestHelper.getPhotoEntry2(dir);
|
||||
const p_faceLess = TestHelper.getPhotoEntry2(dir);
|
||||
delete p_faceLess.metadata.faces;
|
||||
p_faceLess.name = 'fl';
|
||||
const v = TestHelper.getVideoEntry1(dir);
|
||||
|
||||
const setUpSqlDB = async () => {
|
||||
await sqlHelper.initDB();
|
||||
|
||||
const savePhoto = async (photo: PhotoDTO) => {
|
||||
const savedPhoto = await pr.save(photo);
|
||||
if (!photo.metadata.faces) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < photo.metadata.faces.length; i++) {
|
||||
const face = photo.metadata.faces[i];
|
||||
const person = await conn.getRepository(PersonEntry).save({name: face.name});
|
||||
await conn.getRepository(FaceRegionEntry).save({box: face.box, person: person, media: savedPhoto});
|
||||
}
|
||||
};
|
||||
const conn = await SQLConnection.getConnection();
|
||||
|
||||
const pr = conn.getRepository(PhotoEntity);
|
||||
|
||||
await conn.getRepository(DirectoryEntity).save(p.directory);
|
||||
await savePhoto(p);
|
||||
await savePhoto(p2);
|
||||
await savePhoto(p_faceLess);
|
||||
|
||||
await conn.getRepository(VideoEntity).save(v);
|
||||
|
||||
await SQLConnection.close();
|
||||
};
|
||||
|
||||
|
||||
beforeEach(async () => {
|
||||
await setUpSqlDB();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await sqlHelper.clearDB();
|
||||
});
|
||||
|
||||
|
||||
it('should get sample photos', async () => {
|
||||
const pm = new PersonManager();
|
||||
const map: { [key: string]: PhotoDTO } = {};
|
||||
p.metadata.faces.forEach(face => {
|
||||
map[face.name] = <any>{
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
directory: {
|
||||
path: p.directory.path,
|
||||
name: p.directory.name,
|
||||
},
|
||||
metadata: {
|
||||
size: p.metadata.size,
|
||||
faces: [p.metadata.faces.find(f => f.name === face.name)]
|
||||
},
|
||||
readyIcon: false,
|
||||
readyThumbnails: []
|
||||
};
|
||||
|
||||
});
|
||||
expect(await pm.getSamplePhotos(p.metadata.faces.map(f => f.name))).to.deep.equal(map);
|
||||
});
|
||||
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user