Merge branch 'mobile_face' of https://github.com/ente-io/auth into mobile_face
This commit is contained in:
commit
b1cbf8526b
|
@ -261,21 +261,21 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
// Precompute face thumbnails for next suggestions, in case there are
|
// Precompute face thumbnails for next suggestions, in case there are
|
||||||
const precompute = 6;
|
const precomputeSuggestions = 6;
|
||||||
const maxComputations = 10;
|
const maxPrecomputations = 10;
|
||||||
int compCount = 0;
|
int compCount = 0;
|
||||||
|
|
||||||
if (allSuggestions.length > currentSuggestionIndex + 1) {
|
if (allSuggestions.length > currentSuggestionIndex + 1) {
|
||||||
for (final suggestion in allSuggestions.sublist(
|
for (final suggestion in allSuggestions.sublist(
|
||||||
currentSuggestionIndex + 1,
|
currentSuggestionIndex + 1,
|
||||||
min(allSuggestions.length, currentSuggestionIndex + precompute),
|
min(allSuggestions.length, currentSuggestionIndex + precomputeSuggestions),
|
||||||
)) {
|
)) {
|
||||||
final files = suggestion.filesInCluster;
|
final files = suggestion.filesInCluster;
|
||||||
final clusterID = suggestion.clusterIDToMerge;
|
final clusterID = suggestion.clusterIDToMerge;
|
||||||
for (final file in files.sublist(0, min(files.length, 8))) {
|
for (final file in files.sublist(0, min(files.length, 8))) {
|
||||||
unawaited(PersonFaceWidget.precomputeFaceCrops(file, clusterID));
|
unawaited(PersonFaceWidget.precomputeNextFaceCrops(file, clusterID));
|
||||||
compCount++;
|
compCount++;
|
||||||
if (compCount >= maxComputations) {
|
if (compCount >= maxPrecomputations) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,6 +300,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
|
||||||
child: PersonFaceWidget(
|
child: PersonFaceWidget(
|
||||||
files[start + index],
|
files[start + index],
|
||||||
clusterID: cluserId,
|
clusterID: cluserId,
|
||||||
|
useFullFile: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -19,6 +19,7 @@ class PersonFaceWidget extends StatelessWidget {
|
||||||
final EnteFile file;
|
final EnteFile file;
|
||||||
final String? personId;
|
final String? personId;
|
||||||
final int? clusterID;
|
final int? clusterID;
|
||||||
|
final bool useFullFile;
|
||||||
|
|
||||||
// PersonFaceWidget constructor checks that both personId and clusterID are not null
|
// PersonFaceWidget constructor checks that both personId and clusterID are not null
|
||||||
// and that the file is not null
|
// and that the file is not null
|
||||||
|
@ -26,6 +27,7 @@ class PersonFaceWidget extends StatelessWidget {
|
||||||
this.file, {
|
this.file, {
|
||||||
this.personId,
|
this.personId,
|
||||||
this.clusterID,
|
this.clusterID,
|
||||||
|
this.useFullFile = true,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : assert(
|
}) : assert(
|
||||||
personId != null || clusterID != null,
|
personId != null || clusterID != null,
|
||||||
|
@ -33,7 +35,7 @@ class PersonFaceWidget extends StatelessWidget {
|
||||||
),
|
),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
static Future<void> precomputeFaceCrops(file, clusterID) async {
|
static Future<void> precomputeNextFaceCrops(file, clusterID) async {
|
||||||
try {
|
try {
|
||||||
final Face? face = await FaceMLDataDB.instance.getCoverFaceForPerson(
|
final Face? face = await FaceMLDataDB.instance.getCoverFaceForPerson(
|
||||||
recentFileID: file.uploadedFileID!,
|
recentFileID: file.uploadedFileID!,
|
||||||
|
@ -176,6 +178,13 @@ class PersonFaceWidget extends StatelessWidget {
|
||||||
faceCropCache.put(face.faceID, data);
|
faceCropCache.put(face.faceID, data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
if (!useFullFile) {
|
||||||
|
final Uint8List? cachedFaceThumbnail =
|
||||||
|
faceCropThumbnailCache.get(face.faceID);
|
||||||
|
if (cachedFaceThumbnail != null) {
|
||||||
|
return cachedFaceThumbnail;
|
||||||
|
}
|
||||||
|
}
|
||||||
EnteFile? fileForFaceCrop = file;
|
EnteFile? fileForFaceCrop = file;
|
||||||
if (face.fileID != file.uploadedFileID!) {
|
if (face.fileID != file.uploadedFileID!) {
|
||||||
fileForFaceCrop =
|
fileForFaceCrop =
|
||||||
|
@ -191,12 +200,17 @@ class PersonFaceWidget extends StatelessWidget {
|
||||||
{
|
{
|
||||||
face.faceID: face.detection.box,
|
face.faceID: face.detection.box,
|
||||||
},
|
},
|
||||||
|
useFullFile: useFullFile,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final Uint8List? computedCrop = result?[face.faceID];
|
final Uint8List? computedCrop = result?[face.faceID];
|
||||||
if (computedCrop != null) {
|
if (computedCrop != null) {
|
||||||
|
if (useFullFile) {
|
||||||
faceCropCache.put(face.faceID, computedCrop);
|
faceCropCache.put(face.faceID, computedCrop);
|
||||||
faceCropCacheFile.writeAsBytes(computedCrop).ignore();
|
faceCropCacheFile.writeAsBytes(computedCrop).ignore();
|
||||||
|
} else {
|
||||||
|
faceCropThumbnailCache.put(face.faceID, computedCrop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return computedCrop;
|
return computedCrop;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import "dart:io";
|
import "dart:io" show File;
|
||||||
|
|
||||||
import "package:flutter/foundation.dart";
|
import "package:flutter/foundation.dart";
|
||||||
import "package:photos/core/cache/lru_map.dart";
|
import "package:photos/core/cache/lru_map.dart";
|
||||||
|
@ -12,13 +12,16 @@ import "package:photos/utils/thumbnail_util.dart";
|
||||||
import "package:pool/pool.dart";
|
import "package:pool/pool.dart";
|
||||||
|
|
||||||
final LRUMap<String, Uint8List?> faceCropCache = LRUMap(1000);
|
final LRUMap<String, Uint8List?> faceCropCache = LRUMap(1000);
|
||||||
|
final LRUMap<String, Uint8List?> faceCropThumbnailCache = LRUMap(1000);
|
||||||
final pool = Pool(10, timeout: const Duration(seconds: 15));
|
final pool = Pool(10, timeout: const Duration(seconds: 15));
|
||||||
Future<Map<String, Uint8List>?> getFaceCrops(
|
Future<Map<String, Uint8List>?> getFaceCrops(
|
||||||
EnteFile file,
|
EnteFile file,
|
||||||
Map<String, FaceBox> faceBoxeMap,
|
Map<String, FaceBox> faceBoxeMap, {
|
||||||
|
bool useFullFile = true,
|
||||||
|
}
|
||||||
) async {
|
) async {
|
||||||
late String? imagePath;
|
late String? imagePath;
|
||||||
if (file.fileType != FileType.video) {
|
if (useFullFile && file.fileType != FileType.video) {
|
||||||
final File? ioFile = await getFile(file);
|
final File? ioFile = await getFile(file);
|
||||||
if (ioFile == null) {
|
if (ioFile == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Reference in a new issue