[mob] Zip embeddings
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user