[mob] Persist remote feedback before running clustering

This commit is contained in:
Neeraj Gupta 2024-04-05 15:59:53 +05:30
parent 18f202d3e4
commit 1996d86835
5 changed files with 158 additions and 109 deletions

View file

@ -482,6 +482,24 @@ class FaceMLDataDB {
);
}
Future<void> bulkAssignClusterToPersonID(
Map<int, String> clusterToPersonID,) async {
final db = await instance.database;
final batch = db.batch();
for (final entry in clusterToPersonID.entries) {
final clusterID = entry.key;
final personID = entry.value;
batch.insert(
clusterPersonTable,
{
personIdColumn: personID,
cluserIDColumn: clusterID,
},
);
}
await batch.commit(noResult: true);
}
Future<void> captureNotPersonFeedback({
required String personID,
required int clusterID,

View file

@ -36,8 +36,7 @@ const createFaceClustersTable = '''
CREATE TABLE IF NOT EXISTS $faceClustersTable (
$fcFaceId TEXT NOT NULL,
$fcClusterID INTEGER NOT NULL,
PRIMARY KEY($fcFaceId),
FOREIGN KEY($fcFaceId) REFERENCES $facesTable($faceIDColumn)
PRIMARY KEY($fcFaceId)
);
''';
// -- Creating a non-unique index on clusterID for query optimization

View file

@ -84,6 +84,24 @@ class PersonService {
return PersonEntity(result.id, data);
}
Future<void> storeRemoteFeedback() async {
final entities = await entityService.getEntities(EntityType.person);
entities.sort((a, b) => a.updatedAt.compareTo(b.updatedAt));
final Map<String, int> faceIdToClusterID = {};
final Map<int, String> clusterToPersonID = {};
for (var e in entities) {
final personData = PersonData.fromJson(json.decode(e.data));
for (var cluster in personData.assigned!) {
for (var faceId in cluster.faces) {
faceIdToClusterID[faceId] = cluster.id;
}
clusterToPersonID[cluster.id] = e.id;
}
}
await faceMLDataDB.updateClusterIdToFaceId(faceIdToClusterID);
await faceMLDataDB.bulkAssignClusterToPersonID(clusterToPersonID);
}
Future<void> updatePerson(PersonEntity updatePerson) async {
await entityService.addOrUpdate(
EntityType.person,

View file

@ -737,6 +737,7 @@ class SearchService {
}
Future<List<GenericSearchResult>> getAllFace(int? limit) async {
try {
debugPrint("getting faces");
final Map<int, Set<int>> fileIdToClusterID =
await FaceMLDataDB.instance.getFileIdToClusterIds();
@ -755,7 +756,8 @@ class SearchService {
}
final cluserIds = fileIdToClusterID[f.uploadedFileID ?? -1]!;
for (final cluster in cluserIds) {
final PersonEntity? p = personIdToPerson[clusterIDToPersonID[cluster] ?? ""];
final PersonEntity? p =
personIdToPerson[clusterIDToPersonID[cluster] ?? ""];
if (p != null) {
if (personIdToFiles.containsKey(p.remoteID)) {
personIdToFiles[p.remoteID]!.add(f);
@ -807,8 +809,9 @@ class SearchService {
}
final sortedClusterIds = clusterIdToFiles.keys.toList()
..sort(
(a, b) =>
clusterIdToFiles[b]!.length.compareTo(clusterIdToFiles[a]!.length),
(a, b) => clusterIdToFiles[b]!
.length
.compareTo(clusterIdToFiles[a]!.length),
);
for (final clusterId in sortedClusterIds) {
@ -817,7 +820,8 @@ class SearchService {
final String clusterName = "${files.length}";
if (clusterIDToPersonID[clusterId] != null) {
throw Exception("Cluster $clusterId should not have person id ${clusterIDToPersonID[clusterId]}");
throw Exception(
"Cluster $clusterId should not have person id ${clusterIDToPersonID[clusterId]}");
}
if (files.length < 3) {
continue;
@ -849,6 +853,10 @@ class SearchService {
} else {
return facesResult;
}
} catch (e, s) {
_logger.severe("Error in getAllFace", e, s);
rethrow;
}
}
Future<List<GenericSearchResult>> getAllLocationTags(int? limit) async {

View file

@ -159,6 +159,7 @@ class _FaceDebugSectionWidgetState extends State<FaceDebugSectionWidget> {
trailingIcon: Icons.chevron_right_outlined,
trailingIconIsMuted: true,
onTap: () async {
await PersonService.instance.storeRemoteFeedback();
await FaceMlService.instance
.clusterAllImages(clusterInBuckets: true);
Bus.instance.fire(PeopleChangedEvent());
@ -225,10 +226,15 @@ class _FaceDebugSectionWidgetState extends State<FaceDebugSectionWidget> {
"You will need to again re-index all the faces. You can drop feedback if you want to label again",
firstButtonLabel: "Yes, confirm",
firstButtonOnTap: () async {
try {
await FaceMLDataDB.instance
.dropClustersAndPersonTable(faces: true);
Bus.instance.fire(PeopleChangedEvent());
showShortToast(context, "Done");
} catch (e, s) {
_logger.warning('drop feedback failed ', e, s);
await showGenericErrorDialog(context: context, error: e);
}
},
);
},