[mob][photos] Change embeddings server structure

This commit is contained in:
laurenspriem 2024-05-20 14:18:34 +05:30
parent 09b2732d76
commit 76848c826e
4 changed files with 44 additions and 37 deletions

View file

@ -1,5 +1,6 @@
import "package:photos/face/model/detection.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";
// FileInfo contains the image width and height of the image the face was detected in.
class FileInfo {
@ -12,13 +13,17 @@ class FileInfo {
}
class Face {
final int fileID;
final String faceID;
final List<double> embedding;
Detection detection;
final double score;
final double blur;
///#region Local DB fields
// This is not stored on the server, using it for local DB row
FileInfo? fileInfo;
final int fileID;
///#endregion
bool get isBlurry => blur < kLaplacianHardThreshold;
@ -55,10 +60,12 @@ class Face {
}
factory Face.fromJson(Map<String, dynamic> json) {
final String faceID = json['faceID'] as String;
final int fileID = getFileIdFromFaceId(faceID);
return Face(
json['faceID'] as String,
json['fileID'] as int,
List<double>.from(json['embeddings'] as List),
faceID,
fileID,
List<double>.from((json['embedding'] ?? json['embeddings']) as List),
json['score'] as double,
Detection.fromJson(json['detection'] as Map<String, dynamic>),
// high value means t
@ -66,10 +73,11 @@ class Face {
);
}
// Note: Keep the information in toJson minimum. Keep in sync with desktop.
// Derive fields like fileID from other values whenever possible
Map<String, dynamic> toJson() => {
'faceID': faceID,
'fileID': fileID,
'embeddings': embedding,
'embedding': embedding,
'detection': detection.toJson(),
'score': score,
'blur': blur,

View file

@ -12,6 +12,7 @@ import "package:flutter/foundation.dart" show debugPrint, kDebugMode;
import "package:flutter_image_compress/flutter_image_compress.dart";
import "package:logging/logging.dart";
import "package:onnxruntime/onnxruntime.dart";
import "package:package_info_plus/package_info_plus.dart";
import "package:photos/core/configuration.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/db/files_db.dart";
@ -88,6 +89,7 @@ class FaceMlService {
final _computer = Computer.shared();
bool isInitialized = false;
late String client;
bool canRunMLController = false;
bool isImageIndexRunning = false;
@ -125,6 +127,11 @@ class FaceMlService {
_logger.severe("Could not initialize mobilefacenet", e, s);
}
// Get client name
final packageInfo = await PackageInfo.fromPlatform();
client = "${packageInfo.packageName}/${packageInfo.version}";
_logger.info("client: $client");
isInitialized = true;
canRunMLController = !Platform.isAndroid || kDebugMode;
@ -621,7 +628,6 @@ class FaceMlService {
faces.add(
Face.empty(
fileMl.fileID,
error: (fileMl.faceEmbedding.error ?? false),
),
);
} else {
@ -715,11 +721,6 @@ class FaceMlService {
"because version is ${fileMl.faceEmbedding.version} and we need $faceMlVersion");
return true;
}
if (fileMl.faceEmbedding.error ?? false) {
debugPrint("Discarding remote embedding for fileID ${fileMl.fileID} "
"because error is true");
return true;
}
// are all landmarks equal?
bool allLandmarksEqual = true;
if (fileMl.faceEmbedding.faces.isEmpty) {
@ -823,19 +824,24 @@ class FaceMlService {
}
}
_logger.info("inserting ${faces.length} faces for ${result.fileId}");
await RemoteFileMLService.instance.putFileEmbedding(
enteFile,
FileMl(
enteFile.uploadedFileID!,
FaceEmbeddings(
faces,
result.mlVersion,
error: result.errorOccured ? true : null,
if (!result.errorOccured) {
await RemoteFileMLService.instance.putFileEmbedding(
enteFile,
FileMl(
enteFile.uploadedFileID!,
FaceEmbeddings(
faces,
result.mlVersion,
client: client,
),
height: result.decodedImageSize.height,
width: result.decodedImageSize.width,
),
height: result.decodedImageSize.height,
width: result.decodedImageSize.width,
),
);
);
} else {
_logger.warning(
'Skipped putting embedding because of error ${result.toJsonString()}',);
}
await FaceMLDataDB.instance.bulkInsertFaces(faces);
return true;
} catch (e, s) {

View file

@ -4,11 +4,8 @@ class FileMl {
final int fileID;
final int? height;
final int? width;
// json: face
final FaceEmbeddings faceEmbedding;
final ClipEmbedding? clipEmbedding;
// int updationTime that is not serialized
int? updationTime;
FileMl(
this.fileID,
@ -45,15 +42,13 @@ class FileMl {
class FaceEmbeddings {
final List<Face> faces;
final int version;
// Platform: appVersion
final String? client;
final bool? error;
// pkgname/version
final String client;
FaceEmbeddings(
this.faces,
this.version, {
this.client,
this.error,
required this.client,
});
// toJson
@ -61,7 +56,6 @@ class FaceEmbeddings {
'faces': faces.map((x) => x.toJson()).toList(),
'version': version,
'client': client,
'error': error,
};
// fromJson
factory FaceEmbeddings.fromJson(Map<String, dynamic> json) {
@ -70,8 +64,8 @@ class FaceEmbeddings {
json['faces'].map((x) => Face.fromJson(x as Map<String, dynamic>)),
),
json['version'] as int,
client: json['client'] as String?,
error: json['error'] as bool?,
client: json['client'] ??
'unknown',
);
}
}

View file

@ -1,6 +1,5 @@
import "dart:async";
import "dart:convert";
import "dart:typed_data";
import "package:computer/computer.dart";
import "package:logging/logging.dart";
@ -37,7 +36,7 @@ class RemoteFileMLService {
final encryptionKey = getFileKey(file);
final embeddingJSON = jsonEncode(fileML.toJson());
final encryptedEmbedding = await CryptoUtil.encryptChaCha(
utf8.encode(embeddingJSON) as Uint8List,
utf8.encode(embeddingJSON),
encryptionKey,
);
final encryptedData =