mirror of
https://github.com/ente-io/ente.git
synced 2025-07-26 03:25:52 +00:00
[mob][photos] Cache results for Magic section (only visible to internal users) (#2282)
## Description - Use cached results for magic section so that it does't anymore have to wait for ML framework to be initialised and doesn't have to re-compute results every time, which means faster loading of the search tab. - For internal users, all results in [here](https://discover.ente.io/v1.json) will show up. - For non-internal users, once available, results will be limited to 4. - 4 random prompts are selected from [here](https://discover.ente.io/v1.json) with non-empty results and are cached. - The cache updates when the data updates [here](https://discover.ente.io/v1.json) (checks size to compare) or in 3 days since the last update.
This commit is contained in:
commit
f67dc4893f
@ -37,6 +37,7 @@ import "package:photos/services/machine_learning/face_ml/person/person_service.d
|
|||||||
import 'package:photos/services/machine_learning/file_ml/remote_fileml_service.dart';
|
import 'package:photos/services/machine_learning/file_ml/remote_fileml_service.dart';
|
||||||
import "package:photos/services/machine_learning/machine_learning_controller.dart";
|
import "package:photos/services/machine_learning/machine_learning_controller.dart";
|
||||||
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
|
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
|
||||||
|
import "package:photos/services/magic_cache_service.dart";
|
||||||
import 'package:photos/services/memories_service.dart';
|
import 'package:photos/services/memories_service.dart';
|
||||||
import 'package:photos/services/push_service.dart';
|
import 'package:photos/services/push_service.dart';
|
||||||
import 'package:photos/services/remote_sync_service.dart';
|
import 'package:photos/services/remote_sync_service.dart';
|
||||||
@ -303,6 +304,8 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
|
|||||||
preferences,
|
preferences,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
MagicCacheService.instance.init(preferences);
|
||||||
|
|
||||||
initComplete = true;
|
initComplete = true;
|
||||||
_logger.info("Initialization done");
|
_logger.info("Initialization done");
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
@ -13,7 +13,6 @@ import "package:photos/models/collection/collection_items.dart";
|
|||||||
import "package:photos/models/search/search_result.dart";
|
import "package:photos/models/search/search_result.dart";
|
||||||
import "package:photos/models/typedefs.dart";
|
import "package:photos/models/typedefs.dart";
|
||||||
import "package:photos/services/collections_service.dart";
|
import "package:photos/services/collections_service.dart";
|
||||||
import "package:photos/services/machine_learning/semantic_search/frameworks/ml_framework.dart";
|
|
||||||
import "package:photos/services/search_service.dart";
|
import "package:photos/services/search_service.dart";
|
||||||
import "package:photos/ui/viewer/gallery/collection_page.dart";
|
import "package:photos/ui/viewer/gallery/collection_page.dart";
|
||||||
import "package:photos/ui/viewer/location/add_location_sheet.dart";
|
import "package:photos/ui/viewer/location/add_location_sheet.dart";
|
||||||
@ -292,8 +291,6 @@ extension SectionTypeExtensions on SectionType {
|
|||||||
switch (this) {
|
switch (this) {
|
||||||
case SectionType.location:
|
case SectionType.location:
|
||||||
return [Bus.instance.on<LocationTagUpdatedEvent>()];
|
return [Bus.instance.on<LocationTagUpdatedEvent>()];
|
||||||
case SectionType.magic:
|
|
||||||
return [Bus.instance.on<MLFrameworkInitializationUpdateEvent>()];
|
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -267,6 +267,49 @@ class SemanticSearchService {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<int>> getMatchingFileIDs(String query, double minScore) async {
|
||||||
|
final textEmbedding = await _getTextEmbedding(query);
|
||||||
|
|
||||||
|
final queryResults =
|
||||||
|
await _getScores(textEmbedding, scoreThreshold: minScore);
|
||||||
|
|
||||||
|
final queryResultIds = <int>[];
|
||||||
|
for (QueryResult result in queryResults) {
|
||||||
|
queryResultIds.add(result.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
final filesMap = await FilesDB.instance.getFilesFromIDs(
|
||||||
|
queryResultIds,
|
||||||
|
);
|
||||||
|
final results = <EnteFile>[];
|
||||||
|
|
||||||
|
final ignoredCollections =
|
||||||
|
CollectionsService.instance.getHiddenCollectionIds();
|
||||||
|
final deletedEntries = <int>[];
|
||||||
|
for (final result in queryResults) {
|
||||||
|
final file = filesMap[result.id];
|
||||||
|
if (file != null && !ignoredCollections.contains(file.collectionID)) {
|
||||||
|
results.add(file);
|
||||||
|
}
|
||||||
|
if (file == null) {
|
||||||
|
deletedEntries.add(result.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.info(results.length.toString() + " results");
|
||||||
|
|
||||||
|
if (deletedEntries.isNotEmpty) {
|
||||||
|
unawaited(EmbeddingsDB.instance.deleteEmbeddings(deletedEntries));
|
||||||
|
}
|
||||||
|
|
||||||
|
final matchingFileIDs = <int>[];
|
||||||
|
for (EnteFile file in results) {
|
||||||
|
matchingFileIDs.add(file.uploadedFileID!);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingFileIDs;
|
||||||
|
}
|
||||||
|
|
||||||
void _addToQueue(EnteFile file) {
|
void _addToQueue(EnteFile file) {
|
||||||
if (!LocalSettings.instance.hasEnabledMagicSearch()) {
|
if (!LocalSettings.instance.hasEnabledMagicSearch()) {
|
||||||
return;
|
return;
|
||||||
|
225
mobile/lib/services/magic_cache_service.dart
Normal file
225
mobile/lib/services/magic_cache_service.dart
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
import "dart:async";
|
||||||
|
import "dart:convert";
|
||||||
|
import "dart:io";
|
||||||
|
|
||||||
|
import "package:logging/logging.dart";
|
||||||
|
import "package:path_provider/path_provider.dart";
|
||||||
|
import "package:photos/models/file/file.dart";
|
||||||
|
import "package:photos/models/search/generic_search_result.dart";
|
||||||
|
import "package:photos/models/search/search_types.dart";
|
||||||
|
import "package:photos/service_locator.dart";
|
||||||
|
import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart";
|
||||||
|
import "package:photos/services/remote_assets_service.dart";
|
||||||
|
import "package:photos/services/search_service.dart";
|
||||||
|
import "package:shared_preferences/shared_preferences.dart";
|
||||||
|
|
||||||
|
class MagicCache {
|
||||||
|
final String title;
|
||||||
|
final List<int> fileUploadedIDs;
|
||||||
|
MagicCache(this.title, this.fileUploadedIDs);
|
||||||
|
|
||||||
|
factory MagicCache.fromJson(Map<String, dynamic> json) {
|
||||||
|
return MagicCache(
|
||||||
|
json['title'],
|
||||||
|
List<int>.from(json['fileUploadedIDs']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'title': title,
|
||||||
|
'fileUploadedIDs': fileUploadedIDs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static String encodeListToJson(List<MagicCache> magicCaches) {
|
||||||
|
final jsonList = magicCaches.map((cache) => cache.toJson()).toList();
|
||||||
|
return jsonEncode(jsonList);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<MagicCache> decodeJsonToList(String jsonString) {
|
||||||
|
final jsonList = jsonDecode(jsonString) as List;
|
||||||
|
return jsonList.map((json) => MagicCache.fromJson(json)).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MagicCacheServiceExtension on MagicCache {
|
||||||
|
Future<GenericSearchResult> toGenericSearchResult() async {
|
||||||
|
final allEnteFiles = await SearchService.instance.getAllFiles();
|
||||||
|
final enteFilesInMagicCache = <EnteFile>[];
|
||||||
|
for (EnteFile file in allEnteFiles) {
|
||||||
|
if (file.uploadedFileID != null &&
|
||||||
|
fileUploadedIDs.contains(file.uploadedFileID as int)) {
|
||||||
|
enteFilesInMagicCache.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GenericSearchResult(
|
||||||
|
ResultType.magic,
|
||||||
|
title,
|
||||||
|
enteFilesInMagicCache,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MagicCacheService {
|
||||||
|
static const _lastMagicCacheUpdateTime = "last_magic_cache_update_time";
|
||||||
|
static const _kMagicPromptsDataUrl = "https://discover.ente.io/v1.json";
|
||||||
|
|
||||||
|
/// Delay is for cache update to be done not during app init, during which a
|
||||||
|
/// lot of other things are happening.
|
||||||
|
static const _kCacheUpdateDelay = Duration(seconds: 10);
|
||||||
|
|
||||||
|
late SharedPreferences _prefs;
|
||||||
|
final Logger _logger = Logger((MagicCacheService).toString());
|
||||||
|
MagicCacheService._privateConstructor();
|
||||||
|
|
||||||
|
static final MagicCacheService instance =
|
||||||
|
MagicCacheService._privateConstructor();
|
||||||
|
|
||||||
|
void init(SharedPreferences preferences) {
|
||||||
|
_prefs = preferences;
|
||||||
|
_updateCacheIfTheTimeHasCome();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> resetLastMagicCacheUpdateTime() async {
|
||||||
|
await _prefs.setInt(
|
||||||
|
_lastMagicCacheUpdateTime,
|
||||||
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get lastMagicCacheUpdateTime {
|
||||||
|
return _prefs.getInt(_lastMagicCacheUpdateTime) ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateCacheIfTheTimeHasCome() async {
|
||||||
|
final jsonFile = await RemoteAssetsService.instance
|
||||||
|
.getAssetIfUpdated(_kMagicPromptsDataUrl);
|
||||||
|
if (jsonFile != null) {
|
||||||
|
Future.delayed(_kCacheUpdateDelay, () {
|
||||||
|
unawaited(_updateCache());
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lastMagicCacheUpdateTime <
|
||||||
|
DateTime.now()
|
||||||
|
.subtract(const Duration(days: 3))
|
||||||
|
.millisecondsSinceEpoch) {
|
||||||
|
Future.delayed(_kCacheUpdateDelay, () {
|
||||||
|
unawaited(_updateCache());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _getCachePath() async {
|
||||||
|
return (await getApplicationSupportDirectory()).path + "/cache/magic_cache";
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<int>> _getMatchingFileIDsForPromptData(
|
||||||
|
Map<String, dynamic> promptData,
|
||||||
|
) async {
|
||||||
|
final result = await SemanticSearchService.instance.getMatchingFileIDs(
|
||||||
|
promptData["prompt"] as String,
|
||||||
|
promptData["minimumScore"] as double,
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateCache() async {
|
||||||
|
try {
|
||||||
|
_logger.info("updating magic cache");
|
||||||
|
final magicPromptsData = await _loadMagicPrompts();
|
||||||
|
final magicCaches = await nonEmptyMagicResults(magicPromptsData);
|
||||||
|
final file = File(await _getCachePath());
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
file.createSync(recursive: true);
|
||||||
|
}
|
||||||
|
file.writeAsBytesSync(MagicCache.encodeListToJson(magicCaches).codeUnits);
|
||||||
|
unawaited(
|
||||||
|
resetLastMagicCacheUpdateTime().onError((error, stackTrace) {
|
||||||
|
_logger.warning(
|
||||||
|
"Error resetting last magic cache update time",
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
_logger.info("Error updating magic cache", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<MagicCache>?> _getMagicCache() async {
|
||||||
|
final file = File(await _getCachePath());
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
_logger.info("No magic cache found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final jsonString = file.readAsStringSync();
|
||||||
|
return MagicCache.decodeJsonToList(jsonString);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> clearMagicCache() async {
|
||||||
|
File(await _getCachePath()).deleteSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<GenericSearchResult>> getMagicGenericSearchResult() async {
|
||||||
|
try {
|
||||||
|
final magicCaches = await _getMagicCache();
|
||||||
|
if (magicCaches == null) {
|
||||||
|
_logger.info("No magic cache found");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<GenericSearchResult> genericSearchResults = [];
|
||||||
|
for (MagicCache magicCache in magicCaches) {
|
||||||
|
final genericSearchResult = await magicCache.toGenericSearchResult();
|
||||||
|
genericSearchResults.add(genericSearchResult);
|
||||||
|
}
|
||||||
|
return genericSearchResults;
|
||||||
|
} catch (e) {
|
||||||
|
_logger.info("Error getting magic generic search result", e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<dynamic>> _loadMagicPrompts() async {
|
||||||
|
final file =
|
||||||
|
await RemoteAssetsService.instance.getAsset(_kMagicPromptsDataUrl);
|
||||||
|
|
||||||
|
final json = jsonDecode(await file.readAsString());
|
||||||
|
return json["prompts"];
|
||||||
|
}
|
||||||
|
|
||||||
|
///Returns random non-empty magic results from magicPromptsData
|
||||||
|
///Length is capped at [limit], can be less than [limit] if there are not enough
|
||||||
|
///non-empty results
|
||||||
|
Future<List<MagicCache>> nonEmptyMagicResults(
|
||||||
|
List<dynamic> magicPromptsData,
|
||||||
|
) async {
|
||||||
|
//Show all magic prompts to internal users for feedback on results
|
||||||
|
final limit = flagService.internalUser ? magicPromptsData.length : 4;
|
||||||
|
final results = <MagicCache>[];
|
||||||
|
final randomIndexes = List.generate(
|
||||||
|
magicPromptsData.length,
|
||||||
|
(index) => index,
|
||||||
|
growable: false,
|
||||||
|
)..shuffle();
|
||||||
|
for (final index in randomIndexes) {
|
||||||
|
final files =
|
||||||
|
await _getMatchingFileIDsForPromptData(magicPromptsData[index]);
|
||||||
|
if (files.isNotEmpty) {
|
||||||
|
results.add(
|
||||||
|
MagicCache(
|
||||||
|
magicPromptsData[index]["title"] as String,
|
||||||
|
files,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (results.length >= limit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
@ -21,17 +21,46 @@ class RemoteAssetsService {
|
|||||||
Future<File> getAsset(String remotePath, {bool refetch = false}) async {
|
Future<File> getAsset(String remotePath, {bool refetch = false}) async {
|
||||||
final path = await _getLocalPath(remotePath);
|
final path = await _getLocalPath(remotePath);
|
||||||
final file = File(path);
|
final file = File(path);
|
||||||
if (await file.exists() && !refetch) {
|
if (file.existsSync() && !refetch) {
|
||||||
_logger.info("Returning cached file for $remotePath");
|
_logger.info("Returning cached file for $remotePath");
|
||||||
return file;
|
return file;
|
||||||
} else {
|
} else {
|
||||||
final tempFile = File(path + ".temp");
|
final tempFile = File(path + ".temp");
|
||||||
await _downloadFile(remotePath, tempFile.path);
|
await _downloadFile(remotePath, tempFile.path);
|
||||||
await tempFile.rename(path);
|
tempFile.renameSync(path);
|
||||||
return File(path);
|
return File(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Returns asset if the remote asset is new compared to the local copy of it
|
||||||
|
Future<File?> getAssetIfUpdated(String remotePath) async {
|
||||||
|
try {
|
||||||
|
final path = await _getLocalPath(remotePath);
|
||||||
|
final file = File(path);
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
final tempFile = File(path + ".temp");
|
||||||
|
await _downloadFile(remotePath, tempFile.path);
|
||||||
|
tempFile.renameSync(path);
|
||||||
|
return File(path);
|
||||||
|
} else {
|
||||||
|
final existingFileSize = File(path).lengthSync();
|
||||||
|
final tempFile = File(path + ".temp");
|
||||||
|
await _downloadFile(remotePath, tempFile.path);
|
||||||
|
final newFileSize = tempFile.lengthSync();
|
||||||
|
if (existingFileSize != newFileSize) {
|
||||||
|
tempFile.renameSync(path);
|
||||||
|
return File(path);
|
||||||
|
} else {
|
||||||
|
tempFile.deleteSync();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_logger.warning("Error getting asset if updated", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> hasAsset(String remotePath) async {
|
Future<bool> hasAsset(String remotePath) async {
|
||||||
final path = await _getLocalPath(remotePath);
|
final path = await _getLocalPath(remotePath);
|
||||||
return File(path).exists();
|
return File(path).exists();
|
||||||
@ -60,8 +89,8 @@ class RemoteAssetsService {
|
|||||||
Future<void> _downloadFile(String url, String savePath) async {
|
Future<void> _downloadFile(String url, String savePath) async {
|
||||||
_logger.info("Downloading " + url);
|
_logger.info("Downloading " + url);
|
||||||
final existingFile = File(savePath);
|
final existingFile = File(savePath);
|
||||||
if (await existingFile.exists()) {
|
if (existingFile.existsSync()) {
|
||||||
await existingFile.delete();
|
existingFile.deleteSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
await NetworkClient.instance.getDio().download(
|
await NetworkClient.instance.getDio().download(
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import "dart:convert";
|
|
||||||
import "dart:math";
|
import "dart:math";
|
||||||
|
|
||||||
import "package:flutter/cupertino.dart";
|
import "package:flutter/cupertino.dart";
|
||||||
@ -33,13 +32,14 @@ import "package:photos/services/location_service.dart";
|
|||||||
import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart";
|
import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart";
|
||||||
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
|
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
|
||||||
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
|
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
|
||||||
import "package:photos/services/remote_assets_service.dart";
|
import "package:photos/services/magic_cache_service.dart";
|
||||||
import "package:photos/states/location_screen_state.dart";
|
import "package:photos/states/location_screen_state.dart";
|
||||||
import "package:photos/ui/viewer/location/add_location_sheet.dart";
|
import "package:photos/ui/viewer/location/add_location_sheet.dart";
|
||||||
import "package:photos/ui/viewer/location/location_screen.dart";
|
import "package:photos/ui/viewer/location/location_screen.dart";
|
||||||
import "package:photos/ui/viewer/people/cluster_page.dart";
|
import "package:photos/ui/viewer/people/cluster_page.dart";
|
||||||
import "package:photos/ui/viewer/people/people_page.dart";
|
import "package:photos/ui/viewer/people/people_page.dart";
|
||||||
import 'package:photos/utils/date_time_util.dart';
|
import 'package:photos/utils/date_time_util.dart';
|
||||||
|
import "package:photos/utils/local_settings.dart";
|
||||||
import "package:photos/utils/navigation_util.dart";
|
import "package:photos/utils/navigation_util.dart";
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
@ -49,9 +49,6 @@ class SearchService {
|
|||||||
final _logger = Logger((SearchService).toString());
|
final _logger = Logger((SearchService).toString());
|
||||||
final _collectionService = CollectionsService.instance;
|
final _collectionService = CollectionsService.instance;
|
||||||
static const _maximumResultsLimit = 20;
|
static const _maximumResultsLimit = 20;
|
||||||
static const _kMagicPromptsDataUrl = "https://discover.ente.io/v1.json";
|
|
||||||
|
|
||||||
var magicPromptsData = [];
|
|
||||||
|
|
||||||
SearchService._privateConstructor();
|
SearchService._privateConstructor();
|
||||||
|
|
||||||
@ -63,17 +60,6 @@ class SearchService {
|
|||||||
_cachedFilesFuture = null;
|
_cachedFilesFuture = null;
|
||||||
_cachedHiddenFilesFuture = null;
|
_cachedHiddenFilesFuture = null;
|
||||||
});
|
});
|
||||||
if (flagService.internalUser) {
|
|
||||||
_loadMagicPrompts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> _loadMagicPrompts() async {
|
|
||||||
final file = await RemoteAssetsService.instance
|
|
||||||
.getAsset(_kMagicPromptsDataUrl, refetch: true);
|
|
||||||
|
|
||||||
final json = jsonDecode(await file.readAsString());
|
|
||||||
magicPromptsData = json["prompts"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<int> ignoreCollections() {
|
Set<int> ignoreCollections() {
|
||||||
@ -192,26 +178,12 @@ class SearchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<GenericSearchResult>> getMagicSectionResutls() async {
|
Future<List<GenericSearchResult>> getMagicSectionResutls() async {
|
||||||
if (!SemanticSearchService.instance.isMagicSearchEnabledAndReady()) {
|
if (LocalSettings.instance.hasEnabledMagicSearch() &&
|
||||||
|
flagService.internalUser) {
|
||||||
|
return MagicCacheService.instance.getMagicGenericSearchResult();
|
||||||
|
} else {
|
||||||
return <GenericSearchResult>[];
|
return <GenericSearchResult>[];
|
||||||
}
|
}
|
||||||
final searchResuts = <GenericSearchResult>[];
|
|
||||||
for (Map<String, dynamic> magicPrompt in magicPromptsData) {
|
|
||||||
final files = await SemanticSearchService.instance.getMatchingFiles(
|
|
||||||
magicPrompt["prompt"],
|
|
||||||
scoreThreshold: magicPrompt["minimumScore"],
|
|
||||||
);
|
|
||||||
if (files.isNotEmpty) {
|
|
||||||
searchResuts.add(
|
|
||||||
GenericSearchResult(
|
|
||||||
ResultType.magic,
|
|
||||||
magicPrompt["title"],
|
|
||||||
files,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return searchResuts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<GenericSearchResult>> getRandomMomentsSearchResults(
|
Future<List<GenericSearchResult>> getRandomMomentsSearchResults(
|
||||||
|
@ -33,28 +33,6 @@ class _MagicSectionState extends State<MagicSection> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
_magicSearchResults = widget.magicSearchResults;
|
_magicSearchResults = widget.magicSearchResults;
|
||||||
|
|
||||||
//At times, ml framework is not initialized when the search results are
|
|
||||||
//requested (widget.momentsSearchResults is empty) and is initialized
|
|
||||||
//(which fires MLFrameworkInitializationUpdateEvent with
|
|
||||||
//InitializationState.initialized) before initState of this widget is
|
|
||||||
//called. We do listen to MLFrameworkInitializationUpdateEvent and reload
|
|
||||||
//this widget but the event with InitializationState.initialized would have
|
|
||||||
//already been fired in the above case.
|
|
||||||
if (_magicSearchResults.isEmpty) {
|
|
||||||
SectionType.magic
|
|
||||||
.getData(
|
|
||||||
context,
|
|
||||||
limit: kSearchSectionLimit,
|
|
||||||
)
|
|
||||||
.then((value) {
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_magicSearchResults = value as List<GenericSearchResult>;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final streamsToListenTo = SectionType.magic.sectionUpdateEvents();
|
final streamsToListenTo = SectionType.magic.sectionUpdateEvents();
|
||||||
for (Stream<Event> stream in streamsToListenTo) {
|
for (Stream<Event> stream in streamsToListenTo) {
|
||||||
streamSubscriptions.add(
|
streamSubscriptions.add(
|
||||||
@ -84,7 +62,6 @@ class _MagicSectionState extends State<MagicSection> {
|
|||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant MagicSection oldWidget) {
|
void didUpdateWidget(covariant MagicSection oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
//widget.magicSearch is empty when doing a hot reload
|
|
||||||
if (widget.magicSearchResults.isNotEmpty) {
|
if (widget.magicSearchResults.isNotEmpty) {
|
||||||
_magicSearchResults = widget.magicSearchResults;
|
_magicSearchResults = widget.magicSearchResults;
|
||||||
}
|
}
|
||||||
@ -262,7 +239,7 @@ class MagicRecommendation extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxWidth: 76,
|
maxWidth: 88,
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user