[mob] Add generic type for fileID

This commit is contained in:
Neeraj Gupta
2025-01-28 13:30:24 +05:30
parent 69661b0d30
commit 6bdc1f5d65
10 changed files with 444 additions and 36 deletions

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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"),

File diff suppressed because it is too large Load Diff

View File

@@ -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,

View File

@@ -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)],
),
);
}

View File

@@ -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');

View File

@@ -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) {

View File

@@ -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(),
),
);

View File

@@ -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));