[mob] Read face embeddings using sqlite async

This commit is contained in:
laurenspriem 2024-04-12 12:57:03 +05:30
parent ba107c2d25
commit 3860d0a230
2 changed files with 49 additions and 16 deletions

View file

@ -1,4 +1,5 @@
import 'dart:async';
import "dart:io" show Directory;
import "dart:math";
import "package:collection/collection.dart";
@ -13,6 +14,7 @@ import "package:photos/face/model/face.dart";
import "package:photos/models/file/file.dart";
import 'package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqlite_async/sqlite_async.dart' as sqlite_async;
/// Stores all data for the ML-related features. The database can be accessed by `MlDataDB.instance.database`.
///
@ -29,13 +31,20 @@ class FaceMLDataDB {
static final FaceMLDataDB instance = FaceMLDataDB._privateConstructor();
// only have a single app-wide reference to the database
static Future<Database>? _dbFuture;
static Future<sqlite_async.SqliteDatabase>? _sqliteAsyncDBFuture;
Future<Database> get database async {
_dbFuture ??= _initDatabase();
return _dbFuture!;
}
Future<sqlite_async.SqliteDatabase> get sqliteAsyncDB async {
_sqliteAsyncDBFuture ??= _initSqliteAsyncDatabase();
return _sqliteAsyncDBFuture!;
}
Future<Database> _initDatabase() async {
final documentsDirectory = await getApplicationDocumentsDirectory();
final String databaseDirectory =
@ -47,6 +56,15 @@ class FaceMLDataDB {
);
}
Future<sqlite_async.SqliteDatabase> _initSqliteAsyncDatabase() async {
final Directory documentsDirectory =
await getApplicationDocumentsDirectory();
final String databaseDirectory =
join(documentsDirectory.path, _databaseName);
_logger.info("Opening sqlite_async access: DB path " + databaseDirectory);
return sqlite_async.SqliteDatabase(path: databaseDirectory);
}
Future _onCreate(Database db, int version) async {
await db.execute(createFacesTable);
await db.execute(createFaceClustersTable);
@ -398,18 +416,22 @@ class FaceMLDataDB {
w.logAndReset(
'reading as float offset: $offset, maxFaces: $maxFaces, batchSize: $batchSize',
);
final db = await instance.database;
final db = await instance.sqliteAsyncDB;
final Map<String, (int?, Uint8List)> result = {};
while (true) {
// Query a batch of rows
final List<Map<String, dynamic>> maps = await db.query(
facesTable,
columns: [faceIDColumn, faceEmbeddingBlob],
where: '$faceScore > $minScore and $faceBlur > $minClarity',
limit: batchSize,
offset: offset,
orderBy: '$faceIDColumn DESC',
final List<Map<String, dynamic>> maps = await db.getAll(
'SELECT $faceIDColumn, $faceEmbeddingBlob FROM $facesTable'
' WHERE $faceScore > $minScore AND $faceBlur > $minClarity'
' ORDER BY $faceIDColumn'
' DESC LIMIT $batchSize OFFSET $offset',
// facesTable,
// columns: [faceIDColumn, faceEmbeddingBlob],
// where: '$faceScore > $minScore and $faceBlur > $minClarity',
// limit: batchSize,
// offset: offset,
// orderBy: '$faceIDColumn DESC',
);
// Break the loop if no more rows
if (maps.isEmpty) {

View file

@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
import "package:logging/logging.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/events/people_changed_event.dart";
import "package:photos/extensions/stop_watch.dart";
import "package:photos/face/db.dart";
import "package:photos/face/model/person.dart";
import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart";
@ -333,13 +332,25 @@ class _FaceDebugSectionWidgetState extends State<FaceDebugSectionWidget> {
trailingIcon: Icons.chevron_right_outlined,
trailingIconIsMuted: true,
onTap: () async {
final EnteWatch watch = EnteWatch("read_embeddings")..start();
final result = await FaceMLDataDB.instance.getFaceEmbeddingMap();
watch.logAndReset('read embeddings ${result.length} ');
showShortToast(
context,
"Read ${result.length} face embeddings in ${watch.elapsed.inSeconds} secs",
);
final int totalFaces =
await FaceMLDataDB.instance.getTotalFaceCount();
_logger.info('start reading embeddings for $totalFaces faces');
final time = DateTime.now();
try {
final result = await FaceMLDataDB.instance
.getFaceEmbeddingMap(maxFaces: totalFaces);
final endTime = DateTime.now();
_logger.info(
'Read embeddings of ${result.length} faces in ${time.difference(endTime).inSeconds} secs',
);
showShortToast(
context,
"Read embeddings of ${result.length} faces in ${time.difference(endTime).inSeconds} secs",
);
} catch (e, s) {
_logger.warning('read embeddings failed ', e, s);
await showGenericErrorDialog(context: context, error: e);
}
},
),
],