[mob] Add generic type for fileID
This commit is contained in:
@@ -5,7 +5,7 @@ import "package:photos/models/ml/face/face.dart";
|
||||
import "package:photos/models/ml/vector.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/face_clustering/face_db_info_for_clustering.dart";
|
||||
|
||||
abstract class IMLDataDB {
|
||||
abstract class IMLDataDB<T> {
|
||||
Future<void> bulkInsertFaces(List<Face> faces);
|
||||
Future<void> updateFaceIdToClusterId(Map<String, String> faceIDToClusterID);
|
||||
Future<Map<int, int>> faceIndexedFileIds({int minimumMlVersion});
|
||||
@@ -24,12 +24,12 @@ abstract class IMLDataDB {
|
||||
int? limit,
|
||||
});
|
||||
Future<Face?> getCoverFaceForPerson({
|
||||
required int recentFileID,
|
||||
required T recentFileID,
|
||||
String? personID,
|
||||
String? avatarFaceId,
|
||||
String? clusterID,
|
||||
});
|
||||
Future<List<Face>?> getFacesForGivenFileID(int fileUploadID);
|
||||
Future<List<Face>?> getFacesForGivenFileID(T fileUploadID);
|
||||
Future<Map<String, Iterable<String>>> getClusterToFaceIDs(
|
||||
Set<String> clusterIDs,
|
||||
);
|
||||
@@ -43,7 +43,7 @@ abstract class IMLDataDB {
|
||||
Future<Set<String>> getFaceIDsForPerson(String personID);
|
||||
Future<Iterable<double>> getBlurValuesForCluster(String clusterID);
|
||||
Future<Map<String, String?>> getFaceIdsToClusterIds(Iterable<String> faceIds);
|
||||
Future<Map<int, Set<String>>> getFileIdToClusterIds();
|
||||
Future<Map<T, Set<String>>> getFileIdToClusterIds();
|
||||
Future<void> forceUpdateClusterIds(Map<String, String> faceIDToClusterID);
|
||||
Future<void> removeFaceIdToClusterId(Map<String, String> faceIDToClusterID);
|
||||
Future<void> removePerson(String personID);
|
||||
@@ -57,8 +57,8 @@ abstract class IMLDataDB {
|
||||
);
|
||||
Future<int> getTotalFaceCount();
|
||||
Future<int> getErroredFaceCount();
|
||||
Future<Set<int>> getErroredFileIDs();
|
||||
Future<void> deleteFaceIndexForFiles(List<int> fileIDs);
|
||||
Future<Set<T>> getErroredFileIDs();
|
||||
Future<void> deleteFaceIndexForFiles(List<T> fileIDs);
|
||||
Future<int> getClusteredOrFacelessFileCount();
|
||||
Future<double> getClusteredToIndexableFilesRatio();
|
||||
Future<int> getUnclusteredFaceCount();
|
||||
@@ -84,8 +84,8 @@ abstract class IMLDataDB {
|
||||
required String personID,
|
||||
required String clusterID,
|
||||
});
|
||||
Future<Map<int, Set<String>>> getFileIdToClusterIDSet(String personID);
|
||||
Future<Map<int, Set<String>>> getFileIdToClusterIDSetForCluster(
|
||||
Future<Map<T, Set<String>>> getFileIdToClusterIDSet(String personID);
|
||||
Future<Map<T, Set<String>>> getFileIdToClusterIDSetForCluster(
|
||||
Set<String> clusterIDs,
|
||||
);
|
||||
Future<void> clusterSummaryUpdate(Map<String, (Uint8List, int)> summary);
|
||||
@@ -99,10 +99,10 @@ abstract class IMLDataDB {
|
||||
Future<Map<String, String>> getClusterIDToPersonID();
|
||||
Future<void> dropClustersAndPersonTable({bool faces});
|
||||
Future<void> dropFacesFeedbackTables();
|
||||
Future<List<int>> getFileIDsOfPersonID(String personID);
|
||||
Future<List<int>> getFileIDsOfClusterID(String clusterID);
|
||||
Future<Set<int>> getAllFileIDsOfFaceIDsNotInAnyCluster();
|
||||
Future<Set<int>> getAllFilesAssociatedWithAllClusters({
|
||||
Future<List<T>> getFileIDsOfPersonID(String personID);
|
||||
Future<List<T>> getFileIDsOfClusterID(String clusterID);
|
||||
Future<Set<T>> getAllFileIDsOfFaceIDsNotInAnyCluster();
|
||||
Future<Set<T>> getAllFilesAssociatedWithAllClusters({
|
||||
List<String>? exceptClusters,
|
||||
});
|
||||
|
||||
@@ -110,6 +110,6 @@ abstract class IMLDataDB {
|
||||
Future<Map<int, int>> clipIndexedFileWithVersion();
|
||||
Future<int> getClipIndexedFileCount({int minimumMlVersion});
|
||||
Future<void> putClip(List<ClipEmbedding> embeddings);
|
||||
Future<void> deleteClipEmbeddings(List<int> fileIDs);
|
||||
Future<void> deleteClipEmbeddings(List<T> fileIDs);
|
||||
Future<void> deleteClipIndexes();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import 'package:sqlite_async/sqlite_async.dart';
|
||||
///
|
||||
/// [clipTable] - Stores the embeddings of the CLIP model
|
||||
/// [fileDataTable] - Stores data about the files that are already processed by the ML models
|
||||
class MLDataDB extends IMLDataDB {
|
||||
class MLDataDB extends IMLDataDB<int> {
|
||||
static final Logger _logger = Logger("MLDataDB");
|
||||
|
||||
static const _databaseName = "ente.ml.db";
|
||||
@@ -582,7 +582,7 @@ class MLDataDB extends IMLDataDB {
|
||||
for (final map in maps) {
|
||||
final clusterID = map[clusterIDColumn] as String;
|
||||
final faceID = map[faceIDColumn] as String;
|
||||
final fileID = getFileIdFromFaceId(faceID);
|
||||
final fileID = getFileIdFromFaceId<int>(faceID);
|
||||
result[fileID] = (result[fileID] ?? {})..add(clusterID);
|
||||
}
|
||||
return result;
|
||||
@@ -783,7 +783,7 @@ class MLDataDB extends IMLDataDB {
|
||||
);
|
||||
final Set<int> clusteredFileIDs = {};
|
||||
for (final map in clustered) {
|
||||
final int fileID = getFileIdFromFaceId(map[faceIDColumn] as String);
|
||||
final int fileID = getFileIdFromFaceId<int>(map[faceIDColumn] as String);
|
||||
clusteredFileIDs.add(fileID);
|
||||
}
|
||||
|
||||
@@ -928,7 +928,8 @@ class MLDataDB extends IMLDataDB {
|
||||
for (final map in maps) {
|
||||
final clusterID = map[clusterIDColumn] as String;
|
||||
final String faceID = map[faceIDColumn] as String;
|
||||
final fileID = getFileIdFromFaceId(faceID);
|
||||
final fileID = getFileIdFromFaceId<int>
|
||||
(faceID);
|
||||
result[fileID] = (result[fileID] ?? {})..add(clusterID);
|
||||
}
|
||||
return result;
|
||||
@@ -953,7 +954,7 @@ class MLDataDB extends IMLDataDB {
|
||||
for (final map in maps) {
|
||||
final clusterID = map[clusterIDColumn] as String;
|
||||
final faceID = map[faceIDColumn] as String;
|
||||
final fileID = getFileIdFromFaceId(faceID);
|
||||
final fileID = getFileIdFromFaceId<int>(faceID);
|
||||
result[fileID] = (result[fileID] ?? {})..add(clusterID);
|
||||
}
|
||||
return result;
|
||||
|
||||
19
mobile/lib/generated/intl/messages_nl.dart
generated
19
mobile/lib/generated/intl/messages_nl.dart
generated
@@ -490,6 +490,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"blog": MessageLookupByLibrary.simpleMessage("Blog"),
|
||||
"cachedData": MessageLookupByLibrary.simpleMessage("Cachegegevens"),
|
||||
"calculating": MessageLookupByLibrary.simpleMessage("Berekenen..."),
|
||||
"canNotOpenBody": MessageLookupByLibrary.simpleMessage(
|
||||
"Sorry, dit album kan niet worden geopend in de app."),
|
||||
"canNotOpenTitle":
|
||||
MessageLookupByLibrary.simpleMessage("Kan dit album niet openen"),
|
||||
"canNotUploadToAlbumsOwnedByOthers":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Kan niet uploaden naar albums die van anderen zijn"),
|
||||
@@ -812,8 +816,12 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Bewerkte locatie wordt alleen gezien binnen Ente"),
|
||||
"eligible": MessageLookupByLibrary.simpleMessage("gerechtigd"),
|
||||
"email": MessageLookupByLibrary.simpleMessage("E-mail"),
|
||||
"emailAlreadyRegistered":
|
||||
MessageLookupByLibrary.simpleMessage("E-mail is al geregistreerd."),
|
||||
"emailChangedTo": m30,
|
||||
"emailNoEnteAccount": m31,
|
||||
"emailNotRegistered":
|
||||
MessageLookupByLibrary.simpleMessage("E-mail niet geregistreerd."),
|
||||
"emailVerificationToggle":
|
||||
MessageLookupByLibrary.simpleMessage("E-mailverificatie"),
|
||||
"emailYourLogs":
|
||||
@@ -981,6 +989,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Bespaar ruimte op je apparaat door bestanden die al geback-upt zijn te wissen."),
|
||||
"freeUpSpace": MessageLookupByLibrary.simpleMessage("Ruimte vrijmaken"),
|
||||
"freeUpSpaceSaving": m39,
|
||||
"gallery": MessageLookupByLibrary.simpleMessage("Galerij"),
|
||||
"galleryMemoryLimitInfo": MessageLookupByLibrary.simpleMessage(
|
||||
"Tot 1000 herinneringen getoond in de galerij"),
|
||||
"general": MessageLookupByLibrary.simpleMessage("Algemeen"),
|
||||
@@ -1011,6 +1020,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Verbergt app-inhoud in de app-schakelaar en schakelt schermopnamen uit"),
|
||||
"hideContentDescriptionIos": MessageLookupByLibrary.simpleMessage(
|
||||
"Verbergt de inhoud van de app in de app-schakelaar"),
|
||||
"hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage(
|
||||
"Verberg gedeelde bestanden uit de galerij"),
|
||||
"hiding": MessageLookupByLibrary.simpleMessage("Verbergen..."),
|
||||
"hostedAtOsmFrance":
|
||||
MessageLookupByLibrary.simpleMessage("Gehost bij OSM France"),
|
||||
@@ -1073,6 +1084,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Bestanden tonen het aantal resterende dagen voordat ze permanent worden verwijderd"),
|
||||
"itemsWillBeRemovedFromAlbum": MessageLookupByLibrary.simpleMessage(
|
||||
"Geselecteerde items zullen worden verwijderd uit dit album"),
|
||||
"join": MessageLookupByLibrary.simpleMessage("Deelnemen"),
|
||||
"joinAlbum":
|
||||
MessageLookupByLibrary.simpleMessage("Deelnemen aan album"),
|
||||
"joinAlbumSubtext": MessageLookupByLibrary.simpleMessage(
|
||||
"om je foto\'s te bekijken en toe te voegen"),
|
||||
"joinAlbumSubtextViewer": MessageLookupByLibrary.simpleMessage(
|
||||
"om dit aan gedeelde albums toe te voegen"),
|
||||
"joinDiscord": MessageLookupByLibrary.simpleMessage("Join de Discord"),
|
||||
"keepPhotos": MessageLookupByLibrary.simpleMessage("Foto\'s behouden"),
|
||||
"kiloMeterUnit": MessageLookupByLibrary.simpleMessage("km"),
|
||||
@@ -1422,6 +1440,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage("Privé back-ups"),
|
||||
"privateSharing": MessageLookupByLibrary.simpleMessage("Privé delen"),
|
||||
"proceed": MessageLookupByLibrary.simpleMessage("Verder"),
|
||||
"processed": MessageLookupByLibrary.simpleMessage("Verwerkt"),
|
||||
"processingImport": m54,
|
||||
"publicLinkCreated":
|
||||
MessageLookupByLibrary.simpleMessage("Publieke link aangemaakt"),
|
||||
|
||||
383
mobile/lib/generated/intl/messages_ro.dart
generated
383
mobile/lib/generated/intl/messages_ro.dart
generated
File diff suppressed because it is too large
Load Diff
@@ -94,7 +94,7 @@ class Face {
|
||||
|
||||
factory Face.fromJson(Map<String, dynamic> json) {
|
||||
final String faceID = json['faceID'] as String;
|
||||
final int fileID = getFileIdFromFaceId(faceID);
|
||||
final int fileID = getFileIdFromFaceId<int>(faceID);
|
||||
return Face(
|
||||
faceID,
|
||||
fileID,
|
||||
|
||||
@@ -331,7 +331,7 @@ ClusteringResult runLinearClustering(Map args) {
|
||||
clusterId: face.clusterId,
|
||||
rejectedClusterIds: face.rejectedClusterIds,
|
||||
fileCreationTime:
|
||||
fileIDToCreationTime?[getFileIdFromFaceId(face.faceID)],
|
||||
fileIDToCreationTime?[getFileIdFromFaceId<int>(face.faceID)],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -507,7 +507,7 @@ ClusteringResult _runCompleteClustering(Map args) {
|
||||
EVector.fromBuffer(entry.value).values,
|
||||
dtype: DType.float32,
|
||||
),
|
||||
fileCreationTime: fileIDToCreationTime?[getFileIdFromFaceId(entry.key)],
|
||||
fileCreationTime: fileIDToCreationTime?[getFileIdFromFaceId<int>(entry.key)],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class ClusterSuggestion {
|
||||
);
|
||||
}
|
||||
|
||||
class ClusterFeedbackService {
|
||||
class ClusterFeedbackService<T> {
|
||||
final Logger _logger = Logger("ClusterFeedbackService");
|
||||
final _computer = Computer.shared();
|
||||
ClusterFeedbackService._privateConstructor();
|
||||
@@ -145,7 +145,7 @@ class ClusterFeedbackService {
|
||||
.getFaceIDsForPerson(p.remoteID)
|
||||
.then((iterable) => iterable.toList());
|
||||
faceIDs.retainWhere((faceID) {
|
||||
final fileID = getFileIdFromFaceId(faceID);
|
||||
final fileID = getFileIdFromFaceId<int>(faceID);
|
||||
return files.any((file) => file.uploadedFileID == fileID);
|
||||
});
|
||||
final embeddings =
|
||||
@@ -211,7 +211,7 @@ class ClusterFeedbackService {
|
||||
.getFaceIDsForCluster(clusterID)
|
||||
.then((iterable) => iterable.toList());
|
||||
faceIDs.retainWhere((faceID) {
|
||||
final fileID = getFileIdFromFaceId(faceID);
|
||||
final fileID = getFileIdFromFaceId<int>(faceID);
|
||||
return files.any((file) => file.uploadedFileID == fileID);
|
||||
});
|
||||
final embeddings =
|
||||
@@ -278,7 +278,7 @@ class ClusterFeedbackService {
|
||||
final faceIDs = await faceMlDb.getFaceIDsForCluster(personClusterID);
|
||||
final ignoredClusters = await faceMlDb.getPersonIgnoredClusters(p.remoteID);
|
||||
if (faceIDs.length < 2 * kMinimumClusterSizeSearchResult) {
|
||||
final fileIDs = faceIDs.map(getFileIdFromFaceId).toSet();
|
||||
final fileIDs = faceIDs.map(getFileIdFromFaceId<int>).toSet();
|
||||
if (fileIDs.length < kMinimumClusterSizeSearchResult) {
|
||||
_logger.info(
|
||||
'Cluster $personClusterID has less than $kMinimumClusterSizeSearchResult faces, not doing automatic merges',
|
||||
@@ -433,7 +433,7 @@ class ClusterFeedbackService {
|
||||
final faceIdsOfCluster =
|
||||
await faceMlDb.getFaceIDsForCluster(clusterID);
|
||||
final uniqueFileIDs =
|
||||
faceIdsOfCluster.map(getFileIdFromFaceId).toSet();
|
||||
faceIdsOfCluster.map(getFileIdFromFaceId<int>).toSet();
|
||||
susClusters.add((clusterID, uniqueFileIDs.length));
|
||||
_logger.info(
|
||||
'[CheckMixedClusters] Detected that cluster $clusterID with size ${uniqueFileIDs.length} might be mixed',
|
||||
@@ -534,7 +534,7 @@ class ClusterFeedbackService {
|
||||
final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID);
|
||||
final personFaceIDs =
|
||||
await MLDataDB.instance.getFaceIDsForPerson(p.remoteID);
|
||||
final personFileIDs = personFaceIDs.map(getFileIdFromFaceId).toSet();
|
||||
final personFileIDs = personFaceIDs.map(getFileIdFromFaceId<int>).toSet();
|
||||
w?.log(
|
||||
'${p.data.name} has ${personClusters.length} existing clusters, getting all database data done',
|
||||
);
|
||||
@@ -573,7 +573,7 @@ class ClusterFeedbackService {
|
||||
for (final suggestion in suggestionsMeanBigClusters) {
|
||||
// Skip suggestions that have a high overlap with the person's files
|
||||
final suggestionSet = allClusterIdToFaceIDs[suggestion.$1]!
|
||||
.map((faceID) => getFileIdFromFaceId(faceID))
|
||||
.map((faceID) => getFileIdFromFaceId<int>(faceID))
|
||||
.toSet();
|
||||
final overlap = personFileIDs.intersection(suggestionSet);
|
||||
if (overlap.isNotEmpty &&
|
||||
@@ -978,7 +978,7 @@ class ClusterFeedbackService {
|
||||
);
|
||||
final fileIdToDistanceMap = {};
|
||||
for (final entry in faceIdToVectorMap.entries) {
|
||||
fileIdToDistanceMap[getFileIdFromFaceId(entry.key)] =
|
||||
fileIdToDistanceMap[getFileIdFromFaceId<int>(entry.key)] =
|
||||
1 - personAvg.dot(entry.value);
|
||||
}
|
||||
w?.log('calculated distances for cluster $clusterID');
|
||||
|
||||
@@ -145,8 +145,14 @@ class FaceResult {
|
||||
}
|
||||
}
|
||||
|
||||
int getFileIdFromFaceId(String faceId) {
|
||||
return int.parse(faceId.split("_").first);
|
||||
T getFileIdFromFaceId<T>(String faceId) {
|
||||
if (T == int) {
|
||||
return int.parse(faceId.split("_").first) as T;
|
||||
} else if (T == String) {
|
||||
return faceId.split("_").first as T;
|
||||
} else {
|
||||
throw ArgumentError("Unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
int? tryGetFileIdFromFaceId(String faceId) {
|
||||
|
||||
@@ -216,7 +216,7 @@ class _AppBarWidgetState extends State<ClusterAppBar> {
|
||||
}
|
||||
// Get the files for the biggest new cluster
|
||||
final biggestClusterFileIDs = newClusterIDToFaceIDs[biggestClusterID]!
|
||||
.map((e) => getFileIdFromFaceId(e))
|
||||
.map((e) => getFileIdFromFaceId<int>(e))
|
||||
.toList();
|
||||
biggestClusterFiles = await FilesDB.instance
|
||||
.getFileIDToFileFromIDs(
|
||||
@@ -260,7 +260,7 @@ class _AppBarWidgetState extends State<ClusterAppBar> {
|
||||
|
||||
final allFileIDs = newClusterIDToFaceIDs.values
|
||||
.expand((e) => e)
|
||||
.map((e) => getFileIdFromFaceId(e))
|
||||
.map((e) => getFileIdFromFaceId<int>(e))
|
||||
.toList();
|
||||
|
||||
final fileIDtoFile = await FilesDB.instance.getFileIDToFileFromIDs(
|
||||
@@ -271,7 +271,7 @@ class _AppBarWidgetState extends State<ClusterAppBar> {
|
||||
(key, value) => MapEntry(
|
||||
key,
|
||||
value
|
||||
.map((faceId) => fileIDtoFile[getFileIdFromFaceId(faceId)]!)
|
||||
.map((faceId) => fileIDtoFile[getFileIdFromFaceId<int>(faceId)]!)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -110,7 +110,8 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
await MLDataDB.instance.getFaceIDsForCluster(widget.clusterID!);
|
||||
}
|
||||
if (allFaces != null) {
|
||||
final allFileIDs = allFaces.map((e) => getFileIdFromFaceId(e)).toSet();
|
||||
final allFileIDs =
|
||||
allFaces.map((e) => getFileIdFromFaceId<int>(e)).toSet();
|
||||
final hiddenFileIDs = await SearchService.instance
|
||||
.getHiddenFiles()
|
||||
.then((onValue) => onValue.map((e) => e.uploadedFileID));
|
||||
|
||||
Reference in New Issue
Block a user