[mob] Zip embeddings

This commit is contained in:
Neeraj Gupta
2024-07-23 13:32:06 +05:30
parent 5a003b6d5c
commit bfc67d741d
5 changed files with 79 additions and 52 deletions

View File

@@ -89,7 +89,7 @@ class FaceRecognitionService {
}
Future<void> _syncFaceEmbeddings({int retryFetchCount = 10}) async {
final filesToIndex = await getFilesForMlIndexing();
final List<FileMLInstruction> filesToIndex = await getFilesForMlIndexing();
final List<List<FileMLInstruction>> chunks =
filesToIndex.chunks(_embeddingFetchLimit); // Chunks of 200
int fetchedCount = 0;

View File

@@ -1,45 +1,58 @@
import "package:photos/face/model/face.dart";
const _faceKey = 'face';
const _clipKey = 'clip';
class RemoteFileML {
final int fileID;
final Map<String, dynamic> remoteRawData;
final RemoteFaceEmbedding? faceEmbedding;
final RemoteClipEmbedding? clipEmbedding;
RemoteFileML(
this.fileID,
this.remoteRawData, {
required this.faceEmbedding,
this.clipEmbedding,
});
this.remoteRawData,
);
// toJson
Map<String, dynamic> toJson() {
throw UnimplementedError();
}
// fromRemote
factory RemoteFileML.fromRemote(int fileID, Map<String, dynamic> json) {
return RemoteFileML(
fileID,
json,
faceEmbedding: json['face'] != null
? RemoteFaceEmbedding.fromJson(
json['face'] as Map<String, dynamic>,
)
: null,
clipEmbedding: json['clip'] == null
? null
: RemoteClipEmbedding.fromJson(
json['clip'] as Map<String, dynamic>,
),
);
}
static RemoteFileML empty(int i) {
final Map<String, dynamic> json = {};
return RemoteFileML(i, json);
}
void putFaceIfNotNull(RemoteFaceEmbedding? faceEmbedding) {
if (faceEmbedding != null) {
remoteRawData[_faceKey] = faceEmbedding.toJson();
}
}
void putClipIfNotNull(RemoteClipEmbedding? clipEmbedding) {
if (clipEmbedding != null) {
remoteRawData[_clipKey] = clipEmbedding.toJson();
}
}
RemoteFaceEmbedding? get faceEmbedding => remoteRawData[_faceKey] != null
? RemoteFaceEmbedding.fromJson(
remoteRawData[_faceKey] as Map<String, dynamic>,
)
: null;
RemoteClipEmbedding? get clipEmbedding => remoteRawData[_clipKey] != null
? RemoteClipEmbedding.fromJson(
remoteRawData[_clipKey] as Map<String, dynamic>,
)
: null;
}
class RemoteFaceEmbedding {
final List<Face> faces;
final int version;
// packageName/version
final String client;
final int height;

View File

@@ -3,7 +3,7 @@ import "dart:convert";
import "dart:io";
import "package:computer/computer.dart";
import "package:flutter/foundation.dart" show Uint8List, debugPrint;
import "package:flutter/foundation.dart" show Uint8List;
import "package:logging/logging.dart";
import "package:photos/core/network/network.dart";
import "package:photos/db/files_db.dart";
@@ -28,14 +28,19 @@ class RemoteFileMLService {
void init(SharedPreferences prefs) {}
Future<void> putFileEmbedding(EnteFile file, RemoteFileML fileML) async {
throw Exception("need to update implementation");
Future<void> putFileEmbedding(
EnteFile file,
RemoteFileML fileML, {
RemoteClipEmbedding? clipEmbedding,
RemoteFaceEmbedding? faceEmbedding,
}) async {
fileML.putClipIfNotNull(clipEmbedding);
fileML.putFaceIfNotNull(faceEmbedding);
final encryptionKey = getFileKey(file);
final embeddingJSON = jsonEncode(fileML.toJson());
final encryptedEmbedding = await CryptoUtil.encryptChaCha(
utf8.encode(embeddingJSON),
encryptionKey,
);
final embeddingJSON = jsonEncode(fileML.remoteRawData);
final compressedData = gzipUInt8List(utf8.encode(embeddingJSON));
final encryptedEmbedding =
await CryptoUtil.encryptChaCha(compressedData, encryptionKey);
final encryptedData =
CryptoUtil.bin2base64(encryptedEmbedding.encryptedData!);
final header = CryptoUtil.bin2base64(encryptedEmbedding.header!);
@@ -44,12 +49,11 @@ class RemoteFileMLService {
"/embeddings",
data: {
"fileID": file.uploadedFileID!,
"model": 'file-ml-clip-face',
"model": 'ggml-clip',
"encryptedEmbedding": encryptedData,
"decryptionHeader": header,
},
);
// final updationTime = response.data["updatedAt"];
} catch (e, s) {
_logger.severe("Failed to put embedding", e, s);
rethrow;
@@ -127,6 +131,13 @@ Uint8List ungzipUint8List(Uint8List compressedData) {
return Uint8List.fromList(decompressedList);
}
// gzipUInt8List
Uint8List gzipUInt8List(Uint8List data) {
final codec = GZipCodec();
final compressedData = codec.encode(data);
return Uint8List.fromList(compressedData);
}
Future<Map<int, RemoteFileML>> _decryptFileMLComputer(
Map<String, dynamic> args,
) async {
@@ -140,7 +151,6 @@ Future<Map<int, RemoteFileML>> _decryptFileMLComputer(
decryptArgs["header"] =
CryptoUtil.base642bin(input.embedding.decryptionHeader);
final embeddingData = chachaDecryptData(decryptArgs);
// unzip the gzip data
final unzippedData = ungzipUint8List(embeddingData);
final decodedJson = jsonDecode(utf8.decode(unzippedData));
final RemoteFileML decodedEmbedding = RemoteFileML.fromRemote(

View File

@@ -469,24 +469,26 @@ class MLService {
if (!result.errorOccured) {
await RemoteFileMLService.instance.putFileEmbedding(
instruction.enteFile,
RemoteFileML(
instruction.enteFile.uploadedFileID!,
{},
faceEmbedding: RemoteFaceEmbedding(
faces,
result.mlVersion,
client: client,
height: result.decodedImageSize.height,
width: result.decodedImageSize.width,
),
clipEmbedding: result.clipRan
? RemoteClipEmbedding(
result.clip!.embedding,
version: result.mlVersion,
client: client,
)
: null,
),
instruction.existingRemoteFileML ??
RemoteFileML.empty(
instruction.enteFile.uploadedFileID!,
),
faceEmbedding: result.facesRan
? RemoteFaceEmbedding(
faces,
result.mlVersion,
client: client,
height: result.decodedImageSize.height,
width: result.decodedImageSize.width,
)
: null,
clipEmbedding: result.clipRan
? RemoteClipEmbedding(
result.clip!.embedding,
version: result.mlVersion,
client: client,
)
: null,
);
} else {
_logger.warning(

View File

@@ -32,12 +32,14 @@ class FileMLInstruction {
final bool shouldRunFaces;
final bool shouldRunClip;
RemoteFileML? existingRemoteFileML;
FileMLInstruction({
required this.enteFile,
required this.shouldRunFaces,
required this.shouldRunClip,
});
}
Future<IndexStatus> getIndexStatus() async {