Add db for offline ml data

This commit is contained in:
Neeraj Gupta
2025-04-15 15:40:27 +05:30
parent 7f34870e3a
commit 3f262c5ba2
5 changed files with 1279 additions and 21 deletions

View File

@@ -9,7 +9,7 @@ import "package:photos/services/machine_learning/face_ml/face_clustering/face_db
abstract class IMLDataDB<T> {
Future<void> bulkInsertFaces(List<Face> faces);
Future<void> updateFaceIdToClusterId(Map<String, String> faceIDToClusterID);
Future<Map<int, int>> faceIndexedFileIds({int minimumMlVersion});
Future<Map<T, int>> faceIndexedFileIds({int minimumMlVersion});
Future<int> getFaceIndexedFileCount({int minimumMlVersion});
Future<Map<String, int>> clusterIdToFaceCount();
Future<Set<String>> getPersonIgnoredClusters(String personID);

View File

@@ -49,13 +49,13 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
static final MLDataDB instance = MLDataDB._privateConstructor();
static final _migrationScripts = [
createFacesTable,
getCreateFacesTable(false),
createFaceClustersTable,
createClusterPersonTable,
createClusterSummaryTable,
createNotPersonFeedbackTable,
fcClusterIDIndex,
createClipEmbeddingsTable,
getCreateClipEmbeddingsTable(false),
createFileDataTable,
];
@@ -337,10 +337,10 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
(element) => (element[fileIDColumn] as int) == avatarFileId,
);
if (row != null) {
return mapRowToFace(row);
return mapRowToFace<int>(row);
}
}
return mapRowToFace(faceMaps.first);
return mapRowToFace<int>(faceMaps.first);
}
}
if (clusterID != null) {
@@ -384,7 +384,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
if (maps.isEmpty) {
return null;
}
return maps.map((e) => mapRowToFace(e)).toList();
return maps.map((e) => mapRowToFace<int>(e)).toList();
}
@override
@@ -401,7 +401,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
}
final result = <int, List<FaceWithoutEmbedding>>{};
for (final map in maps) {
final face = mapRowToFaceWithoutEmbedding(map);
final face = mapRowToFaceWithoutEmbedding<int>(map);
final fileID = map[fileIDColumn] as int;
result.putIfAbsent(fileID, () => <FaceWithoutEmbedding>[]).add(face);
}
@@ -1060,7 +1060,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
final db = await instance.asyncDB;
if (faces) {
await db.execute(deleteFacesTable);
await db.execute(createFacesTable);
await db.execute(getCreateFacesTable(false));
await db.execute(deleteFaceClustersTable);
await db.execute(createFaceClustersTable);
await db.execute(fcClusterIDIndex);

View File

@@ -7,7 +7,7 @@ import "package:photos/models/ml/face/face.dart";
import "package:photos/models/ml/face/face_with_embedding.dart";
import "package:photos/models/ml/ml_versions.dart";
Map<String, dynamic> mapRemoteToFaceDB(Face face) {
Map<String, dynamic> mapRemoteToFaceDB<T>(Face<T> face) {
return {
faceIDColumn: face.faceID,
fileIDColumn: face.fileID,
@@ -24,10 +24,10 @@ Map<String, dynamic> mapRemoteToFaceDB(Face face) {
};
}
Face mapRowToFace(Map<String, dynamic> row) {
Face mapRowToFace<T>(Map<String, dynamic> row) {
return Face(
row[faceIDColumn] as String,
row[fileIDColumn] as int,
row[fileIDColumn] as T,
EVector.fromBuffer(row[embeddingColumn] as List<int>).values,
row[faceScore] as double,
Detection.fromJson(json.decode(row[faceDetectionColumn] as String)),
@@ -39,10 +39,12 @@ Face mapRowToFace(Map<String, dynamic> row) {
);
}
FaceWithoutEmbedding mapRowToFaceWithoutEmbedding(Map<String, dynamic> row) {
return FaceWithoutEmbedding(
FaceWithoutEmbedding<T> mapRowToFaceWithoutEmbedding<T>(
Map<String, dynamic> row,
) {
return FaceWithoutEmbedding<T>(
row[faceIDColumn] as String,
row[fileIDColumn] as int,
row[fileIDColumn] as T,
row[faceScore] as double,
Detection.fromJson(json.decode(row[faceDetectionColumn] as String)),
row[faceBlur] as double,

File diff suppressed because it is too large Load Diff

View File

@@ -16,8 +16,9 @@ const mlVersionColumn = 'ml_version';
const personIdColumn = 'person_id';
const clusterIDColumn = 'cluster_id';
const createFacesTable = '''CREATE TABLE IF NOT EXISTS $facesTable (
$fileIDColumn INTEGER NOT NULL,
String getCreateFacesTable(bool isOfflineDB) {
return '''CREATE TABLE IF NOT EXISTS $facesTable (
$fileIDColumn ${isOfflineDB ? 'TEXT' : 'INTEGER'} NOT NULL,
$faceIDColumn TEXT NOT NULL UNIQUE,
$faceDetectionColumn TEXT NOT NULL,
$embeddingColumn BLOB NOT NULL,
@@ -30,6 +31,7 @@ const createFacesTable = '''CREATE TABLE IF NOT EXISTS $facesTable (
PRIMARY KEY($fileIDColumn, $faceIDColumn)
);
''';
}
const deleteFacesTable = 'DELETE FROM $facesTable';
// End of Faces Table Fields & Schema Queries
@@ -97,18 +99,20 @@ const deleteNotPersonFeedbackTable = 'DELETE FROM $notPersonFeedback';
// ## CLIP EMBEDDINGS TABLE
const clipTable = 'clip';
const createClipEmbeddingsTable = '''
CREATE TABLE IF NOT EXISTS $clipTable (
$fileIDColumn INTEGER NOT NULL,
String getCreateClipEmbeddingsTable(bool isOfflineDB) {
return '''CREATE TABLE IF NOT EXISTS $clipTable (
$fileIDColumn ${isOfflineDB ? 'TEXT' : 'INTEGER'} NOT NULL,
$embeddingColumn BLOB NOT NULL,
$mlVersionColumn INTEGER NOT NULL,
PRIMARY KEY ($fileIDColumn)
PRIMARY KEY($fileIDColumn)
);
''';
''';
}
const deleteClipEmbeddingsTable = 'DELETE FROM $clipTable';
const fileDataTable = 'filedata';
const createFileDataTable = '''
CREATE TABLE IF NOT EXISTS $fileDataTable (
$fileIDColumn INTEGER NOT NULL,