From b45dfa9cfc58474e5fb0c96de6fff4bafc701f9e Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 12:58:10 +0530 Subject: [PATCH 1/9] [mob][photos] Show error on UI in debugMode --- .../ui/viewer/people/add_person_action_sheet.dart | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mobile/lib/ui/viewer/people/add_person_action_sheet.dart b/mobile/lib/ui/viewer/people/add_person_action_sheet.dart index a0f9f76a70..83a19ac316 100644 --- a/mobile/lib/ui/viewer/people/add_person_action_sheet.dart +++ b/mobile/lib/ui/viewer/people/add_person_action_sheet.dart @@ -188,7 +188,16 @@ class _PersonActionSheetState extends State { if (snapshot.hasError) { log("Error: ${snapshot.error} ${snapshot.stackTrace}}"); //Need to show an error on the UI here - return const SizedBox.shrink(); + if (kDebugMode) { + return Column( + children: [ + Text('${snapshot.error}'), + Text('${snapshot.stackTrace}'), + ], + ); + } else { + return const SizedBox.shrink(); + } } else if (snapshot.hasData) { final persons = snapshot.data!; final searchResults = _searchQuery.isNotEmpty @@ -320,7 +329,8 @@ class _PersonActionSheetState extends State { final files = clustersToFiles.values.expand((e) => e).toList(); if (files.isEmpty) { debugPrint( - "Person ${kDebugMode ? person.data.name : person.remoteID} has no files"); + "Person ${kDebugMode ? person.data.name : person.remoteID} has no files", + ); continue; } personAndFileID.add((person, files.first)); From 9a8c4d9cfd99ac128d007599258ccb59e847a1b3 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 15:06:22 +0530 Subject: [PATCH 2/9] [mob][photos] Calculate cosine distance inline --- .../face_clustering/cosine_distance.dart | 8 +-- .../face_clustering_service.dart | 22 ++++---- .../face_ml/feedback/cluster_feedback.dart | 17 +++--- .../lib/ui/viewer/people/cluster_app_bar.dart | 55 ------------------- 4 files changed, 21 insertions(+), 81 deletions(-) diff --git a/mobile/lib/services/machine_learning/face_ml/face_clustering/cosine_distance.dart b/mobile/lib/services/machine_learning/face_ml/face_clustering/cosine_distance.dart index 0611a1d838..c081ef4520 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_clustering/cosine_distance.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_clustering/cosine_distance.dart @@ -5,17 +5,15 @@ import "package:ml_linalg/linalg.dart"; /// Calculates the cosine distance between two embeddings/vectors using SIMD from ml_linalg /// /// WARNING: This assumes both vectors are already normalized! +/// WARNING: For even more performance, consider calculating the logic below inline! +@pragma("vm:prefer-inline") double cosineDistanceSIMD(Vector vector1, Vector vector2) { - if (vector1.length != vector2.length) { - throw ArgumentError('Vectors must be the same length'); - } - return 1 - vector1.dot(vector2); } /// Calculates the cosine distance between two embeddings/vectors using SIMD from ml_linalg /// -/// WARNING: Only use when you're not sure if vectors are normalized. If you're sure they are, use [cosineDistanceSIMD] instead for better performance. +/// WARNING: Only use when you're not sure if vectors are normalized. If you're sure they are, use [cosineDistanceSIMD] instead for better performance, or inline for best performance. double cosineDistanceSIMDSafe(Vector vector1, Vector vector2) { if (vector1.length != vector2.length) { throw ArgumentError('Vectors must be the same length'); diff --git a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart index 1a635b0f07..8407698640 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart @@ -565,10 +565,10 @@ class FaceClusteringService { for (int j = i - 1; j >= 0; j--) { late double distance; if (sortedFaceInfos[i].vEmbedding != null) { - distance = cosineDistanceSIMD( - sortedFaceInfos[i].vEmbedding!, - sortedFaceInfos[j].vEmbedding!, - ); + distance = 1 - + sortedFaceInfos[i] + .vEmbedding! + .dot(sortedFaceInfos[j].vEmbedding!); } else { distance = cosineDistForNormVectors( sortedFaceInfos[i].embedding!, @@ -814,10 +814,8 @@ class FaceClusteringService { double closestDistance = double.infinity; for (int j = 0; j < totalFaces; j++) { if (i == j) continue; - final double distance = cosineDistanceSIMD( - faceInfos[i].vEmbedding!, - faceInfos[j].vEmbedding!, - ); + final double distance = + 1 - faceInfos[i].vEmbedding!.dot(faceInfos[j].vEmbedding!); if (distance < closestDistance) { closestDistance = distance; closestIdx = j; @@ -870,10 +868,10 @@ class FaceClusteringService { for (int i = 0; i < clusterIds.length; i++) { for (int j = 0; j < clusterIds.length; j++) { if (i == j) continue; - final double newDistance = cosineDistanceSIMD( - clusterIdToMeanEmbeddingAndWeight[clusterIds[i]]!.$1, - clusterIdToMeanEmbeddingAndWeight[clusterIds[j]]!.$1, - ); + final double newDistance = 1 - + clusterIdToMeanEmbeddingAndWeight[clusterIds[i]]! + .$1 + .dot(clusterIdToMeanEmbeddingAndWeight[clusterIds[j]]!.$1); if (newDistance < distance) { distance = newDistance; clusterIDsToMerge = (clusterIds[i], clusterIds[j]); diff --git a/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart b/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart index 8567e88685..b354719f9a 100644 --- a/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart +++ b/mobile/lib/services/machine_learning/face_ml/feedback/cluster_feedback.dart @@ -13,7 +13,6 @@ import "package:photos/face/db.dart"; import "package:photos/face/model/person.dart"; import "package:photos/generated/protos/ente/common/vector.pb.dart"; import "package:photos/models/file/file.dart"; -import "package:photos/services/machine_learning/face_ml/face_clustering/cosine_distance.dart"; import "package:photos/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart"; import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; import "package:photos/services/machine_learning/face_ml/face_ml_result.dart"; @@ -434,7 +433,9 @@ class ClusterFeedbackService { distanceThreshold: 0.22, ); - if (clusterResult == null || clusterResult.newClusterIdToFaceIds == null || clusterResult.isEmpty) { + if (clusterResult == null || + clusterResult.newClusterIdToFaceIds == null || + clusterResult.isEmpty) { _logger.warning('No clusters found or something went wrong'); return ClusteringResult(newFaceIdToCluster: {}); } @@ -537,8 +538,7 @@ class ClusterFeedbackService { EVector.fromBuffer(clusterSummary.$1).values, dtype: DType.float32, ); - final bigClustersMeanDistance = - cosineDistanceSIMD(biggestMean, currentMean); + final bigClustersMeanDistance = 1 - biggestMean.dot(currentMean); _logger.info( "Mean distance between biggest cluster and current cluster: $bigClustersMeanDistance", ); @@ -595,8 +595,7 @@ class ClusterFeedbackService { final List trueDistances = []; for (final biggestEmbedding in biggestSampledEmbeddings) { for (final currentEmbedding in currentSampledEmbeddings) { - distances - .add(cosineDistanceSIMD(biggestEmbedding, currentEmbedding)); + distances.add(1 - biggestEmbedding.dot(currentEmbedding)); trueDistances.add( biggestEmbedding.distanceTo( currentEmbedding, @@ -789,7 +788,7 @@ class ClusterFeedbackService { final List distances = []; for (final otherEmbedding in sampledOtherEmbeddings) { for (final embedding in sampledEmbeddings) { - distances.add(cosineDistanceSIMD(embedding, otherEmbedding)); + distances.add(1 - embedding.dot(otherEmbedding)); } } distances.sort(); @@ -1086,7 +1085,7 @@ class ClusterFeedbackService { final fileIdToDistanceMap = {}; for (final entry in faceIdToVectorMap.entries) { fileIdToDistanceMap[getFileIdFromFaceId(entry.key)] = - cosineDistanceSIMD(personAvg, entry.value); + 1 - personAvg.dot(entry.value); } w?.log('calculated distances for cluster $clusterID'); suggestion.filesInCluster.sort((b, a) { @@ -1141,7 +1140,7 @@ List<(int, double)> _calcSuggestionsMean(Map args) { continue; } final Vector avg = clusterAvg[personCluster]!; - final distance = cosineDistanceSIMD(avg, otherAvg); + final distance = 1 - avg.dot(otherAvg); comparisons++; if (distance < maxClusterDistance) { if (minDistance == null || distance < minDistance) { diff --git a/mobile/lib/ui/viewer/people/cluster_app_bar.dart b/mobile/lib/ui/viewer/people/cluster_app_bar.dart index 83ebe54284..8b95d4247e 100644 --- a/mobile/lib/ui/viewer/people/cluster_app_bar.dart +++ b/mobile/lib/ui/viewer/people/cluster_app_bar.dart @@ -3,7 +3,6 @@ import 'dart:async'; import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; -import "package:ml_linalg/linalg.dart"; import 'package:photos/core/configuration.dart'; import 'package:photos/core/event_bus.dart'; import "package:photos/db/files_db.dart"; @@ -11,12 +10,10 @@ import "package:photos/events/people_changed_event.dart"; import 'package:photos/events/subscription_purchased_event.dart'; import "package:photos/face/db.dart"; import "package:photos/face/model/person.dart"; -import "package:photos/generated/protos/ente/common/vector.pb.dart"; import "package:photos/models/file/file.dart"; import 'package:photos/models/gallery_type.dart'; import 'package:photos/models/selected_files.dart'; import 'package:photos/services/collections_service.dart'; -import "package:photos/services/machine_learning/face_ml/face_clustering/cosine_distance.dart"; import "package:photos/services/machine_learning/face_ml/face_ml_result.dart"; import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; import 'package:photos/ui/actions/collection/collection_sharing_actions.dart'; @@ -160,58 +157,6 @@ class _AppBarWidgetState extends State { return actions; } - @Deprecated( - 'Used for debugging an issue with conflicts on cluster IDs, resolved now', - ) - Future _validateCluster(BuildContext context) async { - _logger.info('_validateCluster called'); - final faceMlDb = FaceMLDataDB.instance; - - final faceIDs = await faceMlDb.getFaceIDsForCluster(widget.clusterID); - final fileIDs = faceIDs.map((e) => getFileIdFromFaceId(e)).toList(); - - final embeddingsBlobs = await faceMlDb.getFaceEmbeddingMapForFile(fileIDs); - embeddingsBlobs.removeWhere((key, value) => !faceIDs.contains(key)); - final embeddings = embeddingsBlobs - .map((key, value) => MapEntry(key, EVector.fromBuffer(value).values)); - - for (final MapEntry> embedding in embeddings.entries) { - double closestDistance = double.infinity; - double closestDistance32 = double.infinity; - double closestDistance64 = double.infinity; - String? closestFaceID; - for (final MapEntry> otherEmbedding - in embeddings.entries) { - if (embedding.key == otherEmbedding.key) { - continue; - } - final distance64 = cosineDistanceSIMD( - Vector.fromList(embedding.value, dtype: DType.float64), - Vector.fromList(otherEmbedding.value, dtype: DType.float64), - ); - final distance32 = cosineDistanceSIMD( - Vector.fromList(embedding.value, dtype: DType.float32), - Vector.fromList(otherEmbedding.value, dtype: DType.float32), - ); - final distance = cosineDistForNormVectors( - embedding.value, - otherEmbedding.value, - ); - if (distance < closestDistance) { - closestDistance = distance; - closestDistance32 = distance32; - closestDistance64 = distance64; - closestFaceID = otherEmbedding.key; - } - } - if (closestDistance > 0.3) { - _logger.severe( - "Face ${embedding.key} is similar to $closestFaceID with distance $closestDistance, and float32 distance $closestDistance32, and float64 distance $closestDistance64", - ); - } - } - } - Future _onIgnoredClusterClicked(BuildContext context) async { await showChoiceDialog( context, From 89a47026d95eb8bc556cd720fe3ec76f38ce1689 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 15:18:44 +0530 Subject: [PATCH 3/9] [mob][photos] Clustering cleanup --- .../face_clustering_service.dart | 120 +----------------- 1 file changed, 2 insertions(+), 118 deletions(-) diff --git a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart index 8407698640..2a35cd0dac 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart @@ -10,11 +10,9 @@ import "package:logging/logging.dart"; import "package:ml_linalg/dtype.dart"; import "package:ml_linalg/vector.dart"; import "package:photos/generated/protos/ente/common/vector.pb.dart"; -import 'package:photos/services/machine_learning/face_ml/face_clustering/cosine_distance.dart'; import "package:photos/services/machine_learning/face_ml/face_clustering/face_info_for_clustering.dart"; import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; import "package:photos/services/machine_learning/face_ml/face_ml_result.dart"; -import "package:simple_cluster/simple_cluster.dart"; import "package:synchronized/synchronized.dart"; class FaceInfo { @@ -22,7 +20,6 @@ class FaceInfo { final double? faceScore; final double? blurValue; final bool? badFace; - final List? embedding; final Vector? vEmbedding; int? clusterId; String? closestFaceId; @@ -33,14 +30,13 @@ class FaceInfo { this.faceScore, this.blurValue, this.badFace, - this.embedding, this.vEmbedding, this.clusterId, this.fileCreationTime, }); } -enum ClusterOperation { linearIncrementalClustering, dbscanClustering } +enum ClusterOperation { linearIncrementalClustering } class ClusteringResult { final Map newFaceIdToCluster; @@ -129,10 +125,6 @@ class FaceClusteringService { final result = FaceClusteringService.runLinearClustering(args); sendPort.send(result); break; - case ClusterOperation.dbscanClustering: - final result = FaceClusteringService._runDbscanClustering(args); - sendPort.send(result); - break; } } catch (e, stackTrace) { sendPort @@ -203,8 +195,6 @@ class FaceClusteringService { /// Runs the clustering algorithm [runLinearClustering] on the given [input], in an isolate. /// /// Returns the clustering result, which is a list of clusters, where each cluster is a list of indices of the dataset. - /// - /// WARNING: Make sure to always input data in the same ordering, otherwise the clustering can less less deterministic. Future predictLinear( Set input, { Map? fileIDToCreationTime, @@ -401,55 +391,6 @@ class FaceClusteringService { } } - Future>> predictDbscan( - Map input, { - Map? fileIDToCreationTime, - double eps = 0.3, - int minPts = 5, - }) async { - if (input.isEmpty) { - _logger.warning( - "DBSCAN Clustering dataset of embeddings is empty, returning empty list.", - ); - return []; - } - if (isRunning) { - _logger.warning( - "DBSCAN Clustering is already running, returning empty list.", - ); - return []; - } - - isRunning = true; - - // Clustering inside the isolate - _logger.info( - "Start DBSCAN clustering on ${input.length} embeddings inside computer isolate", - ); - final stopwatchClustering = Stopwatch()..start(); - // final Map faceIdToCluster = - // await _runLinearClusteringInComputer(input); - final List> clusterFaceIDs = await _runInIsolate( - ( - ClusterOperation.dbscanClustering, - { - 'input': input, - 'fileIDToCreationTime': fileIDToCreationTime, - 'eps': eps, - 'minPts': minPts, - } - ), - ); - // return _runLinearClusteringInComputer(input); - _logger.info( - 'DBSCAN Clustering executed in ${stopwatchClustering.elapsed.inSeconds} seconds', - ); - - isRunning = false; - - return clusterFaceIDs; - } - static ClusteringResult? runLinearClustering(Map args) { // final input = args['input'] as Map; final input = args['input'] as Set; @@ -563,18 +504,10 @@ class FaceClusteringService { log("[ClusterIsolate] ${DateTime.now()} Processed ${offset != null ? i + offset : i} faces"); } for (int j = i - 1; j >= 0; j--) { - late double distance; - if (sortedFaceInfos[i].vEmbedding != null) { - distance = 1 - + final double distance = 1 - sortedFaceInfos[i] .vEmbedding! .dot(sortedFaceInfos[j].vEmbedding!); - } else { - distance = cosineDistForNormVectors( - sortedFaceInfos[i].embedding!, - sortedFaceInfos[j].embedding!, - ); - } if (distance < closestDistance) { if (sortedFaceInfos[j].badFace! && distance > conservativeDistanceThreshold) { @@ -942,55 +875,6 @@ class FaceClusteringService { newClusterIdToFaceIds: clusterIdToFaceIds, ); } - - static List> _runDbscanClustering(Map args) { - final input = args['input'] as Map; - final fileIDToCreationTime = args['fileIDToCreationTime'] as Map?; - final eps = args['eps'] as double; - final minPts = args['minPts'] as int; - - log( - "[ClusterIsolate] ${DateTime.now()} Copied to isolate ${input.length} faces", - ); - - final DBSCAN dbscan = DBSCAN( - epsilon: eps, - minPoints: minPts, - distanceMeasure: cosineDistForNormVectors, - ); - - // Organize everything into a list of FaceInfo objects - final List faceInfos = []; - for (final entry in input.entries) { - faceInfos.add( - FaceInfo( - faceID: entry.key, - embedding: EVector.fromBuffer(entry.value).values, - fileCreationTime: - fileIDToCreationTime?[getFileIdFromFaceId(entry.key)], - ), - ); - } - - if (fileIDToCreationTime != null) { - _sortFaceInfosOnCreationTime(faceInfos); - } - - // Get the embeddings - final List> embeddings = - faceInfos.map((faceInfo) => faceInfo.embedding!).toList(); - - // Run the DBSCAN clustering - final List> clusterOutput = dbscan.run(embeddings); - // final List> clusteredFaceInfos = clusterOutput - // .map((cluster) => cluster.map((idx) => faceInfos[idx]).toList()) - // .toList(); - final List> clusteredFaceIDs = clusterOutput - .map((cluster) => cluster.map((idx) => faceInfos[idx].faceID).toList()) - .toList(); - - return clusteredFaceIDs; - } } /// Sort the faceInfos based on fileCreationTime, in descending order, so newest faces are first From 50968fd6a112be0d9942a3241f15bfab1c0e7a85 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 15:20:44 +0530 Subject: [PATCH 4/9] [mob][photos] Comment --- .../face_ml/face_clustering/face_clustering_service.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart index 2a35cd0dac..f826cc7855 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart @@ -503,6 +503,7 @@ class FaceClusteringService { if (i % 250 == 0) { log("[ClusterIsolate] ${DateTime.now()} Processed ${offset != null ? i + offset : i} faces"); } + // WARNING: The loop below is now O(n^2) so be very careful with anything you put in there! for (int j = i - 1; j >= 0; j--) { final double distance = 1 - sortedFaceInfos[i] From b64077d5e7a651a23fa817eaa7e42ba06c40ab18 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 15:41:20 +0530 Subject: [PATCH 5/9] [mob][photos] Skip cluster bucket if everything already has a clusterID --- .../face_clustering/face_clustering_service.dart | 4 +--- .../machine_learning/face_ml/face_ml_service.dart | 12 ++++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart index f826cc7855..310deb964a 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart @@ -506,9 +506,7 @@ class FaceClusteringService { // WARNING: The loop below is now O(n^2) so be very careful with anything you put in there! for (int j = i - 1; j >= 0; j--) { final double distance = 1 - - sortedFaceInfos[i] - .vEmbedding! - .dot(sortedFaceInfos[j].vEmbedding!); + sortedFaceInfos[i].vEmbedding!.dot(sortedFaceInfos[j].vEmbedding!); if (distance < closestDistance) { if (sortedFaceInfos[j].badFace! && distance > conservativeDistanceThreshold) { diff --git a/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart b/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart index a8d13297d8..b9ec603e2a 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart @@ -651,6 +651,18 @@ class FaceMlService { min(offset + bucketSize, allFaceInfoForClustering.length), ); + if (faceInfoForClustering.every((face) => face.clusterId != null)) { + _logger.info('Everything in bucket $bucket is already clustered'); + if (offset + bucketSize >= totalFaces) { + _logger.info('All faces clustered'); + break; + } else { + _logger.info('Skipping to next bucket'); + offset += offsetIncrement; + bucket++; + } + } + final clusteringResult = await FaceClusteringService.instance.predictLinear( faceInfoForClustering.toSet(), From 8975af7a716429663b8f78ce911f124065934462 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 15:47:46 +0530 Subject: [PATCH 6/9] [mob][photos] Dont forget to continue --- .../lib/services/machine_learning/face_ml/face_ml_service.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart b/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart index b9ec603e2a..1297f4cac0 100644 --- a/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/face_ml_service.dart @@ -660,6 +660,7 @@ class FaceMlService { _logger.info('Skipping to next bucket'); offset += offsetIncrement; bucket++; + continue; } } From 853f291de3268f926051f3445b2d4c192733e5b6 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 16:20:33 +0530 Subject: [PATCH 7/9] [mob][photos] Fix face thumbnail generation pool issue --- mobile/lib/ui/viewer/file_details/face_widget.dart | 6 +++++- .../ui/viewer/file_details/faces_item_widget.dart | 8 +++++++- .../ui/viewer/search/result/person_face_widget.dart | 6 +++++- mobile/lib/utils/face/face_box_crop.dart | 13 +++++++++++-- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/mobile/lib/ui/viewer/file_details/face_widget.dart b/mobile/lib/ui/viewer/file_details/face_widget.dart index 1ec7a2eb2d..67d2368d71 100644 --- a/mobile/lib/ui/viewer/file_details/face_widget.dart +++ b/mobile/lib/ui/viewer/file_details/face_widget.dart @@ -293,7 +293,7 @@ class _FaceWidgetState extends State { } } - Future?> getFaceCrop() async { + Future?> getFaceCrop({int fetchAttempt = 1}) async { try { final Uint8List? cachedFace = faceCropCache.get(widget.face.faceID); if (cachedFace != null) { @@ -326,6 +326,10 @@ class _FaceWidgetState extends State { error: e, stackTrace: s, ); + resetPool(fullFile: true); + if (fetchAttempt <= retryLimit) { + return getFaceCrop(fetchAttempt: fetchAttempt + 1); + } return null; } } diff --git a/mobile/lib/ui/viewer/file_details/faces_item_widget.dart b/mobile/lib/ui/viewer/file_details/faces_item_widget.dart index ed2fb0f12e..cb22e53b82 100644 --- a/mobile/lib/ui/viewer/file_details/faces_item_widget.dart +++ b/mobile/lib/ui/viewer/file_details/faces_item_widget.dart @@ -173,7 +173,9 @@ class _FacesItemWidgetState extends State { } Future?> getRelevantFaceCrops( - Iterable faces, + Iterable faces, { + int fetchAttempt = 1, + } ) async { try { final faceIdToCrop = {}; @@ -223,6 +225,10 @@ class _FacesItemWidgetState extends State { error: e, stackTrace: s, ); + resetPool(fullFile: true); + if(fetchAttempt <= retryLimit) { + return getRelevantFaceCrops(faces, fetchAttempt: fetchAttempt + 1); + } return null; } } diff --git a/mobile/lib/ui/viewer/search/result/person_face_widget.dart b/mobile/lib/ui/viewer/search/result/person_face_widget.dart index 8be99e5f6e..57fe5af654 100644 --- a/mobile/lib/ui/viewer/search/result/person_face_widget.dart +++ b/mobile/lib/ui/viewer/search/result/person_face_widget.dart @@ -121,7 +121,7 @@ class PersonFaceWidget extends StatelessWidget { ); } - Future getFaceCrop() async { + Future getFaceCrop({int fetchAttempt = 1}) async { try { final Face? face = await _getFace(); if (face == null) { @@ -187,6 +187,10 @@ class PersonFaceWidget extends StatelessWidget { error: e, stackTrace: s, ); + resetPool(fullFile: useFullFile); + if(fetchAttempt <= retryLimit) { + return getFaceCrop(fetchAttempt: fetchAttempt + 1); + } return null; } } diff --git a/mobile/lib/utils/face/face_box_crop.dart b/mobile/lib/utils/face/face_box_crop.dart index 281c0ef495..4dd1778f72 100644 --- a/mobile/lib/utils/face/face_box_crop.dart +++ b/mobile/lib/utils/face/face_box_crop.dart @@ -11,11 +11,20 @@ import "package:photos/utils/image_ml_isolate.dart"; import "package:photos/utils/thumbnail_util.dart"; import "package:pool/pool.dart"; +void resetPool({required bool fullFile}) { + if (fullFile) { + poolFullFileFaceGenerations = Pool(20, timeout: const Duration(seconds: 15)); + } else { + poolThumbnailFaceGenerations = Pool(100, timeout: const Duration(seconds: 15)); + } +} + +const int retryLimit = 3; final LRUMap faceCropCache = LRUMap(1000); final LRUMap faceCropThumbnailCache = LRUMap(1000); -final poolFullFileFaceGenerations = +Pool poolFullFileFaceGenerations = Pool(20, timeout: const Duration(seconds: 15)); -final poolThumbnailFaceGenerations = +Pool poolThumbnailFaceGenerations = Pool(100, timeout: const Duration(seconds: 15)); Future?> getFaceCrops( EnteFile file, From 433c23ca0782a2dfb375fbcb87d890a9ac49ebc4 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 16:35:56 +0530 Subject: [PATCH 8/9] [mob][photos] Put MLController timeout back to 15 seconds --- .../services/machine_learning/machine_learning_controller.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/lib/services/machine_learning/machine_learning_controller.dart b/mobile/lib/services/machine_learning/machine_learning_controller.dart index 3b78fd8c9e..1ecb053f01 100644 --- a/mobile/lib/services/machine_learning/machine_learning_controller.dart +++ b/mobile/lib/services/machine_learning/machine_learning_controller.dart @@ -18,7 +18,7 @@ class MachineLearningController { static const kMaximumTemperature = 42; // 42 degree celsius static const kMinimumBatteryLevel = 20; // 20% - static const kDefaultInteractionTimeout = Duration(seconds: 10); + static const kDefaultInteractionTimeout = Duration(seconds: 15); static const kUnhealthyStates = ["over_heat", "over_voltage", "dead"]; bool _isDeviceHealthy = true; From b10f4ee18a28ebde48ed177cfc82f6d4e64afb99 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Tue, 28 May 2024 16:41:40 +0530 Subject: [PATCH 9/9] [mob][photos] Bump --- mobile/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index ed3bf47193..7b06f7f420 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -12,7 +12,7 @@ description: ente photos application # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.8.120+640 +version: 0.8.122+642 publish_to: none environment: