[mob] Read face embeddings using sqlite async
This commit is contained in:
parent
ba107c2d25
commit
3860d0a230
2 changed files with 49 additions and 16 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
|
|
Loading…
Add table
Reference in a new issue