Vishnu Mohandas 1 anno fa
parent
commit
5bbf227344

+ 92 - 34
lib/services/location_service.dart

@@ -1,11 +1,14 @@
 import "dart:convert";
+import "dart:io";
 import "dart:math";
 
+import "package:computer/computer.dart";
 import "package:logging/logging.dart";
 import "package:photos/core/constants.dart";
 import "package:photos/core/event_bus.dart";
 import "package:photos/events/location_tag_updated_event.dart";
 import "package:photos/models/api/entity/type.dart";
+import "package:photos/models/file/file.dart";
 import "package:photos/models/local_entity_data.dart";
 import "package:photos/models/location/location.dart";
 import 'package:photos/models/location_tag/location_tag.dart';
@@ -17,7 +20,7 @@ import "package:shared_preferences/shared_preferences.dart";
 class LocationService {
   late SharedPreferences prefs;
   final Logger _logger = Logger((LocationService).toString());
-  final List<City> _cities = [];
+  final Computer _computer = Computer.shared();
 
   LocationService._privateConstructor();
 
@@ -25,6 +28,8 @@ class LocationService {
 
   static const kCitiesRemotePath = "https://assets.ente.io/world_cities.json";
 
+  List<City> _cities = [];
+
   void init(SharedPreferences preferences) {
     prefs = preferences;
     if (FeatureFlagService.instance.isInternalUserOrDebugBuild()) {
@@ -39,8 +44,19 @@ class LocationService {
     );
   }
 
-  List<City> getAllCities() {
-    return _cities;
+  Future<Map<City, List<EnteFile>>> getFilesInCity(
+    List<EnteFile> allFiles,
+    String query,
+  ) async {
+    final result = await _computer.compute(
+      getCityResults,
+      param: {
+        "query": query,
+        "cities": _cities,
+        "files": allFiles,
+      },
+    );
+    return result;
   }
 
   Future<Iterable<LocalEntity<LocationTag>>> getLocationTags() {
@@ -77,14 +93,6 @@ class LocationService {
     }
   }
 
-  ///The area bounded by the location tag becomes more elliptical with increase
-  ///in the magnitude of the latitude on the caritesian plane. When latitude is
-  ///0 degrees, the ellipse is a circle with a = b = r. When latitude incrases,
-  ///the major axis (a) has to be scaled by the secant of the latitude.
-  double _scaleFactor(double lat) {
-    return 1 / cos(lat * (pi / 180));
-  }
-
   Future<List<LocalEntity<LocationTag>>> enclosingLocationTags(
     Location fileCoordinates,
   ) async {
@@ -110,22 +118,6 @@ class LocationService {
     }
   }
 
-  bool isFileInsideLocationTag(
-    Location centerPoint,
-    Location fileCoordinates,
-    double radius,
-  ) {
-    final a =
-        (radius * _scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
-    final b = radius / kilometersPerDegree;
-    final x = centerPoint.latitude! - fileCoordinates.latitude!;
-    final y = centerPoint.longitude! - fileCoordinates.longitude!;
-    if ((x * x) / (a * a) + (y * y) / (b * b) <= 1) {
-      return true;
-    }
-    return false;
-  }
-
   /// returns [lat, lng]
   List<String>? convertLocationToDMS(Location centerPoint) {
     if (centerPoint.latitude == null || centerPoint.longitude == null) {
@@ -218,14 +210,15 @@ class LocationService {
 
   Future<void> _loadCities() async {
     try {
-      final data =
+      final file =
           await RemoteAssetsService.instance.getAsset(kCitiesRemotePath);
-      final citiesJson = json.decode(await data.readAsString());
-      final List<dynamic> jsonData = citiesJson['data'];
-      final cities =
-          jsonData.map<City>((jsonItem) => City.fromMap(jsonItem)).toList();
-      _cities.clear();
-      _cities.addAll(cities);
+      final startTime = DateTime.now();
+      _cities =
+          await _computer.compute(parseCities, param: {"filePath": file.path});
+      final endTime = DateTime.now();
+      _logger.info(
+        "Loaded cities in ${(endTime.millisecondsSinceEpoch - startTime.millisecondsSinceEpoch)}ms",
+      );
       _logger.info("Loaded cities");
     } catch (e, s) {
       _logger.severe("Failed to load cities", e, s);
@@ -233,6 +226,71 @@ class LocationService {
   }
 }
 
+Future<List<City>> parseCities(Map args) async {
+  final file = File(args["filePath"]);
+  final citiesJson = json.decode(await file.readAsString());
+
+  final List<dynamic> jsonData = citiesJson['data'];
+  final cities =
+      jsonData.map<City>((jsonItem) => City.fromMap(jsonItem)).toList();
+  return cities;
+}
+
+Map<City, List<EnteFile>> getCityResults(Map args) {
+  final query = (args["query"] as String).toLowerCase();
+  final cities = args["cities"] as List<City>;
+  final files = args["files"] as List<EnteFile>;
+
+  final matchingCities = cities.where(
+    (city) => city.city.toLowerCase().contains(query),
+  );
+
+  final Map<City, List<EnteFile>> results = {};
+  for (final city in matchingCities) {
+    final List<EnteFile> matchingFiles = [];
+    final cityLocation = Location(latitude: city.lat, longitude: city.lng);
+    for (final file in files) {
+      if (file.hasLocation) {
+        if (isFileInsideLocationTag(
+          cityLocation,
+          file.location!,
+          defaultCityRadius,
+        )) {
+          matchingFiles.add(file);
+        }
+      }
+    }
+    if (matchingFiles.isNotEmpty) {
+      results[city] = matchingFiles;
+    }
+  }
+  return results;
+}
+
+bool isFileInsideLocationTag(
+  Location centerPoint,
+  Location fileCoordinates,
+  double radius,
+) {
+  final a =
+      (radius * _scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
+  final b = radius / kilometersPerDegree;
+  final x = centerPoint.latitude! - fileCoordinates.latitude!;
+  final y = centerPoint.longitude! - fileCoordinates.longitude!;
+  if ((x * x) / (a * a) + (y * y) / (b * b) <= 1) {
+    return true;
+  }
+  return false;
+}
+
+///The area bounded by the location tag becomes more elliptical with increase
+///in the magnitude of the latitude on the caritesian plane. When latitude is
+///0 degrees, the ellipse is a circle with a = b = r. When latitude incrases,
+///the major axis (a) has to be scaled by the secant of the latitude.
+double _scaleFactor(double lat) {
+  return 1 / cos(lat * (pi / 180));
+}
+
 class City {
   final String city;
   final String country;

+ 5 - 37
lib/services/search_service.dart

@@ -3,7 +3,6 @@ import "dart:math";
 import "package:flutter/cupertino.dart";
 import "package:intl/intl.dart";
 import 'package:logging/logging.dart';
-import "package:photos/core/constants.dart";
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/data/holidays.dart';
 import 'package:photos/data/months.dart';
@@ -18,7 +17,6 @@ import "package:photos/models/file/extensions/file_props.dart";
 import 'package:photos/models/file/file.dart';
 import 'package:photos/models/file/file_type.dart';
 import "package:photos/models/local_entity_data.dart";
-import "package:photos/models/location/location.dart";
 import "package:photos/models/location_tag/location_tag.dart";
 import 'package:photos/models/search/album_search_result.dart';
 import 'package:photos/models/search/generic_search_result.dart';
@@ -620,7 +618,7 @@ class SearchService {
     for (EnteFile file in allFiles) {
       if (file.hasLocation) {
         for (LocalEntity<LocationTag> tag in result.keys) {
-          if (LocationService.instance.isFileInsideLocationTag(
+          if (isFileInsideLocationTag(
             tag.item.centerPoint,
             file.location!,
             tag.item.radius,
@@ -639,7 +637,7 @@ class SearchService {
           return false;
         }
         for (LocalEntity<LocationTag> tag in locationTagEntities) {
-          if (LocationService.instance.isFileInsideLocationTag(
+          if (isFileInsideLocationTag(
             tag.item.centerPoint,
             file.location!,
             tag.item.radius,
@@ -684,36 +682,9 @@ class SearchService {
   }
 
   Future<List<GenericSearchResult>> getCityResults(String query) async {
-    final startTime = DateTime.now().microsecondsSinceEpoch;
-    final List<GenericSearchResult> searchResults = [];
-    final cities = LocationService.instance.getAllCities();
-    final matchingCities = <City>[];
-    final queryLower = query.toLowerCase();
-    for (City city in cities) {
-      if (city.city.toLowerCase().startsWith(queryLower)) {
-        matchingCities.add(city);
-      }
-    }
     final files = await getAllFiles();
-    final Map<City, List<EnteFile>> results = {};
-    for (final city in matchingCities) {
-      final List<EnteFile> matchingFiles = [];
-      final cityLocation = Location(latitude: city.lat, longitude: city.lng);
-      for (final file in files) {
-        if (file.hasLocation) {
-          if (LocationService.instance.isFileInsideLocationTag(
-            cityLocation,
-            file.location!,
-            defaultCityRadius,
-          )) {
-            matchingFiles.add(file);
-          }
-        }
-      }
-      if (matchingFiles.isNotEmpty) {
-        results[city] = matchingFiles;
-      }
-    }
+    final results = await LocationService.instance.getFilesInCity(files, query);
+    final List<GenericSearchResult> searchResults = [];
     for (final entry in results.entries) {
       searchResults.add(
         GenericSearchResult(
@@ -723,9 +694,6 @@ class SearchService {
         ),
       );
     }
-    final endTime = DateTime.now().microsecondsSinceEpoch;
-    _logger
-        .info("Time taken " + ((endTime - startTime) / 1000).toString() + "ms");
     return searchResults;
   }
 
@@ -745,7 +713,7 @@ class SearchService {
       for (EnteFile file in allFiles) {
         if (file.hasLocation) {
           for (LocalEntity<LocationTag> tag in tagToItemsMap.keys) {
-            if (LocationService.instance.isFileInsideLocationTag(
+            if (isFileInsideLocationTag(
               tag.item.centerPoint,
               file.location!,
               tag.item.radius,

+ 5 - 5
lib/services/semantic_search/embedding_store.dart

@@ -133,12 +133,12 @@ class EmbeddingStore {
       return;
     }
     final inputs = <EmbeddingsDecoderInput>[];
+    final fileMap = await FilesDB.instance
+        .getFilesFromIDs(remoteEmbeddings.map((e) => e.fileID).toList());
+
     for (final embedding in remoteEmbeddings) {
-      final file = await FilesDB.instance.getAnyUploadedFile(embedding.fileID);
-      if (file == null) {
-        continue;
-      }
-      final fileKey = getFileKey(file);
+      final file = fileMap[embedding.fileID];
+      final fileKey = getFileKey(file!);
       final input = EmbeddingsDecoderInput(embedding, fileKey);
       inputs.add(input);
     }

+ 6 - 1
lib/services/semantic_search/semantic_search_service.dart

@@ -13,6 +13,7 @@ import 'package:photos/events/embedding_updated_event.dart';
 import "package:photos/events/file_uploaded_event.dart";
 import "package:photos/models/embedding.dart";
 import "package:photos/models/file/file.dart";
+import "package:photos/services/collections_service.dart";
 import "package:photos/services/semantic_search/embedding_store.dart";
 import "package:photos/services/semantic_search/frameworks/ggml.dart";
 import "package:photos/services/semantic_search/frameworks/ml_framework.dart";
@@ -215,8 +216,12 @@ class SemanticSearchService {
     final filesMap = await FilesDB.instance
         .getFilesFromIDs(queryResults.map((e) => e.id).toList());
     final results = <EnteFile>[];
+
+    final ignoredCollections =
+        CollectionsService.instance.getHiddenCollectionIds();
     for (final result in queryResults) {
-      if (filesMap.containsKey(result.id)) {
+      final file = filesMap[result.id];
+      if (file != null && !ignoredCollections.contains(file.collectionID)) {
         results.add(filesMap[result.id]!);
       }
     }

+ 1 - 1
lib/ui/viewer/location/dynamic_location_gallery_widget.dart

@@ -62,7 +62,7 @@ class _DynamicLocationGalleryWidgetState
       final stopWatch = Stopwatch()..start();
       final copyOfFiles = List<EnteFile>.from(result.files);
       copyOfFiles.removeWhere((f) {
-        return !LocationService.instance.isFileInsideLocationTag(
+        return !isFileInsideLocationTag(
           InheritedLocationTagData.of(context).centerPoint,
           f.location!,
           selectedRadius,

+ 1 - 1
lib/ui/viewer/location/location_screen.dart

@@ -205,7 +205,7 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
       final stopWatch = Stopwatch()..start();
       final filesInLocation = allFilesWithLocation;
       filesInLocation.removeWhere((f) {
-        return !LocationService.instance.isFileInsideLocationTag(
+        return !isFileInsideLocationTag(
           centerPoint,
           f.location!,
           selectedRadius,

+ 1 - 1
pubspec.yaml

@@ -12,7 +12,7 @@ description: ente photos application
 # Read more about iOS versioning at
 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 
-version: 0.8.32+552
+version: 0.8.33+553
 
 environment:
   sdk: ">=3.0.0 <4.0.0"