diff --git a/.github/workflows/mobile-daily-internal.yml b/.github/workflows/mobile-daily-internal.yml index e05600e312..2dee4c4ef4 100644 --- a/.github/workflows/mobile-daily-internal.yml +++ b/.github/workflows/mobile-daily-internal.yml @@ -8,6 +8,7 @@ on: env: FLUTTER_VERSION: "3.32.8" + RUST_VERSION: "1.85.1" permissions: contents: read @@ -38,6 +39,14 @@ jobs: flutter-version: ${{ env.FLUTTER_VERSION }} cache: true + - name: Install Rust ${{ env.RUST_VERSION }} + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} + + - name: Install Flutter Rust Bridge + run: cargo install flutter_rust_bridge_codegen + - name: Increment version code for build run: | CURRENT_VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //') diff --git a/.github/workflows/mobile-internal-release-rust.yml b/.github/workflows/mobile-internal-release-rust.yml deleted file mode 100644 index e5c85f1e37..0000000000 --- a/.github/workflows/mobile-internal-release-rust.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: "Internal release (photos with rust)" - -on: - workflow_dispatch: # Allow manually running the action - -env: - FLUTTER_VERSION: "3.32.8" - RUST_VERSION: "1.85.1" - -permissions: - contents: write - -jobs: - build: - runs-on: ubuntu-latest - - defaults: - run: - working-directory: mobile/apps/photos - - steps: - - name: Checkout code and submodules - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Setup JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - - name: Install Flutter ${{ env.FLUTTER_VERSION }} - uses: subosito/flutter-action@v2 - with: - channel: "stable" - flutter-version: ${{ env.FLUTTER_VERSION }} - cache: true - - - name: Install Rust ${{ env.RUST_VERSION }} - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ env.RUST_VERSION }} - - - name: Install Flutter Rust Bridge - run: cargo install flutter_rust_bridge_codegen - - - name: Setup keys - uses: timheuer/base64-to-file@v1 - with: - fileName: "keystore/ente_photos_key.jks" - encodedString: ${{ secrets.SIGNING_KEY_PHOTOS }} - - - name: Build PlayStore AAB - run: | - flutter build appbundle --dart-define=cronetHttpNoPlay=true --release --flavor playstore - env: - SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_photos_key.jks" - SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS_PHOTOS }} - SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD_PHOTOS }} - SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD_PHOTOS }} - - - name: Upload AAB to PlayStore - uses: r0adkll/upload-google-play@v1 - with: - serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }} - packageName: io.ente.photos - releaseFiles: mobile/apps/photos/build/app/outputs/bundle/playstoreRelease/app-playstore-release.aab - track: internal - - - name: Notify Discord - uses: sarisia/actions-status-discord@v1 - with: - webhook: ${{ secrets.DISCORD_INTERNAL_RELEASE_WEBHOOK }} - nodetail: true - title: "🏆 Internal release available for Photos" - description: "[Download](https://play.google.com/store/apps/details?id=io.ente.photos)" - color: 0x00ff00 diff --git a/.github/workflows/mobile-internal-release.yml b/.github/workflows/mobile-internal-release.yml index 8ce8febf9f..768609dfa3 100644 --- a/.github/workflows/mobile-internal-release.yml +++ b/.github/workflows/mobile-internal-release.yml @@ -5,6 +5,7 @@ on: env: FLUTTER_VERSION: "3.32.8" + RUST_VERSION: "1.85.1" permissions: contents: write @@ -35,6 +36,14 @@ jobs: flutter-version: ${{ env.FLUTTER_VERSION }} cache: true + - name: Install Rust ${{ env.RUST_VERSION }} + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} + + - name: Install Flutter Rust Bridge + run: cargo install flutter_rust_bridge_codegen + - name: Setup keys uses: timheuer/base64-to-file@v1 with: diff --git a/docs/docs/.vitepress/sidebar.ts b/docs/docs/.vitepress/sidebar.ts index 4cd620992e..cc83fb3d69 100644 --- a/docs/docs/.vitepress/sidebar.ts +++ b/docs/docs/.vitepress/sidebar.ts @@ -26,6 +26,10 @@ export const sidebar = [ text: "Collecting photos", link: "/photos/features/collect", }, + { + text: "Custom domains", + link: "/photos/features/custom-domains/", + }, { text: "Deduplicate", link: "/photos/features/deduplicate", diff --git a/docs/docs/photos/faq/desktop.md b/docs/docs/photos/faq/desktop.md index f590c956a9..b705bedfc4 100644 --- a/docs/docs/photos/faq/desktop.md +++ b/docs/docs/photos/faq/desktop.md @@ -35,4 +35,4 @@ be specific to your distro (e.g. `xdg-desktop-menu forceupdate`). > [!NOTE] > > If you're using an AppImage and not seeing the icon, you'll need to -> [enable AppImage desktop integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration). \ No newline at end of file +> [enable AppImage desktop integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration). diff --git a/docs/docs/photos/features/custom-domains/cf.png b/docs/docs/photos/features/custom-domains/cf.png new file mode 100644 index 0000000000..0bb47d8678 Binary files /dev/null and b/docs/docs/photos/features/custom-domains/cf.png differ diff --git a/docs/docs/photos/features/custom-domains/index.md b/docs/docs/photos/features/custom-domains/index.md new file mode 100644 index 0000000000..444ea00d44 --- /dev/null +++ b/docs/docs/photos/features/custom-domains/index.md @@ -0,0 +1,105 @@ +--- +title: Custom domains +description: Use your own domain when sharing photos and videos stored in Ente Photos +--- + +# Custom domains + +Custom domains allow you to serve your public links with your own personalized domain. + +For example, if I have an Ente album and wish to share it with my friends, I can go to the album's sharing settings and create a public link. When I copy this link, it will of the form of + +``` +https://albums.ente.io/?t=... +``` + +The custom domains feature allows you to instead create a link that uses your own domain, say + +``` +https://pics.example.org/?t=... +``` + +You don't need to run any servers or manage any services, Ente will still host and serve your album for you, the only thing that changes is that you can serve your links using your personalized domain. + +## Availability + +The custom domains feature requires the ability to publicly share albums which for abuse prevention reasons can only be done by people with an active Ente subscription. + +## Setup + +The setup involves two steps: + +1. Letting Ente know about the domain you wish to use for serving your public links +2. Updating your DNS settings to point your domain (or subdomain) to **my.ente.io** + +For people who are comfortable with changing DNS settings on their domain provider, this entire process is very simple will take a minute. For people who are not comfortable with changing DNS, we will provide a more detailed breakdown below. + +Let's dive in. + +To make the process concrete, let's assume we're trying to use _pics.example.org_ as our custom domain. Note that there is no restriction to use a subdomain, a top level domain can be used as a custom domain too. That is, either of _example.org_ or _subdomain.example.org_ is fine, Ente will work with both. + +### Step 1 - Link your domain + +The first step is to let Ente know about the domain or subdomain you wish to use by linking it to your account. + +> [!WARNING] +> +> Currently (Aug 2025) the ability to link a custom domain is only present in Ente's web app, [web.ente.io](https://web.ente.io). It will come to Ente mobile and desktop when their next versions get released. + +Head over to Preferences > Custom domains, in the domain field enter "pics.example.org" (replace with your subdomain) and press "Save". That's it. The linking is done. + +### Step 2 - Add DNS entry + +The second step is to add a CNAME entry in your DNS provider that forwards requests for pics.example.org (replace with your subdomain) to **my.ente.io**. + +Specifically, you need to add a `CNAME record` from the domain (or subdomain) of your choice to `my.ente.io`. You can leave the `TTL` at its default. + +| Record Type | Name | Value | TTL | +| ----------- | :------------------------: | -----------: | -------------- | +| CNAME | Your subdomain, e.g `pics` | `my.ente.io` | Auto (default) | + +The exact steps for doing this depend on the DNS provider that you're using. + +> Your DNS provider usually is the service from which you bought your domain. The domain name seller will provide some sort of an admin panel where you can configure your DNS settings. + +As concrete examples, here is how this step would look for Cloudflare: + +![Adding a CNAME for custom domain in Cloudflare](cf.png) + +Note that orange proxy option is off. And here is how it would look for Namecheap: + +![Adding a CNAME for custom domain in Namecheap](nc.png) + +> [!NOTE] +> +> The examples are using "pics" as the subdomain, but that's just an example, you can use anything you like (or use "@" if you'd like to use the root domain itself). + +The time it takes for DNS records to update is dependent on your DNS provider. Usually the changes should start reflecting within a few minutes, and should almost always reflect within an hour. + +Once the DNS changes have been applied, then you can take any public link to your shared albums, replace `albums.ente.io` with your choice (e.g. `pics.example.org`), and the link will still work. + +You don't need to do this manually though, the apps will do it for you. More on this in the next section. But first, some troubleshooting tips. + +### Troubleshooting + +If your domain is not working, go through the following checklist. + +- The CNAME should be from your domain to my.ente.io, not the other way around. That is, `pics.example.org => my.ente.io`. + +- If you're using Cloudflare DNS, make sure that the "Orange" proxy status toggle is off, and the Proxy status is the "Grey" DNS only. + +## Using + +Using is trivial. When you go to an album's sharing options and copy the link to it, Ente will automatically copy the link that uses your configured domain. + +> [!WARNING] +> +> Currently (Aug 2025) the ability to automatically substitute your custom domain is only present in Ente's web app, [web.ente.io](https://web.ente.io). It will come to Ente mobile and desktop when their next versions get released. + +## Unsetting + +To stop using your custom domain, we need to undo the two steps we did during setup. + +1. Unlink your domain in Ente. This can be done just by going to Preferences > Custom Domains, clearing the value in the "Domain" input and pressing "Update". + +2. Remove the CNAME record you added during setup in your DNS provider. diff --git a/docs/docs/photos/features/custom-domains/nc.png b/docs/docs/photos/features/custom-domains/nc.png new file mode 100644 index 0000000000..b6a34a0081 Binary files /dev/null and b/docs/docs/photos/features/custom-domains/nc.png differ diff --git a/docs/docs/photos/troubleshooting/desktop-install/index.md b/docs/docs/photos/troubleshooting/desktop-install/index.md index 85e6cb5e62..8543b78e34 100644 --- a/docs/docs/photos/troubleshooting/desktop-install/index.md +++ b/docs/docs/photos/troubleshooting/desktop-install/index.md @@ -112,4 +112,4 @@ ip addr add 10.10.10.1/24 dev dummy0 ip link set dummy0 up ``` -Once the interface is up, Ente correctly detects that the system is online. \ No newline at end of file +Once the interface is up, Ente correctly detects that the system is online. diff --git a/mobile/apps/auth/android/app/build.gradle b/mobile/apps/auth/android/app/build.gradle index 5cf5b50776..4633c502f3 100644 --- a/mobile/apps/auth/android/app/build.gradle +++ b/mobile/apps/auth/android/app/build.gradle @@ -30,11 +30,13 @@ if (keystorePropertiesFile.exists()) { android { namespace "io.ente.auth" - compileSdk 35 + compileSdk 36 ndkVersion flutter.ndkVersion compileOptions { - coreLibraryDesugaringEnabled = true + // Flag to enable support for the new language APIs + coreLibraryDesugaringEnabled true + // Sets Java compatibility to Java 8 sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } @@ -57,8 +59,8 @@ android { applicationId "io.ente.auth" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion 22 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 35 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -117,5 +119,6 @@ flutter { } dependencies { + // For AGP 7.4+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") } diff --git a/mobile/apps/auth/android/gradle/wrapper/gradle-wrapper.properties b/mobile/apps/auth/android/gradle/wrapper/gradle-wrapper.properties index 9c5194d3a2..3c85cfe057 100644 --- a/mobile/apps/auth/android/gradle/wrapper/gradle-wrapper.properties +++ b/mobile/apps/auth/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip diff --git a/mobile/apps/auth/android/settings.gradle b/mobile/apps/auth/android/settings.gradle index 58725889bd..3ddaae5aa3 100644 --- a/mobile/apps/auth/android/settings.gradle +++ b/mobile/apps/auth/android/settings.gradle @@ -19,8 +19,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.2.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + id "com.android.application" version "8.6.0" apply false + id "org.jetbrains.kotlin.android" version "2.1.10" apply false } include ":app" diff --git a/mobile/apps/auth/assets/custom-icons/_data/custom-icons.json b/mobile/apps/auth/assets/custom-icons/_data/custom-icons.json index 4ef6f6694c..2e85ad557d 100644 --- a/mobile/apps/auth/assets/custom-icons/_data/custom-icons.json +++ b/mobile/apps/auth/assets/custom-icons/_data/custom-icons.json @@ -1358,6 +1358,13 @@ "r10.net" ] }, + { + "title": "RaiderIO", + "slug": "raider_io", + "altNames": [ + "raider.io" + ] + }, { "title": "Raindrop.io", "slug": "raindrop_io", @@ -1501,6 +1508,10 @@ { "title": "Skinport" }, + { + "title": "Skyscanner", + "hex": "0770E3" + }, { "title": "SMSPool", "slug": "sms_pool_net", diff --git a/mobile/apps/auth/assets/custom-icons/icons/raider_io.svg b/mobile/apps/auth/assets/custom-icons/icons/raider_io.svg new file mode 100644 index 0000000000..56b9849f6f --- /dev/null +++ b/mobile/apps/auth/assets/custom-icons/icons/raider_io.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mobile/apps/auth/assets/custom-icons/icons/skyscanner.svg b/mobile/apps/auth/assets/custom-icons/icons/skyscanner.svg new file mode 100644 index 0000000000..69fa35c34c --- /dev/null +++ b/mobile/apps/auth/assets/custom-icons/icons/skyscanner.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/mobile/apps/auth/lib/utils/platform_util.dart b/mobile/apps/auth/lib/utils/platform_util.dart index bad3c8e738..40ae35ae53 100644 --- a/mobile/apps/auth/lib/utils/platform_util.dart +++ b/mobile/apps/auth/lib/utils/platform_util.dart @@ -59,14 +59,14 @@ class PlatformUtil { if (Platform.isAndroid || Platform.isIOS) { await FileSaver.instance.saveAs( name: fileName, - ext: extension, + fileExtension: extension, bytes: bytes, mimeType: type, ); } else { await FileSaver.instance.saveFile( name: fileName, - ext: extension, + fileExtension: extension, bytes: bytes, mimeType: type, ); diff --git a/mobile/apps/auth/pubspec.lock b/mobile/apps/auth/pubspec.lock index 84bc01d3b9..3c4373c96e 100644 --- a/mobile/apps/auth/pubspec.lock +++ b/mobile/apps/auth/pubspec.lock @@ -540,10 +540,10 @@ packages: dependency: "direct main" description: name: file_saver - sha256: "448b1e30142cffe52f37ee085ea9ca50670d5425bb09b649d193549b2dcf6e26" + sha256: "9d93db09bd4da9e43238f9dd485360fc51a5c138eea5ef5f407ec56e58079ac0" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.3.1" fixnum: dependency: "direct main" description: @@ -555,10 +555,11 @@ packages: fk_user_agent: dependency: "direct main" description: - name: fk_user_agent - sha256: fd6c94e120786985a292d12f61422a581f4e851148d5940af38b819357b8ad0d - url: "https://pub.dev" - source: hosted + path: "." + ref: "458046cd9a88924e5074d96ba45397219d53b230" + resolved-ref: "458046cd9a88924e5074d96ba45397219d53b230" + url: "https://github.com/flutter-fast-kit/fk_user_agent" + source: git version: "2.1.0" flutter: dependency: "direct main" @@ -1145,9 +1146,9 @@ packages: dependency: "direct main" description: path: "." - ref: v2-only - resolved-ref: "0cdfeed654d79636eff0c57110f3f6ad5801ba2f" - url: "https://github.com/ente-io/move_to_background.git" + ref: "91e4d1a9c55b28bf93425d1f12faf410efc1e48d" + resolved-ref: "91e4d1a9c55b28bf93425d1f12faf410efc1e48d" + url: "https://github.com/Sayegh7/move_to_background" source: git version: "1.0.2" native_dio_adapter: @@ -1393,11 +1394,12 @@ packages: qr_code_scanner_plus: dependency: "direct main" description: - name: qr_code_scanner_plus - sha256: "39696b50d277097ee4d90d4292de36f38c66213a4f5216a06b2bdd2b63117859" - url: "https://pub.dev" - source: hosted - version: "2.0.10+1" + path: "." + ref: a2d31633d4744f72ada87cfa85d221358ab082af + resolved-ref: a2d31633d4744f72ada87cfa85d221358ab082af + url: "https://github.com/juliuscanute/qr_code_scanner" + source: git + version: "1.0.0" qr_flutter: dependency: "direct main" description: diff --git a/mobile/apps/auth/pubspec.yaml b/mobile/apps/auth/pubspec.yaml index 04f45cafeb..8145cada7d 100644 --- a/mobile/apps/auth/pubspec.yaml +++ b/mobile/apps/auth/pubspec.yaml @@ -1,4 +1,3 @@ - name: ente_auth description: ente two-factor authenticator version: 4.4.6+446 @@ -8,12 +7,12 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: - adaptive_theme: ^3.1.0 # done + adaptive_theme: ^3.1.0 app_links: ^6.3.3 archive: ^4.0.7 auto_size_text: ^3.0.0 base32: ^2.1.3 - bip39: ^1.0.6 #done + bip39: ^1.0.6 bloc: ^9.0.0 clipboard: ^0.1.3 collection: ^1.18.0 # dart @@ -52,10 +51,12 @@ dependencies: ffi: ^2.1.0 figma_squircle: ^0.6.3 file_picker: ^10.2.0 - # https://github.com/incrediblezayed/file_saver/issues/86 - file_saver: ^0.3.0 + file_saver: ^0.3.1 fixnum: ^1.1.0 - fk_user_agent: ^2.1.0 + fk_user_agent: # no package updates on pub.dev + git: + url: https://github.com/flutter-fast-kit/fk_user_agent + ref: 458046cd9a88924e5074d96ba45397219d53b230 flutter: sdk: flutter flutter_animate: ^4.1.0 @@ -67,7 +68,7 @@ dependencies: # https://github.com/pichillilorenzo/flutter_inappwebview/pull/2548 flutter_inappwebview: ^6.1.4 flutter_launcher_icons: ^0.14.1 - flutter_local_authentication: + flutter_local_authentication: # linux fprintd fix is not published on pub.dev git: url: https://github.com/eaceto/flutter_local_authentication ref: 1ac346a04592a05fd75acccf2e01fa3c7e955d96 @@ -91,10 +92,10 @@ dependencies: local_auth_darwin: ^1.2.2 logging: ^1.0.1 modal_bottom_sheet: ^3.0.0 - move_to_background: # no updates in git, replace package + move_to_background: # no package updates on pub.dev git: - url: https://github.com/ente-io/move_to_background.git - ref: v2-only + url: https://github.com/Sayegh7/move_to_background + ref: 91e4d1a9c55b28bf93425d1f12faf410efc1e48d native_dio_adapter: ^1.4.0 otp: ^3.1.1 package_info_plus: ^8.0.2 @@ -105,8 +106,11 @@ dependencies: pointycastle: ^3.7.3 privacy_screen: ^0.0.6 protobuf: ^4.1.0 - qr_code_scanner_plus: ^2.0.10+1 - qr_flutter: ^4.1.0 + qr_code_scanner: # no package updates on pub.dev + git: + url: https://github.com/juliuscanute/qr_code_scanner + ref: a2d31633d4744f72ada87cfa85d221358ab082af + qr_flutter: ^4.1.0 sentry: ^8.14.2 sentry_flutter: ^8.14.2 share_plus: ^11.0.0 diff --git a/mobile/apps/photos/README.md b/mobile/apps/photos/README.md index 06628b08ab..8558c8ba30 100644 --- a/mobile/apps/photos/README.md +++ b/mobile/apps/photos/README.md @@ -46,25 +46,27 @@ You can alternatively install the build from PlayStore or F-Droid. ## 🧑‍💻 Building from source -1. [Install Flutter v3.32.8](https://flutter.dev/docs/get-started/install). +1. Install [Flutter v3.32.8](https://flutter.dev/docs/get-started/install) and [Rust](https://www.rust-lang.org/tools/install). -2. Pull in all submodules with `git submodule update --init --recursive` +2. Install [Flutter Rust Bridge](https://cjycode.com/flutter_rust_bridge/) with `cargo install flutter_rust_bridge_codegen` -3. Enable repo git hooks `git config core.hooksPath hooks` +3. Pull in all submodules with `git submodule update --init --recursive` -4. If using Visual Studio Code, add the [Flutter +4. Enable repo git hooks `git config core.hooksPath hooks` + +5. If using Visual Studio Code, add the [Flutter Intl](https://marketplace.visualstudio.com/items?itemName=localizely.flutter-intl) extension -5. On Android: +6. On Android: - * For development, run `flutter run -t lib/main.dart --flavor independent` + - For development, run `flutter run -t lib/main.dart --flavor independent` - * For building APK, [setup your + - For building APK, [setup your keystore](https://docs.flutter.dev/deployment/android#create-an-upload-keystore) and run `flutter build apk --release --flavor independent` -6. For iOS, run `flutter build ios` +7. For iOS, run `flutter build ios` Some common issues and troubleshooting tips are in [docs/dev](docs/dev.md). @@ -88,11 +90,12 @@ issue](https://github.com/ente-io/ente/issues/new?title=Request+for+New+Language to have it added. ## Certificate Fingerprints - + - **SHA1**: E1:60:10:18:B6:B0:2E:A3:74:6F:90:67:50:30:29:75:0E:EF:6D:39 - **SHA256**: 35:ED:56:81:B7:0B:B3:BD:35:D9:0D:85:6A:F5:69:4C:50:4D:EF:46:AA:D8:3F:77:7B:1C:67:5C:F4:51:35:0B To verify these fingerprints, use the following command: + ```bash apksigner verify --print-certs ``` diff --git a/mobile/apps/photos/android/app/build.gradle b/mobile/apps/photos/android/app/build.gradle index f1b1ef57a7..00afce576d 100644 --- a/mobile/apps/photos/android/app/build.gradle +++ b/mobile/apps/photos/android/app/build.gradle @@ -30,8 +30,8 @@ if (keystorePropertiesFile.exists()) { android { namespace = "io.ente.photos" - compileSdk = 35 - ndkVersion = flutter.ndkVersion + compileSdk = 36 + ndkVersion = "28.0.13004108" compileOptions { coreLibraryDesugaringEnabled = true @@ -56,7 +56,7 @@ android { defaultConfig { applicationId = "io.ente.photos" minSdk = 26 - targetSdk = flutter.targetSdkVersion + targetSdk = 35 versionCode = flutter.versionCode versionName = flutter.versionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -153,4 +153,4 @@ dependencies { because("Align work-runtime-ktx versions") } } -} \ No newline at end of file +} diff --git a/mobile/apps/photos/assets/ml/text_embeddings.json b/mobile/apps/photos/assets/ml/text_embeddings.json new file mode 100644 index 0000000000..5714cbdc67 --- /dev/null +++ b/mobile/apps/photos/assets/ml/text_embeddings.json @@ -0,0 +1,3530 @@ +{ + "version": "1.0.0", + "embeddings": { + "clip_positive": { + "prompt": "Photo of a precious and nostalgic memory radiating warmth, vibrant energy, or quiet beauty — alive with color, light, or emotion", + "vector": [ + -0.00029399772756733, -0.0024989808443933725, 0.0030610354151576757, + -0.04166121035814285, 0.03460526093840599, 0.050619494169950485, + -0.0188677366822958, 0.017285337671637535, -0.00911393016576767, + -0.013402838259935379, 0.0120625551789999, 0.0006917593418620527, + -0.02497251331806183, -0.022732943296432495, 0.029347892850637436, + 0.5122391581535339, -0.01061850693076849, -0.003770088544115424, + 0.012226847000420094, -0.05049843713641167, 0.0034501501359045506, + -0.02298370562493801, -0.03317851200699806, 0.0007177003426477313, + 0.03588501736521721, -0.05409558489918709, 0.038496412336826324, + 0.02857831120491028, -0.01419836189597845, 0.016654107719659805, + -0.010687682777643204, -0.0005015255883336067, 0.011595616117119789, + -0.020847897976636887, -0.011708027683198452, -0.020311785861849785, + -0.007099180947989225, -0.008629699237644672, -0.025595098733901978, + -0.028958778828382492, 0.014060010202229023, -0.020164787769317627, + 0.01764851063489914, -0.006684124935418367, -0.0515793077647686, + -0.034864671528339386, 0.006900300271809101, -0.015357058495283127, + -0.010073745623230934, 0.02983212284743786, 0.02481686696410179, + 0.05888601765036583, 0.008344347588717937, -0.04051980748772621, + -0.023208526894450188, -0.008880460634827614, -0.02613985724747181, + -0.017466925084590912, -0.02899336628615856, 0.007574765477329493, + 0.005715662147849798, 0.0017726332880556583, 0.03105134889483452, + 0.0461922325193882, -0.07244450598955154, 0.03219275176525116, + -0.013783305883407593, -0.008759403601288795, 0.041064564138650894, + 0.1308203488588333, 0.010998974554240704, 0.002741096541285515, + -0.006476596929132938, -0.007246179506182671, -0.003692265832796693, + 0.0019196323119103909, -0.05541857331991196, -0.024730399250984192, + -0.013100193813443184, -0.022196829319000244, -0.028197843581438065, + -0.02845725230872631, 0.05446740612387657, 0.025188688188791275, + 0.00250762770883739, 0.000709053419996053, 0.005534074734896421, + -0.01690487004816532, 0.036066606640815735, -0.02184230275452137, + 0.026598148047924042, -0.004738552030175924, 0.011768556199967861, + 0.0007177003426477313, -0.006554420106112957, 0.012996429577469826, + -0.012676490470767021, 0.008292465470731258, -0.013281780295073986, + -0.014008128084242344, 0.024574752897024155, 0.02172989211976528, + -0.026814322918653488, 0.0041851443238556385, 0.020839251577854156, + -0.004401318728923798, -0.06879547238349915, -0.01034180261194706, + 0.0008992872317321599, 0.010436920449137688, -0.014950649812817574, + -0.020406901836395264, 0.13213469088077545, -0.009822983294725418, + -0.014103244990110397, -0.01761392317712307, 0.018366212025284767, + 0.013108840212225914, -0.0133509561419487, 0.0009944040793925524, + 0.013437426649034023, -0.025984210893511772, -0.011457265354692936, + 0.008110878989100456, 0.02050201967358589, 0.03446691110730171, + 0.021470481529831886, 0.002836213679984212, -0.00470396364107728, + 0.003147505223751068, -0.04847504198551178, 0.002239570952951908, + 0.016213109716773033, -0.013394190929830074, -0.005931836552917957, + -0.033143918961286545, -0.02115054242312908, -0.0012451668735593557, + -0.002792978659272194, 0.007669882383197546, 0.019818907603621483, + -0.007133768871426582, 0.01491606142371893, -0.023805169388651848, + 0.005404370371252298, -0.0260793287307024, -0.019075265154242516, + 0.010350449942052364, -0.009710571728646755, 0.022041182965040207, + -0.031284816563129425, -0.012953193858265877, -0.025223277509212494, + -0.018997443839907646, -0.042716141790151596, -0.05844501778483391, + 0.03895470127463341, -0.01744963228702545, 0.024635281413793564, + 0.023364173248410225, -0.01995725743472576, 0.009010165929794312, + -0.003735500853508711, -0.006571713835000992, -0.039144936949014664, + -0.030774645507335663, 0.02484280988574028, -0.5175830125808716, + -0.00013835188292432576, -0.029460303485393524, -0.04680616781115532, + 0.07913727313280106, 0.001184638007543981, -0.0010376391001045704, + 0.0103677436709404, 0.013930304907262325, -0.03406050056219101, + -0.022041182965040207, -0.0009165811934508383, 0.038513705134391785, + 0.007324002683162689, -0.0007522883242927492, 0.0077649992890655994, + -0.0019109854474663734, -0.013212604448199272, -0.035461317747831345, + 0.014717180281877518, -0.016334168612957, 0.02303558774292469, + -0.028232431039214134, -0.019723789766430855, -0.039118994027376175, + 0.04071004316210747, -0.03521054983139038, 0.03808135166764259, + -0.033066097646951675, 0.022058477625250816, -0.056828033179044724, + -0.03027312271296978, -0.016766518354415894, 0.04006151854991913, + -0.06835447251796722, 0.03892011195421219, 0.0032945042476058006, + -0.014587475918233395, 0.010289921425282955, 0.05095672607421875, + -0.015063060447573662, -0.008396229706704617, -0.017302630469202995, + -0.02613985724747181, 0.023173939436674118, -0.058012671768665314, + 0.038505055010318756, -0.025067631155252457, -0.017795508727431297, + 0.03590231016278267, 0.004807727411389351, 0.022231418639421463, + -0.029304657131433487, -0.021980654448270798, -0.016558989882469177, + -0.005413017235696316, 0.0230528824031353, 0.025819920003414154, + 0.012693784199655056, -0.010921151377260685, 0.0011586970649659634, + 0.026165800169110298, -0.04114238917827606, -0.02717749774456024, + 0.017155632376670837, -0.010549331083893776, -0.019057970494031906, + -0.007254826370626688, -0.024756338447332382, -0.0039170878008008, + -0.022854000329971313, -0.007220238912850618, -0.00874210987240076, + 0.001642928458750248, 0.017216162756085396, -0.03951675444841385, + 0.006787888705730438, -0.08730003982782364, -0.004505082964897156, + -0.04747198894619942, 0.03839264437556267, -0.0714760422706604, + -0.02231788821518421, 0.02241300418972969, -0.01946437917649746, + -0.037977591156959534, 0.05524563416838646, -0.05752843618392944, + -0.0018331623869016767, -0.022577296942472458, -0.02236112207174301, + -0.00878534372895956, 0.0025595095939934254, 0.014976590871810913, + -0.03655948489904404, -0.005629192106425762, 0.002792978659272194, + 0.020303137600421906, -0.03268563002347946, 0.006104776635766029, + -0.03560831397771835, 0.014475065283477306, 0.03400862216949463, + -0.028379429131746292, 0.002991859335452318, -0.007384531665593386, + -0.02546539157629013, 0.028102725744247437, 0.02373599447309971, + 0.019879436120390892, -0.013644954189658165, -0.031820930540561676, + -0.05662915110588074, -0.008214643225073814, -0.03750200942158699, + -0.009260928258299828, 0.005101725459098816, 0.012287376448512077, + -0.0027583905030041933, -0.029373833909630775, 0.013316367752850056, + -0.0017380454810336232, -0.037839241325855255, -0.026969969272613525, + -0.017345866188406944, -0.03754524141550064, -0.026451149955391884, + -0.000432349625043571, 0.020432842895388603, -0.05502945929765701, + 0.12296022474765778, 0.03770088404417038, -0.00823193695396185, + -0.01582399755716324, -0.002083925064653158, -0.003778735874220729, + -0.021487776190042496, 0.033636800944805145, 0.012218199670314789, + 0.026831617578864098, 0.03803811967372894, -0.047506578266620636, + -0.006044247653335333, 0.08365964889526367, 0.02974565327167511, + 0.04988449811935425, -0.009900806471705437, 0.019628673791885376, + -0.041557442396879196, -0.051933836191892624, -0.03379244729876518, + -0.036023370921611786, -0.02920953929424286, 0.0035193259827792645, + 0.03687077388167381, -0.051933836191892624, 0.03700912743806839, + -0.046927228569984436, -0.0038652056828141212, 0.0414709746837616, + 0.012909960001707077, -0.032296519726514816, -0.037899766117334366, + 0.023312291130423546, 0.0060356007888913155, 0.02307017706334591, + 0.04563017934560776, -0.01060121227055788, -0.008672933094203472, + -0.028673425316810608, 0.06280311197042465, 0.016109347343444824, + -0.011050855740904808, 0.007799586746841669, 0.013878422789275646, + 0.026503032073378563, 0.015443528071045876, 0.034890614449977875, + 0.0038652056828141212, -0.01761392317712307, 0.0453534759581089, + -0.022611886262893677, -0.010203450918197632, -0.021435894072055817, + 0.03638654574751854, -0.01030721515417099, -0.008880460634827614, + -0.0024643929209560156, 0.01574617438018322, 0.048907388001680374, + -0.007324002683162689, -0.01999184675514698, -0.0032772100530564785, + 0.006148011423647404, -0.017821451649069786, 0.022888587787747383, + -0.00996998231858015, 0.00530060613527894, -0.0028535074088722467, + 0.012174965813755989, -0.007263473235070705, -0.0059664249420166016, + 0.027722256258130074, -0.03201116621494293, 0.012140377424657345, + -0.012339258566498756, -0.03099946863949299, 0.02184230275452137, + -0.023355526849627495, 0.04307067021727562, 0.019663261249661446, + -0.15298259258270264, 0.009044754318892956, 0.0033896209206432104, + 0.0019369263900443912, -0.026433855295181274, -0.002127160085365176, + 0.0015564586501568556, -0.010557977482676506, -0.0012711079325526953, + 0.00004323495886637829, 0.03380109369754791, -0.06299334019422531, + 0.040390100330114365, -0.05773596838116646, 0.023208526894450188, + 0.027644433081150055, 0.005490840412676334, 0.02726396732032299, + -0.006433362141251564, -0.026814322918653488, -0.015296529047191143, + -0.014207008294761181, 0.008915049023926258, -0.034328557550907135, + 0.0038392646238207817, -0.023441996425390244, -0.0007177003426477313, + 0.030688177794218063, -0.06485243886709213, -0.06524156033992767, + -0.010350449942052364, -0.0582980215549469, 0.02074413374066353, + -0.012166318483650684, -0.010497448965907097, -0.06057218462228775, + 0.01513223722577095, -0.008854520507156849, 0.03753659501671791, + -0.06895976513624191, 0.011431324295699596, 0.004055439494550228, + 0.05822884663939476, -0.0021876890677958727, -0.017743628472089767, + -0.008845873177051544, -0.010142921470105648, -0.0071164751425385475, + 0.03211492672562599, 0.008889107964932919, 0.01885044202208519, + 0.014673946425318718, 0.02731584943830967, 0.016636813059449196, + 0.011647499166429043, -0.008370288647711277, -0.06652131676673889, + 0.03981940075755119, -0.012806195765733719, 0.001418106839992106, + 0.01152644120156765, 0.001720751402899623, 0.008889107964932919, + -0.04371919482946396, -0.013307721354067326, 0.004686669912189245, + 0.0047644926235079765, -0.019144441932439804, -0.00824058335274458, + -0.00530060613527894, -0.00408138008788228, -0.04931379854679108, + 0.04058033600449562, 0.0005620545125566423, 0.02373599447309971, + 0.023874346166849136, 0.0047644926235079765, -0.005854013841599226, + -0.01065309438854456, 0.00815411377698183, -0.0022655120119452477, + -0.003303151112049818, 0.012347905896604061, -0.005646485835313797, + -0.005075784400105476, -0.0066149490885436535, 0.01877262070775032, + -0.05195113271474838, -0.000821464229375124, 0.030852466821670532, + 0.061609819531440735, -0.02860425040125847, -0.003311798209324479, + 0.0008560522692278028, 0.00019023384083993733, -0.03269427642226219, + -0.03091299906373024, -0.01030721515417099, 0.012598667293787003, + -0.024453694000840187, 0.017138339579105377, 0.016775164753198624, + -0.04474818706512451, 0.0442812480032444, 0.045647475868463516, + -0.02374464087188244, -0.07572171837091446, -0.0068311239592731, + -0.16558989882469177, 0.021409953013062477, -0.004202438518404961, + 0.03092164546251297, -0.01999184675514698, 0.046512171626091, + -0.00654577324166894, 0.029901299625635147, 0.007998468354344368, + -0.004193791188299656, -0.022542709484696388, -0.04104727506637573, + -0.010238038375973701, -0.01581534929573536, 0.014379948377609253, + -0.014959297142922878, -0.017890628427267075, 0.0078774094581604, + 0.01431941892951727, 0.002749743638560176, -0.034916553646326065, + 0.03393079712986946, 0.00498931435868144, 0.014258889481425285, + 0.007609352935105562, -0.03220139816403389 + ] + }, + "people_activities": { + "admiring": { + "prompt": "Photo of two people admiring or looking at each other in a loving but non-intimate and non-physical way", + "vector": [ + -0.03514610603451729, -0.02812313660979271, -0.03186924010515213, + 0.0643484964966774, 0.015219029039144516, 0.025284234434366226, + 0.007867596112191677, 0.0054588294588029385, -0.03783641383051872, + -0.061493948101997375, 0.027771208435297012, -0.01790934056043625, + -0.013334247283637524, -0.014499526470899582, 0.025425007566809654, + 0.5175095200538635, 0.023548046126961708, 0.02630092203617096, + -0.013521943241357803, -0.004700224380940199, -0.0021350437309592962, + -0.00952557846903801, -0.008117858320474625, 0.000656936492305249, + -0.0020646576303988695, -0.011770112439990044, -0.0049817683175206184, + -0.021170560270547867, -0.021561594679951668, 0.035865604877471924, + -0.001986450981348753, -0.00030500622233375907, 0.03502097353339195, + -0.04644697532057762, -0.026433873921632767, -0.00983840599656105, + -0.04971601441502571, 0.03028164431452751, -0.013514121994376183, + -0.043123189359903336, 0.010245081037282944, 0.0002502615097910166, + -0.012333200313150883, 0.0380319319665432, -0.011332154273986816, + -0.026715418323874474, -0.016024557873606682, -0.053931355476379395, + -0.011457285843789577, 0.03927541896700859, -0.0016579825896769762, + 0.03470032289624214, 0.005028692539781332, 0.02120966464281082, + 0.018581919372081757, 0.008375939913094044, 0.03340991586446762, + 0.0073123290203511715, -0.033738382160663605, -0.01745574176311493, + -0.023508941754698753, 0.026191432029008865, -0.01151202991604805, + 0.06702316552400589, -0.015672627836465836, 0.0440773107111454, + 0.0014468245208263397, -0.0020020920783281326, 0.011918704956769943, + 0.08666869252920151, -0.033965181559324265, 0.03676498308777809, + 0.02721594087779522, 0.040456339716911316, -0.004653300624340773, + -0.01441350020468235, -0.09551387280225754, 0.03524777293205261, + 0.02456473372876644, -0.0435924269258976, -0.03026600182056427, + -0.03004702553153038, 0.019105903804302216, -0.01288846880197525, + 0.005091257859021425, 0.0017909340094774961, -0.0007586052524857223, + -0.021913524717092514, -0.004708044696599245, 0.03254964202642441, + 0.013279502280056477, 0.02537808194756508, -0.01927795819938183, + 0.0407300628721714, -0.033065807074308395, 0.05871760845184326, + 0.0424584299325943, -0.012638206593692303, 0.0023696639109402895, + 0.020411955192685127, 0.0015719551593065262, -0.02852199412882328, + 0.0037695644423365593, -0.01983322575688362, 0.0449688695371151, + 0.06520094722509384, -0.06771138310432434, 0.036256637424230576, + -0.001133997575379908, -0.007437459193170071, 0.01277115847915411, + -0.008985953405499458, 0.15607717633247375, 0.03256528079509735, + 0.018472427502274513, -0.037468839436769485, 0.005607421975582838, + -0.000656936492305249, -0.010049563832581043, 0.030602293089032173, + 0.007640797644853592, -0.028170062229037285, 0.0023774844594299793, + 0.0002033374912571162, 0.010229440405964851, -0.0038164884317666292, + -0.000383212958695367, -0.018433324992656708, 0.001313872984610498, + -0.04119930416345596, 0.015125180594623089, 0.005896787159144878, + -0.0011496389051899314, 0.0011418182402849197, 0.05330570414662361, + 0.0010870734695345163, 0.0002502615097910166, 0.01318565383553505, + 0.038243088871240616, -0.004215342458337545, 0.00880607683211565, + -0.0019395267590880394, -0.024056388065218925, 0.0031908343080431223, + -0.002705952851101756, -0.03058665059506893, -0.022445330396294594, + 0.03086819313466549, -0.05810759961605072, -0.033957358449697495, + -0.0183003731071949, 0.028185702860355377, -0.04283382371068001, + 0.03940054774284363, 0.03269823268055916, 0.013287322595715523, + 0.02150684967637062, 0.01159023679792881, 0.01299795787781477, + -0.030156515538692474, -0.005013051442801952, 0.011339975520968437, + -0.058287475258111954, 0.024901021271944046, -0.04110545292496681, + 0.031525131314992905, 0.021233126521110535, -0.5212634801864624, + 0.004629838280379772, -0.018581919372081757, -0.012685131281614304, + 0.08338400721549988, -0.0017987547907978296, 0.018628841266036034, + -0.013091806322336197, 0.0011261767940595746, 0.022773798555135727, + -0.034129414707422256, 0.022398406639695168, -0.01181703619658947, + -0.0018143960041925311, 0.014280547387897968, -0.02295367419719696, + -0.027935443446040154, 0.010315467603504658, -0.020005280151963234, + -0.03294849395751953, -0.010722142644226551, 0.01478889212012291, + -0.01216114591807127, -0.025135641917586327, -0.0015250311698764563, + 0.045164383947849274, -0.02295367419719696, -0.01304488256573677, + -0.039541322737932205, 0.013576687313616276, 0.05171810835599899, + -0.03906426206231117, 0.01678316295146942, -0.017354073002934456, + 0.02462729811668396, -0.003417633706703782, 0.03437967598438263, + 0.010440598241984844, -0.026777982711791992, 0.001618879148736596, + -0.031994372606277466, -0.01502351276576519, 0.012434869073331356, + 0.01632174476981163, -0.03318311646580696, -0.055472031235694885, + -0.002095940290018916, -0.0010557908099144697, -0.0758214220404625, + -0.009236213751137257, -0.03192398324608803, -0.007320149801671505, + -0.0029874970205128193, 0.0059046074748039246, -0.024955766275525093, + -0.013709639199078083, 0.051647722721099854, -0.01044841855764389, + -0.03086819313466549, 0.021929167211055756, -0.024134594947099686, + -0.01303706131875515, -0.010683038271963596, -0.03432493284344673, + -0.02806839346885681, 0.007140273693948984, -0.04942664876580238, + -0.019567323848605156, 0.035200849175453186, -0.01064393576234579, + -0.04413987696170807, -0.03332388401031494, -0.02324303798377514, + 0.01822216622531414, 0.0031830137595534325, -0.03575611487030983, + 0.021225305274128914, 0.004246625117957592, 0.006279999855905771, + -0.01353758480399847, -0.007335790432989597, -0.07419472187757492, + -0.04053454473614693, 0.006381668616086245, -0.04254445806145668, + 0.027333252131938934, 0.01059701107442379, 0.02210904285311699, + -0.012520897202193737, -0.005599601659923792, 0.054330214858055115, + -0.02067003771662712, 0.037703461945056915, -0.027638258412480354, + -0.013787846080958843, 0.03139999881386757, 0.061705105006694794, + -0.02394689992070198, -0.0218900628387928, 0.01943437196314335, + 0.027192478999495506, 0.009595965966582298, -0.005404084920883179, + 0.0025182566605508327, -0.014585554599761963, -0.0285845585167408, + -0.031665902584791183, 0.04905908182263374, 0.014202342368662357, + -0.01342027448117733, -0.006068842019885778, -0.0059202490374445915, + -0.033214397728443146, 0.05482291802763939, 0.04771392419934273, + -0.026011556386947632, 0.016220074146986008, 0.05205439776182175, + 0.04306844249367714, -0.02675452083349228, 0.016525082290172577, + -0.04948921501636505, -0.035357262939214706, 0.006913474760949612, + -0.006960398517549038, -0.05734899267554283, -0.018941668793559074, + 0.01866794563829899, 0.004614196717739105, -0.03132961690425873, + 0.015195567160844803, 0.048081494867801666, 0.021240947768092155, + 0.0073279705829918385, 0.002627745969220996, 0.013553226366639137, + 0.026410412043333054, 0.003980722278356552, -0.028248269110918045, + -0.031611159443855286, 0.007492204196751118, -0.0015406724996864796, + 0.03597509488463402, 0.032831184566020966, -0.0025730011984705925, + -0.009658530354499817, -0.03331606462597847, -0.015563137829303741, + 0.004801893141120672, -0.06827446818351746, 0.02409549243748188, + -0.05810759961605072, -0.0327138751745224, 0.04088647663593292, + 0.05888184532523155, 0.014085031114518642, 0.04640787094831467, + -0.0346846841275692, -0.013561046682298183, -0.019864508882164955, + 0.04460911825299263, -0.019262315705418587, -0.0020411955192685127, + 0.020028743892908096, -0.02737235277891159, 0.04531297832727432, + 0.044327571988105774, -0.0480189323425293, -0.005888966377824545, + 0.0035349440295249224, -0.021006327122449875, -0.030696140602231026, + -0.02301623858511448, -0.01360797043889761, -0.013013599440455437, + 0.03806321322917938, 0.010870734229683876, -0.014311830513179302, + -0.016634570434689522, 0.0050208717584609985, -0.005302416160702705, + -0.04763571545481682, -0.0004535990010481328, -0.027028243988752365, + 0.038462068885564804, -0.00024244084488600492, -0.05312582850456238, + 0.016110586002469063, 0.04937972500920296, -0.05849863216280937, + -0.03499750792980194, 0.010815990157425404, 0.029616886749863625, + -0.018636662513017654, -0.019629888236522675, -0.001094894134439528, + 0.01528941374272108, 0.03591252863407135, -0.03255745768547058, + -0.00044577830703929067, -0.037007421255111694, 0.03003138303756714, + 0.006577185820788145, -0.027880696579813957, -0.04398346319794655, + -0.03299541771411896, -0.010033923201262951, 0.04370191693305969, + -0.01159023679792881, 0.03227591514587402, -0.04453872889280319, + -0.07761235535144806, 0.0002971855574287474, -0.049590885639190674, + -0.015680449083447456, -0.029718557372689247, 0.008438506163656712, + 0.02980458363890648, 0.008485429920256138, -0.005411905702203512, + -0.007202839478850365, 0.026402590796351433, -0.04015133157372475, + -0.07478127628564835, 0.007476563099771738, 0.01861320249736309, + -0.011379078961908817, -0.02295367419719696, -0.0015406724996864796, + -0.001290410989895463, -0.031063711270689964, -0.03436403349041939, + -0.11970321834087372, -0.02407984994351864, -0.0426461286842823, + -0.023657534271478653, -0.014968767762184143, -0.030633574351668358, + -0.018511531874537468, 0.020232081413269043, 0.011371258646249771, + 0.006788343656808138, -0.02462729811668396, -0.024431781843304634, + 0.01577429659664631, 0.01730714924633503, 0.011050610803067684, + 0.04086301475763321, 0.05634012445807457, 0.011191382072865963, + -0.028170062229037285, 0.007828493602573872, 0.027489662170410156, + 0.045492853969335556, -0.03988543152809143, -0.01239576656371355, + 0.0060923038981854916, -0.022586101666092873, -0.007562590297311544, + 0.006506799720227718, -0.023892154917120934, 0.04185623675584793, + -0.025659628212451935, -0.02623053640127182, -0.021780572831630707, + 0.0010323288151994348, 0.0032221172004938126, -0.05886620655655861, + 0.024204982444643974, 0.032526176422834396, -0.002189788268879056, + -0.013733101077377796, -0.01262256596237421, -0.002056836849078536, + -0.0275991540402174, 0.024197161197662354, 0.01943437196314335, + -0.0056856293231248856, 0.03224463388323784, -0.008915566839277744, + 0.030477160587906837, -0.0035896888002753258, -0.05702834203839302, + -0.03987761214375496, -0.015602242201566696, 0.010385853238403797, + -0.021084534004330635, 0.006827447097748518, -0.001994271529838443, + 0.02142864279448986, 0.03279989957809448, 0.014929663389921188, + 0.037703461945056915, -0.0015719551593065262, 0.008712229318916798, + -0.027739927172660828, -0.03369927778840065, 0.007468742318451405, + 0.04313100874423981, -0.03158769756555557, 0.0424036867916584, + -0.0005318057374097407, 0.02143646404147148, -0.016603287309408188, + 0.013443736359477043, -0.03951003775000572, 0.02334470860660076, + -0.0018769614398479462, -0.010995865799486637, 0.0017127272440120578, + -0.005333698354661465, -0.008939028717577457, 0.018355118110775948, + 0.018574098125100136, 0.10098834335803986, 0.0284359659999609, + -0.016517261043190956, 0.023070983588695526, -0.026715418323874474, + -0.10452328622341156, -0.018808718770742416, 0.006491158157587051, + 0.002627745969220996, 0.025417186319828033, 0.03117320127785206, + 0.035106997936964035, 0.003480199258774519, 0.006592826917767525, + 0.01292757224291563, 0.021029789000749588, -0.029085082933306694, + 0.009580324403941631, -0.00019551682635210454, -0.021905705332756042, + 0.004966127220541239, 0.0443197526037693, 0.007953624241054058, + 0.0203650314360857, 0.02370445802807808, -0.000766425917390734, + 0.01683790795505047, 0.010628294199705124, 0.002705952851101756, + 0.005896787159144878, -0.011989091522991657 + ] + }, + "embracing": { + "prompt": "Photo of people hugging or embracing each other lovingly, without inappropriately kissing or other intimate actions", + "vector": [ + 0.03190479800105095, 0.012113233096897602, -0.022465744987130165, + 0.020599115639925003, 0.026688827201724052, -0.00448123412206769, + 0.016892332583665848, 0.035790298134088516, -0.07396353781223297, + -0.04633476957678795, 0.010511374101042747, -0.010220126248896122, + 0.014443210326135159, 0.01785212568938732, 0.06136709451675415, + 0.5228084325790405, -0.00482543557882309, -0.001628336263820529, + -0.03713400661945343, -0.01580677554011345, -0.032546866685152054, + -0.02028800919651985, -0.060705170035362244, 0.004487853497266769, + 0.010140695609152317, 0.011874939315021038, -0.04372016713023186, + 0.00482543557882309, -0.009644251316785812, 0.041899871081113815, + -0.039265409111976624, -0.016250265762209892, 0.0030117600690573454, + -0.05602535605430603, -0.022598128765821457, -0.0026146050076931715, + -0.0355321504175663, 0.041357092559337616, 0.016131119802594185, + -0.024047747254371643, 0.029846210032701492, -0.009472151286900043, + -0.01952679641544819, 0.04841983690857887, -0.003971552010625601, + -0.05485374853014946, -0.02879374846816063, -0.05014083907008171, + -0.014535878784954548, 0.012867826968431473, -0.028178159147500992, + 0.08048349618911743, -0.0032235761173069477, 0.0004103936953470111, + -0.029998455196619034, -0.017263010144233704, 0.03011760115623474, + 0.020751357078552246, 0.0015224282396957278, -0.0069435965269804, + -0.026126191020011902, 0.006460390519350767, 0.006824449636042118, + 0.015098516829311848, -0.03204380348324776, 0.024511093273758888, + -0.005977185443043709, 0.01679966412484646, 0.00009266954293707386, + 0.04995550215244293, -0.017514541745185852, 0.030223509296774864, + 0.04506387189030647, 0.009313289076089859, 0.002720512915402651, + -0.026251958683133125, -0.0866791158914566, 0.035022467374801636, + 0.02159862220287323, -0.015065419487655163, -0.047625523060560226, + -0.024173511192202568, -0.004501091782003641, -0.027092603966593742, + -0.0005030632601119578, -0.0006751638138666749, -0.013264983892440796, + -0.0020718262530863285, 0.024703051894903183, 0.000052954022976337, + -0.02320048026740551, 0.00013900430349167436, -0.021863391622900963, + 0.04317738488316536, 0.03924554958939552, 0.05359609052538872, + 0.025940852239727974, -0.01834856905043125, 0.00448123412206769, + 0.006056616548448801, 0.006797972600907087, -0.01000831089913845, + -0.024696432054042816, -0.033784665167331696, 0.033579468727111816, + 0.000105908045952674, -0.061559051275253296, 0.034195058047771454, + -0.0034552502911537886, -0.005672699771821499, -0.020228436216711998, + -0.014595451764762402, 0.1076025739312172, -0.028734175488352776, + -0.012219141237437725, -0.04081431403756142, 0.015131612308323383, + -0.016806283965706825, 0.008889656513929367, 0.025762131437659264, + 0.03790184110403061, -0.006811210885643959, -0.04401141032576561, + -0.013119358569383621, 0.023597635328769684, 0.011120345443487167, + 0.03059418871998787, -0.02412055805325508, 0.02811196632683277, + 0.014039434492588043, -0.016395889222621918, -0.008532216772437096, + 0.0004699669370893389, 0.013364271260797977, 0.09090881794691086, + -0.043428920209407806, -0.03463193029165268, 0.022988665848970413, + 0.03298373892903328, -0.020506445318460464, -0.015171327628195286, + -0.031130345538258553, -0.0036803046241402626, -0.043462011963129044, + -0.04213154315948486, -0.017481446266174316, -0.031805507838726044, + 0.006612633820623159, -0.0343870185315609, -0.0011252729455009103, + -0.04397169500589371, -0.00045010916073806584, -0.05562158301472664, + 0.02931005321443081, 0.002177734160795808, -0.026728542521595955, + 0.007737906649708748, -0.008671221323311329, 0.0023564540315419436, + -0.0002581508597359061, -0.013212029822170734, -0.03402295708656311, + -0.05244433879852295, 0.017329204827547073, -0.023498348891735077, + 0.015482432208955288, 0.031825367361307144, -0.5259922742843628, + 0.005176255479454994, 0.014251251704990864, -0.0660402849316597, + 0.07855729013681412, 0.0002912471245508641, 0.004295895341783762, + -0.016124499961733818, 0.005341737065464258, 0.02462361939251423, + 0.01058418583124876, 0.0008538836264051497, -0.015608198940753937, + 0.0002382930979365483, 0.010994579643011093, -0.005679319147020578, + -0.020420394837856293, 0.018613338470458984, -0.001542285899631679, + -0.01722329668700695, -0.027430184185504913, 0.008280685171484947, + -0.017124006524682045, 0.02515977993607521, -0.025808466598391533, + -0.020374059677124023, -0.03683614358305931, -0.03654489666223526, + 0.0013503276277333498, -0.005626365076750517, 0.03961622714996338, + -0.005308640655130148, 0.03429434821009636, 0.003104429692029953, + 0.009088234044611454, -0.002799944020807743, 0.018785439431667328, + 0.009756778366863728, 0.018434619531035423, -0.005910992622375488, + 0.012801635079085827, -0.03344046697020531, -0.020466729998588562, + 0.011537358164787292, -0.03674347326159477, -0.006725160870701075, + 0.016912192106246948, -0.02935638464987278, -0.007545948028564453, + 0.04967087507247925, -0.0028528980910778046, -0.014959512278437614, + 0.007115696556866169, -0.038292378187179565, -0.01070995070040226, + -0.0024623621720820665, 0.028264211490750313, -0.028806986287236214, + 0.00784381479024887, 0.017263010144233704, 0.011821985244750977, + 0.005771988537162542, 0.006149285938590765, -0.05329160392284393, + -0.02453095093369484, 0.05043208971619606, -0.08943934738636017, + -0.01077614352107048, 0.004527568817138672, 0.007757764775305986, + -0.017600594088435173, -0.028284067288041115, -0.015965638682246208, + 0.020771216601133347, -0.0007943103555589914, -0.051775798201560974, + 0.0035677773412317038, 0.03422153741121292, -0.0027469899505376816, + -0.026927120983600616, 0.02281656488776207, -0.050988104194402695, + -0.07974876463413239, -0.005169636569917202, -0.05307317152619362, + -0.005043870769441128, -0.03931836411356926, -0.024358851835131645, + 0.00539469113573432, -0.03316907584667206, 0.05090205371379852, + -0.013079644180834293, 0.015469194389879704, -0.037478212267160416, + -0.03344046697020531, 0.08413070440292358, 0.0449976809322834, + -0.0311104878783226, -0.038385048508644104, 0.023233577609062195, + 0.053238652646541595, -0.023835929110646248, -0.02187001146376133, + -0.023114431649446487, 0.008863179944455624, -0.01641574688255787, + -0.05323203280568123, 0.012192663736641407, 0.03041546605527401, + -0.0014496163930743933, -0.008221112191677094, -0.010279699228703976, + -0.007188509218394756, 0.047671858221292496, 0.03461207449436188, + -0.03889473155140877, -0.0011252729455009103, 0.04734089598059654, + 0.02732427604496479, 0.008935990743339062, 0.02318062260746956, + -0.02584156207740307, -0.04824111610651016, 0.012278714217245579, + -0.025199495255947113, -0.05007464811205864, -0.002343215513974428, + 0.010273081250488758, 0.012656011618673801, 0.002171115018427372, + 0.030355893075466156, 0.030475042760372162, -0.020499825477600098, + -0.004666573368012905, 0.006215478293597698, 0.0042429412715137005, + -0.00016548130952287465, 0.015992116183042526, -0.008234350942075253, + 0.018653053790330887, -0.014079151675105095, 0.01740863546729088, + 0.008088726550340652, 0.04458728805184364, 0.006791353691369295, + 0.0020916839130222797, 0.017554258927702904, -0.0005229209782555699, + 0.05415872484445572, -0.06349187344312668, -0.0031838605646044016, + -0.02958144061267376, 0.006738399155437946, 0.04008619859814644, + 0.015866348519921303, -0.00421646423637867, 0.047850579023361206, + -0.02380945347249508, -0.014628549106419086, 0.007744526024907827, + 0.006592776160687208, -0.022055350244045258, 0.025351738557219505, + -0.04393859952688217, 0.005540314596146345, 0.03927202895283699, + 0.06421337276697159, -0.02761552296578884, -0.012788397260010242, + 0.032990358769893646, -0.04202563688158989, 0.0013768046628683805, + 0.0024425042793154716, 0.005593268666416407, -0.01525075826793909, + 0.033513277769088745, -0.0014099008403718472, 0.04309795796871185, + 0.026748400181531906, -0.02103598602116108, 0.007850433699786663, + -0.05066376179456711, 0.039821427315473557, 0.027675095945596695, + 0.01834856905043125, 0.0060963318683207035, -0.03812689706683159, + 0.013814380392432213, 0.04603028669953346, -0.03898078203201294, + -0.02425956167280674, 0.011239491403102875, 0.011782269924879074, + 0.004527568817138672, -0.010756285861134529, -0.018163230270147324, + 0.013642280362546444, 0.03339413180947304, 0.008379973471164703, + 0.020844027400016785, -0.010570947080850601, -0.0039847902953624725, + 0.029945500195026398, -0.0016680517001077533, 0.027608904987573624, + -0.01834856905043125, -0.0027469899505376816, -0.012278714217245579, + 0.005076967179775238, 0.022373074665665627, -0.027423566207289696, + -0.07132244855165482, 0.013827620074152946, -0.025292163714766502, + -0.011716078035533428, -0.051193300634622574, -0.0197253730148077, + 0.02865474671125412, -0.019718755036592484, -0.05842152610421181, + -0.01763368956744671, 0.014390256255865097, -0.027966342866420746, + -0.09944765269756317, -0.054483070969581604, 0.01760721392929554, + 0.004534188192337751, -0.03393691033124924, -0.005275544710457325, + 0.006420675665140152, -0.03853728994727135, -0.03293078392744064, + -0.1083240807056427, 0.01916273683309555, -0.04758581146597862, + -0.007353989407420158, -0.04179396107792854, -0.009816352277994156, + -0.00542778754606843, 0.008379973471164703, -0.0049776784144341946, + 0.02719189040362835, -0.03471798077225685, -0.04080107435584068, + -0.013681996613740921, 0.027469897642731667, -0.004606999922543764, + 0.04767847806215286, 0.01767340488731861, -0.009968595579266548, + -0.011318922974169254, -0.018427999690175056, 0.0280259158462286, + 0.11136892437934875, -0.005540314596146345, -0.0007479756022803485, + 0.015184566378593445, 0.022465744987130165, 0.032725587487220764, + 0.022399552166461945, -0.06292261928319931, -0.010637139901518822, + -0.029885927215218544, -0.004501091782003641, -0.008022534660995007, + 0.017501303926110268, -0.02910485491156578, -0.0008274066494777799, + 0.04789029434323311, 0.005639603361487389, 0.0008207873906940222, + 0.03124949149787426, 0.017885221168398857, -0.03352651372551918, + 0.03794817626476288, 0.0012973735574632883, 0.0005692557897418737, + -0.001979156630113721, 0.02885994128882885, -0.02382931113243103, + 0.014529259875416756, -0.04982311651110649, -0.07375171780586243, + -0.026046760380268097, -0.004606999922543764, 0.020665308460593224, + -0.020870503038167953, 0.0, -0.013940147124230862, + 0.020387299358844757, 0.024828817695379257, -0.0035082038957625628, + -0.009074995294213295, -0.00007281178113771603, + -0.0051630171947181225, -0.016309838742017746, -0.005851419642567635, + -0.012404480017721653, 0.0197452325373888, -0.015820013359189034, + 0.009505246765911579, -0.0018335330532863736, 0.012920781038701534, + 0.006208859384059906, 0.006586156319826841, 0.014151962473988533, + -0.0014099008403718472, -0.02750299498438835, -0.015052181668579578, + 0.001542285899631679, 0.015045562759041786, 0.011610169894993305, + 0.025424549356102943, -0.0015224282396957278, 0.08096670359373093, + 0.020519685000181198, 0.014403493143618107, -0.01109386794269085, + -0.05837519094347954, -0.08014591038227081, 0.011603550054132938, + -0.003686923999339342, 0.009551581926643848, 0.021049223840236664, + -0.012841351330280304, 0.013463560491800308, -0.02214140072464943, + 0.016601087525486946, 0.018249280750751495, -0.009617773815989494, + -0.003931836225092411, 0.017931556329131126, 0.007042884826660156, + -0.049743685871362686, 0.006930357776582241, 0.006222097668796778, + 0.009114711545407772, 0.01834856905043125, -0.012656011618673801, + -0.0026410820428282022, 0.05188170447945595, 0.04044363647699356, + 0.02556355483829975, 0.036624327301979065, -0.049227382987737656 + ] + }, + "party": { + "prompt": "Photo of people celebrating together", + "vector": [ + 0.021657669916749, 0.02267414890229702, -0.03314313665032387, + -0.04715124890208244, -0.000511949067004025, -0.0014542320277541876, + -0.0359848253428936, 0.02541196346282959, -0.016916576772928238, + -0.03479769825935364, 0.015351051464676857, -0.030872752889990807, + -0.013614876195788383, 0.027786219492554665, 0.01966923102736473, + 0.5486461520195007, 0.01717626117169857, 0.006358555518090725, + 0.004251402802765369, -0.031265988945961, 0.010513504035770893, + -0.023905795067548752, -0.013889400288462639, 0.008072471246123314, + -0.00276007317006588, 0.0044517312198877335, -0.019639553502202034, + 0.019068246707320213, 0.0030494355596601963, 0.0061804866418242455, + 0.011262878775596619, -0.019105345010757446, 0.011819345876574516, + -0.030338546261191368, 0.026970067992806435, 0.004889484494924545, + -0.01432715356349945, -0.0034723500721156597, 0.032045044004917145, + 0.021961871534585953, 0.050638437271118164, -0.015625575557351112, + 0.0026710384991019964, 0.03608127683401108, -0.01342196948826313, + -0.04062946140766144, -0.04177207499742508, -0.021271854639053345, + 0.007694074884057045, 0.020099565386772156, -0.00014839103096164763, + 0.03710517659783363, 0.03411509469151497, 0.03371443971991539, + -0.005497887264937162, -0.0050081973895430565, -0.003316539339721203, + 0.003598482348024845, -0.00483012804761529, 0.0036429997999221087, + -0.03180761635303497, -0.01874178647994995, -0.010439308360219002, + -0.07591685652732849, -0.05038617178797722, 0.015766547992825508, + 0.008658615872263908, 0.018140802159905434, 0.0036504194140434265, + 0.03667484223842621, 0.02351255901157856, 0.023327069357037544, + -0.020492801442742348, 0.0028416882269084454, 0.03282409533858299, + 0.005416272673755884, -0.05294591560959816, 0.03551739454269409, + 0.038648445159196854, 0.0064624291844666, -0.015907518565654755, + -0.015202660113573074, -0.02860979177057743, 0.03502028435468674, + -0.027934610843658447, -0.0004525926196947694, 0.014750069007277489, + -0.012813565321266651, 0.0009497025748714805, 0.0012910020304843783, + -0.0749448910355568, -0.005668537225574255, -0.01867501251399517, + 0.0038433277513831854, 0.035465456545352936, 0.039842989295721054, + -0.06788889318704605, 0.024388065561652184, -0.021627992391586304, + 0.0019661812111735344, -0.014987492933869362, 0.017035290598869324, + 0.0014097146922722459, -0.03465672582387924, 0.016983352601528168, + 0.01953567937016487, -0.05583954229950905, 0.015009752474725246, + 0.008176345378160477, -0.002255543600767851, 0.006900182459503412, + -0.03729808330535889, 0.06202002987265587, -0.0035836431197822094, + -0.0038878447376191616, -0.07182125747203827, 0.021071525290608406, + -0.02357933484017849, 0.003858166979625821, 0.013926498591899872, + 0.04360470175743103, -0.02247382141649723, 0.004414633382111788, + -0.011218362487852573, 0.008220863528549671, -0.0069966367445886135, + -0.0021590893156826496, -0.05723441764712334, 0.025790361687541008, + -0.0016916577005758882, -0.018734367564320564, 0.03210439905524254, + -0.005178846884518862, 0.009422830305993557, 0.009838324971497059, + 0.003464930457994342, -0.009445088915526867, -0.009044433012604713, + 0.013681653887033463, 0.006299199070781469, -0.02753395587205887, + 0.004214304964989424, 0.008703134022653103, -0.04569701850414276, + -0.00042291442514397204, 0.026851356029510498, -0.030234670266509056, + 0.0006529205129481852, -0.010632217861711979, -0.004333017859607935, + -0.02006988599896431, -0.02068571001291275, -0.07169512659311295, + 0.027934610843658447, -0.020982490852475166, -0.010098009370267391, + -0.009007335640490055, 0.004844967275857925, 0.022303171455860138, + -0.026153918355703354, -0.020166339352726936, -0.023304810747504234, + -0.013763267546892166, 0.0, 0.011366752907633781, + -0.023230616003274918, 0.02135346829891205, -0.5525710582733154, + 0.010120267979800701, -0.026547156274318695, -0.007575361989438534, + 0.054407574236392975, -0.012294196523725986, 0.014431027695536613, + 0.006425331346690655, 0.011099648661911488, 0.026302309706807137, + 0.0069966367445886135, -0.019884398207068443, -0.008027954958379269, + 0.000022258655008045025, 0.007961179129779339, 0.03180019557476044, + 0.010216722264885902, 0.03761712461709976, -0.009504444897174835, + -0.010847384110093117, -0.00271555595099926, 0.03042016178369522, + -0.009556381963193417, 0.03968718275427818, 0.013948756270110607, + -0.004592702724039555, -0.01942438632249832, 0.004889484494924545, + -0.027563635259866714, -0.0013280997518450022, 0.0203518308699131, + -0.014831682667136192, 0.054207246750593185, -0.010290917940437794, + 0.029329488053917885, -0.01600397191941738, -0.02216220088303089, + 0.016946256160736084, 0.029908213764429092, -0.033261850476264954, + -0.008799588307738304, 0.015195241197943687, -0.00010387371730757877, + -0.00605435436591506, 0.003924942575395107, 0.04178691282868385, + -0.049599699676036835, -0.02055215835571289, -0.014193601906299591, + 0.018860500305891037, -0.03188923001289368, -0.037253569811582565, + -0.014816843904554844, -0.02642844244837761, 0.04197240248322487, + 0.0062546818517148495, 0.0545337051153183, 0.0038433277513831854, + 0.02878785878419876, 0.005304979160428047, 0.013607458211481571, + 0.0035094479098916054, 0.0005490467883646488, -0.0031162116210907698, + -0.010980935767292976, 0.006796309258788824, -0.02159089408814907, + -0.016642054542899132, -0.02638392336666584, -0.022110262885689735, + 0.0011055131908506155, -0.025864554569125175, -0.0061433888040483, + -0.024224834516644478, -0.009519284591078758, -0.02364611066877842, + 0.014935556799173355, -0.027571052312850952, 0.046246062964200974, + -0.010357693769037724, 0.02444000169634819, -0.03789164870977402, + -0.00968993455171585, -0.0007122769602574408, -0.018793722614645958, + -0.038336820900440216, 0.009170565754175186, 0.010847384110093117, + -0.009749290533363819, -0.028275910764932632, 0.006506946869194508, + -0.01429747510701418, 0.021538957953453064, -0.027867835015058517, + -0.026242952793836594, 0.018133383244276047, 0.04194272309541702, + 0.02547873929142952, -0.030895013362169266, 0.021895095705986023, + 0.0123832318931818, 0.006685015745460987, -0.01955793797969818, + -0.016211720183491707, 0.003086533397436142, -0.018289193511009216, + -0.03897490352392197, 0.03490899130702019, -0.019832462072372437, + 0.01676076650619507, -0.010060911998152733, 0.0003264602564740926, + 0.006640498526394367, -0.004563024267554283, 0.019565356895327568, + 0.025975851342082024, 0.0015803645364940166, 0.001528427586890757, + 0.0447324737906456, -0.025582613423466682, 0.0214350838214159, + -0.02679941989481449, 0.018519200384616852, -0.03084307350218296, + -0.03813649341464043, -0.03435994312167168, 0.0012539041927084327, + 0.025107761844992638, -0.0014022953109815717, -0.0023223196621984243, + 0.0049191624857485294, 0.025352606549859047, -0.011938057839870453, + 0.003976879641413689, 0.0017584336455911398, 0.025419384241104126, + -0.018400488421320915, 0.02435096725821495, 0.00271555595099926, + 0.01448296383023262, 0.014445867389440536, 0.016901738941669464, + 0.005312399007380009, -0.013043572194874287, 0.017391428351402283, + -0.00848796684294939, 0.011952897533774376, -0.020960234105587006, + -0.0005045294528827071, -0.05082392692565918, 0.004770771600306034, + -0.025419384241104126, 0.007456648629158735, 0.04484377056360245, + 0.0020997331012040377, -0.034582529217004776, 0.010550602339208126, + -0.011099648661911488, 0.01111448835581541, -0.008339575491845608, + 0.048338379710912704, -0.0051046512089669704, 0.009927359409630299, + 0.02717781625688076, -0.005557244177907705, 0.029997248202562332, + 0.0941837877035141, -0.0033536371774971485, 0.0005416272324509919, + 0.019899237900972366, -0.034078001976013184, 0.01092899963259697, + 0.006751792039722204, 0.0010387372458353639, -0.018712108954787254, + 0.09233631193637848, 0.0031458898447453976, -0.012665174901485443, + -0.0008606679039075971, -0.0024336129426956177, -0.011789667420089245, + -0.1166427731513977, -0.007790528703480959, -0.0031681484542787075, + 0.0247664637863636, -0.011307395994663239, -0.05511242896318436, + 0.012820985168218613, 0.01980278268456459, -0.12772756814956665, + 0.014490384608507156, 0.008228282444179058, -0.06526979058980942, + 0.04523700475692749, -0.007894402369856834, -0.04649832844734192, + -0.016048489138484, 0.04359728470444679, 0.027281688526272774, + 0.02774912118911743, 0.0015581058105453849, 0.008154086768627167, + 0.025048404932022095, 0.02400224842131138, 0.034582529217004776, + -0.008027954958379269, 0.008495386689901352, -0.010936419479548931, + 0.017866279929876328, 0.017799504101276398, -0.0154104083776474, + -0.09984490275382996, 0.0003042016178369522, -0.037698738276958466, + -0.005534985102713108, -0.04093366488814354, -0.014260378666222095, + 0.036036763340234756, -0.02932206727564335, -0.031473737210035324, + -0.025842297822237015, 0.033588312566280365, 0.018712108954787254, + -0.08542871475219727, -0.04044397547841072, 0.014156504534184933, + -0.00941541139036417, 0.007130189333111048, 0.007708914112299681, + 0.00834699533879757, -0.077052041888237, 0.020700549706816673, + -0.11950672417879105, 0.043901484459638596, -0.002745233941823244, + -0.05080166831612587, -0.040369778871536255, 0.003962040413171053, + 0.02371288649737835, 0.016901738941669464, 0.030368225648999214, + 0.0167978648096323, -0.04108205810189247, 0.006907602306455374, + 0.006284359842538834, -0.010943838395178318, 0.0029381425119936466, + 0.020084725692868233, 0.01667173206806183, -0.01258355937898159, + -0.0014171343063935637, 0.01907566748559475, 0.004488828592002392, + 0.052448805421590805, -0.048649996519088745, -0.014883620664477348, + 0.00984574481844902, 0.07379485666751862, 0.004614960867911577, + 0.004243983421474695, -0.0037023562472313643, -0.010498665273189545, + -0.027778800576925278, -0.01744336634874344, -0.03314313665032387, + 0.00989026203751564, 0.0028045906219631433, -0.032905708998441696, + 0.051499105989933014, 0.012858081609010696, 0.009118628688156605, + -0.030345967039465904, 0.007070832885801792, -0.02464032918214798, + 0.006173066794872284, -0.05717506259679794, 0.017821762710809708, + 0.03601450473070145, 0.0081911850720644, 0.009229921735823154, + 0.002574584446847439, 0.0038952643517404795, -0.02324545569717884, + -0.026257792487740517, 0.005045294761657715, 0.004362696316093206, + 0.014000694267451763, -0.020989911630749702, 0.012049351818859577, + 0.004703995771706104, 0.027734283357858658, -0.015172983519732952, + -0.00726374052464962, 0.0008458288502879441, -0.011277717538177967, + -0.011351913213729858, -0.010172205045819283, -0.016285916790366173, + 0.05145459249615669, -0.002567164832726121, -0.006314038299024105, + -0.031362444162368774, -0.014534901827573776, 0.007597620598971844, + -0.03720904886722565, 0.032245371490716934, 0.009927359409630299, + -0.006202745251357555, 0.02470710687339306, 0.004941421095281839, + 0.01927599497139454, 0.009422830305993557, 0.018956953659653664, + 0.013926498591899872, -0.0029900791123509407, 0.02242930419743061, + -0.027385564520955086, -0.013956177048385143, -0.047099314630031586, + -0.11699148267507553, 0.0574495866894722, -0.007597620598971844, + 0.03949427232146263, 0.02099733054637909, 0.01011284813284874, + 0.01009058952331543, 0.004674317315220833, 0.01161159761250019, + 0.006729532964527607, -0.012271937914192677, -0.004384954925626516, + 0.010342855006456375, 0.012323874980211258, 0.007545683532953262, + 0.005282720550894737, -0.037542931735515594, 0.012368392199277878, + -0.0074789077043533325, -0.026020366698503494, -0.007627299055457115, + 0.019335351884365082, 0.062405843287706375, -0.004058494698256254, + -0.009370893239974976, -0.06802986562252045 + ] + }, + "hiking": { + "prompt": "Photo of people hiking or walking together in nature", + "vector": [ + 0.002063393360003829, 0.0015020288992673159, -0.013541018590331078, + -0.007646692916750908, 0.026111029088497162, 0.0011834166944026947, + -0.02757512778043747, 0.007176360581070185, 0.019071215763688087, + -0.006736371666193008, -0.005340547300875187, -0.00493848929181695, + 0.0006903264438733459, 0.02783305011689663, 0.05169862136244774, + 0.5473757982254028, 0.010901088826358318, 0.008154954761266708, + 0.010863158851861954, -0.02394143119454384, 0.018168481066823006, + -0.0024426935706287622, -0.02306145429611206, -0.009588710032403469, + 0.01046110037714243, 0.00219235522672534, -0.029919203370809555, + -0.009262511506676674, 0.02251526340842247, 0.007934961467981339, + 0.028439931571483612, -0.0003868862404488027, 0.011454867199063301, + -0.01567268557846546, 0.031299855560064316, -0.016143018379807472, + 0.004331608768552542, -0.03375013545155525, 0.006872919853776693, + 0.0354645736515522, 0.0011682447511702776, -0.002533725695684552, + 0.0012441047001630068, -0.01750091277062893, -0.05769156292080879, + -0.022204237058758736, 0.03236947953701019, -0.047382187098264694, + 0.004976418800652027, 0.022613881155848503, 0.020360836759209633, + 0.008807350881397724, -0.0078970305621624, 0.029555076733231544, + -0.023433169350028038, -0.018456749618053436, -0.004399883095175028, + -0.04163958132266998, -0.007092914544045925, -0.0014640989247709513, + -0.04121476411819458, -0.0076922085136175156, -0.02539035677909851, + 0.026065511628985405, -0.026725493371486664, 0.015361659228801727, + -0.027309618890285492, 0.004134372808039188, 0.03704246133565903, + 0.015437520109117031, 0.004862628877162933, 0.014974773861467838, + -0.00012137607700424269, -0.03316601365804672, -0.03244534134864807, + 0.008905969560146332, -0.07830274105072021, 0.008481153286993504, + 0.06572514027357101, 0.028963366523385048, -0.021453222259879112, + -0.015354073606431484, -0.005780535284429789, -0.0006675684126093984, + 0.022181479260325432, 0.018722258508205414, -0.03245292976498604, + -0.0019192592008039355, 0.010499031282961369, 0.025853104889392853, + 0.005105380900204182, -0.01422375999391079, 0.00827633123844862, + -0.012342429719865322, -0.003967480733990669, 0.019033284857869148, + -0.08297571539878845, 0.03469838574528694, -0.013412055559456348, + 0.017940901219844818, -0.030533669516444206, -0.013503088615834713, + -0.01873743161559105, -0.06481482833623886, 0.0069411941803991795, + 0.020633932203054428, -0.05540059506893158, 0.014603059738874435, + 0.004559189081192017, -0.03791484981775284, -0.01018800400197506, + 0.0024730374570935965, -0.03339359536767006, -0.009528021328151226, + -0.023736609145998955, -0.013707909733057022, 0.009300441481173038, + -0.012926552444696426, 0.035995591431856155, -0.0003793002397287637, + 0.03805140033364296, -0.008162541314959526, 0.002298559295013547, + -0.014542371965944767, -0.012539665214717388, 0.00940664578229189, + 0.02364557795226574, -0.045121558010578156, -0.001008938648737967, + 0.00028068217216059566, 0.0036792121827602386, 0.02761305682361126, + 0.0065012057311832905, 0.020907029509544373, 0.06558859348297119, + 0.0028144079260528088, -0.01451202668249607, -0.005530197639018297, + -0.0006144663784652948, -0.0013199648819863796, 0.00856459978967905, + -0.0002958541736006737, -0.008079095743596554, 0.024707617238163948, + -0.007957719266414642, -0.003110261866822839, -0.002966127824038267, + 0.02645239792764187, -0.02149873785674572, 0.011318319477140903, + -0.04584981128573418, 0.014557542279362679, -0.005317789502441883, + 0.04957453906536102, -0.010324552655220032, 0.030859868973493576, + 0.024131080135703087, -0.002784063806757331, 0.0037702443078160286, + -0.024692445993423462, 0.0030950899235904217, 0.017834696918725967, + 0.009232167154550552, 0.012243811041116714, -0.0712856873869896, + 0.05383029207587242, 0.014056866988539696, -0.551009476184845, + 0.02320558950304985, -0.027984770014882088, -0.02834131382405758, + 0.05802535265684128, 0.0036033522337675095, -0.0293881818652153, + -0.04008444771170616, 0.0006068804068490863, -0.0058260513469576836, + -0.0210663340985775, 0.02102840505540371, 0.04547051340341568, + 0.006994296796619892, 0.03524458035826683, -0.0028523379005491734, + -0.01225898414850235, 0.042170602828264236, -0.015574067831039429, + -0.0283716581761837, -0.015346487052738667, 0.014436166733503342, + -0.012023817747831345, -0.0017220231238752604, 0.025845518335700035, + 0.03774796053767204, -0.050879333168268204, -0.026035169139504433, + -0.006121905520558357, 0.017622290179133415, -0.0962739810347557, + 0.00798806268721819, 0.011826581321656704, 0.04728356748819351, + 0.09593261033296585, 0.04386227950453758, 0.014322377741336823, + 0.03848380222916603, -0.01191002782434225, 0.017265748232603073, + -0.0007661865092813969, -0.013943076133728027, 0.01731126382946968, + 0.02589862048625946, -0.00002275801307405345, 0.0014640989247709513, + -0.009528021328151226, -0.011735549196600914, -0.011477624997496605, + 0.058154311031103134, -0.029744725674390793, -0.004635049030184746, + -0.020163599401712418, -0.02444210648536682, 0.009581124410033226, + 0.0047943550162017345, 0.05439165234565735, 0.020869098603725433, + 0.008041164837777615, 0.011098324321210384, -0.029911616817116737, + -0.023653162643313408, -0.08817972242832184, -0.010347310453653336, + -0.03296118974685669, 0.01143969502300024, -0.03907550871372223, + 0.0034440462477505207, -0.03758106753230095, -0.023251105099916458, + 0.02484416589140892, -0.011758306995034218, -0.034068744629621506, + -0.00598535779863596, 0.0004551603051368147, -0.03244534134864807, + -0.002495795488357544, 0.008503912016749382, 0.07327321916818619, + -0.026505500078201294, 0.013798942789435387, -0.08673837780952454, + -0.018540196120738983, -0.007790826726704836, -0.042034052312374115, + -0.055635757744312286, -0.029524730518460274, -0.0075860051438212395, + 0.007714967243373394, -0.0019799470901489258, -0.06055907532572746, + -0.0005386063130572438, 0.0027157897129654884, -0.04244369640946388, + 0.003686798270791769, 0.014519614167511463, 0.010984535329043865, + -0.0255344919860363, -0.021741488948464394, 0.005355719476938248, + 0.022014586254954338, -0.01018800400197506, -0.012941723689436913, + -0.0000910320522962138, 0.0032923261169344187, -0.0024654516018927097, + 0.02062634751200676, 0.03338600695133209, 0.005014349240809679, + 0.00467297900468111, 0.004202646669000387, 0.02229526825249195, + 0.00722187664359808, 0.014595472253859043, 0.009300441481173038, + 0.009376302361488342, -0.01757677271962166, -0.042360249906778336, + 0.0059019117616117, 0.009072861634194851, 0.009649398736655712, + -0.009679742157459259, 0.008132196962833405, -0.007889444939792156, + -0.005598471499979496, 0.03568456694483757, -0.0014489268651232123, + 0.007009468041360378, 0.028508204966783524, -0.03474390134215355, + -0.10007457435131073, 0.015376831404864788, -0.0013047928223386407, + -0.03398530185222626, 0.013578948564827442, 0.016431285068392754, + 0.017963659018278122, 0.027415819466114044, -0.01756918616592884, + -0.013442400842905045, 0.016363011673092842, 0.013783770613372326, + 0.04548568278551102, 0.05770673602819443, -0.000963422644417733, + -0.018100207671523094, -0.002875095698982477, 0.010051456280052662, + 0.05289721488952637, -0.03294602036476135, 0.016939548775553703, + -0.05000694468617439, -0.030321259051561356, 0.04122234880924225, + 0.008208057843148708, 0.03441770374774933, -0.008746663108468056, + 0.003239224199205637, -0.009725257754325867, -0.043528493493795395, + 0.0073811826296150684, 0.002905439818277955, 0.021946312859654427, + 0.020679449662566185, 0.0052874451503157616, -0.03149709105491638, + 0.05969427153468132, 0.0024882094003260136, -0.01367756724357605, + 0.024798648431897163, -0.026027580723166466, -0.018380889669060707, + -0.06441276520490646, 0.007593590300530195, -0.002723375800997019, + 0.026975832879543304, -0.010309380479156971, 0.004232990555465221, + -0.0185477826744318, 0.010787298902869225, 0.006175007671117783, + 0.00040964424260891974, 0.01695472002029419, -0.00923975370824337, + 0.002556483494117856, 0.02156701311469078, -0.07915237545967102, + 0.01619611866772175, 0.004278506617993116, -0.019078800454735756, + 0.02157459780573845, -0.0014792709844186902, -0.0033302560914307833, + 0.020641518756747246, -0.019526375457644463, -0.0314212329685688, + -0.013078272342681885, -0.005461923312395811, -0.00219235522672534, + -0.027734432369470596, -0.02193872444331646, 0.01945810206234455, + 0.020239459350705147, -0.008344604633748531, 0.019518790766596794, + -0.04682840779423714, 0.006834989879280329, 0.007237048353999853, + -0.01417065691202879, 0.028690271079540253, -0.014921671710908413, + -0.061385948210954666, -0.015703029930591583, 0.003117847954854369, + -0.007358424365520477, -0.02138494700193405, -0.007343252655118704, + 0.05872325971722603, -0.01699265092611313, 0.020307734608650208, + -0.016605764627456665, 0.02196907065808773, 0.006599824409931898, + 0.02062634751200676, 0.0405016764998436, -0.0021771832834929228, + 0.04533396288752556, 0.015134080313146114, -0.020535314455628395, + -0.006250868085771799, -0.015217525884509087, 0.02823510952293873, + -0.1144576445221901, 0.023304205387830734, 0.03866586834192276, + 0.0056212292984128, 0.012175537645816803, -0.02510209009051323, + -0.012592768296599388, -0.002336489502340555, 0.06109009310603142, + -0.004953661002218723, 0.009482505731284618, -0.03818794712424278, + -0.008177713491022587, 0.00503710750490427, -0.0011758307227864861, + 0.014542371965944767, 0.0022378715220838785, -0.0035274922847747803, + 0.0026854455936700106, 0.023380065336823463, 0.02768133208155632, + 0.11998025327920914, -0.07625452429056168, -0.06897195428609848, + 0.02488209493458271, 0.015012702904641628, -0.020057396963238716, + -0.010756954550743103, 0.01931396685540676, 0.03437977284193039, + -0.002108909422531724, -0.004710908979177475, 0.012069333344697952, + 0.008147369138896465, -0.027150310575962067, -0.06366175413131714, + 0.01267621386796236, 0.023304205387830734, 0.03529009595513344, + -0.016309909522533417, -0.0025792415253818035, -0.004415054805576801, + 0.00925492588430643, 0.007745311129838228, -0.026497915387153625, + 0.0015247869305312634, 0.020679449662566185, -0.019943606108427048, + 0.022644223645329475, 0.0021013233345001936, -0.0057729496620595455, + -0.057418469339609146, 0.016567833721637726, -0.040615469217300415, + 0.021111849695444107, -0.016051985323429108, -0.017409881576895714, + -0.027529612183570862, 0.00851149670779705, -0.016271980479359627, + -0.01257000956684351, 0.01160658709704876, -0.03044263832271099, + -0.011447281576693058, 0.03321152925491333, 0.010286622680723667, + 0.05867016315460205, -0.0005006763385608792, 0.005651573650538921, + 0.02270491234958172, 0.019670508801937103, 0.009103205054998398, + 0.0033909440971910954, 0.007828757166862488, 0.012486563995480537, + -0.06490585952997208, 0.014314791187644005, -0.02128632925450802, + 0.01449685450643301, 0.02833372727036476, -0.006053632125258446, + -0.001084798714146018, 0.03882517293095589, 0.021870451048016548, + -0.016522318124771118, 0.0028826817870140076, -0.049089036881923676, + -0.06481482833623886, 0.0018206412205472589, 0.023296620696783066, + 0.019404999911785126, 0.02746892161667347, 0.031079862266778946, + 0.01899535581469536, -0.040478918701410294, 0.04027410224080086, + 0.01311620231717825, -0.001866157166659832, -0.055635757744312286, + -0.016234049573540688, 0.0015323730185627937, -0.021407704800367355, + -0.009050103835761547, -0.007494972553104162, 0.011614173650741577, + -0.00951285008341074, -0.018889151513576508, -0.01571820117533207, + 0.012501736171543598, 0.06539894640445709, -0.006281211972236633, + 0.011727963574230671, -0.04220853000879288 + ] + }, + "feast": { + "prompt": "Photo of people having a big feast together", + "vector": [ + -0.029508370906114578, 0.006410595495253801, -0.022999616339802742, + -0.04990297555923462, 0.017683882266283035, -0.010110467672348022, + -0.023958561941981316, 0.004115164279937744, -0.03147157281637192, + -0.0791093111038208, -0.01019352674484253, 0.03028610162436962, + -0.005285532213747501, 0.016543716192245483, 0.01726858876645565, + 0.5275111794471741, -0.016181280836462975, -0.005934897810220718, + -0.017427153885364532, -0.01871078461408615, -0.007905646227300167, + -0.03548102453351021, 0.024102026596665382, 0.005323286168277264, + -0.00561021501198411, -0.002605012385174632, -0.01120532862842083, + -0.006410595495253801, 0.030542826279997826, 0.03679485619068146, + -0.009483755566179752, -0.035435717552900314, 0.0168155450373888, + 0.012134072370827198, -0.004001902882009745, 0.04106858745217323, + -0.013289338909089565, -0.009597016498446465, -0.026314400136470795, + 0.014791940338909626, 0.07266851514577866, -0.017094921320676804, + -0.00034733497886918485, 0.020719286054372787, -0.03684015944600105, + -0.051322516053915024, -0.026714589446783066, -0.0372932069003582, + -0.004938197322189808, 0.017162878066301346, 0.013908501714468002, + 0.011575316078960896, 0.03738381713628769, -0.004032106138765812, + -0.01874098740518093, -0.011099617928266525, -0.01941300556063652, + 0.003224174724891782, -0.03239276260137558, 0.008056661114096642, + -0.029923664405941963, 0.008396445773541927, -0.012330392375588417, + -0.0709695965051651, -0.04053248465061188, 0.006886293180286884, + -0.005647968500852585, -0.04843812808394432, 0.004855139181017876, + 0.009838640689849854, 0.00040774105582386255, -0.025453614071011543, + -0.017955707386136055, 0.02265983261168003, 0.029281847178936005, + -0.01099390722811222, -0.06056464836001396, 0.009732929989695549, + 0.09662707895040512, 0.01938280090689659, 0.00030203041387721896, + -0.02985570766031742, -0.011424301192164421, -0.007709326688200235, + 0.019480960443615913, 0.047864269465208054, 0.0035111038014292717, + -0.006252029910683632, 0.0017517763189971447, -0.007497905287891626, + -0.016649426892399788, 0.015033564530313015, -0.02813413366675377, + 0.0017895301571115851, -0.012141622602939606, 0.022909006103873253, + -0.13033367693424225, 0.0323852114379406, -0.02679009921848774, + 0.015373348258435726, -0.0010118018835783005, 0.024849552661180496, + -0.010050062090158463, 0.05398038774728775, 0.021149680018424988, + 0.008532359264791012, -0.04978971555829048, 0.012164275161921978, + 0.03536776453256607, -0.009438450448215008, 0.006908946204930544, + -0.028670238330960274, 0.04793977737426758, -0.03107893094420433, + -0.00043039332376793027, -0.09445246309041977, 0.041287556290626526, + -0.03239276260137558, 0.013568716123700142, 0.031305454671382904, + -0.010352092795073986, -0.00006795684748794883, -0.019397905096411705, + -0.045115794986486435, 0.005270430818200111, -0.006206724792718887, + 0.04941217601299286, -0.031645238399505615, 0.0459916815161705, + 0.006365290842950344, -0.017872650176286697, 0.029508370906114578, + -0.00622937735170126, 0.005776331759989262, -0.014505011029541492, + -0.014248285442590714, -0.009763133712112904, -0.009702727198600769, + 0.01652861386537552, 0.03707423433661461, -0.00672017689794302, + 0.025831151753664017, -0.009242130443453789, -0.044255007058382034, + 0.006395494099706411, -0.018363449722528458, 0.00662201689556241, + 0.030399363487958908, -0.015713132917881012, 0.018167128786444664, + -0.015833944082260132, 0.0032543777488172054, -0.06430982798337936, + 0.02250126749277115, 0.014172777533531189, 0.03633425757288933, + 0.02984815463423729, -0.01769143156707287, 0.0005814085598103702, + -0.01925443857908249, -0.037919919937849045, -0.012254884466528893, + -0.008396445773541927, 0.009959452785551548, 0.057582102715969086, + -0.04155183583498001, 0.013508310541510582, -0.5311808586120605, + -0.0006191623397171497, 0.002084009815007448, -0.008177473209798336, + 0.04822670668363571, -0.02510627917945385, 0.027484769001603127, + 0.003480900777503848, -0.0014119921252131462, 0.040977977216243744, + -0.010004756972193718, -0.01550926174968481, -0.002846636576578021, + 0.023565921932458878, 0.016400251537561417, 0.014384198933839798, + 0.009068462997674942, 0.04809079319238663, -0.013712181709706783, + 0.0087739834561944, -0.02348286472260952, -0.010978804901242256, + -0.02327144332230091, 0.024630580097436905, 0.004923095460981131, + -0.0450025349855423, -0.018431406468153, -0.02188965491950512, + -0.029259197413921356, -0.020983561873435974, 0.023807547986507416, + -0.02648051828145981, 0.05487137287855148, 0.0007550760637968779, + 0.003443146590143442, -0.00040019029984250665, -0.02216148190200329, + -0.008992955088615417, -0.01047290489077568, -0.0007324237376451492, + -0.027545172721147537, 0.024086926132440567, -0.008917448110878468, + 0.01448235847055912, 0.0016838194569572806, -0.004462499171495438, + -0.013025062158703804, 0.022674933075904846, 0.023867953568696976, + -0.09708012640476227, -0.013727283105254173, -0.031886860728263855, + 0.008034009486436844, -0.0067352778278291225, 0.05508279800415039, + 0.010352092795073986, 0.02363388054072857, 0.004024555440992117, + -0.010676775127649307, 0.0008456851937808096, -0.016800440847873688, + 0.00014346445095725358, -0.0004152918409090489, 0.01708737015724182, + 0.03860703855752945, -0.011877345852553844, -0.02216903120279312, + -0.02170843631029129, 0.056842122226953506, 0.003428045427426696, + -0.005051458720117807, -0.0659709945321083, -0.0037753803189843893, + -0.004175570793449879, 0.011620620265603065, -0.0223502516746521, + 0.011507358402013779, -0.07293279469013214, 0.0331176333129406, + 0.006810786202549934, -0.00946110300719738, -0.03183400630950928, + 0.0026276647113263607, -0.021610276773571968, -0.04296382516622543, + -0.059968139976263046, 0.02210862748324871, -0.022448411211371422, + 0.00127607851754874, -0.030225694179534912, -0.02345266193151474, + 0.008215227164328098, 0.03343476727604866, -0.016249235719442368, + -0.030784450471401215, 0.017955707386136055, 0.014965606853365898, + 0.009159073233604431, -0.015214783139526844, 0.044353168457746506, + -0.012813640758395195, -0.011673475615680218, 0.004084961488842964, + 0.010276584886014462, 0.03187175840139389, 0.006093463860452175, + 0.0021972714457660913, 0.004681471269577742, -0.02412468008697033, + -0.005330836866050959, 0.008260532282292843, 0.013968906365334988, + 0.030852409079670906, 0.012488958425819874, 0.03156217932701111, + 0.028957165777683258, -0.0005889593157917261, 0.01711002178490162, + 0.026835402473807335, 0.019216684624552727, 0.004704123828560114, + -0.029644286260008812, -0.006319986190646887, -0.041868966072797775, + -0.017321443185210228, -0.015086418949067593, -0.04332626610994339, + 0.011439401656389236, 0.0019707484170794487, -0.012889147736132145, + -0.047192253172397614, 0.017525315284729004, 0.016543716192245483, + 0.030225694179534912, -0.014301139861345291, 0.02335450053215027, + -0.005693273153156042, 0.039082735776901245, -0.011937752366065979, + 0.02835310623049736, 0.019110973924398422, -0.002778679830953479, + -0.010654122568666935, -0.05033336952328682, -0.018997713923454285, + -0.03303457424044609, 0.0017593271331861615, 0.015071317553520203, + 0.05412385240197182, -0.0390600822865963, 0.01020862814038992, + -0.04464764520525932, 0.005149618722498417, 0.021353550255298615, + 0.014633373357355595, -0.008940099738538265, 0.050348468124866486, + 0.003941496834158897, 0.003722524968907237, -0.026095427572727203, + 0.006168971303850412, 0.018514463678002357, 0.009989656507968903, + 0.003216624027118087, -0.0018952408572658896, 0.010231280699372292, + 0.09087339788675308, -0.020960910245776176, -0.004696573130786419, + 0.01754041574895382, -0.02033419720828533, -0.027296001091599464, + -0.018869351595640182, -0.036387115716934204, 0.028859006240963936, + 0.058525945991277695, -0.015373348258435726, 0.00786789320409298, + -0.03333660960197449, 0.024056723341345787, -0.004628615919500589, + -0.06604650616645813, 0.022116176784038544, -0.010404948145151138, + 0.0031713193748146296, 0.019692381843924522, -0.08060436695814133, + 0.015637625008821487, 0.017261039465665817, -0.11375976353883743, + 0.008041559718549252, 0.00019631977193057537, -0.05997568741440773, + 0.041045933961868286, -0.005315735470503569, -0.002378489589318633, + 0.01956401951611042, 0.05740842968225479, 0.005942448507994413, + 0.022486163303256035, 0.002099111443385482, 0.02795291505753994, + -0.03366883844137192, -0.014572967775166035, -0.0296065304428339, + 0.018793843686580658, -0.016490861773490906, -0.0028390861116349697, + 0.021549871191382408, 0.04615779593586922, -0.019088322296738625, + -0.12028361111879349, -0.010571064427495003, -0.032709892839193344, + -0.026865605264902115, -0.02486465498805046, 0.006221826653927565, + 0.013802791014313698, -0.0009060912416316569, 0.01171122957020998, + 0.0067352778278291225, 0.05201718956232071, 0.01818978041410446, + -0.09494326263666153, -0.004756979178637266, -0.014452156610786915, + 0.014799490571022034, 0.005647968500852585, 0.058926135301589966, + 0.006916496902704239, 0.014051965437829494, -0.012874046340584755, + -0.06671097129583359, 0.023679183796048164, 0.028405960649251938, + -0.01400666031986475, -0.03927905485033989, -0.015849046409130096, + 0.005126966163516045, 0.04285811632871628, 0.04158203676342964, + 0.014505011029541492, -0.053074296563863754, -0.00996700394898653, + 0.021210087463259697, 0.008940099738538265, 0.02851167321205139, + 0.01449745986610651, 0.008185024373233318, 0.00274092610925436, + 0.022425759583711624, 0.009408247657120228, -0.007052409928292036, + 0.03719504550099373, -0.02506852336227894, 0.016490861773490906, + -0.011046762578189373, 0.052311670035123825, 0.018756089732050896, + -0.009415797889232635, 0.0008683374035172164, 0.022403106093406677, + -0.03511858731508255, 0.0030807103030383587, -0.01668718084692955, + -0.00672017689794302, -0.015562117099761963, -0.005376141518354416, + 0.021595174446702003, 0.027409261092543602, -0.00037753803189843893, + -0.004605963826179504, 0.016294540837407112, -0.030135085806250572, + 0.0011477156076580286, -0.03647017478942871, -0.044413574039936066, + 0.010835341177880764, 0.02777169644832611, -0.00030203041387721896, + 0.04723755642771721, -0.004636167082935572, -0.0037602786906063557, + -0.06221826747059822, 0.003178870305418968, -0.011628171429038048, + 0.004175570793449879, -0.02207842469215393, -0.02427569404244423, + 0.007361991330981255, 0.01446725707501173, 0.02302226796746254, + -0.004930646624416113, -0.0018423855071887374, -0.008653171360492706, + 0.0005436547799035907, 0.0017593271331861615, 0.012300188653171062, + 0.026533372700214386, -0.03156972676515579, 0.021655581891536713, + -0.05373876169323921, -0.005013705231249332, -0.009204376488924026, + 0.00019631977193057537, 0.04528946056962013, 0.02777169644832611, + 0.022116176784038544, -0.024577725678682327, -0.02348286472260952, + -0.004855139181017876, 0.007445049937814474, 0.010246382094919682, + -0.0012911800295114517, -0.0016309642232954502, 0.0021897205151617527, + -0.044776007533073425, -0.06371331959962845, -0.00727138202637434, + -0.09274598956108093, 0.03334415704011917, 0.030724044889211655, + -0.006418146193027496, 0.02210862748324871, -0.019345048815011978, + -0.019178932532668114, -0.041159193962812424, -0.009159073233604431, + 0.008290735073387623, -0.014746634289622307, 0.000823032867629081, + 0.023520618677139282, -0.008502155542373657, 0.01005761232227087, + -0.0026654184330254793, 0.0026427661068737507, 0.006297334562987089, + 0.02388305403292179, -0.011371445842087269, -0.014286038465797901, + 0.016279440373182297, 0.045025184750556946, 0.00844930112361908, + 0.024653233587741852, -0.13621573150157928 + ] + }, + "selfies": { + "prompt": "Happy and nostalgic selfie with people, clearly taken from the front camera of a phone", + "vector": [ + 0.015917416661977768, 0.050739727914333344, -0.02502211555838585, + -0.087443046271801, 0.03248291090130806, 0.0026871508453041315, + -0.00765837961807847, 0.007144659757614136, 0.03526490181684494, + 0.001857295399531722, -0.003943788819015026, -0.007460794877260923, + -0.03395294025540352, -0.0075793457217514515, -0.004188793711364269, + 0.4699036478996277, 0.030467547476291656, -0.014897879213094711, + 0.0670839250087738, -0.05165652185678482, -0.015071753412485123, + -0.02868928574025631, 0.025488415732979774, -0.010851346887648106, + 0.017822131514549255, 0.01167329866439104, -0.01135716401040554, + -0.009808100759983063, 0.06773991137742996, 0.01942651905119419, + 0.02820718102157116, -0.041832614690065384, -0.005722050555050373, + 0.01917361095547676, 0.0193316787481308, -0.03930353373289108, 0.0, + 0.0002133913803845644, 0.0028136048931628466, -0.049388252198696136, + -0.035889267921447754, 0.004259924404323101, -0.04313667118549347, + 0.04614786058664322, 0.04571317881345749, -0.05501545965671539, + -0.0005216234130784869, -0.025361960753798485, 0.03127369284629822, + -0.012866709381341934, -0.056959692388772964, 0.07071158289909363, + 0.015150788240134716, -0.027337808161973953, -0.055307887494564056, + -0.046590451151132584, 0.00572995375841856, 0.042409561574459076, + -0.03867916390299797, 0.011823463253676891, -0.01588580198585987, + 0.006188350263983011, -0.03316260129213333, -0.004797354806214571, + -0.08805950731039047, 0.010337627492845058, 0.017490191385149956, + 0.008749046362936497, 0.025891486555337906, 0.049546319991350174, + 0.014629164710640907, 0.054177701473236084, -0.0517592653632164, + 0.015150788240134716, -0.008662109263241291, -0.001414705766364932, + -0.069162517786026, -0.012455734424293041, 0.06672036647796631, + 0.008843887597322464, 0.048005156219005585, -0.04151647910475731, + 0.019766364246606827, 0.020738480612635612, 0.014992720447480679, + 0.04920647293329239, -0.0025211796164512634, 0.019797977060079575, + 0.035960398614406586, 0.0034300689585506916, 0.0030586100183427334, + 0.027100706472992897, 0.024808725342154503, 0.012179115787148476, + -0.013111715205013752, 0.013894150033593178, -0.003643460338935256, + 0.033249542117118835, -0.04278102144598961, -0.020232664421200752, + -0.007176273502409458, 0.01348317414522171, -0.043500229716300964, + -0.01609129086136818, -0.0025369864888489246, 0.0075872489251196384, + -0.042788922786712646, 0.04044952243566513, -0.01958458684384823, + 0.003667170647531748, -0.01606758125126362, -0.023465149104595184, + 0.015032238326966763, -0.059915561228990555, 0.008970341645181179, + 0.03035689890384674, 0.010685376822948456, -0.05084247514605522, + -0.016533881425857544, 0.005737856961786747, 0.03273581713438034, + -0.010369240306317806, 0.014692391268908978, -0.0033431316260248423, + 0.020959775894880295, 0.0011143771698698401, 0.050478916615247726, + -0.04680384323000908, -0.01737954281270504, -0.012890420854091644, + -0.021394461393356323, 0.014945301227271557, -0.023710153996944427, + -0.009657936170697212, 0.008053549565374851, 0.027456358075141907, + 0.0069075580686330795, 0.02016153372824192, 0.0330914705991745, + -0.07644153386354446, -0.02246141992509365, -0.00044258954585529864, + -0.0005216234130784869, -0.026428917422890663, -0.0035091026220470667, + -0.0034853925462812185, -0.0336921289563179, -0.022382386028766632, + 0.031281597912311554, -0.08310408890247345, 0.009657936170697212, + 0.02995382808148861, -0.017901165410876274, 0.0012171212583780289, + 0.022777553647756577, -0.0060223788022994995, -0.0018414886435493827, + -0.01603596843779087, -0.0593465156853199, -0.04250440001487732, + 0.027709266170859337, 0.03439553081989288, -0.03536764532327652, + 0.011199096217751503, 0.03919288516044617, -0.008986148051917553, + 0.017110828310251236, -0.4741714596748352, 0.05406705290079117, + 0.017442768439650536, -0.004923808388411999, 0.05942555144429207, + 0.027914753183722496, -0.009246960282325745, 0.0069154612720012665, + -0.04851888120174408, 0.02397886849939823, 0.0008693723357282579, + 0.022121572867035866, 0.13283218443393707, -0.015245628543198109, + -0.006488678976893425, 0.01965571753680706, -0.012218632735311985, + 0.04632173851132393, 0.057386476546525955, 0.002450049389153719, + -0.02909236028790474, 0.004354765173047781, -0.059259574860334396, + 0.026958445087075233, -0.019473940134048462, 0.0340556837618351, + -0.03817334771156311, 0.004117663484066725, -0.018738925457000732, + 0.0018731020390987396, -0.018154073506593704, -0.03981725126504898, + 0.0010432468261569738, 0.026326173916459084, 0.04975971207022667, + -0.059109412133693695, -0.029021229594945908, -0.02719554677605629, + -0.012756062671542168, -0.02954285219311714, 0.03445085510611534, + 0.050146978348493576, 0.05016278102993965, -0.008511945605278015, + -0.006512389052659273, 0.0041097598150372505, -0.018936509266495705, + -0.024397749453783035, 0.004615576937794685, 0.032064031809568405, + 0.039959512650966644, 0.02782781794667244, 0.0013198652304708958, + 0.015972739085555077, 0.015332565642893314, 0.016280973330140114, + 0.011570555157959461, 0.022659003734588623, 0.010179559700191021, + -0.011910400353372097, 0.015672411769628525, 0.01436835341155529, + -0.017316315323114395, -0.02405790239572525, -0.006046089343726635, + 0.0014779329067096114, -0.07849641144275665, 0.0059828623197972775, + 0.03033319115638733, 0.016968566924333572, -0.03571539372205734, + -0.001509546535089612, -0.020951872691512108, -0.012171212583780289, + 0.004180890507996082, -0.01209217868745327, 0.02031169831752777, + -0.041706159710884094, 0.049570027738809586, 0.015538053587079048, + -0.05229669809341431, -0.019845400005578995, -0.04116082563996315, + 0.011025221087038517, -0.08250343799591064, 0.008551462553441525, + 0.003888465464115143, -0.02114945650100708, -0.025899391621351242, + -0.03126579150557518, -0.061259131878614426, -0.04042581096291542, + 0.015893707051873207, -0.07852012664079666, -0.01596483774483204, + 0.013467367738485336, 0.009444545023143291, 0.040868401527404785, + -0.028807837516069412, -0.027914753183722496, -0.035280708223581314, + 0.016842111945152283, 0.01143619790673256, -0.0288157407194376, + 0.022295447066426277, 0.016178227961063385, -0.031811121851205826, + -0.02838895656168461, 0.025899391621351242, 0.0017466479912400246, + 0.008662109263241291, -0.00922324974089861, 0.001983749447390437, + 0.027764590457081795, -0.026247140020132065, 0.000545333547051996, + -0.061132680624723434, -0.014905783347785473, 0.03196919336915016, + -0.0200824998319149, 0.00834597460925579, -0.02823088876903057, + 0.004931711591780186, -0.03958805650472641, -0.03649783134460449, + -0.021916085854172707, 0.03401616960763931, 0.002126010600477457, + 0.014921589754521847, -0.033557772636413574, 0.08977454900741577, + 0.03425326943397522, 0.003366841934621334, 0.005113489460200071, + -0.015617088414728642, -0.025306636467576027, 0.03321792557835579, + -0.007460794877260923, 0.0021655273158103228, 0.006828524172306061, + 0.020201051607728004, -0.016612913459539413, -0.04017290472984314, + -0.04703304171562195, -0.018146172165870667, -0.008290650323033333, + 0.0038252382073551416, 0.018960220739245415, 0.04915114864706993, + -0.049799226224422455, 0.07689203321933746, -0.027377326041460037, + 0.015553861856460571, 0.022303352132439613, -0.06472081691026688, + -0.022706422954797745, 0.036545250564813614, 0.09203491359949112, + -0.020849129185080528, 0.007049818988889456, 0.06066638231277466, + -0.02196350507438183, 0.008496138267219067, 0.03311518207192421, + -0.00007903384539531544, 0.021694790571928024, 0.04487541690468788, + 0.007895481772720814, -0.03597620874643326, -0.0013751889346167445, + 0.015648702159523964, -0.0345061756670475, 0.01453432347625494, + -0.01897602714598179, -0.031155141070485115, 0.026492144912481308, + -0.0359208844602108, 0.008164196275174618, -0.042354241013526917, + -0.021268006414175034, -0.014613358303904533, -0.13114877045154572, + 0.018509726971387863, 0.004489122424274683, -0.013570111244916916, + 0.01238460373133421, -0.030949654057621956, 0.025646483525633812, + 0.015846285969018936, -0.09424786269664764, 0.024674367159605026, + -0.044029753655195236, 0.01856505125761032, -0.01834375597536564, + 0.02671344019472599, -0.005263654049485922, 0.0069075580686330795, + 0.020398635417222977, 0.013720275834202766, 0.0563037134706974, + 0.044614605605602264, -0.000987923122011125, -0.008369684219360352, + 0.036972030997276306, -0.03273581713438034, 0.01824101060628891, + -0.03617379069328308, 0.014423677697777748, -0.02711651287972927, + 0.07519280165433884, -0.03147917985916138, 0.05080295726656914, + 0.0008061452535912395, -0.021220587193965912, -0.0074449884705245495, + 0.007531925570219755, -0.0281518567353487, 0.03056238777935505, + -0.03332066908478737, -0.017387446016073227, -0.004196696914732456, + 0.06400161236524582, -0.10398483276367188, -0.061053644865751266, + -0.07527974247932434, -0.008646302856504917, 0.022255931049585342, + 0.01205266173928976, 0.026223430410027504, -0.03162934258580208, + -0.031613539904356, 0.0017071310430765152, -0.08489025384187698, + 0.0036592669785022736, -0.07139917463064194, 0.0009009858476929367, + -0.0031139336060732603, 0.043626684695482254, 0.003651363542303443, + 0.019900722429156303, 0.03483021631836891, -0.007500311825424433, + 0.02757490798830986, -0.04568946361541748, 0.028302019461989403, + -0.015119175426661968, -0.008203713223338127, -0.012835096567869186, + 0.042615048587322235, -0.039279818534851074, 0.02332288771867752, + -0.0243898443877697, -0.03396874666213989, 0.052881546318531036, + -0.07279808074235916, -0.03365261107683182, 0.02646053023636341, + 0.039121754467487335, 0.015893707051873207, 0.007421278394758701, + 0.025788743048906326, 0.020675254985690117, 0.010637955740094185, + 0.011657492257654667, -0.03491715341806412, -0.03268839791417122, + 0.0022682715207338333, 0.019813785329461098, 0.01329349260777235, + -0.004133470356464386, 0.0031139336060732603, 0.012961551547050476, + -0.023204337805509567, -0.032166775315999985, -0.06231028214097023, + -0.08763272315263748, -0.0237259604036808, -0.0020074595231562853, + -0.034245364367961884, -0.04824225977063179, -0.017703581601381302, + -0.015640798956155777, -0.023836607113480568, -0.019015545025467873, + -0.014605454169213772, 0.06023959815502167, -0.028136050328612328, + -0.0054454319179058075, 0.009989878162741661, 0.0352570004761219, + -0.0196320079267025, 0.023267565295100212, 0.017624547705054283, + -0.00889130774885416, -0.020422345027327538, 0.010313916951417923, + 0.011823463253676891, -0.06701279431581497, 0.0280333049595356, + -0.03893997520208359, -0.01917361095547676, -0.027179740369319916, + -0.043421193957328796, -0.02129962295293808, -0.027582813054323196, + -0.005413818638771772, -0.0025923100765794516, 0.006164640188217163, + -0.02005879022181034, 0.03063351847231388, 0.05219395086169243, + -0.021995117887854576, 0.04875598102807999, -0.02876041643321514, + -0.005168813746422529, 0.04773644357919693, 0.015134981833398342, + 0.000940502795856446, 0.02046186290681362, -0.08118356764316559, + 0.013554304838180542, -0.005737856961786747, 0.02631036750972271, + 0.04408508166670799, 0.027203449979424477, -0.02306997962296009, + 0.003619750263169408, -0.03498038277029991, 0.014012700878083706, + -0.0035011994186788797, -0.008021934889256954, + -0.000023710153982392512, 0.0044337990693748, 0.012487347237765789, + -0.01917361095547676, 0.015142884105443954, -0.02519599162042141, + 0.005413818638771772, -0.0033826485741883516, 0.0006796910893172026, + 0.047341275960206985, 0.039556439965963364, -0.018130365759134293, + -0.027353614568710327, -0.05560821294784546 + ] + }, + "posing": { + "prompt": "Photo of people posing together in a funny manner for the camera", + "vector": [ + 0.010862172581255436, -0.002259705914184451, -0.019589310511946678, + -0.02353210747241974, 0.011734886094927788, -0.021841226145625114, + 0.0055947196669876575, 0.027217766270041466, 0.024350278079509735, + -0.04710317775607109, 0.01493743434548378, -0.04109547659754753, + 0.028659304603934288, 0.005968740209937096, -0.009934913367033005, + 0.568651020526886, 0.019573727622628212, -0.05230829492211342, + 0.009732319042086601, -0.033996883779764175, -0.004534995649009943, + -0.017352983355522156, -0.023680157959461212, -0.019028281792998314, + 0.007347939535975456, 0.011236192658543587, -0.006218086928129196, + -0.007293395232409239, 0.0030700829811394215, -0.0027506074402481318, + 0.003638905705884099, -0.00935829896479845, -0.007698584347963333, + 0.03275015205144882, 0.013737453147768974, -0.009693358093500137, + -0.007371315732598305, 0.004075262695550919, 0.0011064766440540552, + 0.02505156584084034, 0.02505156584084034, 0.003989549353718758, + -0.0027817757800221443, -0.013114085420966148, 0.01835816167294979, + -0.022285373881459236, -0.02734243869781494, -0.021069807931780815, + 0.038516294211149216, -0.008438833057880402, -0.03540725260972977, + 0.041056517511606216, 0.008960902690887451, -0.00017921804101206362, + -0.014890681952238083, -0.04561488702893257, 0.01084658782929182, + -0.00024155476421583444, -0.0013480314519256353, + -0.0008415456395596266, -0.010643993504345417, 0.0029609936755150557, + -0.037277352064847946, -0.016129624098539352, 0.0026804786175489426, + 0.002703854814171791, -0.009732319042086601, -0.0028441124595701694, + -0.00356877688318491, 0.07399367541074753, 0.011415409855544567, + 0.015599762089550495, -0.0187165979295969, 0.012638768181204796, + -0.009264794178307056, 0.01648026891052723, -0.05869780480861664, + -0.005649264436215162, 0.03279690444469452, 0.028955401852726936, + -0.011197231709957123, -0.027981389313936234, 0.004449282772839069, + -0.010519320145249367, -0.01870880462229252, -0.007340147625654936, + -0.0010207636514678597, -0.0014804968377575278, -0.008002475835382938, + 0.005890819244086742, 0.005602512042969465, -0.00751157384365797, + 0.02130357176065445, -0.015358206816017628, 0.02491910010576248, + 0.022565890103578568, -0.020968511700630188, -0.010106339119374752, + 0.0006467433995567262, 0.006779117044061422, -0.01658935658633709, + 0.0009506348869763315, -0.019472431391477585, 0.01172709371894598, + -0.0008415456395596266, 0.03326442837715149, -0.038874730467796326, + -0.008968694135546684, -0.00034285191213712096, + -0.0005688224919140339, -0.020898383110761642, -0.02009579725563526, + 0.08457533270120621, -0.007698584347963333, 0.00875051598995924, + -0.0446486696600914, 0.011633588932454586, -0.01245955005288124, + -0.00289086508564651, 0.004145391285419464, 0.05244075879454613, + -0.011571251787245274, 0.015389375388622284, -0.00446486659348011, + -0.01843608170747757, -0.017368566244840622, 0.02174772135913372, + -0.013371225446462631, 0.0169244185090065, -0.012412797659635544, + -0.01758674345910549, 0.005228491500020027, -0.03711371868848801, + 0.015623139217495918, 0.05841728672385216, 0.001667506992816925, + -0.026095706969499588, 0.0027272312436252832, 0.002477884292602539, + -0.022908741608262062, -0.023773664608597755, 0.022191869094967842, + 0.0031480039469897747, -0.013238758780062199, 0.019519183784723282, + 0.02527753636240959, 0.005290828179568052, -0.014056929387152195, + 0.0027272312436252832, -0.0545835867524147, -0.009023238904774189, + 0.028893064707517624, -0.04298895597457886, 0.0009194665472023189, + -0.027482695877552032, -0.008134940639138222, -0.0074726128950715065, + -0.011220607906579971, -0.037963055074214935, -0.029111245647072792, + -0.020578907802700996, 0.019550351426005363, -0.02579960599541664, + 0.006779117044061422, -0.02009579725563526, 0.037822797894477844, + -0.018038686364889145, -0.5727107524871826, 0.025674933567643166, + 0.01623092219233513, -0.028682678937911987, 0.05233946070075035, + 0.015288078226149082, 0.0012545263161882758, 0.0124439662322402, + -0.015132236294448376, 0.012771233916282654, 0.0011454371269792318, + -0.004254480358213186, 0.03370078653097153, -0.003444103291258216, + 0.038072146475315094, 0.020789293572306633, -0.02684374526143074, + 0.021202275529503822, 0.008197277784347534, -0.022978870198130608, + -0.024404821917414665, 0.027825549244880676, 0.0008415456395596266, + 0.02039968967437744, -0.015420544892549515, 0.054692670702934265, + -0.044461656361818314, -0.005851858761161566, 0.007231058552861214, + -0.021326947957277298, 0.00887518934905529, 0.0011376449838280678, + 0.0008882981492206454, 0.05418618768453598, 0.03594490885734558, + -0.05126415193080902, -0.014914058148860931, 0.006646651774644852, + -0.009334922768175602, -0.025900904089212418, -0.006108997855335474, + 0.025791816413402557, 0.03403584286570549, -0.0022674978245049715, + -0.0010129715083166957, 0.01477380096912384, -0.026391804218292236, + -0.022830819711089134, 0.04309804365038872, -0.012825778685510159, + 0.020984094589948654, 0.014984187670052052, 0.012217995710670948, + 0.002127240179106593, 0.03755787014961243, -0.006911583244800568, + 0.021342530846595764, 0.0182179044932127, 0.00843103975057602, + -0.0045583718456327915, 0.0017532199854031205, -0.009038823656737804, + -0.03983315825462341, -0.02408534660935402, -0.03221249580383301, + 0.006171334534883499, -0.016293257474899292, -0.0228230282664299, + 0.01149333082139492, -0.007223266176879406, 0.007893386296927929, + -0.015116652473807335, -0.0013012788258492947, -0.002251913771033287, + 0.0013090709690004587, -0.06694962829351425, 0.014999771490693092, + -0.05226153880357742, 0.015124444849789143, -0.0295398086309433, + -0.009015446528792381, -0.01918412186205387, -0.02356327697634697, + 0.017758170142769814, -0.048490170389413834, 0.0064206812530756, + 0.01907503418624401, -0.018062062561511993, -0.002470092149451375, + -0.03808772936463356, 0.011158271692693233, -0.04685383290052414, + -0.006560939364135265, -0.014025759883224964, 0.0011376449838280678, + -0.005859650671482086, 0.01603611931204796, 0.027334649115800858, + 0.03127744421362877, -0.0018934777472168207, 0.015747811645269394, + 0.01681532710790634, 0.0050960262306034565, -0.01601274311542511, + -0.005072650033980608, -0.014329652301967144, -0.029080074280500412, + 0.006864830385893583, -0.017204932868480682, 0.03066966123878956, + 0.00846220925450325, -0.01464912761002779, -0.04285648837685585, + 0.021599670872092247, -0.023687949404120445, -0.00855571310967207, + -0.07308200001716614, -0.01865426078438759, 0.01531145442277193, + 0.0014181601582095027, 0.009810240007936954, -0.04577852413058281, + 0.02196589857339859, 0.002251913771033287, -0.0351189449429512, + 0.0013480314519256353, 0.02700738050043583, 0.021623047068715096, + -0.012997204437851906, -0.012864738702774048, 0.04727460443973541, + 0.014477700926363468, -0.012927074916660786, 0.00814273301512003, + -0.005610303953289986, 0.00518173910677433, 0.011072558350861073, + -0.005750561598688364, -0.009693358093500137, -0.009428427554666996, + -0.003638905705884099, 0.0159036535769701, -0.005485630594193935, + -0.003701242385432124, -0.019558142870664597, -0.004316817037761211, + 0.022994454950094223, 0.03232158347964287, 0.04605124890804291, + -0.04007471352815628, 0.01918412186205387, -0.036615025252103806, + -0.01489847432821989, 0.05593161657452583, -0.018155567348003387, + -0.03229821100831032, 0.02337626740336418, 0.005649264436215162, + 0.0005610304069705307, -0.041601963341236115, 0.05302516743540764, + 0.027381401509046555, 0.017127012833952904, 0.0003506439970806241, + -0.010527112521231174, 0.020703580230474472, 0.13976670801639557, + -0.013464730232954025, 0.0022129532881081104, -0.002766191493719816, + -0.03004629537463188, -0.0017610121285542846, -0.014049137011170387, + 0.00998945813626051, -0.019215291365981102, 0.04412660002708435, + -0.02331393025815487, 0.014158225618302822, 0.007277811411768198, + -0.012763441540300846, -0.01570885069668293, -0.05846404284238815, + 0.0004207728197798133, -0.011968648061156273, 0.011337489821016788, + -0.03463583439588547, -0.06321722269058228, 0.017376359552145004, + 0.01678415946662426, -0.08861164003610611, -0.00014804970123805106, + 0.005111610516905785, 0.014345236122608185, 0.015093276277184486, + 0.011267360299825668, -0.005158362910151482, 0.002189577091485262, + 0.03795526549220085, 0.0333501435816288, 0.0015194573206827044, + 0.05777055025100708, -0.005859650671482086, -0.02086721360683441, + 0.041407160460948944, 0.027981389313936234, 0.011392033658921719, + -0.011734886094927788, 0.009997250512242317, -0.0025713893119245768, + 0.0315345823764801, -0.006451849360018969, -0.03194756433367729, + -0.025815190747380257, -0.02221524529159069, -0.010262181051075459, + -0.021093184128403664, -0.00021817849483340979, 0.023103544488549232, + -0.021311363205313683, -0.014127057045698166, -0.03778383880853653, + 0.035095568746328354, -0.002080487785860896, -0.09577256441116333, + -0.01047256775200367, 0.018724389374256134, 0.024069763720035553, + -0.00024934683460742235, -0.006475226022303104, -0.0117972232401371, + -0.019885409623384476, 0.02056332305073738, -0.09992574900388718, + -0.013223174959421158, -0.0048233033157885075, 0.0032882613595575094, + -0.006498602218925953, 0.029781363904476166, 0.0034129349514842033, + 0.004301233217120171, 0.030957968905568123, -0.02788788452744484, + 0.003864876227453351, -0.049043409526348114, 0.020298391580581665, + 0.02144382894039154, -0.02499702200293541, -0.006895998492836952, + 0.011142686940729618, -0.022838613018393517, 0.016682861372828484, + -0.0020259430166333914, -0.020711371675133705, 0.07982216030359268, + -0.059983499348163605, 0.0027350231539458036, 0.018584132194519043, + 0.04217857867479324, 0.014945225790143013, -0.04072924703359604, + 0.025784023106098175, 0.004909015726298094, 0.012779026292264462, + -0.02458404004573822, 0.006584315560758114, 0.0033739744685590267, + -0.006740157026797533, 0.003498647827655077, 0.016745198518037796, + 0.005431086290627718, 0.0233684740960598, -0.01979190669953823, + 0.004199936054646969, -0.0400669202208519, 0.003405143041163683, + -0.02759178727865219, 0.017454279586672783, -0.013456937856972218, + -0.015132236294448376, -0.021342530846595764, 0.027404775843024254, + -0.04580968990921974, -0.016667278483510017, -0.026446349918842316, + -0.005220699589699507, 0.003296053735539317, -0.008384287357330322, + -0.047781091183423996, -0.01192189659923315, -0.03818902745842934, + 0.02091396600008011, 0.001558417803607881, 0.0072466423735022545, + 0.010301141999661922, -0.02191135287284851, 0.0022207454312592745, + 0.005220699589699507, 0.007644039113074541, 0.08062474429607391, + -0.016916625201702118, 0.002470092149451375, -0.01870880462229252, + -0.016971170902252197, -0.02560480497777462, -0.014602375216782093, + 0.0215295422822237, -0.005625888239592314, 0.01019984483718872, + 0.006327176000922918, 0.009498557075858116, -0.021326947957277298, + 0.01393225509673357, 0.005353164859116077, 0.007036256603896618, + 0.005555759649723768, 0.03422285243868828, 0.01172709371894598, + 0.05642251297831535, -0.026228170841932297, -0.1293564736843109, + 0.006514186505228281, -0.007121969014406204, 0.023243801668286324, + 0.028394371271133423, 0.014197185635566711, 0.009646606631577015, + -0.012038777582347393, 0.014656919054687023, 0.020321767777204514, + -0.014960811473429203, 0.004262272734194994, 0.051965437829494476, + 0.014298483729362488, -0.0017298436723649502, 0.0006779117393307388, + -0.005119402427226305, -0.02624375745654106, -0.011937480419874191, + -0.014797177165746689, -0.0035921530798077583, 0.039622772485017776, + 0.05270569026470184, 0.01697896234691143, 0.01007517147809267, + -0.0711028128862381 + ] + }, + "background": { + "prompt": "Photo of people with an absolutely stunning or interesting background", + "vector": [ + -0.014705854468047619, 0.001741824671626091, 0.005927403923124075, + 0.010000327602028847, -0.0043155658058822155, -0.010771583765745163, + 0.02611004002392292, -0.00355297583155334, 0.030156968161463737, + 0.03655232489109039, 0.005528777372092009, 0.025919392704963684, + 0.02458486147224903, 0.0015945063205435872, 0.0063086990267038345, + 0.5186651945114136, -0.012028124183416367, -0.009879006072878838, + -0.0039082737639546394, -0.02218443527817726, 0.004506213590502739, + -0.02672531269490719, 0.0031110206618905067, -0.01181147899478674, + 0.005953401327133179, 0.01045094896107912, -0.007365925703197718, + 0.006889307405799627, 0.04576406255364418, 0.03521779179573059, + -0.025555429980158806, 0.0023137673269957304, 0.018926095217466354, + 0.006438686046749353, -0.0043068998493254185, 0.0019931329879909754, + -0.020711250603199005, 0.014021256938576698, 0.0008059189422056079, + -0.021716482937335968, -0.00024264225794468075, -0.009047090075910091, + 0.021248528733849525, -0.03074624016880989, -0.003864944912493229, + -0.020468607544898987, 0.018232833594083786, -0.01973201520740986, + 0.021499838680028915, 0.009463047608733177, 0.012669392861425877, + 0.033042676746845245, 0.02818116545677185, 0.005927403923124075, + -0.018068183213472366, -0.02570274844765663, 0.07050491124391556, + -0.010112982243299484, -0.02271305024623871, 0.008076520636677742, + 0.05238473042845726, -0.010745585896074772, -0.03836347535252571, + 0.014974493533372879, -0.029784338548779488, 0.0220631156116724, + 0.0046448661014437675, -0.035989049822092056, 0.0028250492177903652, + 0.06036592647433281, -0.00710595166310668, 0.026664651930332184, + -0.026629988104104996, 0.023718280717730522, -0.024810170754790306, + 0.011768150143325329, -0.08320896327495575, 0.0017331590643152595, + 0.10377290099859238, 0.04410889744758606, -0.01850147359073162, + -0.07739421725273132, 0.008449150249361992, 0.0003206344263162464, + 0.029567692428827286, 0.024463539943099022, -0.003795618424192071, + 0.00887377467006445, -0.03964601084589958, -0.009168410673737526, + -0.018683454021811485, 0.018024854362010956, -0.01592773012816906, + -0.00891710352152586, -0.00811118446290493, 0.01965402439236641, + 0.026803303509950638, 0.007989862933754921, 0.017738882452249527, + -0.01795552857220173, 0.009437051601707935, -0.03222808986902237, + -0.024402879178524017, 0.06099853292107582, 0.035859059542417526, + 0.03632701188325882, -0.05632766708731651, -0.006845978554338217, + -0.009428384713828564, 0.016369687393307686, 0.0005632766988128424, + -0.015329791232943535, 0.10203107446432114, -0.046647973358631134, + -0.009272401221096516, 0.02673397958278656, -0.01079758070409298, + 0.013042021542787552, -0.006118051242083311, 0.027340583503246307, + 0.000372629176126793, -0.031101539731025696, 0.04186445474624634, + 0.012964029796421528, 0.021673154085874557, 0.01696762628853321, + 0.09339127689599991, -0.022669721394777298, -0.003986265975981951, + -0.012808045372366905, -0.016291694715619087, 0.021621158346533775, + -0.017314258962869644, 0.03532177954912186, 0.026335351169109344, + 0.004714192356914282, -0.02821582928299904, 0.02479284070432186, + 0.002209777943789959, -0.0157284177839756, 0.01334532443434, + -0.017392251640558243, -0.004956834949553013, 0.004835513886064291, + 0.013267332687973976, 0.0009359058458358049, -0.012868705205619335, + -0.010650262236595154, -0.030269624665379524, -0.03364061564207077, + 0.015269131399691105, -0.007556573487818241, -0.06311298906803131, + -0.013631295412778854, -0.04714192450046539, 0.012028124183416367, + -0.006499346345663071, -0.006663996260613203, 0.023865601047873497, + -0.00870912428945303, -0.05077289417386055, 0.025720080360770226, + 0.007816547527909279, 0.012392086908221245, -0.025538098067045212, + 0.01365729235112667, 0.004142250400036573, -0.5228767395019531, + -0.021447842940688133, -0.0018544801278039813, -0.0165516696870327, + 0.07093819975852966, 0.03947269544005394, -0.024229563772678375, + 0.010849575512111187, 0.008041857741773129, -0.0050954874604940414, + -0.016976293176412582, -0.0007019293843768537, 0.05097220838069916, + -0.004497547633945942, 0.028293821960687637, -0.01125686801970005, + -0.01136085670441389, 0.005468116607517004, -0.003431654768064618, + -0.019350720569491386, -0.021612493321299553, -0.0026084042619913816, + 0.014610530808568, -0.030962886288762093, -0.030148301273584366, + 0.04546942561864853, -0.10783714801073074, -0.003925605211406946, + -0.03533044829964638, 0.021629825234413147, 0.003284336533397436, + -0.01100555993616581, -0.02330232411623001, 0.024844834581017494, + 0.012591400183737278, -0.009965664707124233, -0.004722858313471079, + 0.02870977856218815, -0.013908601365983486, 0.00006932636460987851, + -0.017886200919747353, -0.005277469288557768, -0.016083715483546257, + 0.004956834949553013, 0.027409909293055534, -0.020061315968632698, + -0.003535644384101033, 0.004705526866018772, 0.04721991717815399, + -0.0024437541142106056, -0.03354529291391373, 0.010606933385133743, + -0.015347123146057129, 0.022565731778740883, 0.03150016441941261, + 0.02127452753484249, 0.03058158978819847, -0.021586496382951736, + -0.01185480784624815, 0.018388817086815834, 0.005173479672521353, + -0.0035789732355624437, -0.0014471877366304398, -0.003864944912493229, + 0.022739047184586525, -0.008249836973845959, 0.027461905032396317, + -0.022028449922800064, 0.017825540155172348, -0.020061315968632698, + -0.00854447390884161, -0.007027959916740656, -0.02036461792886257, + -0.034524526447057724, 0.0005632766988128424, -0.09423185139894485, + -0.012756050564348698, -0.07407521456480026, -0.0036482997238636017, + -0.03629234805703163, -0.06251505017280579, -0.04469817131757736, + -0.013189340010285378, -0.005156148225069046, -0.02992299012839794, + 0.0010918901534751058, 0.006984631065279245, -0.01935938559472561, + -0.023137671872973442, -0.008189177140593529, -0.04037394002079964, + -0.03426455333828926, 0.011204873211681843, -0.007617233786731958, + -0.004523545037955046, 0.0020711252000182867, -0.0011958797695115209, + -0.016040386632084846, 0.019541367888450623, -0.007088620215654373, + 0.00893443450331688, -0.018258830532431602, 0.020130641758441925, + 0.028805101290345192, -0.009827012196183205, -0.02884843200445175, + -0.02470618113875389, -0.007989862933754921, 0.017149608582258224, + -0.0020711252000182867, -0.0030936887487769127, -0.028432471677660942, + -0.027990518137812614, -0.03516579791903496, -0.002495748922228813, + -0.002781720133498311, -0.059612005949020386, 0.01388260442763567, + -0.004428221378475428, 0.005797416903078556, 0.006404022686183453, + -0.013024689629673958, -0.013908601365983486, 0.013267332687973976, + -0.00565876392647624, -0.014428549446165562, 0.009073087014257908, + 0.006057390943169594, -0.013995259068906307, -0.04328564926981926, + 0.06733322888612747, 0.012903369031846523, 0.012669392861425877, + 0.006430020090192556, -0.002686396474018693, -0.003934271167963743, + 0.005780085455626249, -0.008674461394548416, 0.002036461839452386, + 0.006741988472640514, 0.013068018481135368, 0.0038736106362193823, + 0.0034143230877816677, 0.0636935904622078, 0.01019964087754488, + -0.028623120859265327, -0.003682962851598859, 0.027115274220705032, + 0.06764519959688187, -0.05486314743757248, -0.017036952078342438, + -0.04303433746099472, 0.003241007449105382, 0.03711559996008873, + 0.006499346345663071, 0.0020451275631785393, 0.03806883841753006, + 0.030390942469239235, 0.018215501680970192, -0.0263180211186409, + 0.05684761330485344, 0.005026161205023527, -0.02772187814116478, + 0.0043155658058822155, 0.00480085052549839, 0.009376389905810356, + 0.09580903500318527, 0.019628025591373444, 0.006586004514247179, + -0.03949002921581268, -0.018146174028515816, -0.02420356497168541, + -0.030217627063393593, -0.005303466692566872, 0.02084990404546261, + 0.002625735942274332, -0.005953401327133179, 0.01721893437206745, + -0.026785971596837044, -0.022123774513602257, -0.021257195621728897, + -0.07881540805101395, -0.013891268521547318, 0.007747221272438765, + -0.014610530808568, -0.00005199477163841948, -0.07542707771062851, + 0.036396339535713196, 0.029706347733736038, -0.007383257150650024, + 0.001325866673141718, -0.021040551364421844, -0.017738882452249527, + 0.003145683789625764, -0.012071453034877777, 0.03554708883166313, + 0.003596305148676038, 0.029117072001099586, 0.006915304809808731, + -0.01483584102243185, -0.011187541298568249, -0.008163179270923138, + 0.008267167955636978, -0.014740517362952232, 0.003466318128630519, + -0.011343525722622871, -0.02442021109163761, 0.054941143840551376, + -0.040573254227638245, 0.01577174663543701, -0.020017987117171288, + -0.061795786023139954, -0.004280902910977602, -0.010520275682210922, + -0.04650065675377846, -0.021031884476542473, 0.0007885873783379793, + 0.022938359528779984, 0.013293329626321793, -0.001325866673141718, + -0.05081622302532196, 0.02681197039783001, -0.03442053869366646, + -0.10379889607429504, -0.03584172949194908, 0.035191792994737625, + 0.0017678221920505166, 0.009922335855662823, -0.008969098329544067, + -0.0127473846077919, -0.06911838054656982, 0.01127419900149107, + -0.12100916355848312, -0.021031884476542473, -0.00002599738581920974, + 0.01791219785809517, -0.0077992151491343975, -0.027990518137812614, + 0.008882440626621246, 0.00002599738581920974, 0.043432965874671936, + -0.013778614811599255, -0.045339442789554596, 0.006447351537644863, + -0.004584205336868763, 0.02495748922228813, -0.0038909418508410454, + 0.0056500984355807304, 0.005494114011526108, -0.012418084777891636, + 0.035191792994737625, -0.012634729035198689, -0.01898675598204136, + 0.09869474172592163, -0.08138915151357651, -0.03569440916180611, + 0.01558110024780035, -0.015147809870541096, 0.0030936887487769127, + -0.014064585790038109, 0.028276490047574043, 0.008631131611764431, + -0.018154840916395187, -0.013206670992076397, -0.0013691956410184503, + -0.02682063728570938, 0.0019498037872835994, -0.01621370203793049, + 0.010095651261508465, 0.009740353561937809, 0.0278865285217762, + -0.01866612210869789, 0.016569001600146294, -0.034082572907209396, + -0.03928204998373985, -0.03595438227057457, 0.04257505014538765, + 0.03925605118274689, -0.007686560042202473, -0.007209941744804382, + 0.04557341709733009, -0.013024689629673958, -0.005364127457141876, + -0.02342364378273487, 0.004688194952905178, -0.018423479050397873, + -0.011846141889691353, -0.03744490072131157, 0.02342364378273487, + -0.0050954874604940414, 0.02503548189997673, 0.02118786983191967, + 0.019350720569491386, 0.006178712006658316, -0.047159258276224136, + 0.006005396135151386, -0.01779954321682453, 0.030962886288762093, + 0.1288430541753769, -0.017946861684322357, 0.011066220700740814, + 0.013475310988724232, -0.0294550359249115, -0.0018804774153977633, + 0.002530412282794714, 0.008041857741773129, -0.027583226561546326, + -0.04444686323404312, 0.009151079691946507, -0.041769132018089294, + -0.011724821291863918, -0.004904840141534805, 0.010320961475372314, + -0.013033355586230755, -0.013293329626321793, 0.04311233386397362, + -0.02163849025964737, 0.08099918812513351, -0.023241661489009857, + -0.18601128458976746, 0.027739210054278374, 0.013232668861746788, + 0.043337639421224594, 0.020009320229291916, -0.03266138210892677, + -0.0010138980578631163, 0.0072446041740477085, 0.011724821291863918, + 0.0009359058458358049, -0.034663181751966476, -0.02565941959619522, + 0.021534500643610954, -0.031352847814559937, 0.017444245517253876, + -0.007071288768202066, 0.009047090075910091, -0.020667921751737595, + -0.015468443743884563, -0.0004766187339555472, -0.017262263223528862, + 0.021993787959218025, 0.012357424013316631, -0.00497416639700532, + -0.022149773314595222, -0.017392251640558243 + ] + }, + "sports": { + "prompt": "Photo of people joyfully playing sports together", + "vector": [ + -0.005494717042893171, 0.014157154597342014, -0.007176160346716642, + -0.06306163221597672, -0.02043253928422928, 0.015883635729551315, + -0.017932895570993423, 0.008880123496055603, -0.03749468922615051, + -0.036038439720869064, -0.010418944992125034, -0.015861116349697113, + 0.010839304886758327, 0.020199840888381004, 0.01848086528480053, + 0.5462063550949097, 0.013301420025527477, 0.017745234072208405, + 0.022181542590260506, -0.061507806181907654, 0.010126193054020405, + -0.0285244882106781, 0.01592867448925972, -0.021588532254099846, + 0.024313373491168022, -0.03855309635400772, -0.03058875910937786, + 0.00425615394487977, -0.030160890892148018, 0.02802155539393425, + 0.0383354127407074, -0.011372262611985207, 0.027969012036919594, + -0.0023945558350533247, 0.012610825709998608, -0.004083505365997553, + 0.009570715948939323, -0.010929382406175137, 0.011529898270964622, + 0.02537928707897663, 0.013316432014107704, -0.01292609702795744, + 0.0003377899993211031, 0.012032830156385899, -0.011297198012471199, + -0.025033991783857346, 0.0018315722700208426, -0.008910148404538631, + -0.006342945154756308, 0.019621845334768295, 0.01180013082921505, + 0.03567812964320183, 0.004196102265268564, 0.008797552436590195, + 0.008519813418388367, -0.010914369486272335, 0.01219797134399414, + -0.01037390623241663, 0.0065831514075398445, 0.02144591137766838, + -0.045661699026823044, -0.0022969720885157585, -0.03618856891989708, + -0.029072457924485207, -0.01758759841322899, 0.010741720907390118, + 0.005885052029043436, 0.0196593776345253, 0.010156218893826008, + 0.026677902787923813, 0.02429835870862007, 0.034169334918260574, + -0.012858538888394833, -0.03154958412051201, -0.019306574016809464, + 0.009345523081719875, -0.058467693626880646, 0.06812848895788193, + 0.048529159277677536, 0.023134861141443253, -0.0144949434325099, + -0.024658668786287308, -0.015253094024956226, 0.02557445503771305, + -0.01504291407763958, 0.05085615813732147, -0.012265530414879322, + 0.02958289533853531, 0.030363567173480988, 0.010148712433874607, + -0.04953502491116524, 0.0010358892614021897, -0.018240658566355705, + -0.0057799615897238255, 0.019937116652727127, 0.04628473520278931, + -0.09602243453264236, -0.0007431379635818303, -0.013699259608983994, + 0.029042433947324753, -0.0016814435366541147, 0.03136942908167839, + 0.014419878832995892, -0.03038608655333519, 0.039776645600795746, + 0.0373820923268795, -0.0472155325114727, 0.043604932725429535, + -0.0056523522362113, 0.0011259665479883552, 0.0028824745677411556, + -0.0006980992620810866, 0.06918689608573914, -0.0010208763414993882, + 0.013166302815079689, -0.07102597504854202, -0.008249581791460514, + -0.015883635729551315, 0.007619041018188, 0.04771095886826515, + 0.07880265265703201, -0.03757726028561592, 0.006523100193589926, + -0.01739243045449257, -0.0012460697907954454, -0.013383990153670311, + 0.04241140931844711, -0.008865110576152802, 0.0324128232896328, + 0.023127354681491852, -0.058385126292705536, 0.008444749750196934, + -0.005592301022261381, -0.009713338688015938, 0.012881058268249035, + -0.007011018693447113, -0.00820454303175211, -0.008925162255764008, + 0.027075743302702904, 0.02810412459075451, 0.021903803572058678, + 0.019404157996177673, -0.009540691040456295, -0.05063847079873085, + 0.012866045348346233, 0.010906863026320934, -0.015906155109405518, + 0.016048777848482132, -0.026189984753727913, -0.0010358892614021897, + 0.004714047070592642, 0.019839532673358917, -0.04477594047784805, + 0.06558380275964737, -0.00998357031494379, 0.02143840305507183, + 0.03393663465976715, -0.007829220965504646, 0.014900291338562965, + -0.021986374631524086, -0.017752740532159805, -0.01670183800160885, + -0.031609635800123215, 0.03666897863149643, -0.026017336174845695, + 0.007341302931308746, 0.017880350351333618, -0.5495617985725403, + -0.010741720907390118, -0.027683766558766365, -0.014374840073287487, + 0.054324135184288025, 0.03813273459672928, 0.028156671673059464, + -0.016273971647024155, 0.012858538888394833, -0.007371328305453062, + 0.03422938287258148, -0.04352236166596413, 0.013203836046159267, + 0.014637566171586514, 0.0077091180719435215, 0.02092796564102173, + -0.0005930090555921197, -0.010366398841142654, -0.012798487208783627, + -0.040970172733068466, -0.038800809532403946, 0.021490950137376785, + 0.004714047070592642, 0.024628642946481705, 0.011927739717066288, + 0.06314420700073242, -0.013368976302444935, -0.02664787508547306, + -0.002281959168612957, 0.0007281251018866897, 0.0177001953125, + -0.03793756663799286, 0.058355093002319336, 0.025011472404003143, + 0.016641788184642792, -0.008737500756978989, 0.00806192122399807, + 0.02567203901708126, 0.018345749005675316, -0.004308698698878288, + -0.020237373188138008, 0.014284763485193253, 0.019899582490324974, + -0.025296716019511223, 0.013871908187866211, -0.015163017436861992, + -0.015478287823498249, -0.011650001630187035, -0.0025521910283714533, + -0.002664787694811821, 0.009916013106703758, 0.009383055381476879, + 0.0029575389344245195, 0.0007731637451797724, 0.05487960949540138, + -0.03497252240777016, 0.0012085374910384417, -0.025131573900580406, + 0.0034754835069179535, 0.019877063110470772, 0.002056765602901578, + -0.0093380156904459, -0.07027532905340195, 0.004045973066240549, + -0.03432697057723999, 0.015313146635890007, -0.04633728042244911, + 0.009345523081719875, -0.07399101555347443, -0.03498753532767296, + -0.002154349349439144, -0.01072670891880989, -0.024463500827550888, + -0.01210038736462593, -0.012460697442293167, -0.0177077017724514, + 0.0077916886657476425, -0.04800371080636978, 0.018630994483828545, + 0.00602016830816865, -0.004000934772193432, -0.028171684592962265, + -0.0006755799986422062, 0.0035730674862861633, -0.06694997847080231, + -0.004083505365997553, -0.01709968037903309, -0.01528311986476183, + -0.01997464708983898, 0.01439735945314169, -0.016446620225906372, + -0.029470300301909447, 0.016101323068141937, 0.0025822166353464127, + 0.003452964359894395, -0.01640908606350422, 0.004473840352147818, + 0.014254736714065075, -0.019726933911442757, 0.0068533835001289845, + -0.019509248435497284, 0.01494533009827137, 0.007836727425456047, + -0.03067133203148842, 0.020522618666291237, -0.0002927513269241899, + -0.019103901460766792, 0.011026966385543346, 0.011815142817795277, + 0.031331900507211685, 0.020605187863111496, -0.009593235328793526, + -0.0004503866657614708, -0.0006380477570928633, 0.0030476164538413286, + 0.02152848243713379, -0.012468203902244568, 0.0038207799661904573, + 0.0017640143632888794, 0.006733280140906572, 0.02990567311644554, + -0.03845551237463951, -0.006800837814807892, -0.013759312219917774, + -0.05141913890838623, -0.03612851724028587, 0.021798713132739067, + 0.011214627884328365, 0.017354898154735565, -0.00008257088484242558, + -0.03302835300564766, 0.043011926114559174, 0.00012010310456389561, + -0.02448602020740509, 0.03386157006025314, 0.013399002142250538, + 0.04048225283622742, 0.028764694929122925, -0.019546780735254288, + 0.03656388819217682, 0.02310483530163765, 0.010749228298664093, + 0.00043537377496249974, 0.012956122867763042, 0.012610825709998608, + -0.027608701959252357, 0.0018315722700208426, 0.008902642875909805, + 0.00983344204723835, -0.038305383175611496, -0.0017715208232402802, + -0.02928263694047928, -0.018360761925578117, 0.013691754080355167, + -0.0030250968411564827, -0.050210606306791306, 0.056485991925001144, + -0.02546936459839344, 0.01750502735376358, -0.0015463274903595448, + 0.06896920502185822, 0.011199614964425564, 0.0015313145704567432, + -0.019524261355400085, -0.01533566601574421, 0.05636589229106903, + 0.08704472333192825, -0.023119846358895302, -0.0022594397887587547, + 0.003993428312242031, 0.0024771266616880894, -0.016897005960345268, + -0.03360635042190552, -0.007191173732280731, -0.021956348791718483, + 0.0373445600271225, 0.02390802465379238, 0.010486502200365067, + -0.03097158670425415, -0.010809279978275299, -0.024088179692626, + -0.04976021870970726, 0.017152225598692894, -0.010741720907390118, + -0.004226128105074167, -0.004976772237569094, -0.08818570524454117, + 0.0011935245711356401, 0.039288729429244995, -0.051389116793870926, + -0.007123615127056837, 0.017377417534589767, -0.018218139186501503, + -0.0009533183765597641, -0.018345749005675316, -0.03401920571923256, + 0.013901934027671814, 0.03311843052506447, 0.0007131121819838881, + 0.015808571130037308, -0.01238563284277916, 0.01092187687754631, + 0.015418236143887043, 0.03311843052506447, -0.039093561470508575, + 0.006673228461295366, -0.0020342464558780193, 0.0029275130946189165, + -0.03431195393204689, 0.029192563146352768, -0.0120553495362401, + -0.06441279500722885, 0.016183892264962196, -0.03513015806674957, + -0.020124776288866997, -0.030558735132217407, -0.004383763298392296, + 0.01282851304858923, -0.01631150208413601, 0.008872617036104202, + -0.033185988664627075, 0.02941024675965309, 0.06830864399671555, + -0.031121715903282166, 0.012265530414879322, 0.013008668087422848, + -0.01798544079065323, 0.0006455541588366032, -0.012212984263896942, + -0.02881723828613758, -0.09747868776321411, 0.09067033976316452, + -0.13611434400081635, 0.0013511599972844124, -0.03847803175449371, + -0.00820454303175211, -0.009112823754549026, 0.03943134844303131, + -0.013016173616051674, 0.01494533009827137, 0.012340594083070755, + 0.01140979491174221, 0.01633402146399021, -0.022046426311135292, + 0.017362404614686966, -0.009127836674451828, -0.012535762041807175, + 0.0019141433294862509, -0.01858595572412014, -0.011019459925591946, + 0.037922557443380356, 0.0324353463947773, -0.006763305980712175, + 0.0619506798684597, -0.023855479434132576, 0.0074914307333528996, + 0.01439735945314169, 0.05958615615963936, 0.019839532673358917, + -0.00004503866512095556, -0.01229555532336235, 0.009593235328793526, + -0.013931960798799992, -0.010809279978275299, -0.02095799148082733, + -0.006402996834367514, -0.027360988780856133, -0.03969407454133034, + 0.039086051285266876, -0.002116817282512784, 0.04214868322014809, + -0.006950967013835907, -0.0016814435366541147, -0.061410218477249146, + 0.030904032289981842, -0.03679658845067024, -0.032773133367300034, + 0.017857830971479416, 0.0015988725936040282, 0.009525677189230919, + 0.007041044998914003, -0.01429977547377348, -0.022241592407226562, + -0.003385406220331788, 0.010201257653534412, 0.010846812278032303, + 0.028967367485165596, -0.02282709628343582, -0.004413789138197899, + -0.04995538666844368, -0.009323003701865673, 0.0046014501713216305, + -0.04801872372627258, -0.015425742603838444, -0.018661020323634148, + -0.021581025794148445, 0.01170254684984684, -0.011777611449360847, + 0.014337308704853058, -0.013263886794447899, 0.007123615127056837, + -0.026272553950548172, 0.01780528575181961, -0.034747328609228134, + -0.019103901460766792, 0.05255261808633804, 0.017264820635318756, + -0.0270532239228487, 0.024230802431702614, 0.02319491095840931, + -0.009855961427092552, -0.008024388924241066, -0.02516160160303116, + 0.008677449077367783, -0.0028224231209605932, 0.028449421748518944, + 0.00840721745043993, 0.08323144912719727, -0.009713338688015938, + -0.04470087215304375, -0.017940400168299675, 0.011529898270964622, + 0.006215335801243782, 0.016641788184642792, 0.0046915276907384396, + 0.008887629956007004, 0.02921508252620697, -0.008437243290245533, + -0.013113757595419884, 0.013301420025527477, 0.010148712433874607, + -0.004211115185171366, 0.009548196569085121, 0.004623969551175833, + 0.0022969720885157585, -0.00997606385499239, 0.017362404614686966, + -0.016138853505253792, -0.017947906628251076, -0.0021768687292933464, + 0.028246749192476273, 0.03518270328640938, -0.0038508058059960604, + 0.0022294139489531517, -0.10991685837507248 + ] + }, + "roadtrip": { + "prompt": "Photo of people on a road trip together", + "vector": [ + -0.004912007600069046, 0.0011731297709047794, 0.0019375563133507967, + 0.02452976442873478, 0.015061472542583942, -0.02907847985625267, + -0.0028987659607082605, 0.01586374267935753, -0.020556261762976646, + -0.016181621700525284, -0.03766882047057152, -0.02740582451224327, + -0.009059589356184006, 0.021070925518870354, -0.002868491690605879, + 0.5225347280502319, -0.007871323265135288, 0.010830637067556381, + 0.017354751005768776, -0.0008022694382816553, 0.032658420503139496, + -0.018527882173657417, -0.0190047025680542, 0.0072355614975094795, + 0.025120114907622337, 0.00825731921941042, -0.0001665087474975735, + 0.018641412258148193, 0.03140203654766083, 0.03611725941300392, + 0.0012261098017916083, 0.00574455177411437, -0.02322797104716301, + -0.0031031176913529634, 0.007129601668566465, -0.007651833817362785, + -0.030705727636814117, -0.002891197334975004, -0.010179739445447922, + -0.01948152296245098, 0.031053880229592323, 0.012442744337022305, + -0.017438005656003952, 0.01353261899203062, -0.043587446212768555, + -0.051943160593509674, -0.04392046853899956, -0.008302731439471245, + 0.011148517020046711, 0.04066597670316696, 0.0070009357295930386, + -0.009914839640259743, 0.012972544878721237, 0.01281360536813736, + -0.007311247289180756, -0.046047236770391464, -0.02214566245675087, + -0.0011201497400179505, -0.009771035984158516, -0.007818342186510563, + -0.0008249751408584416, 0.052904367446899414, -0.030183492228388786, + 0.04566124081611633, -0.08333005756139755, 0.01936042681336403, + -0.02107849344611168, 0.0004238404508214444, 0.03165179863572121, + 0.03735850751399994, -0.012041609734296799, 0.02590724639594555, + -0.020253518596291542, -0.005517494399100542, -0.050595950335264206, + 0.022032134234905243, -0.06305383890867233, 0.0010066210525110364, + 0.11184089630842209, 0.06904814392328262, -0.016052957624197006, + -0.011193929240107536, 0.02701982855796814, 0.01279089879244566, + 0.0417180098593235, 0.0484994575381279, -0.018777644261717796, + 0.0058126687072217464, -0.023439889773726463, 0.026868455111980438, + -0.014274340122938156, -0.013456934131681919, 0.02573316916823387, + -0.025786150246858597, 0.005313142668455839, 0.03297629952430725, + -0.055485256016254425, 0.04085519164800644, 0.015462607145309448, + 0.05586368218064308, -0.034747347235679626, -0.0027246885001659393, + -0.002020810730755329, -0.07925816625356674, -0.011322595179080963, + 0.03522416949272156, -0.06007181107997894, -0.009831584990024567, + -0.012041609734296799, 0.014047283679246902, 0.020450301468372345, + -0.013441797345876694, 0.05773312598466873, -0.02776155062019825, + -0.02318255975842476, -0.03757042810320854, 0.0023386909160763025, + -0.0450330451130867, -0.00011352869478287175, 0.007364227436482906, + 0.0449119508266449, -0.057589318603277206, -0.012828742153942585, + -0.02518066205084324, -0.025543956086039543, -0.04224780946969986, + 0.048923294991254807, -0.026096461340785027, 0.000628192035946995, + -0.0224711112678051, -0.017475849017500877, 0.03426295891404152, + 0.004927145317196846, 0.050686776638031006, 0.030804118141531944, + 0.004283815622329712, -0.024257296696305275, -0.02782209776341915, + -0.005721846129745245, -0.004450324922800064, 0.01995077356696129, + 0.07054673135280609, 0.03744933009147644, -0.0414758138358593, + -0.025665052235126495, -0.038879793137311935, -0.006849563680589199, + 0.00522231962531805, -0.047856125980615616, -0.04316360875964165, + -0.016022682189941406, 0.03517875447869301, 0.0066981930285692215, + 0.0018088903743773699, 0.042686786502599716, 0.029086049646139145, + -0.04600939154624939, 0.020359478890895844, 0.0003557232266757637, + -0.008075674064457417, -0.019640464335680008, -0.020972533151507378, + 0.0026868456043303013, 0.005434240214526653, 0.055190082639455795, + -0.032923322170972824, 0.017248792573809624, -0.5268185138702393, + 0.0002573317033238709, 0.03440675884485245, 0.021328255534172058, + 0.04710683599114418, -0.008976335637271404, 0.008590337820351124, + 0.0345429964363575, -0.020654652267694473, -0.020215675234794617, + 0.01556099858134985, 0.006645212881267071, 0.02641434222459793, + 0.019859952852129936, -0.0069706616923213005, 0.033248770982027054, + -0.023031188175082207, 0.07042562961578369, -0.010823068208992481, + 0.030138082802295685, 0.0007114464533515275, -0.010807931423187256, + -0.007462618872523308, 0.014092694967985153, -0.03826673701405525, + 0.0121475700289011, 0.03548149764537811, 0.014796572737395763, + -0.01946638524532318, 0.017218517139554024, -0.09220042824745178, + -0.012639527209103107, 0.010104053653776646, 0.02154017798602581, + 0.02644461579620838, -0.01799808256328106, -0.02150990255177021, + 0.0053434171713888645, -0.007099327631294727, -0.0258769728243351, + 0.01148153468966484, 0.026391636580228806, -0.006350038107484579, + -0.030713295564055443, -0.018558157607913017, 0.024552471935749054, + -0.017074715346097946, 0.005146633833646774, -0.012510862201452255, + 0.00226300535723567, -0.018671685829758644, 0.02938879281282425, + -0.002633865689858794, -0.0011428555008023977, -0.0028609230648726225, + -0.03088737092912197, 0.04949093982577324, 0.031000901013612747, + 0.004018915817141533, 0.005456945393234491, 0.0007568579749204218, + -0.016227034851908684, -0.04377666488289833, -0.024143768474459648, + -0.034611113369464874, -0.014766298234462738, -0.04628186300396919, + -0.001967830816283822, -0.0005600748700089753, -0.019973481073975563, + 0.027352845296263695, 0.007409639656543732, 0.009483429603278637, + -0.02866221033036709, 0.016022682189941406, -0.017839141190052032, + 0.0030804118141531944, -0.056567560881376266, 0.05664324760437012, + -0.02036704681813717, 0.04857514426112175, -0.03882681205868721, + 0.01077765692025423, -0.042936552315950394, -0.042611103504896164, + -0.03981829434633255, 0.06430265307426453, 0.001150424126535654, + 0.002346259541809559, -0.04794694855809212, -0.06702733784914017, + 0.013419090770184994, -0.00125638407189399, 0.008582768961787224, + -0.03512577712535858, -0.008151359856128693, 0.010368953458964825, + 0.03081168793141842, -0.005948903504759073, 0.01629515178501606, + -0.007091759238392115, 0.014122968539595604, -0.03186371922492981, + -0.03385425731539726, 0.01768776960670948, -0.03588263317942619, + -0.06287219375371933, -0.011875101365149021, -0.015333942137658596, + -0.00028003743500448763, -0.018020788207650185, 0.020806023851037025, + -0.008787120692431927, 0.009876996278762817, 0.014804141595959663, + 0.05313899368047714, -0.04797722399234772, -0.002611159812659025, + -0.0019753992091864347, -0.0010293268132954836, 0.006675486918538809, + -0.025279054418206215, -0.011965923942625523, -0.015470176003873348, + -0.028942245990037918, -0.029517458751797676, 0.007878891192376614, + 0.02733014151453972, 0.01634056307375431, -0.018020788207650185, + -0.10486266762018204, 0.01142855454236269, 0.02041245810687542, + -0.009990525431931019, -0.029070913791656494, 0.02555152401328087, + 0.018807919695973396, 0.020344341173768044, -0.02085900492966175, + 0.004647107794880867, -0.005517494399100542, 0.03657137602567673, + 0.0006963092600926757, 0.03387695923447609, 0.007379364687949419, + -0.01353261899203062, -0.02150990255177021, -0.01656005159020424, + 0.041203346103429794, -0.04540390521287918, 0.020927121862769127, + -0.04470759630203247, -0.05180692300200462, 0.022758718580007553, + 0.06918437778949738, -0.0031182547099888325, -0.006864701863378286, + 0.010800362564623356, -0.020314067602157593, -0.03897061571478844, + 0.0869629755616188, 0.002891197334975004, -0.0037615839391946793, + 0.02598293125629425, -0.013956460170447826, 0.00941531267017126, + 0.051958296447992325, -0.0029063343536108732, 0.0208741407841444, + 0.02943420596420765, -0.034656524658203125, -0.03898575156927109, + 0.006569527089595795, -0.021305551752448082, 0.014440849423408508, + 0.07355902343988419, -0.0035875067114830017, 0.010626285336911678, + -0.03583722561597824, -0.01316175889223814, -0.01621946506202221, + -0.0011958355316892266, 0.008620611391961575, -0.02355341799557209, + 0.01207945216447115, 0.040537308901548386, -0.07472458481788635, + -0.02253166027367115, 0.011171223595738411, -0.048226986080408096, + -0.020450301468372345, 0.002346259541809559, 0.018921447917819023, + -0.0008855237392708659, -0.030539218336343765, -0.012162706814706326, + -0.011125811375677586, 0.007326385006308556, 0.006804152857512236, + 0.026331087574362755, 0.009899700991809368, 0.007553441915661097, + -0.011958355084061623, 0.008310300298035145, 0.004889302421361208, + -0.03930363059043884, 0.02355341799557209, 0.019738854840397835, + -0.022493818774819374, 0.02474168688058853, -0.013267719186842442, + -0.08479836583137512, 0.030357571318745613, -0.01624973863363266, + -0.03583722561597824, 0.008045399561524391, -0.025309329852461815, + 0.034997113049030304, -0.0174228698015213, 0.009286646731197834, + -0.027042534202337265, 0.02798103727400303, -0.043292272835969925, + -0.05818723887205124, 0.007606422062963247, -0.019352857023477554, + 0.021971585229039192, -0.005926197394728661, 0.02698955498635769, + -0.017074715346097946, -0.008151359856128693, 0.07210585474967957, + -0.08330735564231873, 0.03763097524642944, 0.008211908861994743, + -0.029948867857456207, -0.0052980054169893265, 0.023931847885251045, + -0.001922419061884284, 0.03935661166906357, 0.09029315412044525, + -0.03508793190121651, 0.015053904615342617, -0.02816268429160118, + 0.004964988213032484, -0.0021192021667957306, 0.002020810730755329, + 0.02364424243569374, 0.04837078973650932, -0.005161771085113287, + 0.01001323014497757, -0.010959303006529808, 0.02909361943602562, + 0.10385604947805405, -0.07229506969451904, -0.026853321120142937, + 0.0004314090183470398, 0.007167445030063391, -0.046864643692970276, + -0.037547722458839417, 0.0433603897690773, 0.0007492893491871655, + -0.008590337820351124, -0.0056158858351409435, 0.000983915408141911, + 0.01420622318983078, 0.02777668461203575, -0.03675302118062973, + 0.007318815682083368, -0.005721846129745245, 0.022387858480215073, + -0.028185389935970306, 0.00484389066696167, -0.020480575039982796, + 0.011875101365149021, -0.0156291164457798, 0.011345300823450089, + 0.01621946506202221, 0.004480598960071802, 0.013752108439803123, + 0.0014683044282719493, -0.005494788289070129, -0.021116336807608604, + -0.071303591132164, 0.0020662222523242235, -0.02361396700143814, + -0.008726571686565876, 0.0031560976058244705, -0.0024900624994188547, + 0.0008855237392708659, 0.03772936761379242, 0.009089863859117031, + 0.0033982922323048115, 0.04201318323612213, -0.02085900492966175, + 0.002278142375871539, 0.0008552494109608233, 0.035383109003305435, + 0.03050137497484684, 0.020049167796969414, 0.011262046173214912, + -0.03053164854645729, -0.055840980261564255, 0.016317857429385185, + 0.01570480316877365, 0.04692519083619118, 0.024340549483895302, + -0.00008325437374878675, 0.003148528980091214, -0.00414001289755106, + 0.019246896728873253, -0.003254489041864872, -0.004026484210044146, + 0.0005222319741733372, 0.006191097665578127, 0.047871265560388565, + -0.021146610379219055, 0.013055799528956413, -0.02017783187329769, + -0.07355145364999771, -0.019935637712478638, 0.00869629718363285, + -0.0010520325740799308, 0.015886448323726654, 0.04725820943713188, + 0.03541338071227074, 0.005631023086607456, 0.004034052602946758, + -0.010361384600400925, 0.007515599485486746, -0.015825899317860603, + 0.009082295000553131, -0.005911060608923435, -0.009967818856239319, + 0.01814945414662361, -0.010247856378555298, -0.021562881767749786, + -0.0366092175245285, 0.004238404333591461, 0.04177099093794823, + 0.0060851373709738255, 0.04944552853703499, -0.007666971068829298, + 0.022804129868745804, -0.055992353707551956 + ] + } + }, + "clip_memory_types": { + "sunrise": { + "prompt": "Photo of an absolutely stunning sunrise or sunset", + "vector": [ + 0.015730585902929306, 0.01055071223527193, 0.01939469203352928, + -0.019281307235360146, 0.012806463055312634, 0.006988056469708681, + -0.018081819638609886, 0.04163592681288719, 0.0742190033197403, + 0.01209631934762001, -0.002148335101082921, -0.03029748983681202, + -0.03369305282831192, -0.011308596469461918, -0.01473399717360735, + 0.5191869139671326, -0.023709263652563095, -0.020820945501327515, + 0.014399810694158077, -0.007214825134724379, -0.005866148043423891, + -0.00647484278306365, -0.003377659944817424, 0.02588743530213833, + 0.011099730618298054, -0.04701869562268257, 0.031532783061265945, + 0.013230162672698498, 0.009476544335484505, -0.030768930912017822, + -0.000035805580409942195, -0.012388731352984905, -0.01604686863720417, + 0.015098019503057003, -0.03659927472472191, 0.034164492040872574, + 0.004624887835234404, 0.0031270210165530443, -0.04144496098160744, + 0.025583088397979736, 0.041230130940675735, -0.016422826796770096, + 0.004636823199689388, -0.023184115067124367, -0.006450972519814968, + -0.03528043255209923, 0.0026615483220666647, 0.041188355535268784, + -0.007155148778110743, 0.019484205171465874, 0.006892574951052666, + 0.042525097727775574, -0.047812387347221375, 0.034898508340120316, + -0.014883186668157578, 0.01724635623395443, 0.04145689681172371, + 0.0011517462553456426, -0.014799641445279121, 0.013128713704645634, + 0.018666643649339676, -0.0030434743966907263, 0.005376805085688829, + 0.014960765838623047, 0.007292403373867273, 0.028608661144971848, + 0.04778851941227913, -0.008903655223548412, 0.04611162468791008, + 0.023643620312213898, 0.013701601885259151, -0.024174736812710762, + -0.04187462851405144, -0.025075843557715416, 0.019740810617804527, + 0.030040884390473366, 0.0019454365829005837, 0.04633242264389992, + 0.0022915571462363005, -0.012394699268043041, -0.012448407709598541, + -0.025970982387661934, 0.031562622636556625, -0.010216525755822659, + -0.02288573607802391, -0.045198578387498856, 0.015903646126389503, + -0.022080110386013985, 0.010950540192425251, 0.023184115067124367, + 0.030351197347044945, 0.011887453496456146, -0.02117900364100933, + 0.02244413271546364, -0.002118496922776103, -0.027277885004878044, + -0.03205793350934982, -0.00811593234539032, 0.03711845353245735, + 0.006695643533021212, -0.013528542593121529, -0.009279613383114338, + -0.019621457904577255, 0.02236655354499817, 0.05651910975575447, + -0.002482520416378975, -0.047746747732162476, 0.03063167631626129, + -0.014268524944782257, -0.03448674455285072, 0.022312846034765244, + -0.012018740177154541, 0.04589679092168808, -0.01978258416056633, + -0.04169560223817825, -0.03168197348713875, -0.001808181987144053, + -0.017144907265901566, -0.02877575345337391, -0.011195212602615356, + 0.01444755308330059, -0.045335836708545685, -0.002822673413902521, + 0.012991459108889103, 0.029909595847129822, 0.01564704068005085, + 0.03973226249217987, 0.010467165149748325, 0.01981242187321186, + 0.010109109804034233, 0.014184977859258652, -0.0038550677709281445, + -0.02150125242769718, 0.027779165655374527, -0.06068449467420578, + -0.041063033044338226, -0.05965806543827057, 0.01097441092133522, + 0.006158560514450073, -0.02341088280081749, 0.0131645193323493, + 0.016536211594939232, -0.005472286604344845, -0.05319515988230705, + 0.05447222664952278, -0.05522414296865463, -0.015760423615574837, + -0.0232557263225317, -0.03621137887239456, 0.0044100540690124035, + -0.0027212242130190134, -0.02476552687585354, 0.024353764951229095, + -0.03384821116924286, -0.02725401520729065, -0.04609968513250351, + 0.009279613383114338, -0.07156343013048172, -0.034164492040872574, + -0.008682853542268276, 0.006588227115571499, -0.0029181549325585365, + 0.057515699416399, 0.00784739013761282, -0.022121882066130638, + -0.07184987515211105, 0.004069901071488857, -0.5235790610313416, + 0.027546430006623268, 0.005042619537562132, -0.02073740027844906, + 0.04766916483640671, -0.019621457904577255, -0.046302586793899536, + -0.024711819365620613, 0.018756156787276268, -0.0039863549172878265, + -0.023005086928606033, -0.015849938616156578, -0.012663241475820541, + 0.02015257440507412, 0.015885744243860245, 0.050837960094213486, + 0.04939976707100868, 0.010592484846711159, -0.004505535587668419, + -0.0480152890086174, -0.029109938070178032, 0.016178155317902565, + 0.03152681514620781, -0.004929235205054283, -0.015277048572897911, + -0.0026973539497703314, -0.07340145111083984, -0.004702466540038586, + -0.021184969693422318, -0.005663249641656876, -0.0696597620844841, + -0.020940298214554787, -0.028447536751627922, 0.058261651545763016, + -0.06172285974025726, 0.03253534063696861, 0.02317814715206623, + 0.016792817041277885, 0.025672603398561478, 0.0007161116227507591, + 0.013242097571492195, -0.027337562292814255, 0.0019693071953952312, + 0.013838857412338257, 0.02570243924856186, -0.013677733018994331, + 0.01089086476713419, 0.004135544877499342, -0.021877212449908257, + -0.02387038804590702, -0.0032583081629127264, 0.02525487169623375, + -0.020098866894841194, -0.03658733889460564, 0.007525139953941107, + 0.02305879443883896, -0.03377063199877739, 0.005030684173107147, + -0.034039173275232315, -0.002482520416378975, 0.004923267289996147, + 0.056495241820812225, -0.016333313658833504, 0.00896929856389761, + 0.0319385789334774, -0.030315391719341278, -0.02822076715528965, + -0.02798803150653839, 0.0642889216542244, 0.017359739169478416, + 0.030237814411520958, 0.04572969675064087, 0.015551558695733547, + 0.0075370753183960915, 0.015581395477056503, -0.04787803068757057, + 0.024819236248731613, -0.07242872565984726, 0.017019586637616158, + -0.05419175326824188, -0.028584789484739304, -0.0478004552423954, + -0.025833727791905403, 0.027904484421014786, -0.02554728277027607, + -0.0031270210165530443, 0.06221219524741173, -0.03958307206630707, + 0.02147141471505165, 0.012155994772911072, -0.026895960792899132, + -0.012388731352984905, 0.009267677552998066, 0.0232557263225317, + 0.01873825490474701, -0.024150865152478218, -0.012490181252360344, + 0.013128713704645634, 0.04901784285902977, -0.008772367611527443, + 0.03884309157729149, -0.0010204591089859605, 0.04531793296337128, + 0.02846544049680233, -0.02359587885439396, 0.00020289829990360886, + -0.010616355575621128, 0.004069901071488857, 0.060063865035772324, + 0.011982935480773449, -0.014059659093618393, -0.008676886558532715, + -0.01345096342265606, -0.01842794008553028, -0.023607812821865082, + 0.027993997558951378, -0.0009488479699939489, -0.006242106202989817, + 0.017532799392938614, -0.03568026423454285, 0.052837107330560684, + 0.0027391270268708467, 0.012931782752275467, -0.028196895495057106, + -0.0020707561634480953, 0.013940306380391121, 0.023106535896658897, + 0.007017894182354212, 0.04989507794380188, -0.032821785658597946, + 0.08213800936937332, 0.002106561791151762, 0.0013606121065095067, + -0.033329032361507416, -0.014757867902517319, -0.026525970548391342, + -0.015945419669151306, -0.019203728064894676, 0.020928362384438515, + 0.022927507758140564, 0.035328175872564316, -0.04256686940789223, + 0.009589928202331066, 0.1263817697763443, -0.014907057397067547, + 0.007602719124406576, 0.00035805581137537956, 0.022491874173283577, + 0.03591896593570709, -0.03532220795750618, 0.015599298290908337, + -0.07282259315252304, 0.00899913627654314, 0.015396400354802608, + -0.03627702593803406, 0.010562647134065628, 0.026794511824846268, + -0.04384990409016609, 0.015306886285543442, 0.020647887140512466, + 0.07979274541139603, -0.015378497540950775, 0.06526760756969452, + -0.015736553817987442, -0.007471431512385607, -0.04404086619615555, + 0.06075610592961311, -0.021214807406067848, 0.04585501551628113, + -0.017174743115901947, -0.0015873807715252042, 0.056328147649765015, + 0.017234420403838158, -0.017634248360991478, 0.022098012268543243, + 0.027248049154877663, -0.027242079377174377, 0.005257453303784132, + 0.008921558037400246, 0.022038336843252182, 0.013176454231142998, + 0.004380216356366873, 0.03504173085093498, -0.016643628478050232, + 0.0297246016561985, 0.011791972443461418, -0.001861890428699553, + 0.016166219487786293, -0.03747054189443588, 0.057521671056747437, + -0.0038431326393038034, -0.013594185933470726, 0.02111932635307312, + -0.0290801003575325, 0.011768100783228874, 0.01912018097937107, + -0.01493092905730009, 0.014662385918200016, 0.039523396641016006, + 0.02468794956803322, 0.0033120163716375828, 0.01601702906191349, + -0.010031530633568764, -0.015020442195236683, 0.013051135465502739, + -0.01444755308330059, -0.023816680535674095, 0.02502213604748249, + 0.012454375624656677, 0.025863565504550934, -0.006773222703486681, + -0.06847818195819855, -0.03054216131567955, 0.001545607578009367, + -0.03384821116924286, -0.0265438724309206, -0.003395562758669257, + 0.0016351215308532119, 0.018421972170472145, 0.005895986221730709, + -0.03442706912755966, -0.003222502302378416, 0.014190945774316788, + 0.04217897355556488, -0.05589848384261131, 0.07648072391748428, + -0.03790617734193802, -0.018111657351255417, -0.03603235259652138, + 0.004421989433467388, -0.0255771204829216, 0.02341088280081749, + -0.028089478611946106, 0.002977831056341529, -0.006874672137200832, + -0.021835438907146454, -0.02285589650273323, -0.007948839105665684, + 0.024371666833758354, -0.05104682594537735, 0.004875526763498783, + -0.033102262765169144, -0.012639370746910572, -0.07154552638530731, + -0.025404062122106552, 0.02471778728067875, -0.035035762935876846, + 0.02645435929298401, 0.023452656343579292, 0.04376635700464249, + 0.010747642256319523, -0.021053681150078773, -0.01824294403195381, + 0.031085213646292686, -0.03658733889460564, -0.006558389402925968, + 0.012239541858434677, 0.030560065060853958, -0.00466069346293807, + -0.03072715923190117, 0.019818389788269997, 0.0128422686830163, + 0.009774924255907536, -0.0230408925563097, 0.04861801490187645, + -0.03312016278505325, -0.008855913765728474, -0.071014404296875, + 0.019925806671380997, 0.008121899329125881, 0.017240388318896294, + -0.016118479892611504, -0.02033757045865059, -0.008867849595844746, + -0.024276185780763626, -0.038496967405080795, -0.0337885357439518, + 0.03429577872157097, -0.02477746270596981, 0.015945419669151306, + 0.07845599949359894, 0.0008473987691104412, -0.034838832914829254, + 0.012925814837217331, 0.031610362231731415, 0.010437327437102795, + 0.02356604114174843, 0.007173051591962576, -0.02039724588394165, + 0.029366547241806984, 0.07196921855211258, 0.03641427680850029, + 0.010377652011811733, -0.05049780756235123, -0.017210550606250763, + -0.018732286989688873, 0.03511931002140045, 0.008265122771263123, + 0.016804754734039307, -0.05049780756235123, 0.012018740177154541, + -0.009028973989188671, 0.0064629074186086655, -0.02353620156645775, + 0.02248590625822544, 0.01842794008553028, -0.00395054928958416, + 0.0018260846845805645, 0.03070925548672676, -0.0533025786280632, + 0.019424527883529663, 0.0476512610912323, -0.0015635105082765222, + -0.00694031547755003, -0.02583969570696354, 0.010789415799081326, + 0.014358039014041424, 0.02073740027844906, -0.043706681579351425, + -0.1288284808397293, 0.023858454078435898, -0.023721197620034218, + 0.007256597746163607, -0.030583932995796204, 0.011236985214054585, + -0.03825826570391655, -0.00011338433978380635, 0.02393006533384323, + 0.016649596393108368, -0.006325652822852135, 0.0010741675505414605, + -0.02848334237933159, -0.05317725986242294, -0.005633411929011345, + -0.0004117641947232187, -0.016655564308166504, -0.0066240327432751656, + -0.018947120755910873, -0.032887428998947144, -0.009339289739727974, + -0.00281073828227818, -0.0724346935749054, 0.006809028331190348, + 0.028817525133490562, 0.011236985214054585 + ] + }, + "mountains": { + "prompt": "Photo of a beautiful mountain range", + "vector": [ + 0.028191275894641876, 0.017811166122555733, 0.016408821567893028, + -0.01227052602916956, -0.007121717091649771, 0.0009211487486027181, + 0.01934412308037281, 0.01587950438261032, 0.060747694224119186, + 0.03486616536974907, -0.007527296897023916, -0.034934911876916885, + 0.016594424843788147, -0.015742018818855286, 0.016945011913776398, + 0.5609795451164246, -0.02234816737473011, 0.01763930916786194, + 0.022746874019503593, 0.007767895702272654, -0.02878246083855629, + -0.020210279151797295, -0.026953911408782005, 0.0035608585458248854, + 0.009871414862573147, -0.014834619127213955, 0.007898506708443165, + 0.005911849904805422, -0.019674086943268776, 0.06762880831956863, + 0.012765471823513508, 0.006894866470247507, -0.030885977670550346, + 0.023221196606755257, -0.004729480016976595, 0.04720543324947357, + -0.0018697944469749928, -0.016367575153708458, -0.026534583419561386, + -0.014552775770425797, 0.05517268180847168, 0.012256776914000511, + -0.013940966688096523, -0.0313534289598465, -0.017467455938458443, + -0.023915493860840797, -0.009713307023048401, -0.015418929047882557, + 0.03967126086354256, -0.010758192278444767, 0.015714522451162338, + 0.019323501735925674, -0.03575294464826584, 0.01787990890443325, + -0.010187629610300064, -0.022086946293711662, -0.01875981315970421, + 0.014277804642915726, -0.012524873949587345, 0.05602509155869484, + -0.006626770831644535, 0.01602386310696602, 0.005052569787949324, + -0.004777600057423115, 0.011748083867132664, 0.038976967334747314, + -0.006778004579246044, -0.011775580234825611, 0.03699030727148056, + 0.0200384221971035, 0.02092519775032997, 0.05463649332523346, + -0.029153671115636826, -0.008297212421894073, 0.006503034848719835, + 0.018780436366796494, -0.024458561092615128, -0.0017666807398200035, + 0.05913224816322327, 0.04763163626194, 0.014085326343774796, + -0.019818445667624474, 0.04759039357304573, 0.006757382303476334, + -0.0011342503130435944, -0.04072989523410797, 0.006331178825348616, + -0.007616662420332432, -0.027950676158070564, -0.00705984840169549, + 0.04116297513246536, 0.040283069014549255, -0.0158382598310709, + -0.00376708572730422, -0.01117752119898796, 0.02269187942147255, + -0.009974528104066849, 0.03630288317799568, 0.002378488425165415, + 0.009369594044983387, -0.022526897490024567, -0.009837043471634388, + 0.03181400150060654, -0.03449495509266853, 0.03248080238699913, + -0.001739183790050447, -0.07973435521125793, 0.02408735267817974, + 0.028761839494109154, -0.0025847158394753933, 0.002447230974212289, + -0.011748083867132664, 0.011225640773773193, -0.016511933878064156, + 0.006723010912537575, -0.007499800529330969, 0.009665187448263168, + 0.010256372392177582, -0.022224431857466698, 0.01949535682797432, + -0.012545496225357056, -0.03436434641480446, 0.02019652910530567, + 0.012353016994893551, 0.00017185609613079578, 0.006846747361123562, + 0.08900771290063858, -0.05629318580031395, 0.03059038706123829, + 0.015460175462067127, 0.016078857704997063, -0.007726650685071945, + -0.021275784820318222, 0.0033958766143769026, -0.0042620315216481686, + -0.015858881175518036, -0.035587962716817856, 0.010373233817517757, + -0.038317035883665085, -0.005774364806711674, 0.011074407026171684, + -0.005361910443753004, 0.03155965358018875, -0.030576638877391815, + 0.008214721456170082, -0.061325132846832275, 0.016003241762518883, + 0.007149213925004005, -0.03575294464826584, -0.006083706393837929, + -0.03567732870578766, 0.004674485884606838, 0.031195318326354027, + 0.002089770045131445, -0.0007630411419086158, -0.024018609896302223, + 0.0002337243058718741, 0.020258398726582527, -0.014724631793797016, + -0.024836644530296326, 0.0029971706680953503, 0.013466645032167435, + 0.029263656586408615, -0.02874808944761753, -0.046380527317523956, + -0.0888427272439003, -0.01563890650868416, -0.5659977793693542, + 0.007719775661826134, -0.0003299637173768133, -0.021715737879276276, + 0.07681968063116074, -0.004983827006071806, -0.008393452502787113, + -0.0009898912394419312, -0.013535386882722378, -0.009802672080695629, + -0.002502224873751402, -0.003457744838669896, -0.034274980425834656, + 0.003457744838669896, 0.008757786825299263, -0.027648210525512695, + 0.015006475150585175, -0.018711691722273827, 0.01304044108837843, + -0.021667618304491043, -0.003925193566828966, -0.0010723820887506008, + 0.021970083937048912, -0.026108378544449806, -0.014133445918560028, + -0.02007966674864292, -0.08935829997062683, -0.006619896739721298, + -0.03663284704089165, 0.005801862105727196, -0.04136919975280762, + -0.0002337243058718741, 0.03229519724845886, 0.016120102256536484, + -0.01900041103363037, 0.040063098073005676, 0.00628993334248662, + 0.01516458299010992, 0.017556820064783096, 0.015006475150585175, + 0.01216053869575262, 0.006152448244392872, 0.02019652910530567, + 0.011218766681849957, -0.003004044760018587, 0.027263253927230835, + -0.015515169128775597, -0.011363125406205654, 0.0010036396561190486, + 0.016285084187984467, -0.020141534507274628, 0.008297212421894073, + -0.0020760218612849712, 0.03229519724845886, -0.001251112436875701, + 0.01255924440920353, 0.02153700776398182, -0.007980997674167156, + -0.004798222333192825, 0.04441449046134949, -0.012380514293909073, + -0.04238659143447876, -0.12834900617599487, -0.01211929228156805, + 0.022018203511834145, 0.0024884764570742846, -0.04711607098579407, + -0.022169437259435654, -0.04123859107494354, -0.026768306270241737, + -0.02793005295097828, 0.022685006260871887, 0.001230489695444703, + 0.018966039642691612, 0.006475538015365601, -0.04930895194411278, + -0.01402345858514309, -0.016890017315745354, 0.04635303094983101, + -0.02617024816572666, -0.020175905898213387, -0.09306351840496063, + 0.025744043290615082, 0.0014779624762013555, -0.013769110664725304, + -0.031119702383875847, 0.0618063323199749, -0.02091832458972931, + -0.019447235390543938, 0.004681359976530075, -0.037313397973775864, + 0.019055403769016266, 0.009005260653793812, 0.011493736878037453, + 0.0022135067265480757, 0.00628993334248662, 0.029682986438274384, + -0.009142744354903698, 0.0007767896167933941, -0.0029078051447868347, + 0.03637849912047386, 0.005781239364296198, -0.017591191455721855, + 0.005788113921880722, 0.03366317227482796, -0.008194099180400372, + 0.014112822711467743, 0.012263651937246323, 0.07155400514602661, + 0.014820870012044907, 0.015212701633572578, 0.023399926722049713, + -0.039863742887973785, -0.007905380800366402, -0.011919938959181309, + -0.00044682587031275034, -0.008104734122753143, 0.01003639679402113, + -0.00793975219130516, 0.014188440516591072, 0.017268100753426552, + 0.029717355966567993, -0.007334818597882986, -0.018010521307587624, + -0.0061180773191154, -0.00934209767729044, -0.01255924440920353, + -0.014167816378176212, 0.005836233496665955, 0.010778814554214478, + 0.024025484919548035, 0.022300047799944878, -0.0062211910262703896, + 0.004825719632208347, 0.013452896848320961, 0.006468663923442364, + 0.006908615585416555, -0.0013336034025996923, -0.006303681991994381, + -0.001196118537336588, -0.008785284124314785, 0.0030796611681580544, + -0.009314601309597492, 0.12067047506570816, 0.002900931052863598, + 0.005478772800415754, 0.000006874244263599394, 0.03638537600636482, + 0.03177963197231293, -0.05441651493310928, 0.019323501735925674, + -0.05815610662102699, 0.01652568206191063, -0.01169308926910162, + 0.0001099879082175903, -0.005547515116631985, 0.03231582045555115, + -0.048649027943611145, 0.013315411284565926, -0.04281279072165489, + 0.02011403813958168, 0.009280229918658733, 0.006186820100992918, + -0.012724226340651512, 0.021688241511583328, -0.01447028387337923, + 0.03657785430550575, -0.02612212672829628, 0.03006106987595558, + -0.011143149808049202, -0.007589165586978197, 0.008352206088602543, + 0.0020004052203148603, 0.01792115531861782, -0.0023234945256263018, + 0.010118887759745121, -0.005774364806711674, 0.0017666807398200035, + 0.00853781122714281, 0.007974122650921345, 0.0260465107858181, + -0.025668427348136902, -0.00188354286365211, -0.0027565720956772566, + -0.02824626863002777, 0.0030590386595577, -0.02823939360678196, + 0.017164988443255424, -0.008874649181962013, 0.011129401624202728, + 0.049879513680934906, 0.023399926722049713, 0.018347356468439102, + 0.03853701055049896, -0.011012539267539978, -0.01439466793090105, + -0.020712098106741905, -0.025070369243621826, 0.015975743532180786, + 0.02597089484333992, -0.008393452502787113, -0.0273594930768013, + 0.013665997423231602, -0.008056613616645336, 0.0016566927079111338, + -0.01768055558204651, -0.01298544742166996, 0.03688719496130943, + -0.032879509031772614, 0.02878246083855629, 0.023255567997694016, + -0.11043473333120346, 0.015996364876627922, -0.030157307162880898, + 0.015267697162926197, 0.0006599274347536266, -0.00775414751842618, + 0.007486051879823208, -0.010187629610300064, -0.016429442912340164, + -0.022671258077025414, 0.0036433495115488768, 0.022588767111301422, + -0.08365267515182495, 0.016553180292248726, -0.004014558624476194, + 0.0021310157608240843, 0.010118887759745121, -0.014710881747305393, + -0.010703197680413723, -0.008702793158590794, -0.0023166202008724213, + 0.006049334537237883, 0.007369189988821745, 0.004853216465562582, + 0.01109503023326397, 0.004097049590200186, 0.03899071365594864, + 0.015398306772112846, -0.05756492167711258, 0.024266080930829048, + -0.014676511287689209, 0.005547515116631985, -0.03958189859986305, + -0.07155400514602661, -0.00853781122714281, -0.013975338079035282, + 0.011961184442043304, -0.006503034848719835, 0.017206232994794846, + -0.010297617875039577, 0.01186494529247284, 0.02049212157726288, + 0.03522362560033798, 0.0033408827148377895, -0.07305946946144104, + 0.016346951946616173, -0.014772751368582249, -0.022685006260871887, + -0.010029522702097893, 0.014140320010483265, -0.028528112918138504, + 0.04158230498433113, -0.0033958766143769026, 0.021055810153484344, + -0.01737808994948864, 0.024568548426032066, -0.016250712797045708, + 0.0015192078426480293, -0.03339507803320885, 0.026672067120671272, + -0.02617024816572666, -0.008585930801928043, 0.0057124970480799675, + 0.023839877918362617, 0.020835833624005318, 0.02408047765493393, + 0.05790863186120987, 0.01695876009762287, 0.04110110551118851, + -0.03364942595362663, 0.0041520437225699425, -0.008895271457731724, + -0.046909842640161514, -0.025902152061462402, -0.0009142744820564985, + -0.03301699459552765, 0.0013817230938002467, -0.018979787826538086, + 0.018773561343550682, 0.06643269956111908, 0.02223818004131317, + -0.011088155210018158, 0.005485646892338991, -0.009135870262980461, + 0.0015879502752795815, 0.018670447170734406, 0.03186212107539177, + 0.07482614368200302, 0.016044486314058304, 0.031380925327539444, + 0.019275380298495293, 0.003258391749113798, -0.019426614046096802, + 0.04843592271208763, 0.000653053168207407, 0.002935302210971713, + -0.02835625782608986, 0.022018203511834145, -0.012284274213016033, + 0.0032927629072219133, 0.005623131524771452, 0.01645006611943245, + -0.01730247400701046, -0.015027097426354885, 0.009727055206894875, + 0.04178165644407272, -0.003045290242880583, 0.0011686214711517096, + -0.060933299362659454, -0.013129807077348232, 0.01575576700270176, + -0.009424588643014431, -0.02685767039656639, 0.003175900550559163, + -0.0057606166228652, -0.0051900544203817844, -0.01298544742166996, + -0.004502630326896906, -0.05713871866464615, -0.0021378900855779648, + -0.00451637851074338, 0.0018560459138825536, -0.007444805931299925, + -0.011954310350120068, 0.001340477610938251, -0.020251523703336716, + -0.006063083186745644, -0.02438981831073761, 0.010318240150809288, + -0.02720825746655464, 0.0004399516328703612, -0.014387793838977814, + 0.01875981315970421, -0.018704818561673164 + ] + }, + "greenery": { + "prompt": "Photo of lush greenery", + "vector": [ + -0.0024188209790736437, 0.01026985514909029, -0.003033661050722003, + -0.026080025359988213, -0.0058240885846316814, 0.01385079137980938, + -0.00429712375625968, 0.006621353793889284, -0.027606990188360214, + -0.01551288552582264, 0.02874883823096752, -0.009891491383314133, + 0.050639841705560684, 0.016256099566817284, 0.01855330355465412, + 0.5217559337615967, -0.01582368277013302, 0.004567382857203484, + -0.0029998787213116884, -0.03520803526043892, -0.025161145254969597, + -0.03884977847337723, -0.025248978286981583, -0.023296354338526726, + -0.011242789216339588, -0.006371363997459412, 0.015810171142220497, + -0.049180444329977036, -0.019958652555942535, 0.043504998087882996, + -0.018661407753825188, -0.01766820438206196, 0.03996460139751434, + 0.00032431120052933693, 0.03405267745256424, 0.017087146639823914, + 0.01268867589533329, 0.01987757533788681, -0.032836511731147766, + 0.015175062231719494, 0.012208965606987476, -0.013506210409104824, + 0.013877816498279572, -0.0033444594591856003, 0.06924044340848923, + -0.012499494478106499, 0.024073351174592972, -0.01617502234876156, + 0.016803374513983727, 0.04507249966263771, -0.009715823456645012, + 0.030127162113785744, -0.013742687180638313, -0.036971479654312134, + -0.04819399490952492, -0.0032431120052933693, -0.012877857312560081, + -0.0001891815336421132, -0.021620746701955795, 0.01589125022292137, + -0.02408010885119438, -0.022796375676989555, -0.002952583134174347, + -0.0651325061917305, 0.04060646519064903, 0.027938058599829674, + -0.026154346764087677, -0.009945543482899666, 0.001378322602249682, + 0.06817292422056198, 0.0241882111877203, -0.009175305254757404, + -0.0001486426335759461, 0.014904802665114403, 0.022316664457321167, + -0.01551964320242405, -0.11554938554763794, 0.008310474455356598, + -0.06501764059066772, -0.010364445857703686, -0.03290407359600067, + 0.000945907726418227, 0.044180646538734436, 0.02203965000808239, + -0.0035809362307190895, 0.02187073789536953, -0.008040214888751507, + 0.0019053284777328372, -0.0007229437469504774, 0.04820075258612633, + 0.07287543267011642, 0.027829956263303757, 0.01050633192062378, + -0.004222802352160215, -0.02354634366929531, 0.022451795637607574, + -0.11383998394012451, 0.024654408916831017, 0.028411012142896652, + 0.0018242505611851811, -0.00024323341494891793, 0.005445725750178099, + 0.011060363613069057, -0.08840858936309814, 0.009080713614821434, + -0.019992433488368988, -0.0661730021238327, -0.012965692207217216, + -0.00035133716301061213, -0.007580774370580912, -0.042998261749744415, + -0.037802524864673615, 0.02318825200200081, 0.030681191012263298, + -0.0008648298680782318, 0.029519077390432358, -0.012708946131169796, + -0.007553748786449432, -0.000020269450033083558, + 0.0035539104137569666, -0.0003378241672180593, -0.03653906285762787, + 0.009688797406852245, -0.0014256180729717016, -0.000493223313242197, + 0.005526803433895111, 0.03970109671354294, 0.046153537929058075, + 0.025924628600478172, 0.037998463958501816, -0.03274191915988922, + 0.018303314223885536, -0.03343108296394348, 0.0015607477398589253, + 0.06490277498960495, -0.007168628741055727, 0.0011215762933716178, + -0.021816685795783997, 0.011594126001000404, -0.07243625819683075, + 0.005648420192301273, 0.003675527172163129, 0.0022499088663607836, + -0.0335054025053978, -0.011431969702243805, -0.027282679453492165, + 0.033451348543167114, 0.0036417446099221706, 0.012567059136927128, + 0.01567504182457924, 0.013479184359312057, -0.008580734021961689, + 0.024309827014803886, 0.015620989724993706, 0.020796455442905426, + -0.017560100182890892, -0.011479265987873077, 0.0016620948445051908, + 0.014148076064884663, -0.04395768418908119, -0.061193469911813736, + -0.004128211177885532, -0.010053647682070732, -0.0012567059602588415, + 0.04771428927779198, -0.00859424751251936, -0.018499253317713737, + -0.5263165235519409, 0.0033444594591856003, -0.04816021770238876, + -0.004574139136821032, 0.07895626127719879, 0.005851114634424448, + -0.015526398085057735, 0.006472711451351643, 0.0330527164041996, + -0.004364688415080309, -0.0242219939827919, 0.02620839886367321, + 0.07151062041521072, 0.0031350082717835903, -0.018789781257510185, + 0.017310110852122307, -0.014188614673912525, -0.03284326568245888, + -0.01953299343585968, -0.040653761476278305, -0.03721471130847931, + -0.00692539568990469, -0.0022499088663607836, -0.008763158693909645, + -0.027154305949807167, -0.008472629822790623, -0.028451552614569664, + -0.016499333083629608, -0.026823241263628006, 0.023303112015128136, + -0.0004391714173834771, -0.016762835904955864, -0.009182061068713665, + 0.03387025371193886, -0.03335675969719887, 0.0240598376840353, + 0.022296395152807236, 0.011067119427025318, 0.006114617455750704, + 0.020776188001036644, 0.010323906317353249, -0.0014458874939009547, + -0.030167698860168457, 0.03322163224220276, 0.018411418423056602, + -0.011573855765163898, 0.003628231817856431, -0.010026621632277966, + -0.025181414559483528, 0.10141481459140778, -0.01784387417137623, + 0.007533479016274214, -0.025181414559483528, 0.00885774940252304, + -0.0226950291544199, 0.020303232595324516, -0.027255654335021973, + 0.0032160861883312464, -0.024073351174592972, -0.005979487672448158, + -0.023911194875836372, -0.028958288952708244, -0.12885290384292603, + -0.006067322101444006, 0.004905207082629204, -0.028329934924840927, + -0.02904612384736538, 0.00012837319809477776, -0.05159250646829605, + -0.025431403890252113, 0.005729498341679573, -0.009587449952960014, + 0.019505968317389488, 0.0365593321621418, -0.011965733021497726, + -0.04020783305168152, -0.01583719812333584, -0.0029390703421086073, + 0.053862687200307846, -0.02485034614801407, -0.04088348150253296, + -0.1935124397277832, -0.03687012940645218, 0.013898086734116077, + -0.0021350488532334566, -0.008040214888751507, -0.06161237135529518, + -0.0033849983010441065, 0.028910990804433823, 0.004648460540920496, + -0.1203937828540802, -0.01955326274037361, 0.03089739941060543, + -0.00010810373350977898, -0.03483642637729645, -0.00107428093906492, + -0.004526843782514334, 0.004243071656674147, -0.0019931625574827194, + 0.0381808876991272, -0.024809807538986206, 0.01412105094641447, + -0.00003378242035978474, -0.0023917951621115208, -0.00417550653219223, + -0.0034255371429026127, -0.019411375746130943, 0.013404862955212593, + -0.004513331223279238, 0.020404580980539322, 0.003418780630454421, + 0.02103968895971775, -0.017256058752536774, 0.016073673963546753, + -0.07371999323368073, -0.006222721189260483, -0.011040094308555126, + -0.00810778047889471, 0.024316584691405296, 0.009830683469772339, + 0.00512817082926631, 0.062058303505182266, -0.009290164336562157, + -0.04211992025375366, -0.012445442378520966, -0.012540033087134361, + -0.01118198037147522, 0.048356153070926666, 0.010938746854662895, + -0.02669486589729786, 0.024627381935715675, 0.04824129119515419, + -0.007965893484652042, -0.026674598455429077, 0.020343773066997528, + 0.017107415944337845, 0.004371444694697857, -0.013621071353554726, + -0.0003716066130436957, -0.005344378296285868, 0.011175223626196384, + -0.0035539104137569666, 0.006580814719200134, 0.004459279123693705, + -0.01477643009275198, 0.05755172669887543, -0.022093700245022774, + 0.016647975891828537, 0.010546870529651642, -0.027275923639535904, + 0.02605975791811943, 0.021080227568745613, -0.019505968317389488, + -0.035120200365781784, -0.005965975113213062, -0.016492577269673347, + 0.01226301770657301, -0.11921814829111099, 0.0170128270983696, + -0.010060404427349567, -0.04658595100045204, 0.03541748598217964, + -0.040309179574251175, -0.016729053109884262, -0.0359107106924057, + 0.030937936156988144, 0.009384755976498127, -0.01067524403333664, + 0.025627342984080315, -0.014452118426561356, -0.00844560470432043, + 0.050329048186540604, -0.053862687200307846, -0.0006148400134406984, + 0.01387106068432331, 0.00809426698833704, 0.013681878335773945, + 0.03153926506638527, -0.029667718335986137, 0.010094186291098595, + 0.005884896963834763, -0.028275884687900543, -0.006013270001858473, + 0.018107375130057335, 0.0240598376840353, -0.0007905085803940892, + 0.034295909106731415, 0.003891734639182687, 0.02855965495109558, + 0.00927665177732706, 0.02070862241089344, 0.02420172281563282, + -0.06411226838827133, -0.015107497572898865, -0.0016147996066138148, + -0.026593517512083054, 0.01109414640814066, -0.0091888178139925, + 0.02204640582203865, -0.01387106068432331, 0.017303355038166046, + -0.0324040949344635, 0.027302948758006096, 0.04524141550064087, + 0.008803698234260082, -0.0058173323050141335, -0.024005787447094917, + 0.010540113784372807, 0.037829551845788956, 0.03985649719834328, + 0.00512817082926631, -0.02721511386334896, -0.018445199355483055, + -0.01351296715438366, 0.03370809555053711, 0.00960096251219511, + 0.003080956405028701, 0.007202411536127329, -0.004655216820538044, + -0.025154387578368187, 0.007864546962082386, 0.0020134320948272943, + 0.011290083639323711, -0.02401929907500744, -0.001033741980791092, + 0.02604624256491661, 0.0003378241672180593, 0.015039931982755661, + -0.01285083219408989, 0.024316584691405296, -0.014073754660785198, + -0.022255856543779373, 0.011195492930710316, -0.016965530812740326, + 0.011918436735868454, -0.007188898511230946, -0.041951004415750504, + -0.03319460153579712, 0.00554707320407033, -0.012661649845540524, + -0.024303071200847626, -0.008790184743702412, -0.022485578432679176, + -0.018066836521029472, -0.0007769956137053668, 0.023654447868466377, + -0.01251976378262043, 0.001331027247942984, 0.016769591718912125, + -0.0048849377781152725, -0.019978921860456467, -0.021262653172016144, + -0.004830885678529739, 0.03161358833312988, 0.029438000172376633, + -0.02486385963857174, 0.031005503609776497, -0.002533681457862258, + -0.007790225557982922, -0.015769632533192635, 0.005743010900914669, + 0.0035403973888605833, -0.001141845714300871, -0.027174577116966248, + 0.017316866666078568, 0.002533681457862258, 0.015303434804081917, + -0.013992678374052048, 0.016810130327939987, -0.04673459380865097, + 0.015154791995882988, -0.028323179110884666, -0.022086946293711662, + -0.027755632996559143, -0.02791779115796089, 0.05092361569404602, + 0.05913950130343437, 0.008830724284052849, -0.02551248110830784, + 0.002256665611639619, -0.0037498483434319496, 0.01850600726902485, + 0.018397903069853783, -0.046849459409713745, -0.018735729157924652, + -0.03820791468024254, 0.002466116566210985, 0.008425334468483925, + -0.029140714555978775, -0.022086946293711662, 0.058990854769945145, + 0.00925638247281313, 0.01327649038285017, -0.0157155804336071, + 0.04408605396747589, -0.0026958370581269264, 0.022749079391360283, + 0.029269086197018623, 0.037322815507650375, 0.03983622416853905, + -0.018641138449311256, 0.011668447405099869, 0.006871343590319157, + -0.008310474455356598, 0.048998016864061356, -0.005040336865931749, + -0.00425658468157053, 0.0035876925103366375, 0.010067160241305828, + -0.014046729542315006, -0.014843993820250034, 0.007655095774680376, + -0.01109414640814066, 0.005324108991771936, -0.0329243466258049, + 0.03744443133473396, -0.010560383088886738, 0.023167982697486877, + -0.01920192502439022, -0.09798252582550049, 0.04036998748779297, + -0.011472509242594242, -0.0017972246278077364, -0.03458644077181816, + -0.019411375746130943, 0.016587166115641594, -0.008067241869866848, + -0.037457942962646484, 0.0022228830493986607, -0.029242059215903282, + -0.044153619557619095, 0.010648217983543873, -0.011398187838494778, + -0.022147752344608307, 0.014594004489481449, 0.004871424287557602, + -0.0006486224010586739, 0.0050065540708601475, -0.01685742661356926, + -0.033640533685684204, -0.006567301694303751, -0.020323501899838448, + 0.026296233758330345, 0.028992071747779846, 0.04254557564854622 + ] + }, + "beach": { + "prompt": "Photo of a beautiful beach", + "vector": [ + -0.014337359927594662, 0.008085873909294605, 0.004238295368850231, + -0.04446237161755562, -0.008224942721426487, 0.03859497979283333, + 0.022509323433041573, 0.008933532051742077, 0.003609173698350787, + 0.029283974319696426, 0.0250787902623415, -0.01219172216951847, + -0.04351537674665451, 0.011549355462193489, -0.0035694397520273924, + 0.5811630487442017, 0.0009138825116679072, 0.005066087935119867, + -0.02306560054421425, 0.028462804853916168, -0.015257864259183407, + -0.03599240258336067, 0.03354213759303093, -0.04589279368519783, + 0.017860442399978638, -0.0337805412709713, 0.03242295980453491, + -0.018317384645342827, 0.015886986628174782, 0.015211507678031921, + -0.011284462176263332, -0.02511190064251423, 0.021277567371726036, + -0.027005890384316444, -0.0029005836695432663, 0.00967523455619812, + -0.007960048504173756, -0.016794247552752495, -0.037469182163476944, + -0.022012649103999138, 0.006648826412856579, 0.018112091347575188, + -0.003728376002982259, -0.03072764351963997, 0.02964157983660698, + 0.014211534522473812, -0.0009072601678781211, -0.003980024252086878, + 0.018098846077919006, -0.00018542543693911284, 0.02858862839639187, + 0.05057479068636894, 0.013999620452523232, 0.010562627576291561, + 0.006728294305503368, -0.02783368155360222, -0.0021125255152583122, + 0.016271082684397697, -0.030118387192487717, 0.030005808919668198, + -0.000715212372597307, -0.02084711566567421, -0.01541017834097147, + 0.0136089026927948, -0.004278029780834913, 0.028621740639209747, + 0.00102646229788661, -0.030999161303043365, 0.01017853245139122, + -0.03440966084599495, 0.04332995042204857, 0.0114698875695467, + -0.004337630700320005, -0.002880716696381569, 0.03437655046582222, + 0.02301924303174019, -0.05721036717295647, 0.006158773321658373, + 0.04152205213904381, 0.026813842356204987, 0.004033003468066454, + -0.035277191549539566, 0.04628351330757141, 0.023575520142912865, + 0.007695155218243599, 0.002331062685698271, -0.008575926534831524, + 0.015383689664304256, -0.016853848472237587, -0.009536165744066238, + 0.027442965656518936, 0.02937006577849388, 0.029072057455778122, + -0.006390554830431938, -0.028582006692886353, 0.010105686262249947, + -0.05311776325106621, 0.010145420208573341, 0.007761379238218069, + -0.001927100121974945, -0.02185371145606041, -0.012906935065984726, + 0.0002119147829944268, 0.006741539109498262, -0.033409688621759415, + -0.03160179406404495, -0.0758257582783699, 0.02498607710003853, + 0.01603267714381218, -0.023515919223427773, -0.024443047121167183, + 0.00582103431224823, 0.008443479426205158, -0.04087306559085846, + 0.006907097529619932, -0.026899931952357292, -0.0013046003878116608, + 0.006681937724351883, -0.04248891398310661, 0.008714995346963406, + -0.02203913778066635, 0.0157479178160429, 0.02273448370397091, + 0.013747971504926682, 0.0025628444273024797, 0.010734807699918747, + 0.062263209372758865, -0.02872769720852375, -0.008344144560396671, + 0.009390474297106266, -0.0065031349658966064, 0.016449885442852974, + 0.009642122313380241, -0.010681829415261745, -0.024760916829109192, + -0.013589034788310528, -0.026330411434173584, 0.004072736948728561, + -0.0035628171171993017, 0.005973347928375006, 0.006417044438421726, + 0.015886986628174782, 0.0069137196987867355, -0.04590604081749916, + 0.006152151618152857, -0.01846969872713089, -0.012642040848731995, + 0.013456588611006737, -0.03586657717823982, 0.00468861497938633, + 0.004417098592966795, -0.00984079297631979, 0.03658178821206093, + -0.040555190294981, -0.009370607323944569, -0.0043641203083097935, + 0.012165232561528683, 0.006079305429011583, 0.021754376590251923, + -0.017310788854956627, -0.02872769720852375, 0.0004238295659888536, + 0.020304085686802864, 0.00770177785307169, -0.03493282571434975, + -0.055217042565345764, 0.019814031198620796, -0.5854675769805908, + 0.01785382069647312, -0.03142298758029938, -0.011244728229939938, + 0.0694948062300682, -0.009244781918823719, 0.008522948250174522, + 0.00046356357051990926, 0.01653597503900528, -0.025747647508978844, + 0.012787732295691967, -0.017727995291352272, 0.014509540051221848, + 0.012721509672701359, 0.01629757136106491, 0.03692615032196045, + 0.010701696388423443, 0.002225105185061693, 0.006364066153764725, + -0.008264676667749882, 0.01925775595009327, -0.009211670607328415, + 0.032257404178380966, 0.027409851551055908, -0.0293568205088377, + 0.05248864367604256, -0.03565466031432152, -0.0049733747728168964, + -0.04603186249732971, -0.00925140455365181, -0.07718995958566666, + -0.003615796100348234, 0.0067746504209935665, 0.023946372792124748, + 0.024979455396533012, 0.04461468383669853, 0.020747780799865723, + 0.013681747950613499, 0.017330655828118324, 0.007840846665203571, + 0.0059137470088899136, 0.02589995786547661, 0.0298601184040308, + 0.025058923289179802, -0.010589116252958775, -0.006079305429011583, + -0.015032704919576645, 0.011099036782979965, 0.005119066219776869, + -0.025025812909007072, -0.011979807168245316, 0.006324331741780043, + -0.0008277921588160098, -0.019184909760951996, -0.00837725680321455, + 0.002331062685698271, -0.0025495998561382294, -0.016734644770622253, + -0.011046057567000389, 0.03548910468816757, 0.00333765777759254, + 0.004721726290881634, -0.11840076744556427, -0.02340996079146862, + 0.052018459886312485, -0.035422880202531815, -0.06260757148265839, + -0.0006357443635351956, 0.015900231897830963, -0.02202589437365532, + 0.005675342865288258, -0.003993269056081772, -0.0024039081763476133, + -0.01565520465373993, 0.0036422854755073786, -0.06417044252157211, + 0.029144903644919395, -0.05456143245100975, 0.0021323924884200096, + 0.014939992688596249, 0.019516026601195335, -0.10220915079116821, + -0.007814357057213783, 0.007979915477335453, -0.021780867129564285, + -0.010748052969574928, 0.03157530352473259, 0.010489782318472862, + -0.01360228005796671, 0.0098341703414917, -0.08183883875608444, + -0.011363930068910122, 0.00719847995787859, 0.04788611829280853, + -0.01499959360808134, 0.002337685087695718, 0.008642150089144707, + 0.006039571017026901, 0.008940154686570168, -0.0023111954797059298, + 0.034244101494550705, -0.0005231646355241537, -0.019244510680437088, + 0.006880608387291431, -0.009019623510539532, -0.014045977033674717, + 0.02710522525012493, -0.005874013062566519, 0.039998915046453476, + 0.031442854553461075, 0.010701696388423443, 0.0038144660647958517, + -0.005827656481415033, 0.016734644770622253, -0.018098846077919006, + -0.015377067029476166, 0.01251621637493372, 0.011516244150698185, + 0.00788058154284954, -0.0015496269334107637, 0.014542651362717152, + 0.028078708797693253, 0.001377446111291647, -0.030767379328608513, + -0.008383878506720066, -0.0006291220197454095, 0.0060130818746984005, + -0.004278029780834913, 0.020853739231824875, -0.025933071970939636, + -0.016277704387903214, 0.02117823250591755, -0.00002648934787430335, + 0.047144416719675064, -0.015939965844154358, 0.0052647581323981285, + 0.010754674673080444, 0.017251187935471535, 0.0027615143917500973, + 0.027284028008580208, -0.011264595203101635, 0.015608848072588444, + 0.017191587015986443, 0.12382446229457855, 0.007834224961698055, + 0.01678762398660183, 0.014423450455069542, 0.052773404866456985, + 0.02674761787056923, -0.04421072080731392, 0.002198615809902549, + -0.037575140595436096, 0.008469969034194946, -0.010211643762886524, + -0.015112172812223434, -0.02072129212319851, -0.01097321230918169, + -0.043634578585624695, 0.009483186528086662, -0.03866782784461975, + -0.0001059573914972134, -0.00037747318856418133, -0.01737038977444172, + -0.007887203246355057, 0.016588954254984856, -0.01361552532762289, + -0.004311141092330217, -0.011873849667608738, 0.016747890040278435, + 0.0027615143917500973, 0.001258244039490819, -0.0365486778318882, + 0.03971415385603905, 0.027118470519781113, 0.009536165744066238, + 0.022727860137820244, -0.004562790039926767, -0.02871445193886757, + -0.018198180943727493, -0.011430153623223305, 0.015165151096880436, + -0.03127729892730713, -0.00659584766253829, -0.00333765777759254, + 0.005330981221050024, -0.004648880567401648, -0.023688098415732384, + 0.00942358560860157, -0.015641959384083748, 0.032118331640958786, + -0.01956900581717491, 0.03055546246469021, 0.0069137196987867355, + 0.017946533858776093, -0.005701832007616758, -0.0027350252494215965, + 0.007748133968561888, -0.004423721227794886, 0.01821804977953434, + 0.004940263461321592, -0.026946287602186203, -0.021277567371726036, + 0.0175094585865736, 0.011297707445919514, -0.003609173698350787, + -0.02441655658185482, -0.015489645302295685, -0.02902570180594921, + -0.05147542431950569, 0.017708130180835724, -0.013231429271399975, + -0.03809168189764023, -0.021376904100179672, -0.022237807512283325, + -0.015834007412195206, -0.00043045193888247013, -0.023217912763357162, + 0.03719104453921318, -0.009774569422006607, -0.009046112187206745, + 0.0021390148904174566, 0.004907151684165001, 0.02403908409178257, + -0.022251052781939507, -0.0006357443635351956, 0.01812533661723137, + 0.005357470363378525, 0.02306560054421425, 0.01927100121974945, + -0.010211643762886524, -0.039939314126968384, 0.01617174781858921, + -0.013112226501107216, -0.024363579228520393, 0.009158692322671413, + 0.0050131091848015785, -0.029634958133101463, 0.013648636639118195, + 0.0024039081763476133, 0.0124764833599329, 0.01138379704207182, + 0.0015628715045750141, -0.008569303900003433, 0.01697305031120777, + -0.03660827875137329, 0.01063547283411026, -0.002880716696381569, + -0.0035760619211941957, 0.014343982562422752, 0.005681965034455061, + -0.0039998916909098625, -0.010132175870239735, -0.005973347928375006, + 0.07218346744775772, -0.028707832098007202, -0.04050883278250694, + 0.010820899158716202, 0.01771475002169609, 0.0035429501440376043, + -0.016555842012166977, 0.0013906907988712192, 0.007092522922903299, + 0.014151934534311295, -0.009880526922643185, 0.02850916050374508, + 0.01268839742988348, 0.018979618325829506, -0.018429962918162346, + -0.012761243619024754, 0.00421180622652173, 0.013238051906228065, + -0.0040992265567183495, -0.0006092549883760512, 0.010463292710483074, + 0.008814330212771893, -0.013502945192158222, 0.01138379704207182, + 0.027277406305074692, 0.007860713638365269, 0.013787705451250076, + -0.022217940539121628, 0.013622147962450981, -0.02139677107334137, + -0.05273367092013359, 0.030330302193760872, -0.006655448582023382, + -0.00335090234875679, -0.03293950483202934, -0.001927100121974945, + -0.03336995840072632, 0.02331724762916565, 0.002284706337377429, + -0.024913230910897255, -0.008145473897457123, -0.029648203402757645, + -0.0158737413585186, 0.03517785295844078, 0.04156840965151787, + 0.06958751380443573, 0.024350333958864212, 0.014291003346443176, + -0.014973104000091553, -0.02298613078892231, -0.003072764491662383, + 0.028734320774674416, 0.034634821116924286, 0.004953507799655199, + 0.0064038001000881195, 0.001430424745194614, -0.04593915119767189, + 0.009648744948208332, 0.022330520674586296, -0.0023045733105391264, + -0.02199278026819229, 0.006549491547048092, 0.020747780799865723, + 0.006132283713668585, 0.022549057379364967, -0.012582440860569477, + -0.10984470695257187, -0.00737066101282835, 0.006854118779301643, + 0.028151554986834526, -0.029807137325406075, 0.007483240682631731, + 0.02718469314277172, 0.01227119006216526, -0.0034237480722367764, + -0.00837725680321455, -0.024476157501339912, 0.006834251806139946, + -0.0037879766896367073, -0.003827710635960102, 0.012456615455448627, + -0.04129689559340477, 0.011277839541435242, -0.00726470397785306, + 0.008728240616619587, -0.017986267805099487, 0.013675126247107983, + 0.022820573300123215, 0.014423450455069542, -0.008238187991082668, + 0.02880716510117054, -0.06673328578472137 + ] + }, + "city": { + "prompt": "Beautiful photo showing a metropolitan city", + "vector": [ + -0.02022508904337883, 0.0024308236315846443, -0.024840475991368294, + -0.01621343567967415, -0.018501268699765205, 0.014394289813935757, + -0.004027541261166334, 0.010938706807792187, 0.018445663154125214, + 0.0036859549582004547, 0.0027088590431958437, -0.01409242209047079, + -0.05214355140924454, 0.004583612084388733, 0.031870801001787186, + 0.5370293259620667, -0.007220976520329714, -0.005624258890748024, + 0.015101294033229351, -0.03704225644469261, -0.0075943381525576115, + -0.006609298288822174, -0.03983850032091141, 0.004742489196360111, + 0.011693374253809452, -0.02916988544166088, 0.017015766352415085, + -0.018954068422317505, -0.041300173848867416, 0.004543892573565245, + -0.0018429774791002274, 0.006267712451517582, 0.03637497127056122, + 0.04597910866141319, -0.03643852472305298, 0.003113996470347047, + 0.007316302508115768, -0.012535424903035164, -0.04145904630422592, + -0.01633259281516075, 0.024808701127767563, -0.03063950128853321, + -0.0009453203529119492, -0.043651554733514786, 0.0011359731433913112, + -0.06291543692350388, -0.010231702588498592, -0.005346223711967468, + 0.016547076404094696, 0.0009691519662737846, 0.04871974512934685, + 0.023418523371219635, -0.0007943868404254317, 0.05904677137732506, + -0.012170006521046162, -0.010048992931842804, -0.009111616760492325, + -0.024419451132416725, 0.0007864429499022663, 0.049530018121004105, + 0.020924149081110954, 0.013679341413080692, 0.021392837166786194, + -0.024562440812587738, -0.07822327315807343, 0.024403564631938934, + 0.023760110139846802, 0.003431751159951091, -0.0020177424885332584, + 0.037240855395793915, 0.027882976457476616, 0.0327446274459362, + -0.044167909771203995, 0.025261500850319862, -0.006069115363061428, + 0.004488285630941391, -0.02721569500863552, 0.0396399050951004, + 0.07103406637907028, 0.08251295983791351, 0.014576999470591545, + -0.003503246232867241, 0.03790019452571869, 0.02272740751504898, + 0.03453994169831276, -0.00006355094956234097, -0.05225476622581482, + -0.008023306727409363, 0.006402757950127125, -0.011296181008219719, + 0.02713625505566597, 0.031886689364910126, -0.0186760351061821, + 0.005568651482462883, 0.0008182184537872672, 0.013655510731041431, + -0.05238186940550804, -0.03210911527276039, -0.015625588595867157, + 0.0030583892948925495, -0.01081160455942154, 0.00936582125723362, + 0.025404492393136024, 0.0222031120210886, 0.011423283256590366, + -0.009977499023079872, -0.055519696325063705, 0.010906931944191456, + 0.026516633108258247, 0.011177022941410542, 0.01776248961687088, + -0.05265196040272713, -0.0033920318819582462, -0.05242953449487686, + 0.014608773402869701, 0.02619093470275402, -0.004813984502106905, + -0.0286058709025383, -0.0017079317476600409, -0.0365656279027462, + -0.02855820581316948, 0.012440097518265247, 0.03320537135004997, + 0.02806568518280983, 0.059038832783699036, 0.06320936232805252, + 0.01823117770254612, -0.026921769604086876, 0.00046074436977505684, + 0.0030425016302615404, -0.016960158944129944, -0.005465381313115358, + 0.0365656279027462, 0.016983991488814354, 0.006982659921050072, + -0.032752569764852524, -0.014719988219439983, -0.0045200614258646965, + -0.03741561993956566, -0.04035485163331032, 0.014457839541137218, + 0.00039719342021271586, 0.0050523001700639725, -0.011661598458886147, + -0.007729384116828442, -0.015403159894049168, 0.04833843931555748, + 0.01579241082072258, -0.0315609872341156, 0.0256110318005085, + 0.02179797552525997, -0.022997498512268066, 0.06011919677257538, + -0.024292349815368652, -0.006188273895531893, -0.058022018522024155, + -0.013401305302977562, 0.0030742769595235586, 0.01505363080650568, + 0.020582562312483788, -0.03634319826960564, -0.002605588873848319, + 0.03014698065817356, -0.020963868126273155, -0.009373764507472515, + -0.02958296611905098, -0.020940037444233894, -0.5408344864845276, + -0.026413362473249435, -0.008031250908970833, -0.04113335162401199, + 0.052993547171354294, 0.007681720890104771, 0.015959231182932854, + 0.03058389574289322, -0.041284285485744476, -0.023926932364702225, + 0.00962796900421381, -0.004385015461593866, 0.004933142103254795, + 0.03788430988788605, -0.015371385030448437, -0.00006355094956234097, + 0.021972740069031715, 0.042150165885686874, 0.024530665948987007, + -0.004964917898178101, -0.022830678150057793, -0.02320403978228569, + 0.017031654715538025, -0.009945723228156567, -0.0012710189912468195, + 0.00988217256963253, -0.06859530508518219, -0.026786724105477333, + -0.06705419719219208, -0.0025499816983938217, -0.0145690543577075, + 0.03293528035283089, 0.018080245703458786, 0.03054417483508587, + 0.0023196095135062933, -0.003821000689640641, 0.010891043581068516, + -0.0018112020334228873, 0.021964795887470245, -0.007729384116828442, + -0.014998022466897964, 0.029980158433318138, -0.063360296189785, + 0.016038671135902405, 0.027970358729362488, -0.047059476375579834, + 0.010001330636441708, 0.008960683830082417, -0.009786846116185188, + -0.06726867705583572, -0.03569180145859718, 0.004861647263169289, + -0.020113874226808548, 0.040672607719898224, 0.010954594239592552, + 0.015093350782990456, -0.020415741950273514, -0.02970212511718273, + 0.010334973223507404, 0.011026089079678059, -0.005536876618862152, + -0.027509616687893867, -0.08001858741044998, -0.0019462477648630738, + 0.06487756967544556, -0.021980684250593185, -0.03148949518799782, + -0.01865220256149769, -0.033689945936203, -0.014497559517621994, + -0.012559256516397, 0.0024546554777771235, -0.031441833823919296, + -0.05378793179988861, 0.0027882978320121765, -0.01620549149811268, + -0.021933021023869514, -0.060548167675733566, -0.0010247590253129601, + -0.051984675228595734, -0.016626516357064247, -0.06469486653804779, + 0.005656034220010042, 0.003034557681530714, -0.03561235964298248, + 0.0037415619008243084, 0.053057096898555756, -0.016904551535844803, + -0.008936851285398006, 0.006672849413007498, -0.09151336550712585, + 0.00577519228681922, 0.017873702570796013, 0.013663453981280327, + 0.016435863450169563, -0.027040928602218628, 0.026270372793078423, + -0.02910633571445942, 0.03319742530584335, -0.02999604493379593, + -0.03689132630825043, 0.021392837166786194, 0.01628493145108223, + 0.04634452611207962, 0.037510946393013, -0.018135851249098778, + -0.0022322270087897778, 0.022965723648667336, 0.04292071983218193, + -0.010620951652526855, 0.018985845148563385, 0.005894350353628397, + -0.018374167382717133, -0.04233287647366524, -0.008523771539330482, + -0.0110816964879632, -0.02910633571445942, 0.03639880567789078, + -0.03484180569648743, -0.004369127564132214, 0.02375216595828533, + 0.0009294326300732791, 0.006045283749699593, -0.012432154268026352, + -0.003963990602642298, 0.022910118103027344, -0.014672324992716312, + 0.003868664149194956, -0.0008817694033496082, -0.0002780354116111994, + 0.0354217104613781, 0.03109230101108551, -0.013369530439376831, + -0.02374422363936901, -0.013981208205223083, 0.04003709554672241, + 0.009810677729547024, -0.001469615614041686, 0.004067260771989822, + 0.001199524151161313, -0.0004130811430513859, -0.00815040897578001, + -0.006100891157984734, 0.058482762426137924, -0.0038051127921789885, + -0.015887737274169922, -0.007848542183637619, -0.0013425137149170041, + -0.0055527640506625175, -0.04345295950770378, 0.03109230101108551, + -0.04988749325275421, 0.003821000689640641, 0.05859397351741791, + 0.025380657985806465, 0.013925601728260517, 0.04548659175634384, + -0.05572623386979103, 0.029511472210288048, -0.0542169027030468, + 0.036287590861320496, 0.01865220256149769, -0.028296060860157013, + 0.01213028747588396, -0.010994314216077328, 0.043262310326099396, + 0.032760512083768845, -0.004837815649807453, 0.04880712926387787, + -0.01974051259458065, -0.014918585307896137, -0.02765260450541973, + 0.05876079201698303, -0.014434007927775383, -0.004281744826585054, + -0.010184039361774921, -0.01478353887796402, 0.011439170688390732, + -0.023005442693829536, -0.005187346134334803, 0.037828702479600906, + -0.019518084824085236, -0.004043429158627987, -0.01927182450890541, + -0.0241334717720747, -0.013957376591861248, -0.004575667902827263, + 0.016562964767217636, -0.03171192482113838, -0.013480745255947113, + -0.01922416314482689, -0.024300292134284973, -0.051079075783491135, + -0.028367552906274796, -0.003407919779419899, 0.015919512137770653, + -0.007348078303039074, -0.03191052004694939, 0.021829750388860703, + 0.00914339255541563, -0.008420499972999096, -0.001835033530369401, + -0.02218722365796566, -0.001850921311415732, 0.02117040939629078, + -0.014505504630506039, -0.001517278840765357, 0.04524827376008034, + 0.01832650601863861, 0.010422355495393276, -0.00021448444749694318, + -0.06717334687709808, 0.034690871834754944, 0.007975644432008266, + -0.01573680341243744, 0.002859792672097683, -0.0015887736808508635, + -0.011184967122972012, 0.026747005060315132, -0.04824311286211014, + -0.053875312209129333, -0.001835033530369401, -0.020383967086672783, + 0.0008023307309485972, -0.014195693656802177, 0.0006513972184620798, + 0.011296181008219719, 0.03794785961508751, 0.023378804326057434, + -0.03809085115790367, -0.04352445527911186, 0.023950763046741486, + -0.034253958612680435, 0.04487491399049759, 0.04095064103603363, + 0.0024784868583083153, -0.016928382217884064, 0.006227992940694094, + -0.019931165501475334, 0.010009273886680603, 0.01927976869046688, + 0.02655635215342045, -0.05090431123971939, 0.02217928133904934, + -0.004369127564132214, 0.027255410328507423, -0.017651276662945747, + 0.029868947342038155, 0.01428307592868805, -0.01884285733103752, + 0.04993515834212303, 0.020042380318045616, -0.001644380739890039, + 0.012575143948197365, -0.038750190287828445, -0.032323598861694336, + 0.031251177191734314, -0.03403947502374649, -0.026349812746047974, + 0.001644380739890039, 0.04008476063609123, -0.010295253247022629, + 0.0118204765021801, 0.0033920318819582462, 0.007578450720757246, + -0.001437840168364346, 0.03484180569648743, -0.0423567034304142, + 0.01086721196770668, -0.016110165044665337, -0.0004686882020905614, + 0.006672849413007498, -0.020431628450751305, -0.03305443376302719, + -0.00284390477463603, -0.03195818141102791, 0.03586656600236893, + 0.024276461452245712, 0.02707270160317421, 0.04344501718878746, + 0.01232888363301754, -0.001549054286442697, -0.0779770165681839, + -0.03746328502893448, -0.015299891121685505, -0.015363441780209541, + -0.008237791247665882, 0.010795717127621174, 0.014028871431946754, + -0.007228919770568609, 0.005187346134334803, 0.0533113032579422, + 0.013155045919120312, 0.00529856001958251, -0.06317758560180664, + -0.012519536539912224, 0.0317198671400547, 0.04698003828525543, + 0.08506294339895248, 0.020074155181646347, 0.0237203910946846, + -0.03108435869216919, 0.01625315472483635, -0.004607443697750568, + 0.05777575448155403, -0.01980406418442726, -0.04331791400909424, + -0.031322672963142395, 0.018866688013076782, -0.012908786535263062, + 0.013552239164710045, 0.002859792672097683, 0.038758132606744766, + -0.0037177305202931166, 0.001294850604608655, 0.0073798540979623795, + 0.022004514932632446, 0.027779707685112953, 0.008086858317255974, + -0.12062764167785645, -0.04426323622465134, 0.021035363897681236, + 0.04329408332705498, -0.025285333395004272, 0.030250251293182373, + -0.0031696034129709005, 0.0241334717720747, -0.02515028789639473, + 0.004528005141764879, -0.06219254434108734, 0.01232888363301754, + -0.008023306727409363, 0.02171853743493557, 0.03409508615732193, + 0.02372833527624607, -0.00884946994483471, -0.011065809056162834, + -0.00729247136041522, -0.04056933522224426, -0.005838742945343256, + 0.001421952387318015, -0.023307310417294502, -0.017389127984642982, + 0.014998022466897964, -0.024014314636588097 + ] + }, + "moon": { + "prompt": "Photo of a beautiful moon", + "vector": [ + 0.02025710977613926, 0.018633542582392693, 0.006263218354433775, + -0.03596823289990425, 0.01744708977639675, -0.014811917208135128, + 0.025377586483955383, 0.027844157069921494, 0.0332893468439579, + 0.03457571193575859, -0.019520258530974388, -0.03809135779738426, + -0.03466938063502312, 0.030654177069664, 0.018358785659074783, + 0.5304065346717834, -0.03515645116567612, 0.039383962750434875, + -0.004383628722280264, -0.007081246003508568, 0.0023042147513478994, + 0.026564037427306175, -0.028431138023734093, -0.023691575974225998, + 0.0031971761491149664, -0.05539482459425926, -0.001954523613676429, + -0.022355254739522934, 0.00783682893961668, 0.0347505584359169, + -0.004302449990063906, -0.02996104024350643, -0.03302083536982536, + 0.014168735593557358, -0.017503291368484497, 0.011108938604593277, + -0.00493314303457737, 0.021318672224879265, -0.002660150406882167, + -0.03516269475221634, 0.03971492499113083, 0.05899789184331894, + -0.04307445511221886, -0.0264141708612442, 0.018964501097798347, + -0.017497045919299126, 0.0006494264234788716, -0.012607615441083908, + 0.019201790913939476, -0.0244658924639225, 0.026663949713110924, + -0.008835946209728718, -0.015923436731100082, -0.011358717456459999, + -0.0240787323564291, 0.01980126090347767, 0.0007743160822428763, + 0.010103576816618443, 0.018927032127976418, 0.055344872176647186, + 0.0006993822753429413, -0.003534378483891487, -0.015892215073108673, + -0.0073934695683419704, -0.021100115031003952, 0.03495662659406662, + 0.037054769694805145, 0.007218623999506235, -0.01709739863872528, + -0.027057351544499397, 0.03955256566405296, 0.05627529323101044, + -0.01544885616749525, -0.010003664530813694, 0.016173215582966805, + 0.0055888136848807335, -0.01970134861767292, 0.030410639941692352, + 0.0495624765753746, 0.02790660224854946, -0.03941518813371658, + 0.027250930666923523, 0.012588880956172943, 0.010559423826634884, + -0.012207968160510063, 0.014861873351037502, 0.0033720219507813454, + 0.03432593494653702, -0.04916282743215561, -0.0025227719452232122, + -0.012726260349154472, 0.07261711359024048, 0.003134731436148286, + 0.033969998359680176, -0.01705993339419365, 0.019058167934417725, + -0.039565056562423706, -0.03470684587955475, -0.003278354648500681, + 0.007356002926826477, -0.011421162635087967, 0.026051988825201988, + -0.03685494884848595, -0.05667494237422943, -0.0015111652901396155, + -0.009273060597479343, -0.05809244140982628, 0.0107717365026474, + 0.020725445821881294, -0.024522092193365097, -0.018358785659074783, + -0.006744043901562691, -0.018227651715278625, -0.029786191880702972, + 0.04217524826526642, 0.0341198667883873, 0.03138478100299835, + 0.03781035542488098, -0.03432593494653702, 0.06708449870347977, + 0.03763550892472267, -0.005395234562456608, 0.01049073413014412, + 0.017034955322742462, 0.025102829560637474, 0.049081649631261826, + 0.0868607833981514, 0.02744450978934765, 0.02859349548816681, + 0.04921278357505798, -0.004989343229681253, 0.028019003570079803, + -0.002722595352679491, 0.02356044016778469, -0.0471833273768425, + -0.0012801194097846746, -0.011015270836651325, -0.02095649018883705, + -0.0052765896543860435, 0.016391772776842117, 0.006344396620988846, + -0.013800310902297497, -0.0002560238935984671, -0.037747908383607864, + -0.034457068890333176, 0.005901038181036711, -0.007918006740510464, + -0.027400799095630646, -0.06263842433691025, -0.03289594501256943, + 0.0012613859726116061, 0.0014362315414473414, -0.0148181626573205, + -0.022605035454034805, 0.012951061129570007, 0.034488290548324585, + 0.009497861377894878, 0.011833298951387405, 0.015105409547686577, + -0.014249914325773716, 0.005120477639138699, -0.03333306312561035, + 0.03558731824159622, -0.005526368971914053, -0.02112509310245514, + -0.06097739562392235, -0.003890313906595111, -0.5348338484764099, + -0.01283866073936224, -0.0047832755371928215, -0.025621119886636734, + 0.05942251905798912, 0.0257397647947073, -0.02598954737186432, + -0.012314124032855034, 0.01257639192044735, -0.026695171371102333, + -0.038309913128614426, 0.020163441076874733, 0.005008076783269644, + 0.016597840934991837, 0.026076968759298325, 0.011596008203923702, + 0.015142875723540783, -0.02873087301850319, -0.013787822797894478, + -0.012145522981882095, -0.033826377242803574, 0.011596008203923702, + 0.04476671293377876, 0.022286565974354744, -0.0026289280503988266, + 0.05146079882979393, -0.07879915088415146, -0.0283187385648489, + -0.03071662038564682, 0.0016610330203548074, -0.025077851489186287, + -0.008298920467495918, -0.007468403782695532, 0.03574967756867409, + -0.017940403893589973, 0.059191472828388214, 0.02376650832593441, + 0.0012176745804026723, 0.04235009849071503, 0.03725459426641464, + -0.027669312432408333, -0.049668632447719574, 0.022505123168230057, + 0.03690490499138832, 0.02529640682041645, -0.0446043536067009, + 0.014786939136683941, -0.015261520631611347, 0.01775307022035122, + 0.022018054500222206, -0.032989609986543655, 0.016010858118534088, + -0.03268988057971001, 0.0076120272278785706, -0.03703603893518448, + 0.0003684246039483696, -0.024853048846125603, 0.020937757566571236, + -0.027544422075152397, -0.025658588856458664, -0.022111721336841583, + -0.017084911465644836, -0.037017304450273514, -0.005195411387830973, + 0.05747423693537712, -0.042481228709220886, -0.011614741757512093, + -0.04056417569518089, -0.01143365167081356, -0.010852914303541183, + 0.03895933926105499, 0.013575509190559387, -0.010721780359745026, + 0.0158859696239233, -0.0040464261546730995, 0.00031846872298046947, + -0.0031971761491149664, -0.005083010531961918, -0.011458629742264748, + -0.018683498725295067, -0.039733655750751495, -0.10297779738903046, + -0.013163373805582523, -0.01376284472644329, -0.04125106707215309, + 0.02078164555132389, 0.10747382044792175, -0.0015611212002113461, + 0.02255507931113243, 0.007786872796714306, -0.025589898228645325, + 0.015536277554929256, 0.019538993015885353, -0.011439896188676357, + 0.006381863262504339, 0.0032596210949122906, 0.014568382874131203, + 0.005876060109585524, -0.011508584953844547, 0.018777165561914444, + -0.008967080153524876, 0.012089322321116924, 0.007849317975342274, + -0.0010365844937041402, 0.008342632092535496, -0.011221338994801044, + -0.033514149487018585, -0.02644539251923561, 0.045822031795978546, + 0.01873345486819744, 0.0034407111816108227, -0.04611552134156227, + -0.027506954967975616, -0.006256973836570978, 0.03975863382220268, + -0.007774383760988712, 0.002535260980948806, 0.014549649320542812, + -0.014768206514418125, 0.047795288264751434, -0.024172401055693626, + -0.014649561606347561, 0.011290028691291809, 0.00993497483432293, + 0.011908232234418392, 0.01636679470539093, 0.004002714529633522, + 0.005164189264178276, 0.0002872463082894683, -0.02679508365690708, + 0.10626864433288574, 0.06183912977576256, 0.03245258703827858, + 0.06080879643559456, -0.007705694064497948, -0.0011427407152950764, + -0.0320279635488987, -0.014268646948039532, -0.011271295137703419, + -0.039839811623096466, -0.054364487528800964, 0.02366659790277481, + 0.006981334183365107, 0.054327018558979034, 0.021874429658055305, + -0.03973989933729172, 0.00262268353253603, 0.011302517727017403, + -0.012982283718883991, -0.054183389991521835, 0.016141993924975395, + -0.0916752815246582, -0.013007261790335178, -0.0034094888251274824, + 0.00017484556883573532, -0.06137079745531082, 0.014193713665008545, + -0.008823457174003124, 0.009791351854801178, 0.005189166869968176, + 0.024478379637002945, 0.016323082149028778, 0.018720965832471848, + -0.04423592984676361, 0.006556709297001362, 0.0031222424004226923, + 0.057836420834064484, 0.0016235660295933485, 0.03446955606341362, + 0.005638769827783108, -0.008929613046348095, 0.019538993015885353, + 0.03247756510972977, 0.048176199197769165, 0.003877825103700161, + 0.049949631094932556, 0.004121359903365374, 0.020269596949219704, + -0.027269665151834488, 0.003521889680996537, 0.003290843451395631, + -0.06808985769748688, 0.0010990293230861425, -0.034525755792856216, + 0.014736983925104141, -0.00008117830293485895, -0.0181339830160141, + 0.018995722755789757, -0.001049073413014412, 0.03494413569569588, + -0.025277674198150635, 0.02605823427438736, 0.01771560311317444, + -0.055544693022966385, -0.006893911398947239, -0.004327428061515093, + -0.02199932001531124, 0.03206542879343033, -0.0031472202390432358, + 0.05089879408478737, -0.003315821522846818, -0.06154564023017883, + -0.020163441076874733, -0.0001998235093196854, -0.023429308086633682, + -0.010084843263030052, -0.0064318194054067135, 0.05909780412912369, + -0.015130387619137764, 0.026332993060350418, -0.008698566816747189, + -0.03749188780784607, 0.022018054500222206, 0.014274892397224903, + 0.042031627148389816, -0.026070723310112953, -0.04804506525397301, + -0.03628045693039894, -0.0060633947141468525, -0.025939591228961945, + -0.0007743160822428763, -0.0039402698166668415, -0.008642367087304592, + 0.05587564781308174, 0.02682630717754364, 0.02716975286602974, + -0.015592479147017002, -0.020200908184051514, 0.003771668765693903, + -0.015117897652089596, 0.0006619153427891433, -0.06335654109716415, + -0.00936672743409872, -0.001161474152468145, -0.015642434358596802, + 0.04652765393257141, -0.03859715908765793, 0.033514149487018585, + -0.039871037006378174, -0.06976962834596634, 0.04631534591317177, + -0.042268916964530945, -0.0018421229906380177, 0.019620170816779137, + -0.047620441764593124, 0.017284734174609184, 0.03624923527240753, + -0.00670657679438591, 0.0035281339660286903, -0.02095649018883705, + 0.011683430522680283, 0.006793999578803778, -0.004820742178708315, + -0.028749607503414154, 0.004777031019330025, -0.04409230500459671, + -0.005563836079090834, 0.0033345548436045647, -0.011240072548389435, + 0.007337269838899374, 0.014905585907399654, 0.022911015897989273, + -0.004008959047496319, -0.005513879936188459, 0.0387907400727272, + -0.03369523957371712, 0.002728839870542288, -0.011427407152950764, + 0.017041198909282684, 0.0006931378156878054, -0.04941260814666748, + -0.014318603090941906, -0.03224651888012886, -0.01539265550673008, + -0.02693246304988861, -0.008623633533716202, -0.027456998825073242, + -0.010409556329250336, 0.005969727877527475, 0.031022600829601288, + 0.009460395202040672, -0.056375205516815186, 0.01032213307917118, + -0.009404193609952927, -0.011558541096746922, -0.03071662038564682, + -0.0077993618324398994, -0.02721346542239189, 0.014968030154705048, + -0.0036904902663081884, 0.013144641183316708, -0.01914559118449688, + -0.03774166852235794, -0.05164188891649246, -0.027456998825073242, + -0.030810287222266197, -0.004283716902136803, 0.004964365623891354, + -0.012451502494513988, -0.021137580275535583, 0.013550532050430775, + -0.025770988315343857, 0.01650417409837246, 0.005757415201514959, + 0.06817728281021118, -0.02665146067738533, 0.008592410944402218, + -0.027007395401597023, 0.049050427973270416, -0.027919093146920204, + 0.002316703787073493, 0.028830785304307938, -0.036124344915151596, + -0.008823457174003124, -0.012239189818501472, 0.015386410057544708, + -0.04643398895859718, 0.02435348927974701, -0.020625533536076546, + -0.11875761300325394, 0.026626484468579292, 0.010403310880064964, + 0.020625533536076546, -0.025521209463477135, -0.01702870987355709, + 0.018052807077765465, -0.009091969579458237, 0.008061629720032215, + 0.018571097403764725, -0.01370664406567812, -0.010059865191578865, + 0.006606664974242449, 0.023860175162553787, 0.006987578235566616, + 0.014043846167623997, 0.002360415179282427, -0.01977003924548626, + -0.03860964998602867, -0.020413219928741455, 0.05174804478883743, + 0.012345346622169018, 0.0019482792122289538, 0.024259822443127632, + -0.005020565818995237, -0.01080920360982418 + ] + }, + "onTheRoad": { + "prompt": "Photo of a nostalgic road trip", + "vector": [ + -0.028973080217838287, 0.012647041119635105, -0.008081350475549698, + -0.004977925214916468, 0.04188457131385803, -0.005273489281535149, + 0.004659026395529509, -0.015703797340393066, -0.002621188759803772, + 0.03169538080692291, -0.007015763316303492, -0.02328735589981079, + 0.0030256451573222876, 0.031788717955350876, -0.004262348171323538, + 0.5301334857940674, 0.015089335851371288, 0.018737221136689186, + 0.020642833784222603, -0.030870914459228516, 0.018169425427913666, + -0.0017811637371778488, -0.04613914340734482, -0.020533941686153412, + 0.011495895683765411, -0.019196122884750366, 0.008594698272645473, + 0.011052549816668034, 0.017586076632142067, 0.03496992215514183, + 0.004534578416496515, 0.011340335942804813, -0.028241947293281555, + -0.0016411596443504095, -0.019297238439321518, 0.007552445400506258, + -0.03332098573446274, -0.017827194184064865, -0.017189396545290947, + -0.0345110185444355, 0.028420841321349144, 0.016100475564599037, + -0.03083980083465576, 0.0034534353762865067, -0.037661112844944, + -0.05464828386902809, -0.028024161234498024, 0.027215249836444855, + -0.023940708488225937, 0.014544875361025333, -0.014015969820320606, + -0.025667425245046616, 0.01144922710955143, 0.03073868528008461, + 0.03635440766811371, -0.03593439608812332, -0.040157854557037354, + 0.009139158762991428, -0.022081764414906502, 0.008921375498175621, + -0.013292615301907063, 0.03142315149307251, -0.01682383008301258, + 0.05030815303325653, -0.07767118513584137, 0.010313638485968113, + -0.03102647140622139, -0.006440190598368645, 0.04801364243030548, + 0.06619862467050552, 0.016644936054944992, 0.04493355005979538, + -0.05138152092695236, -0.0172905120998621, -0.04947590455412865, + 0.0029789770487695932, -0.0670386478304863, 0.022462885826826096, + 0.06652530282735825, 0.05179375410079956, 0.0031112032011151314, + -0.012755932286381721, 0.03672775253653526, 0.009388054721057415, + 0.041814569383859634, 0.011145885102450848, -0.02598632499575615, + 0.021902868524193764, -0.03352321311831474, -0.011729235760867596, + 0.05675612390041351, 0.02020726352930069, 0.018114980310201645, + -0.037062209099531174, -0.0000077780077845091, 0.006541304290294647, + -0.04171345755457878, 0.012118136510252953, 0.015524904243648052, + 0.02827305719256401, -0.01118477527052164, -0.00269119068980217, + 0.019258346408605576, -0.06276852637529373, -0.029486428946256638, + 0.03668108582496643, -0.06087847054004669, -0.021941760554909706, + -0.03342209756374359, 0.037871118634939194, -0.014202643185853958, + -0.002006725873798132, 0.07768674194812775, -0.018791666254401207, + -0.022750671952962875, -0.011425893753767014, 0.01854277029633522, + -0.026235220953822136, -0.041231222450733185, 0.012017021887004375, + 0.03198316693305969, -0.03062201477587223, -0.02393293008208275, + -0.009224717505276203, -0.02770526520907879, -0.025216301903128624, + 0.06107291951775551, 0.003430101554840803, -0.028747517615556717, + -0.013035940937697887, -0.012009243480861187, 0.0052034868858754635, + 0.0017578297993168235, 0.039854515343904495, 0.03901448845863342, + -0.012864825315773487, -0.02987532690167427, -0.027619706466794014, + -0.038158904761075974, -0.017368290573358536, 0.04195457324385643, + 0.08762703835964203, 0.03662663698196411, -0.019266124814748764, + 0.0031189811415970325, -0.04515133425593376, -0.012195915915071964, + 0.010196967981755733, -0.022245101630687714, -0.05293712019920349, + -0.001345595344901085, 0.020075038075447083, 0.02769748494029045, + -0.0164349302649498, 0.027339696884155273, -0.0029400868806988, + -0.03755221888422966, 0.011254777200520039, 0.010725872591137886, + 0.008291356265544891, 0.0013844853965565562, -0.007311326917260885, + -0.0008711368427611887, 0.005172375123947859, 0.05788393318653107, + -0.015532681718468666, 0.03155537694692612, -0.5350958108901978, + 0.005615721456706524, 0.03021756000816822, 0.00598128791898489, + 0.047414734959602356, -0.05283600836992264, 0.041231222450733185, + 0.01253814809024334, -0.02467184141278267, -0.03131425753235817, + 0.019903922453522682, 0.0127870449796319, 0.034487687051296234, + 0.028234168887138367, -0.009108047001063824, 0.024228494614362717, + -0.018698330968618393, 0.04494910687208176, -0.014887107536196709, + 0.02439183183014393, -0.01256148237735033, -0.025340748950839043, + -0.013432620093226433, 0.031399816274642944, -0.05150596797466278, + 0.012499258853495121, 0.06501636654138565, 0.025885211303830147, + -0.03263652324676514, 0.03205316886305809, -0.11994465440511703, + -0.022525111213326454, 0.02953309379518032, 0.02495962753891945, + -0.001703383750282228, -0.02562853693962097, -0.006650196388363838, + -0.010593647137284279, 0.0019678359385579824, -0.006984651554375887, + 0.03988562524318695, 0.019157234579324722, -0.03468991443514824, + -0.03913893550634384, 0.007435775361955166, 0.021739531308412552, + -0.02215954288840294, 0.00023334022262133658, 0.0072335475124418736, + 0.007435775361955166, 0.001571157481521368, 0.01637270487844944, + -0.0014933774946257472, 0.008128018118441105, -0.010632536374032497, + -0.03667330741882324, 0.01813831366598606, 0.034378793090581894, + 0.0035934397019445896, 0.0032200952991843224, 0.0061446260660886765, + 0.006525748409330845, -0.06574749946594238, -0.038151130080223083, + -0.011488117277622223, -0.030147558078169823, -0.08026126027107239, + -0.02649189531803131, -0.04459131881594658, -0.029851993545889854, + 0.016956057399511337, 0.009325831197202206, 0.013689294457435608, + -0.030139779672026634, 0.03228650987148285, -0.0043556843884289265, + 0.023847371339797974, -0.10854987800121307, 0.008586919866502285, + -0.011721457354724407, 0.04104454815387726, -0.06776978075504303, + 0.03004644252359867, -0.03847780451178551, -0.026764124631881714, + -0.04989591985940933, 0.04401574656367302, -0.0460146926343441, + -0.0022245103027671576, -0.0211250688880682, -0.07163545489311218, + 0.012491480447351933, -0.004977925214916468, 0.00010889210534514859, + -0.01981058530509472, -0.05246266350150108, -0.016691604629158974, + 0.03320431336760521, -0.0081824641674757, -0.0058179497718811035, + -0.02873195894062519, 0.014568207785487175, -0.011091439053416252, + -0.04647359624505043, -0.006300186738371849, -0.02443072386085987, + -0.03892115131020546, -0.008859150111675262, 0.026258554309606552, + 0.00787134375423193, -0.028607511892914772, -0.02695857547223568, + -0.007490221876651049, 0.01284926850348711, -0.03438657149672508, + 0.04619358852505684, -0.014474872499704361, 0.02334180288016796, + 0.006665752734988928, -0.029463093727827072, 0.018293874338269234, + -0.034254346042871475, -0.007311326917260885, -0.03447213023900986, + -0.004806808661669493, -0.03904559835791588, -0.023940708488225937, + 0.013728183694183826, 0.020557275041937828, -0.0432768352329731, + -0.05826505646109581, 0.025791874155402184, 0.010578090324997902, + 0.00437901820987463, -0.01825498417019844, 0.034767694771289825, + 0.026826348155736923, 0.022112876176834106, 0.004254570230841637, + 0.014093750156462193, 0.0049701472744345665, 0.01739940233528614, + 0.006463524419814348, 0.06456524133682251, 0.009730287827551365, + 0.005825727712363005, -0.018457211554050446, 0.0001866721868282184, + -0.005887951701879501, -0.03931005299091339, 0.030015332624316216, + -0.017889417707920074, -0.034425463527441025, -0.03558438643813133, + 0.018962783738970757, -0.029890885576605797, 0.013098164461553097, + 0.014871550723910332, -0.032815415412187576, -0.0028934190049767494, + 0.05481162294745445, -0.01762496493756771, 0.0022011762484908104, + 0.03169538080692291, -0.009123602882027626, 0.010998102836310863, + 0.042390141636133194, 0.006160182412713766, 0.02678745985031128, + 0.012281473726034164, -0.016893833875656128, -0.0006844646413810551, + 0.052851561456918716, -0.018986117094755173, 0.020230598747730255, + 0.04578135535120964, 0.008151352405548096, 0.027977492660284042, + -0.024578504264354706, -0.02076728083193302, -0.017531629651784897, + 0.011527007445693016, 0.0008711368427611887, -0.025846319273114204, + 0.004386796150356531, 0.04838698357343674, -0.008423582650721073, + -0.005374603439122438, 0.004410130437463522, -0.014599321410059929, + 0.007692449726164341, -0.00984695740044117, 0.016279369592666626, + -0.03129870444536209, -0.021591750904917717, -0.008485806174576283, + -0.030482012778520584, -0.016341593116521835, 0.026172997429966927, + 0.016932722181081772, -0.024111824110150337, 0.0011200332082808018, + -0.009551393799483776, -0.0358099490404129, 0.010896989144384861, + -0.047080282121896744, -0.007357995491474867, 0.00798801425844431, + 0.000575572601519525, 0.016046030446887016, -0.00489236693829298, + -0.10168967396020889, 0.02358292043209076, 0.0017811637371778488, + -0.02100062184035778, 0.014350424520671368, -0.05210487172007561, + 0.028871964663267136, 0.009131381288170815, -0.015066001564264297, + -0.004589024931192398, 0.039691176265478134, -0.0756644606590271, + 0.04063231125473976, 0.004775696899741888, -0.02403404377400875, + 0.01830943115055561, -0.004013451747596264, 0.01505044475197792, + 0.015066001564264297, -0.02248622104525566, 0.05625055357813835, + -0.010313638485968113, 0.04159678518772125, -0.0014467095024883747, + -0.02043282613158226, -0.008820260874927044, 0.020572829991579056, + 0.015447122976183891, 0.0064324126578867435, 0.06067623943090439, + -0.04028230160474777, 0.02981310337781906, 0.004526800476014614, + 0.0035623274743556976, -0.01305149681866169, -0.010313638485968113, + 0.01038364041596651, 0.030474234372377396, -0.018986117094755173, + 0.005584609694778919, -0.013261503539979458, 0.015509347431361675, + 0.04229680448770523, -0.01998170092701912, -0.028716403990983963, + -0.006556860636919737, -0.04452909529209137, -0.05336491018533707, + -0.03118981048464775, 0.05527830123901367, -0.006113514304161072, + -0.011744791641831398, 0.0033523214515298605, -0.010391417890787125, + 0.018970560282468796, 0.019266124814748764, -0.03332098573446274, + 0.013152611441910267, -0.030808690935373306, -0.015641573816537857, + -0.0258152075111866, -0.007357995491474867, -0.005989065859466791, + 0.02151397056877613, -0.010461420752108097, 0.023668477311730385, + 0.014124861918389797, 0.014319312758743763, 0.020176151767373085, + -0.023334022611379623, 0.01225036196410656, -0.04085009917616844, + -0.01138700358569622, -0.01356484554708004, -0.011239221319556236, + -0.02076728083193302, 0.007101321592926979, -0.030233116820454597, + 0.007505777757614851, 0.03353099152445793, 0.01745384931564331, + 0.00538238137960434, 0.026141883805394173, -0.03178093954920769, + 0.01402374729514122, 0.03107313998043537, 0.03692220151424408, + -0.03624551743268967, -0.008081350475549698, 0.026414114981889725, + -0.03165648877620697, -0.031500931829214096, -0.005716835614293814, + 0.05883285030722618, 0.06266740709543228, 0.00887470692396164, + 0.008913597092032433, -0.0015089336084201932, -0.005623499397188425, + 0.029377536848187447, 0.003305653342977166, 0.023995155468583107, + -0.019787251949310303, -0.001804497791454196, 0.0464969277381897, + -0.009528059512376785, 0.02586965449154377, 0.013572623021900654, + -0.09108047187328339, 0.0117603475227952, -0.003056757152080536, + -0.016092699021100998, -0.0019211678300052881, 0.033056534826755524, + 0.028241947293281555, 0.026188552379608154, -0.020518384873867035, + -0.02048727311193943, -0.0033134312834590673, -0.014474872499704361, + 0.01888500340282917, -0.028514178469777107, 0.0027689707931131124, + 0.00927138514816761, -0.024119602516293526, -0.005856839939951897, + -0.017267178744077682, 0.0059268418699502945, 0.04030563682317734, + -0.015556016005575657, 0.021249517798423767, -0.017407182604074478, + 0.01837943308055401, 0.00439457455649972 + ] + }, + "food": { + "prompt": "Photo of delicious looking food", + "vector": [ + -0.03325869143009186, 0.019341137260198593, -0.013895140029489994, + -0.03983273357152939, -0.03497690334916115, 0.013626201078295708, + 0.01961754634976387, -0.015852412208914757, -0.01781715452671051, + -0.032451875507831573, 0.02271033637225628, 0.03895868360996246, + 0.0020319772884249687, 0.021567348390817642, 0.0059166401624679565, + 0.5388176441192627, -0.009412836283445358, 0.0056551722809672356, + -0.003092789091169834, -0.05278659239411354, 0.026774289086461067, + -0.007037215866148472, 0.01334232185035944, -0.018474560230970383, + -0.022807452827692032, -0.0056551722809672356, -0.03127153590321541, + 0.024988839402794838, 0.009196192026138306, 0.0060585797764360905, + -0.014388193376362324, -0.006036167964339256, 0.041065365076065063, + -0.011175875551998615, -0.030292898416519165, 0.0198715440928936, + 0.006290165241807699, -0.0056925248354673386, 0.016285700723528862, + 0.0009114016429521143, 0.05141201615333557, -0.029986606910824776, + -0.01359631959348917, 0.022740216925740242, -0.039907436817884445, + -0.04615277796983719, -0.021769052371382713, 0.0008964606677182019, + -0.02143287844955921, -0.023248212411999702, 0.038293808698654175, + 0.016278231516480446, 0.01688334159553051, -0.0026819114573299885, + -0.03274322301149368, 0.010608118027448654, -0.04260428994894028, + -0.010877056047320366, -0.005221882835030556, 0.05776941776275635, + -0.016225937753915787, -0.0020618592388927937, -0.0018526853527873755, + -0.025810595601797104, -0.08053204417228699, 0.03278804570436478, + 0.016659226268529892, -0.014141666702926159, 0.058658406138420105, + 0.038801804184913635, 0.04038555175065994, -0.02264310047030449, + 0.006320047192275524, -0.015307065099477768, 0.005162118934094906, + 0.015986880287528038, -0.046683184802532196, 0.005931580904871225, + 0.01092934887856245, 0.0175482165068388, -0.01203498337417841, + -0.02484690025448799, 0.02037953771650791, 0.04440468177199364, + -0.010764997452497482, 0.02353956177830696, -0.003369197715073824, + 0.02812645211815834, -0.003204846754670143, -0.02384585328400135, + 0.016173643991351128, 0.05445251241326332, -0.030449779704213142, + 0.019453195855021477, 0.002510089660063386, -0.013842846266925335, + -0.11064565181732178, 0.017436157912015915, -0.015172596089541912, + -0.010899467393755913, -0.019371019676327705, -0.006260283291339874, + 0.022531043738126755, 0.07672955840826035, 0.009509953670203686, + 0.010451236739754677, -0.0635366439819336, 0.02775292657315731, + 0.007963558658957481, 0.008501434698700905, -0.006006286013871431, + -0.008972076699137688, 0.10791891813278198, -0.06624843925237656, + 0.012453332543373108, -0.021500114351511, 0.00781414844095707, + 0.005924110766500235, -0.05336181819438934, 0.0006275224150158465, + -0.019079670310020447, -0.021888580173254013, 0.01606905646622181, + -0.02204546146094799, -0.013730787672102451, 0.03783810883760452, + 0.06955787539482117, -0.004198423586785793, 0.002838792046532035, + 0.00573734799399972, -0.014881246723234653, 0.009076663292944431, + 0.007784266024827957, 0.01649487391114235, -0.014156606048345566, + -0.02323327027261257, 0.008352024480700493, 0.026975994929671288, + 0.008172732777893543, 0.019796838983893394, -0.009495011530816555, + -0.007067097816616297, -0.0028238508384674788, -0.04082631319761276, + 0.004952944815158844, 0.005550585221499205, 0.0071791550144553185, + 0.022822393104434013, -0.018713615834712982, -0.018907848745584488, + -0.012879150919616222, 0.044188037514686584, 0.054788682609796524, + -0.021507585421204567, 0.007433152757585049, -0.0055729965679347515, + 0.02680417336523533, -0.005162118934094906, 0.020237598568201065, + -0.01447036862373352, 0.015045597217977047, 0.008202614262700081, + 0.03884662687778473, 0.03740482032299042, 0.02749892883002758, + -0.08252666890621185, -0.020626064389944077, -0.5434120297431946, + 0.004355304408818483, 0.022000636905431747, 0.013252676464617252, + 0.06556862592697144, 0.007866442203521729, 0.005595408380031586, + 0.004317952319979668, 0.003795016324147582, -0.008150320500135422, + 0.03689682483673096, 0.001180339721031487, 0.0028238508384674788, + -0.00079187355004251, 0.027416754513978958, 0.0027342047542333603, + -0.002689381828531623, -0.0005154648097231984, 0.033213865011930466, + -0.04651883617043495, -0.02916485257446766, 0.0355297215282917, + -0.0036381359677761793, -0.013118207454681396, -0.06837005913257599, + -0.04045278578996658, -0.01098164264112711, -0.002308386145159602, + -0.041267070919275284, -0.0024577961303293705, 0.030001547187566757, + 0.019341137260198593, 0.025960005819797516, 0.03824898600578308, + -0.003966838121414185, 0.01657705195248127, -0.00017929212481249124, + 0.01197521947324276, 0.023569442331790924, 0.045973487198352814, + -0.019333666190505028, 0.02383091114461422, -0.034999314695596695, + -0.002046918496489525, 0.004452420864254236, 0.005259235389530659, + 0.00938295479863882, -0.015971940010786057, 0.011459754779934883, + -0.07136573642492294, -0.00008217555296141654, 0.003354256972670555, + 0.011960278265178204, -0.006925158202648163, 0.022015579044818878, + -0.00782161857932806, -0.005565526429563761, 0.0022785039618611336, + -0.02211269550025463, 0.027215048670768738, -0.030121076852083206, + -0.002756616333499551, -0.05776941776275635, -0.034961964935064316, + 0.05590179190039635, -0.01955031231045723, -0.051270075142383575, + -0.029695259407162666, 0.004639183636754751, -0.016539698466658592, + -0.011616635136306286, 0.015165125951170921, -0.012124629691243172, + -0.01593458652496338, -0.003697899868711829, -0.024772195145487785, + 0.039907436817884445, 0.019206669181585312, 0.0040639545768499374, + 0.03631412610411644, -0.015419123694300652, -0.03551478311419487, + 0.01601676270365715, -0.00938295479863882, -0.02476472407579422, + -0.014948480762541294, 0.05316758155822754, -0.031839292496442795, + -0.042066413909196854, -0.00469147739931941, 0.006529221311211586, + 0.005535644479095936, -0.0032870222348719835, -0.001830273657105863, + -0.0017032751347869635, -0.006387282162904739, 0.010794879868626595, + -0.020954767242074013, -0.015419123694300652, 0.011960278265178204, + -0.01377561129629612, 0.014276135712862015, -0.028201157227158546, + -0.002046918496489525, -0.00322725810110569, 0.015874823555350304, + 0.021798934787511826, -0.010705234482884407, -0.0036754885222762823, + 0.007194096688181162, 0.0313163585960865, 0.003062907140702009, + -0.015314536169171333, 0.02692370116710663, 0.042962875217199326, + 0.00938295479863882, -0.04484543949365616, 0.046578601002693176, + 0.026236414909362793, -0.018355030566453934, -0.00047811231343075633, + 0.019214140251278877, -0.00611834367737174, -0.0389288030564785, + -0.002793968887999654, -0.012931443750858307, -0.010107593610882759, + -0.0041909534484148026, 0.011840750463306904, -0.0026968521997332573, + -0.031346239149570465, 0.03468555584549904, 0.003197376150637865, + 0.023547032848000526, 0.0007246389868669212, 0.028118979185819626, + 0.007134332321584225, 0.017346512526273727, -0.01574782468378544, + 0.027827631682157516, -0.002913497155532241, 0.0016360405134037137, + -0.011198286898434162, 0.023255683481693268, -0.006745866034179926, + 0.032481756061315536, 0.018355030566453934, 0.016173643991351128, + -0.013140617869794369, -0.05315264314413071, -0.0056103491224348545, + -0.06217701733112335, -0.008479023352265358, -0.043373752385377884, + 0.02527271769940853, -0.039264973253011703, 0.048737574368715286, + -0.016517287120223045, -0.0036007834132760763, -0.008411789312958717, + -0.0382564552128315, 0.017660275101661682, 0.015703001990914345, + -0.0026072063483297825, -0.004138659685850143, -0.01969972252845764, + 0.08213820308446884, -0.03620953857898712, -0.012998678721487522, + -0.011594223789870739, 0.01292397454380989, -0.05907675623893738, + 0.009218603372573853, -0.02578071318566799, 0.020521478727459908, + 0.032758165150880814, -0.010764997452497482, 0.009315719828009605, + -0.017129868268966675, 0.0033841386903077364, -0.011280463077127934, + -0.04391910135746002, 0.025534186512231827, -0.006880335509777069, + 0.007440623361617327, -0.019468136131763458, 0.025713477283716202, + -0.012460802681744099, -0.0057672299444675446, 0.050388555973768234, + -0.0032571402844041586, 0.012251628562808037, -0.0466383621096611, + -0.005998815875500441, 0.0018078621942549944, -0.011116111651062965, + 0.004960415419191122, 0.019610077142715454, -0.006842982489615679, + -0.006566573400050402, 0.01104887668043375, 0.0034588437993079424, + 0.015486356802284718, -0.010137475095689297, -0.005094884429126978, + -0.014007197692990303, -0.01934860832989216, 0.029493553563952446, + -0.05791882425546646, 0.01922907866537571, -0.0032944928389042616, + -0.09949218481779099, -0.02040194906294346, -0.010144946165382862, + -0.022770099341869354, 0.0027192640118300915, -0.012849269434809685, + 0.05047820508480072, 0.032011114060878754, -0.008359495550394058, + -0.010578235611319542, 0.02046918496489525, 0.04862551763653755, + -0.045801665633916855, 0.03130141645669937, 0.03137611970305443, + -0.019811779260635376, 0.02223222330212593, -0.017757391557097435, + 0.01899002306163311, 0.025115838274359703, -0.009599599055945873, + 0.07309142500162125, 0.01588229462504387, 0.008404318243265152, + 0.034775201231241226, -0.027760395780205727, 0.004056484438478947, + -0.0008217555587179959, 0.005326470360159874, 0.0442926250398159, + 0.007119391579180956, -0.03139106184244156, -0.022441396489739418, + 0.008635904639959335, -0.005498291924595833, 0.00540117546916008, + 0.0027491459622979164, -0.02805921621620655, -0.033333394676446915, + -0.03194388002157211, -0.017249396070837975, 0.004758711438626051, + 0.07516822218894958, -0.009278367273509502, 0.020715711638331413, + -0.019953718408942223, 0.01878831908106804, 0.014313487336039543, + -0.022740216925740242, 0.0008740490884520113, 0.019707193598151207, + 0.01625581830739975, -0.0039967200718820095, 0.04726588353514671, + -0.0011653987457975745, -0.015590944327414036, -0.01895267143845558, + 0.02831321209669113, 0.006222930736839771, 0.04343351721763611, + -0.001942331320606172, 0.005498291924595833, -0.022822393104434013, + -0.017503393813967705, 0.00837443582713604, -0.0072239781729876995, + 0.016412699595093727, -0.008366965688765049, 0.027028288692235947, + 0.03430455923080444, 0.025145720690488815, 0.021320821717381477, + -0.09243255853652954, 0.00502764992415905, -0.07131344079971313, + 0.009778891690075397, -0.02291204035282135, -0.00046317133819684386, + -0.004325422458350658, 0.01776486076414585, -0.018743496388196945, + -0.02123117446899414, -0.02457796223461628, -0.03160770609974861, + -0.012879150919616222, -0.027640867978334427, 0.010189768858253956, + 0.06280454248189926, -0.0057224067859351635, 0.010839702561497688, + -0.02601976878941059, 0.00540117546916008, -0.006207989528775215, + 0.05945027619600296, 0.0041909534484148026, -0.02009565941989422, + 0.02253851294517517, 0.015755295753479004, -0.028597094118595123, + -0.004796063993126154, 0.03963850066065788, -0.021036941558122635, + 0.00008217555296141654, -0.0003735252539627254, 0.02180640399456024, + -0.044240329414606094, -0.1282835155725479, -0.027775337919592857, + -0.13690447807312012, 0.026587529107928276, 0.003234728705137968, + -0.00243538455106318, -0.026064591482281685, 0.04545802250504494, + -0.017085043713450432, 0.026161709800362587, -0.005035120528191328, + -0.016076527535915375, -0.020274950191378593, -0.008142850361764431, + 0.016860930249094963, -0.025332482531666756, 0.0396459698677063, + -0.047856055200099945, 0.012565389275550842, 0.0017854507314041257, + -0.010712703689932823, -0.03399079665541649, -0.009808773174881935, + 0.018810732290148735, -0.016412699595093727, -0.0073808589950203896, + 0.0021515055559575558, -0.045577552169561386 + ] + }, + "pets": { + "prompt": "Photo of cute pets", + "vector": [ + -0.018412098288536072, 0.015965646132826805, -0.006039677653461695, + -0.006294516380876303, 0.0009683871758170426, 0.0048355646431446075, + -0.01478064525872469, 0.0024400807451456785, 0.019100161269307137, + -0.009696613065898418, 0.016220485791563988, 0.0063645970076322556, + -0.07371847331523895, -0.009652016684412956, -0.012397903949022293, + 0.5433799028396606, -0.030102822929620743, -0.007033549249172211, + 0.0409589558839798, -0.03465806692838669, 0.02250226028263569, + 0.04019443690776825, 0.03446056693792343, -0.03670952096581459, + 0.011556935496628284, -0.05243943631649017, -0.019686290994286537, + 0.023438790813088417, 0.029172662645578384, 0.004740000236779451, + 0.007995565421879292, -0.03016653284430504, 0.01606758125126362, + 0.015060968697071075, 0.006772339344024658, -0.04906919598579407, + -0.004141129087656736, -0.006090645678341389, -0.016711048781871796, + 0.004548871424049139, 0.05233750119805336, -0.028446370735764503, + -0.00853709690272808, -0.039780326187610626, -0.017061451449990273, + -0.024241533130407333, 0.01281838770955801, 0.004765484016388655, + 0.025745080783963203, -0.011263871565461159, 0.061562661081552505, + 0.016252340748906136, 0.002796855056658387, -0.0019240323454141617, + 0.03179113194346428, 0.022610565647482872, -0.04005427658557892, + -0.02130451612174511, 0.0006753226043656468, -0.01755838841199875, + -0.030956534668803215, 0.019405968487262726, -0.019246693700551987, + 0.04778863117098808, -0.049668069928884506, 0.02699379250407219, + 0.0064537907019257545, 0.04073597118258476, 0.015022742561995983, + 0.01813814602792263, 0.002898790407925844, 0.044456616044044495, + -0.003644193522632122, -0.025394678115844727, -0.0014079839456826448, + -0.006358225829899311, -0.09420750290155411, 0.002554758219048381, + -0.01680024154484272, 0.008728226646780968, 0.0413985475897789, + 0.0026120967231690884, 0.019533388316631317, 0.009550080634653568, + -0.029631372541189194, 0.02370637282729149, -0.0016118548810482025, + 0.014251855202019215, -0.03925790637731552, -0.01651354879140854, + 0.027656372636556625, 0.013888711109757423, -0.004982097074389458, + 0.029771532863378525, -0.03363233804702759, 0.00021661292703356594, + -0.07534944266080856, -0.01572354882955551, 0.0008154839160852134, + -0.036212582141160965, -0.0546119399368763, 0.018373873084783554, + -0.015678953379392624, 0.03827040269970894, -0.006937984377145767, + -0.021221693605184555, -0.06097016483545303, 0.005115887615829706, + 0.003408468095585704, -0.013156048953533173, 0.002592983888462186, + -0.009314354509115219, 0.10348363220691681, -0.01737362891435623, + -0.010684113018214703, -0.00946088694036007, -0.014194516465067863, + 0.0004905645619146526, 0.010199920274317265, -0.0007772581302560866, + -0.009989677928388119, -0.02426701784133911, 0.06381798535585403, + -0.009492741897702217, 0.02280169539153576, -0.003121774410828948, + 0.0017456453060731292, 0.00788088794797659, 0.028548305854201317, + 0.02487863041460514, 0.024279760196805, 0.050165001302957535, + 0.006613065022975206, -0.007555968128144741, -0.024540970101952553, + -0.03653113171458244, -0.02502516098320484, 0.011346694082021713, + -0.007849032990634441, 0.007097258232533932, -0.0324983075261116, + -0.0029242741875350475, 0.02594895288348198, 0.0070526618510484695, + 0.004994838964194059, 0.020590970292687416, 0.021954355761408806, + 0.024916857481002808, -0.0013251613127067685, -0.00966475810855627, + 0.01769217848777771, -0.008530725724995136, -0.007262903265655041, + -0.032918792217969894, -0.00833322573453188, -0.020043065771460533, + -0.009702984243631363, 0.0010766936466097832, 0.015156532637774944, + -0.009104114025831223, -0.058128710836172104, 0.03610427677631378, + 0.005963225848972797, 0.02354072593152523, 0.03976758196949959, + 0.02101145125925541, -0.00396911334246397, -0.5477248430252075, + 0.0277455672621727, -0.005084032658487558, -0.017813226208090782, + 0.06590129435062408, 0.015819113701581955, 0.03328193724155426, + 0.029057985171675682, 0.05862564593553543, -0.004217580892145634, + 0.0317656472325325, 0.003930887207388878, -0.027325082570314407, + -0.01633516140282154, 0.013882339932024479, 0.027847502380609512, + 0.005950483959168196, -0.000700806500390172, 0.003962742164731026, + 0.03163185715675354, 0.007619677577167749, -0.018787983804941177, + -0.0214319359511137, 0.007817178033292294, -0.0603075847029686, + -0.0012805645819753408, -0.012984032742679119, -0.022565970197319984, + -0.03361322730779648, 0.014239112846553326, 0.010633145458996296, + 0.02683451771736145, 0.007785323075950146, 0.061683714389801025, + -0.021183468401432037, -0.012461613863706589, -0.021323630586266518, + -0.028860483318567276, 0.01320701651275158, -0.018214598298072815, + 0.028707580640912056, -0.042660001665353775, 0.020329760387539864, + -0.0006753226043656468, -0.010849758982658386, 0.005351613275706768, + -0.04668645188212395, -0.014258225448429585, 0.01813177578151226, + -0.04093347117304802, -0.03286782279610634, 0.017144273966550827, + -0.00764516182243824, 0.012391532771289349, 0.04016895592212677, + -0.0038990324828773737, 0.007237419486045837, -0.02127903327345848, + -0.01976911351084709, 0.008129355497658253, 0.021846048533916473, + -0.011652500368654728, -0.07947145402431488, -0.0050521777011454105, + 0.00004459677802515216, -0.022846290841698647, -0.06710540503263474, + -0.006294516380876303, -0.015405001118779182, -0.030497824773192406, + -0.013385403901338577, 0.037703387439250946, -0.032326292246580124, + -0.012041130103170872, -0.03310991823673248, -0.015303065069019794, + 0.002389112953096628, -0.03407830744981766, -0.007345725782215595, + 0.0293892752379179, -0.03459435701370239, -0.08546654134988785, + -0.006415564566850662, 0.013009516522288322, -0.04607484117150307, + -0.010849758982658386, 0.0468011312186718, -0.013308952562510967, + -0.005848548375070095, -0.010868871584534645, -0.049559760838747025, + -0.007466774433851242, 0.020801210775971413, -0.012920322827994823, + -0.00475911283865571, 0.02626113034784794, 0.020438065752387047, + 0.006396451964974403, 0.026509597897529602, 0.03451153263449669, + -0.0045934682711958885, 0.0024400807451456785, 0.011671612970530987, + -0.012251371517777443, 0.0025675001088529825, -0.010467500425875187, + 0.01026363018900156, 0.05339508131146431, 0.030045485123991966, + 0.04553968086838722, 0.025088870897889137, -0.0013633872149512172, + -0.042672742158174515, 0.015596129931509495, -0.012404275126755238, + -0.01755201630294323, -0.02296096831560135, 0.030472340062260628, + 0.029886210337281227, -0.0198200810700655, 0.04711968079209328, + 0.006218065042048693, -0.004077419172972441, -0.06715000420808792, + 0.007606935687363148, -0.00536435516551137, 0.029344677925109863, + 0.009938710369169712, 0.008581694215536118, 0.012780161574482918, + 0.02591072767972946, 0.016889436170458794, -0.04043653607368469, + -0.02471298538148403, -0.0017265323549509048, 0.003605967853218317, + 0.02171863056719303, 0.02534371055662632, -0.014455726370215416, + 0.0554911345243454, -0.01784508116543293, 0.0418381467461586, + -0.004599838983267546, 0.04076782613992691, 0.03344758227467537, + 0.04495355114340782, -0.00823766179382801, 0.011805403977632523, + -0.023285888135433197, -0.05006306618452072, 0.0018539517186582088, + -0.05221645534038544, -0.01827193610370159, 0.019278548657894135, + 0.03916871175169945, -0.002223467919975519, 0.016112178564071655, + -0.07009975612163544, -0.023763710632920265, -0.000860080705024302, + -0.011862742714583874, 0.014143547974526882, 0.024993307888507843, + -0.010008790530264378, -0.001688306569121778, -0.010633145458996296, + 0.0553446002304554, -0.007396693807095289, 0.024228790774941444, + -0.02114524319767952, -0.02173137106001377, 0.02101145125925541, + 0.023808307945728302, -0.01453854888677597, 0.00426854845136404, + -0.010798790492117405, -0.013079597614705563, -0.005001210141927004, + 0.0015991129912436008, 0.015131048858165741, -0.013920566067099571, + 0.03167008236050606, 0.00898943655192852, -0.011130081489682198, + 0.0063263713382184505, -0.02939564548432827, -0.053458791226148605, + 0.03219250217080116, 0.011875484138727188, 0.02474484033882618, + -0.04773129150271416, -0.033078063279390335, 0.04755927622318268, + 0.014825242571532726, 0.00277137104421854, -0.028102342039346695, + 0.00401371018961072, 0.039347097277641296, 0.032033227384090424, + -0.005969597026705742, -0.016711048781871796, -0.004899274557828903, + 0.02397395297884941, 0.015264839865267277, -0.02385290339589119, + 0.03400822728872299, -0.027452502399683, 0.02171863056719303, + -0.06312992423772812, 0.01647532358765602, -0.013977904804050922, + -0.05996992439031601, -0.004567984025925398, -0.00021661292703356594, + 0.010301855392754078, -0.007078145164996386, -0.024470888078212738, + 0.030676212161779404, 0.009957822971045971, -0.0411054864525795, + -0.033065322786569595, 0.035607341676950455, 0.010894355364143848, + -0.07190274447202682, -0.03331379219889641, 0.022540485486388206, + 0.008887500502169132, 0.005485403351485729, -0.01666645146906376, + -0.0017010484589263797, 0.038002822548151016, -0.028733065351843834, + -0.07052024453878403, 0.033078063279390335, -0.0019877420272678137, + -0.005663790740072727, -0.027675487101078033, 0.024407178163528442, + 0.02864387072622776, 0.009473629295825958, -0.043851371854543686, + 0.05092315003275871, 0.015398629941046238, -0.02924911305308342, + -0.023126613348722458, 0.03863992169499397, -0.00818669330328703, + 0.00558733893558383, 0.02818516455590725, -0.02622290514409542, + -0.02606363035738468, -0.011894597671926022, -0.01845669560134411, + 0.05558669567108154, -0.06443597376346588, 0.07635605335235596, + 0.010945322923362255, 0.028134196996688843, -0.016163146123290062, + -0.005517258308827877, 0.02263605035841465, 0.011773549020290375, + 0.0020896773785352707, -0.02352161332964897, 0.03303983807563782, + 0.008970323018729687, -0.025076130405068398, -0.04618314653635025, + -0.015252097509801388, -0.010958065278828144, 0.03614887222647667, + -0.018647823482751846, 0.02625476010143757, -0.03058064728975296, + 0.015080081298947334, 0.023171210661530495, -0.032587502151727676, + 0.03588129207491875, -0.019527016207575798, 0.009014920331537724, + -0.0513245165348053, 0.040130726993083954, 0.010212661698460579, + -0.07171798497438431, 0.04889081045985222, -0.018832581117749214, + 0.017915163189172745, -0.010187177918851376, -0.039359841495752335, + -0.05723040550947189, -0.022871773689985275, -0.017335403710603714, + -0.0351995974779129, -0.023725485429167747, -0.027255002409219742, + -0.01102177519351244, 0.019858308136463165, 0.02341330796480179, + 0.02624838799238205, 0.054662905633449554, -0.009282500483095646, + -0.020622823387384415, 0.04590919613838196, -0.05874669924378395, + 0.008250403217971325, 0.019450565800070763, -0.015347662381827831, + 0.01154419407248497, 0.011518710292875767, 0.013614758849143982, + 0.023158468306064606, 0.015226613730192184, -0.03371516242623329, + -0.029478468000888824, 0.018647823482751846, 0.010633145458996296, + 0.0005479032406583428, -0.025146210566163063, -0.03495113179087639, + -0.07967532426118851, 0.01184362918138504, 0.015245726332068443, + 0.006307258270680904, 0.02591709792613983, 0.023298630490899086, + 0.021533871069550514, 0.006549355108290911, -0.010798790492117405, + 0.011047258973121643, -0.019527016207575798, -0.0348237119615078, + -0.009620161727070808, -0.009913226589560509, -0.016322419047355652, + -0.015564274974167347, -0.009199677966535091, -0.023336855694651604, + -0.026057260110974312, -0.0160293560475111, -0.02277621068060398, + 0.005351613275706768, 0.022438550367951393, 0.003586854785680771, + 0.01966717839241028, -0.05842814967036247 + ] + } + } + } +} diff --git a/mobile/apps/photos/fastlane/metadata/android/id/full_description.txt b/mobile/apps/photos/fastlane/metadata/android/id/full_description.txt index 7b3deb7985..1f79440d32 100644 --- a/mobile/apps/photos/fastlane/metadata/android/id/full_description.txt +++ b/mobile/apps/photos/fastlane/metadata/android/id/full_description.txt @@ -16,7 +16,7 @@ FITUR - Collaborative albums, so you can pool together photos after a trip - Shared folders, in case you want your partner to enjoy your "Camera" clicks - Link album, yang bisa dilindungi dengan sandi -- Ability to free up space, by removing files that have been safely backed up +Kemampuan untuk membebaskan kapasitas, dengan menghilangkan files yang sudah di back-up dengan aman - Human support, because you're worth it - Descriptions, so you can caption your memories and find them easily - Editor gambar, untuk menyempurnakan fotomu @@ -33,4 +33,4 @@ HARGA Kami tidak menyediakan paket yang gratis seumur hidup, karena penting bagi kami untuk tetap berdiri dan bertahan hingga masa depan. Namun, kami menyediakan paket yang terjangkau, yang bisa kamu bagikan dengan keluargamu. Kamu bisa menemukan informasi lebih lanjut di ente.io. DUKUNGAN -We take pride in offering human support. Jika kamu adalah pelanggan berbayar, kamu bisa menghubungi team@ente.io dan menunggu balasan dari tim kami dalam 24 jam. +Kita bangga untuk menyediakan support berbasis manusia. Jika kamu adalah pelanggan berbayar, kamu bisa menghubungi team@ente.io dan menunggu balasan dari tim kami dalam 24 jam. diff --git a/mobile/apps/photos/fastlane/metadata/android/nn/full_description.txt b/mobile/apps/photos/fastlane/metadata/android/nn/full_description.txt new file mode 100644 index 0000000000..9ba4fe3143 --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/android/nn/full_description.txt @@ -0,0 +1,36 @@ +ente is a simple app to backup and share your photos and videos. + +If you've been looking for a privacy-friendly alternative to Google Photos, you've come to the right place. With ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have open-source apps across Android, iOS, web and desktop, and your photos will seamlessly sync between all of them in an end-to-end encrypted (e2ee) manner. + +ente also makes it simple to share your albums with your loved ones, even if they aren't on ente. You can share publicly viewable links, where they can view your album and collaborate by adding photos to it, even without an account or app. + +Your encrypted data is replicated to 3 different locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Collaborative albums, so you can pool together photos after a trip +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password +- Ability to free up space, by removing files that have been safely backed up +- Human support, because you're worth it +- Descriptions, so you can caption your memories and find them easily +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from Google, Apple, your hard drive and more +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +PERMISSIONS +ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md + +PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. diff --git a/mobile/apps/photos/fastlane/metadata/android/nn/short_description.txt b/mobile/apps/photos/fastlane/metadata/android/nn/short_description.txt new file mode 100644 index 0000000000..7a5fe973db --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/android/nn/short_description.txt @@ -0,0 +1 @@ +ente is an end-to-end encrypted photo storage app \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/android/nn/title.txt b/mobile/apps/photos/fastlane/metadata/android/nn/title.txt new file mode 100644 index 0000000000..3a4fed48fe --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/android/nn/title.txt @@ -0,0 +1 @@ +ente - encrypted photo storage \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/android/sv/short_description.txt b/mobile/apps/photos/fastlane/metadata/android/sv/short_description.txt index 7a5fe973db..fa42784b97 100644 --- a/mobile/apps/photos/fastlane/metadata/android/sv/short_description.txt +++ b/mobile/apps/photos/fastlane/metadata/android/sv/short_description.txt @@ -1 +1 @@ -ente is an end-to-end encrypted photo storage app \ No newline at end of file +ente är en end-to-end-krypterad fotolagringsapp \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/android/sv/title.txt b/mobile/apps/photos/fastlane/metadata/android/sv/title.txt index 3a4fed48fe..8555fdbe27 100644 --- a/mobile/apps/photos/fastlane/metadata/android/sv/title.txt +++ b/mobile/apps/photos/fastlane/metadata/android/sv/title.txt @@ -1 +1 @@ -ente - encrypted photo storage \ No newline at end of file +ente - krypterad fotolagring \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/ios/nn/description.txt b/mobile/apps/photos/fastlane/metadata/ios/nn/description.txt new file mode 100644 index 0000000000..a98a74300a --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/ios/nn/description.txt @@ -0,0 +1,33 @@ +Ente is a simple app to automatically backup and organize your photos and videos. + +If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have apps across all platforms, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner. + +Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links. + +Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password and set to expire +- Ability to free up space, by removing files that have been safely backed up +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from all major storage providers +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. + +TERMS +https://ente.io/terms diff --git a/mobile/apps/photos/fastlane/metadata/ios/nn/keywords.txt b/mobile/apps/photos/fastlane/metadata/ios/nn/keywords.txt new file mode 100644 index 0000000000..e1462baf51 --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/ios/nn/keywords.txt @@ -0,0 +1 @@ +photos,photography,family,privacy,cloud,backup,videos,photo,encryption,storage,album,alternative diff --git a/mobile/apps/photos/fastlane/metadata/ios/nn/name.txt b/mobile/apps/photos/fastlane/metadata/ios/nn/name.txt new file mode 100644 index 0000000000..3a991c4abc --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/ios/nn/name.txt @@ -0,0 +1 @@ +Ente Photos diff --git a/mobile/apps/photos/fastlane/metadata/ios/nn/subtitle.txt b/mobile/apps/photos/fastlane/metadata/ios/nn/subtitle.txt new file mode 100644 index 0000000000..958a35f1c9 --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/ios/nn/subtitle.txt @@ -0,0 +1 @@ +Encrypted photo storage diff --git a/mobile/apps/photos/fastlane/metadata/ios/sv/description.txt b/mobile/apps/photos/fastlane/metadata/ios/sv/description.txt index 3e64345d9a..c44978ba4e 100644 --- a/mobile/apps/photos/fastlane/metadata/ios/sv/description.txt +++ b/mobile/apps/photos/fastlane/metadata/ios/sv/description.txt @@ -1,33 +1,33 @@ -Ente är en enkel app för att automatiskt säkerhetskopiera och organisera dina foton och videor. +Ente är en smidig app för att automatiskt säkerhetskopiera och organisera dina foton och videor. Om du har letat efter ett integritetsvänligt alternativ för att bevara dina minnen, har du kommit rätt. Med Ente lagras de end-to-end-krypterat (e2ee). Det betyder att endast du kan se dem. -We have apps across all platforms, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner. +Vi har appar på alla plattformar och dina foton synkroniseras sömlöst mellan alla dina enheter via end-to-end-kryptering (e2ee). -Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links. +Ente gör det också enkelt att dela dina album med dina nära och kära. Du kan antingen dela dem direkt med andra Ente användare (end-to-end-krypterade), eller med publikt synliga länkar. -Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. +Din krypterade data lagras på flera platser, inklusive ett skyddsrum i Paris. Vi tar eftervärlden på allvar och gör det enkelt att se till att dina minnen överlever dig. -We are here to make the safest photos app ever, come join our journey! +Vi är här för att skapa den säkraste foto-appen någonsin, kom och häng med på vår resa! -FEATURES -- Original quality backups, because every pixel is important -- Family plans, so you can share storage with your family -- Shared folders, in case you want your partner to enjoy your "Camera" clicks -- Album links, that can be protected with a password and set to expire -- Ability to free up space, by removing files that have been safely backed up -- Image editor, to add finishing touches -- Favorite, hide and relive your memories, for they are precious -- One-click import from all major storage providers -- Dark theme, because your photos look good in it -- 2FA, 3FA, biometric auth -- and a LOT more! +FUNKTIONER +- Säkerhetskopior av originalkvalitet, eftersom varje pixel är viktig +- Familjeabonnemang, så att du kan dela lagring med din familj +- Delade mappar, om du vill att din partner ska njuta av dina "Kamera-klick" +- Albumlänkar, som kan skyddas med ett lösenord och automatiska förfallodatum +- Möjlighet att frigöra utrymme, genom att ta bort filer som redan har säkerhetskopierats +- Bildredigerare, för att lägga till en finishing touch +- Favoritmarkera, göm, och återupplev dina värdefulla minnen +- Import med ett klick från alla större lagringsleverantörer +- Mörkt tema, eftersom dina bilder ser bra ut i det +- 2FA, 3FA, biometrisk autentisering +- och MYCKET mer! -PRICING -We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. +PRISER +Vi erbjuder inte gratisabonnemang för alltid, eftersom det är viktigt för oss att vi förblir hållbara och tål tidens prövning. Istället erbjuder vi prisvärda abonnemang som du fritt kan dela med din familj. Mer information hittar du på ente.io. SUPPORT -We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. +Vi är stolta över att erbjuda support med riktiga personer. Om du är en betalande kund, kan du nå ut till team@ente.io och förvänta dig ett svar från vårt team inom 24 timmar. VILLKOR https://ente.io/terms diff --git a/mobile/apps/photos/fastlane/metadata/ios/sv/keywords.txt b/mobile/apps/photos/fastlane/metadata/ios/sv/keywords.txt index 234eb04e17..42a5f0277d 100644 --- a/mobile/apps/photos/fastlane/metadata/ios/sv/keywords.txt +++ b/mobile/apps/photos/fastlane/metadata/ios/sv/keywords.txt @@ -1 +1 @@ -foto, fotografi, familj, integritet, moln, säkerhetskopia, videor, foto, kryptering, lagring, album, alternativ +foton, fotografi, familj, integritet, moln, säkerhetskopia, videor, foto, kryptering, lagring, album, alternativ diff --git a/mobile/apps/photos/fastlane/metadata/playstore/nn/full_description.txt b/mobile/apps/photos/fastlane/metadata/playstore/nn/full_description.txt new file mode 100644 index 0000000000..ec999a783c --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/playstore/nn/full_description.txt @@ -0,0 +1,30 @@ +Ente is a simple app to automatically backup and organize your photos and videos. + +If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them. + +We have apps across Android, iOS, web and Desktop, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner. + +Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links. + +Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you. + +We are here to make the safest photos app ever, come join our journey! + +✨ FEATURES +- Original quality backups, because every pixel is important +- Family plans, so you can share storage with your family +- Shared folders, in case you want your partner to enjoy your "Camera" clicks +- Album links, that can be protected with a password and set to expire +- Ability to free up space, by removing files that have been safely backed up +- Image editor, to add finishing touches +- Favorite, hide and relive your memories, for they are precious +- One-click import from Google, Apple, your hard drive and more +- Dark theme, because your photos look good in it +- 2FA, 3FA, biometric auth +- and a LOT more! + +💲 PRICING +We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io. + +🙋 SUPPORT +We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours. \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/playstore/nn/short_description.txt b/mobile/apps/photos/fastlane/metadata/playstore/nn/short_description.txt new file mode 100644 index 0000000000..6c00229894 --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/playstore/nn/short_description.txt @@ -0,0 +1 @@ +Encrypted photo storage - backup, organize and share your photos and videos \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/playstore/nn/title.txt b/mobile/apps/photos/fastlane/metadata/playstore/nn/title.txt new file mode 100644 index 0000000000..97fdef3be7 --- /dev/null +++ b/mobile/apps/photos/fastlane/metadata/playstore/nn/title.txt @@ -0,0 +1 @@ +Ente Photos \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/playstore/sv/short_description.txt b/mobile/apps/photos/fastlane/metadata/playstore/sv/short_description.txt index 6c00229894..69e11293d5 100644 --- a/mobile/apps/photos/fastlane/metadata/playstore/sv/short_description.txt +++ b/mobile/apps/photos/fastlane/metadata/playstore/sv/short_description.txt @@ -1 +1 @@ -Encrypted photo storage - backup, organize and share your photos and videos \ No newline at end of file +Krypterad lagring av foton - säkerhetskopiera, organisera och dela dina foton och videor \ No newline at end of file diff --git a/mobile/apps/photos/fastlane/metadata/playstore/sv/title.txt b/mobile/apps/photos/fastlane/metadata/playstore/sv/title.txt index 97fdef3be7..5101b0c2c8 100644 --- a/mobile/apps/photos/fastlane/metadata/playstore/sv/title.txt +++ b/mobile/apps/photos/fastlane/metadata/playstore/sv/title.txt @@ -1 +1 @@ -Ente Photos \ No newline at end of file +Ente Foton \ No newline at end of file diff --git a/mobile/apps/photos/flutter_rust_bridge.yaml b/mobile/apps/photos/flutter_rust_bridge.yaml new file mode 100644 index 0000000000..fde31a2f2b --- /dev/null +++ b/mobile/apps/photos/flutter_rust_bridge.yaml @@ -0,0 +1,8 @@ +rust_input: crate::api +rust_root: rust/ +dart_output: lib/src/rust + +dart_preamble: | + // ignore_for_file: require_trailing_commas + +web: false \ No newline at end of file diff --git a/mobile/apps/photos/integration_test/app_init_test.dart b/mobile/apps/photos/integration_test/app_init_test.dart index e3313670c9..3d5160ee16 100644 --- a/mobile/apps/photos/integration_test/app_init_test.dart +++ b/mobile/apps/photos/integration_test/app_init_test.dart @@ -91,10 +91,9 @@ Future dismissUpdateAppDialog(WidgetTester tester) async { await tester.pumpAndSettle(); } - ///Use this widget as floating action buttom in HomeWidget so that frames -///are built and rendered continuously so that timeline trace has continuous -///data. Change the duraiton in `_startTimer()` to control the duraiton of +///are built and rendered continuously so that timeline trace has continuous +///data. Change the duraiton in `_startTimer()` to control the duraiton of ///test on app init. // class TempWidget extends StatefulWidget { @@ -127,4 +126,4 @@ Future dismissUpdateAppDialog(WidgetTester tester) async { // ? const CircularProgressIndicator() // : const SizedBox.shrink(); // } -// } \ No newline at end of file +// } diff --git a/mobile/apps/photos/integration_test/simple_test.dart b/mobile/apps/photos/integration_test/simple_test.dart new file mode 100644 index 0000000000..d55a2badac --- /dev/null +++ b/mobile/apps/photos/integration_test/simple_test.dart @@ -0,0 +1,13 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import "package:photos/src/rust/api/simple.dart"; +import 'package:photos/src/rust/frb_generated.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + setUpAll(() async => await RustLib.init()); + testWidgets('Can call rust function', (WidgetTester tester) async { + final testString = greet(name: "Tom"); + expect(testString.contains('Tom'), true); + }); +} diff --git a/mobile/apps/photos/ios/Podfile.lock b/mobile/apps/photos/ios/Podfile.lock index 785d7a3a52..a152ef181c 100644 --- a/mobile/apps/photos/ios/Podfile.lock +++ b/mobile/apps/photos/ios/Podfile.lock @@ -284,6 +284,7 @@ DEPENDENCIES: - photo_manager (from `.symlinks/plugins/photo_manager/ios`) - privacy_screen (from `.symlinks/plugins/privacy_screen/ios`) - receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`) + - rust_lib_photos (from `.symlinks/plugins/rust_lib_photos/ios`) - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) @@ -407,6 +408,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/privacy_screen/ios" receive_sharing_intent: :path: ".symlinks/plugins/receive_sharing_intent/ios" + rust_lib_photos: + :path: ".symlinks/plugins/rust_lib_photos/ios" sentry_flutter: :path: ".symlinks/plugins/sentry_flutter/ios" share_plus: diff --git a/mobile/apps/photos/ios/Runner.xcodeproj/project.pbxproj b/mobile/apps/photos/ios/Runner.xcodeproj/project.pbxproj index 46e7b2624c..56ba9d2b02 100644 --- a/mobile/apps/photos/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/apps/photos/ios/Runner.xcodeproj/project.pbxproj @@ -564,6 +564,7 @@ "${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework", "${BUILT_PRODUCTS_DIR}/privacy_screen/privacy_screen.framework", "${BUILT_PRODUCTS_DIR}/receive_sharing_intent/receive_sharing_intent.framework", + "${BUILT_PRODUCTS_DIR}/rust_lib_photos/rust_lib_photos.framework", "${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework", "${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", @@ -658,6 +659,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/privacy_screen.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/receive_sharing_intent.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/rust_lib_photos.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", diff --git a/mobile/apps/photos/lib/core/cache/image_cache.dart b/mobile/apps/photos/lib/core/cache/image_cache.dart index c489b019cd..7bcdfab60e 100644 --- a/mobile/apps/photos/lib/core/cache/image_cache.dart +++ b/mobile/apps/photos/lib/core/cache/image_cache.dart @@ -1,4 +1,3 @@ - import "dart:io"; import 'package:photos/core/cache/lru_map.dart'; diff --git a/mobile/apps/photos/lib/core/cache/lru_map.dart b/mobile/apps/photos/lib/core/cache/lru_map.dart index 9e28c84c09..d3760d5809 100644 --- a/mobile/apps/photos/lib/core/cache/lru_map.dart +++ b/mobile/apps/photos/lib/core/cache/lru_map.dart @@ -24,7 +24,7 @@ class LRUMap { final K evictedKey = _map.keys.first; final V? evictedValue = _map.remove(evictedKey); if (_handler != null) { - _handler!(evictedKey, evictedValue); + _handler(evictedKey, evictedValue); } } } diff --git a/mobile/apps/photos/lib/core/errors.dart b/mobile/apps/photos/lib/core/errors.dart index 0c0d16949a..f2bfad2f6d 100644 --- a/mobile/apps/photos/lib/core/errors.dart +++ b/mobile/apps/photos/lib/core/errors.dart @@ -58,7 +58,7 @@ bool isHandledSyncError(Object errObj) { class LockAlreadyAcquiredError extends Error {} -class LockFreedError extends Error{} +class LockFreedError extends Error {} class UnauthorizedError extends Error {} diff --git a/mobile/apps/photos/lib/db/ml/clip_vector_db.dart b/mobile/apps/photos/lib/db/ml/clip_vector_db.dart new file mode 100644 index 0000000000..348cd40b6d --- /dev/null +++ b/mobile/apps/photos/lib/db/ml/clip_vector_db.dart @@ -0,0 +1,311 @@ +import "dart:io" show File; +import "dart:typed_data" show Float32List; + +import "package:flutter_rust_bridge/flutter_rust_bridge.dart" show Uint64List; +import "package:logging/logging.dart"; +import "package:path/path.dart"; +import "package:path_provider/path_provider.dart"; +import "package:photos/models/ml/vector.dart"; +import "package:photos/services/machine_learning/semantic_search/query_result.dart"; +import "package:photos/src/rust/api/usearch_api.dart"; + +class ClipVectorDB { + static final Logger _logger = Logger("ClipVectorDB"); + + static const _databaseName = "ente.ml.vectordb.clip"; + + static final BigInt _embeddingDimension = BigInt.from(512); + + static Logger get logger => _logger; + + // Singleton pattern + ClipVectorDB._privateConstructor(); + static final instance = ClipVectorDB._privateConstructor(); + factory ClipVectorDB() => instance; + + // only have a single app-wide reference to the database + static Future? _vectorDbFuture; + + Future get _vectorDB async { + _vectorDbFuture ??= _initVectorDB(); + return _vectorDbFuture!; + } + + bool? _migrationDone; + + Future _initVectorDB() async { + final documentsDirectory = await getApplicationDocumentsDirectory(); + final String databaseDirectory = + join(documentsDirectory.path, _databaseName); + _logger.info("Opening vectorDB access: DB path " + databaseDirectory); + final vectorDB = VectorDb( + filePath: databaseDirectory, + dimensions: _embeddingDimension, + ); + final stats = await getIndexStats(vectorDB); + _logger.info("VectorDB connection opened with stats: ${stats.toString()}"); + + return vectorDB; + } + + Future checkIfMigrationDone() async { + if (_migrationDone != null) return _migrationDone!; + _logger.info("Checking if ClipVectorDB migration has run"); + final documentsDirectory = await getApplicationDocumentsDirectory(); + final migrationFlagFile = + File(join(documentsDirectory.path, 'clip_vector_migration_done')); + if (await migrationFlagFile.exists()) { + _logger.info("ClipVectorDB migration already done"); + _migrationDone = true; + return _migrationDone!; + } else { + _logger.info("ClipVectorDB migration not done"); + _migrationDone = false; + return _migrationDone!; + } + } + + Future setMigrationDone() async { + _logger.info("Setting ClipVectorDB migration done"); + final documentsDirectory = await getApplicationDocumentsDirectory(); + final migrationFlagFile = + File(join(documentsDirectory.path, 'clip_vector_migration_done')); + await migrationFlagFile.create(recursive: true); + _migrationDone = true; + } + + Future insertEmbedding({ + required int fileID, + required List embedding, + }) async { + final db = await _vectorDB; + try { + await db.addVector(key: BigInt.from(fileID), vector: embedding); + } catch (e, s) { + _logger.severe("Error inserting embedding", e, s); + rethrow; + } + } + + Future bulkInsertEmbeddings({ + required List fileIDs, + required List embeddings, + }) async { + final db = await _vectorDB; + final bigKeys = Uint64List.fromList(fileIDs); + try { + await db.bulkAddVectors(keys: bigKeys, vectors: embeddings); + } catch (e, s) { + _logger.severe("Error bulk inserting embeddings", e, s); + rethrow; + } + } + + Future> getEmbeddings(List fileIDs) async { + final db = await _vectorDB; + try { + final keys = Uint64List.fromList(fileIDs); + final vectors = await db.bulkGetVectors(keys: keys); + return List.generate( + vectors.length, + (index) => EmbeddingVector( + fileID: fileIDs[index], + embedding: vectors[index], + ), + ); + } catch (e, s) { + _logger.severe("Error getting embeddings", e, s); + rethrow; + } + } + + Future deleteEmbeddings(List fileIDs) async { + final db = await _vectorDB; + try { + final deletedCount = + await db.bulkRemoveVectors(keys: Uint64List.fromList(fileIDs)); + _logger.info( + "Deleted $deletedCount embeddings, from ${fileIDs.length} keys", + ); + } catch (e, s) { + _logger.severe("Error bulk deleting specific embeddings", e, s); + rethrow; + } + } + + Future deleteAllEmbeddings() async { + final db = await _vectorDB; + try { + await db.resetIndex(); + } catch (e, s) { + _logger.severe("Error deleting all embeddings", e, s); + rethrow; + } + } + + Future deleteIndex() async { + final db = await _vectorDB; + try { + await db.deleteIndex(); + _vectorDbFuture = null; + } catch (e, s) { + _logger.severe("Error deleting index", e, s); + rethrow; + } + } + + Future getIndexStats([VectorDb? db]) async { + db ??= await _vectorDB; + try { + final stats = await db.getIndexStats(); + return VectorDbStats( + size: stats.$1.toInt(), + capacity: stats.$2.toInt(), + dimensions: stats.$3.toInt(), + fileSize: stats.$4.toInt(), + memoryUsage: stats.$5.toInt(), + expansionAdd: stats.$6.toInt(), + expansionSearch: stats.$7.toInt(), + ); + } catch (e, s) { + _logger.severe("Error getting index stats", e, s); + rethrow; + } + } + + Future<(Uint64List, Float32List)> searchClosestVectors( + List query, + int count, { + bool exact = false, + }) async { + final db = await _vectorDB; + try { + final result = await db.searchVectors( + query: query, + count: BigInt.from(count), + exact: exact, + ); + return result; + } catch (e, s) { + _logger.severe("Error searching closest vectors", e, s); + rethrow; + } + } + + Future<(BigInt, double)> searchClosestVector( + List query, { + bool exact = false, + }) async { + final db = await _vectorDB; + try { + final result = + await db.searchVectors(query: query, count: BigInt.one, exact: exact); + return (result.$1[0], result.$2[0]); + } catch (e, s) { + _logger.severe("Error searching closest vector", e, s); + rethrow; + } + } + + Future<(List, List)> bulkSearchVectors( + List queries, + BigInt count, { + bool exact = false, + }) async { + final db = await _vectorDB; + try { + final result = await db.bulkSearchVectors( + queries: queries, + count: count, + exact: exact, + ); + return result; + } catch (e, s) { + _logger.severe("Error bulk searching vectors", e, s); + rethrow; + } + } + + Future<(Uint64List, List, List)> bulkSearchWithKeys( + Uint64List potentialKeys, + BigInt count, { + bool exact = false, + }) async { + final db = await _vectorDB; + try { + final result = await db.bulkSearchKeys( + potentialKeys: potentialKeys, + count: count, + exact: exact, + ); + return result; + } catch (e, s) { + _logger.severe("Error bulk searching vectors with potential keys", e, s); + rethrow; + } + } + + Future>> computeBulkSimilarities( + Map> textQueryToEmbeddingMap, + Map minimumSimilarityMap, + ) async { + try { + final queryToResults = >{}; + for (final MapEntry> entry + in textQueryToEmbeddingMap.entries) { + final query = entry.key; + final minimumSimilarity = minimumSimilarityMap[query]!; + final textEmbedding = entry.value; + final (potentialFileIDs, distances) = + await searchClosestVectors(textEmbedding, 1000); + final queryResults = []; + for (var i = 0; i < potentialFileIDs.length; i++) { + final similarity = 1 - distances[i]; + if (similarity >= minimumSimilarity) { + queryResults + .add(QueryResult(potentialFileIDs[i].toInt(), similarity)); + } else { + break; + } + } + queryToResults[query] = queryResults; + } + return queryToResults; + } catch (e, s) { + _logger.severe( + "Could not bulk find embeddings similarities using vector DB", + e, + s, + ); + rethrow; + } + } +} + +class VectorDbStats { + final int size; + final int capacity; + final int dimensions; + + // in bytes + final int fileSize; + final int memoryUsage; + + final int expansionAdd; + final int expansionSearch; + + VectorDbStats({ + required this.size, + required this.capacity, + required this.dimensions, + required this.fileSize, + required this.memoryUsage, + required this.expansionAdd, + required this.expansionSearch, + }); + + @override + String toString() { + return "VectorDbStats(size: $size, capacity: $capacity, dimensions: $dimensions, file size on disk (bytes): $fileSize, memory usage (bytes): $memoryUsage, expansionAdd: $expansionAdd, expansionSearch: $expansionSearch)"; + } +} diff --git a/mobile/apps/photos/lib/db/ml/db.dart b/mobile/apps/photos/lib/db/ml/db.dart index 6bd7bd3c31..c29e004706 100644 --- a/mobile/apps/photos/lib/db/ml/db.dart +++ b/mobile/apps/photos/lib/db/ml/db.dart @@ -9,6 +9,7 @@ import 'package:path_provider/path_provider.dart'; import "package:photos/core/event_bus.dart"; import "package:photos/db/common/base.dart"; import "package:photos/db/ml/base.dart"; +import "package:photos/db/ml/clip_vector_db.dart"; import "package:photos/db/ml/db_model_mappers.dart"; import 'package:photos/db/ml/schema.dart'; import "package:photos/events/embedding_updated_event.dart"; @@ -18,6 +19,7 @@ import "package:photos/models/ml/face/face.dart"; import "package:photos/models/ml/face/face_with_embedding.dart"; import "package:photos/models/ml/ml_versions.dart"; import "package:photos/models/ml/vector.dart"; +import "package:photos/service_locator.dart"; import "package:photos/services/machine_learning/face_ml/face_clustering/face_db_info_for_clustering.dart"; import 'package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart'; import "package:photos/services/machine_learning/ml_result.dart"; @@ -1253,6 +1255,111 @@ class MLDataDB with SqlDbBase implements IMLDataDB { return embeddings; } + Future checkMigrateFillClipVectorDB({bool force = false}) async { + final migrationDone = await ClipVectorDB.instance.checkIfMigrationDone(); + if (migrationDone && !force) { + _logger.info("ClipVectorDB migration not needed, already done"); + return; + } + _logger.info("Starting ClipVectorDB migration"); + + // Get total count first to track progress + _logger.info("Getting total count of clip embeddings"); + final db = await instance.asyncDB; + final countResult = + await db.getAll('SELECT COUNT($fileIDColumn) as total FROM $clipTable'); + final totalCount = countResult.first['total'] as int; + if (totalCount == 0) { + _logger.info("No clip embeddings to migrate"); + await ClipVectorDB.instance.setMigrationDone(); + return; + } + _logger.info("Total count of clip embeddings: $totalCount"); + + _logger.info("First time referencing ClipVectorDB rust index in migration"); + final clipVectorDB = ClipVectorDB.instance; + await clipVectorDB.deleteAllEmbeddings(); + _logger.info("ClipVectorDB rust index referenced"); + _logger.info("ClipVectorDB all embeddings cleared"); + + _logger + .info("Starting migration of $totalCount clip embeddings to vector DB"); + const batchSize = 5000; + int offset = 0; + int processedCount = 0; + int weirdCount = 0; + int whileCount = 0; + final stopwatch = Stopwatch()..start(); + try { + while (true) { + whileCount++; + _logger.info("$whileCount st round of while loop"); + // Allow some time for any GC to finish + await Future.delayed(const Duration(milliseconds: 100)); + + _logger.info("Reading $batchSize rows from DB"); + final List> results = await db.getAll(''' + SELECT $fileIDColumn, $embeddingColumn + FROM $clipTable + ORDER BY $fileIDColumn DESC + LIMIT $batchSize OFFSET $offset + '''); + _logger.info("Got ${results.length} results from DB"); + if (results.isEmpty) { + _logger.info("No more results, breaking out of while loop"); + break; + } + _logger.info("Processing ${results.length} results"); + final List fileIDs = []; + final List embeddings = []; + for (final result in results) { + final embedding = + Float32List.view((result[embeddingColumn] as Uint8List).buffer); + if (embedding.length == 512) { + fileIDs.add(result[fileIDColumn] as int); + embeddings.add(Float32List.view(result[embeddingColumn].buffer)); + } else { + weirdCount++; + } + } + _logger.info( + "Got ${fileIDs.length} valid embeddings, $weirdCount weird embeddings", + ); + + await ClipVectorDB.instance + .bulkInsertEmbeddings(fileIDs: fileIDs, embeddings: embeddings); + _logger.info("Inserted ${fileIDs.length} embeddings to ClipVectorDB"); + processedCount += fileIDs.length; + offset += batchSize; + _logger.info( + "migrated $processedCount/$totalCount embeddings to ClipVectorDB", + ); + if (processedCount >= totalCount) { + _logger.info("All embeddings migrated, breaking out of while loop"); + break; + } + // Allow some time for any GC to finish + _logger.info("Waiting for 100ms out of precaution, for GC to finish"); + await Future.delayed(const Duration(milliseconds: 100)); + } + _logger.info( + "migrated all $totalCount embeddings to ClipVectorDB in ${stopwatch.elapsed.inMilliseconds} ms, with $weirdCount weird embeddings not migrated", + ); + await ClipVectorDB.instance.setMigrationDone(); + _logger.info("ClipVectorDB migration done, flag file created"); + } catch (e, s) { + _logger.severe( + "Error migrating ClipVectorDB after ${stopwatch.elapsed.inMilliseconds} ms, clearing out DB again", + e, + s, + ); + await clipVectorDB.deleteAllEmbeddings(); + rethrow; + } finally { + stopwatch.stop(); + } + } + // Get indexed FileIDs @override Future> clipIndexedFileWithVersion() async { @@ -1286,12 +1393,27 @@ class MLDataDB with SqlDbBase implements IMLDataDB { 'INSERT OR REPLACE INTO $clipTable ($fileIDColumn, $embeddingColumn, $mlVersionColumn) VALUES (?, ?, ?)', _getRowFromEmbedding(embeddings.first), ); + if (flagService.enableVectorDb && + await ClipVectorDB.instance.checkIfMigrationDone()) { + await ClipVectorDB.instance.insertEmbedding( + fileID: embeddings.first.fileID, + embedding: embeddings.first.embedding, + ); + } } else { final inputs = embeddings.map((e) => _getRowFromEmbedding(e)).toList(); await db.executeBatch( 'INSERT OR REPLACE INTO $clipTable ($fileIDColumn, $embeddingColumn, $mlVersionColumn) values(?, ?, ?)', inputs, ); + if (flagService.enableVectorDb && + await ClipVectorDB.instance.checkIfMigrationDone()) { + await ClipVectorDB.instance.bulkInsertEmbeddings( + fileIDs: embeddings.map((e) => e.fileID).toList(), + embeddings: + embeddings.map((e) => Float32List.fromList(e.embedding)).toList(), + ); + } } Bus.instance.fire(EmbeddingUpdatedEvent()); } @@ -1302,6 +1424,10 @@ class MLDataDB with SqlDbBase implements IMLDataDB { await db.execute( 'DELETE FROM $clipTable WHERE $fileIDColumn IN (${fileIDs.join(", ")})', ); + if (flagService.enableVectorDb && + await ClipVectorDB.instance.checkIfMigrationDone()) { + await ClipVectorDB.instance.deleteEmbeddings(fileIDs); + } Bus.instance.fire(EmbeddingUpdatedEvent()); } @@ -1309,6 +1435,10 @@ class MLDataDB with SqlDbBase implements IMLDataDB { Future deleteClipIndexes() async { final db = await instance.asyncDB; await db.execute('DELETE FROM $clipTable'); + if (flagService.enableVectorDb && + await ClipVectorDB.instance.checkIfMigrationDone()) { + await ClipVectorDB.instance.deleteAllEmbeddings(); + } Bus.instance.fire(EmbeddingUpdatedEvent()); } diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/box.pb.dart b/mobile/apps/photos/lib/generated/protos/ente/common/box.pb.dart index 41518e9ae0..526c489137 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/box.pb.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/box.pb.dart @@ -37,27 +37,32 @@ class CenterBox extends $pb.GeneratedMessage { return $result; } CenterBox._() : super(); - factory CenterBox.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory CenterBox.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory CenterBox.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory CenterBox.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CenterBox', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), createEmptyInstance: create) + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'CenterBox', + package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), + createEmptyInstance: create) ..a<$core.double>(1, _omitFieldNames ? '' : 'x', $pb.PbFieldType.OF) ..a<$core.double>(2, _omitFieldNames ? '' : 'y', $pb.PbFieldType.OF) ..a<$core.double>(3, _omitFieldNames ? '' : 'height', $pb.PbFieldType.OF) ..a<$core.double>(4, _omitFieldNames ? '' : 'width', $pb.PbFieldType.OF) - ..hasRequiredFields = false - ; + ..hasRequiredFields = false; - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') CenterBox clone() => CenterBox()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CenterBox copyWith(void Function(CenterBox) updates) => super.copyWith((message) => updates(message as CenterBox)) as CenterBox; + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CenterBox copyWith(void Function(CenterBox) updates) => + super.copyWith((message) => updates(message as CenterBox)) as CenterBox; $pb.BuilderInfo get info_ => _i; @@ -66,13 +71,17 @@ class CenterBox extends $pb.GeneratedMessage { CenterBox createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static CenterBox getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CenterBox getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static CenterBox? _defaultInstance; @$pb.TagNumber(1) $core.double get x => $_getN(0); @$pb.TagNumber(1) - set x($core.double v) { $_setFloat(0, v); } + set x($core.double v) { + $_setFloat(0, v); + } + @$pb.TagNumber(1) $core.bool hasX() => $_has(0); @$pb.TagNumber(1) @@ -81,7 +90,10 @@ class CenterBox extends $pb.GeneratedMessage { @$pb.TagNumber(2) $core.double get y => $_getN(1); @$pb.TagNumber(2) - set y($core.double v) { $_setFloat(1, v); } + set y($core.double v) { + $_setFloat(1, v); + } + @$pb.TagNumber(2) $core.bool hasY() => $_has(1); @$pb.TagNumber(2) @@ -90,7 +102,10 @@ class CenterBox extends $pb.GeneratedMessage { @$pb.TagNumber(3) $core.double get height => $_getN(2); @$pb.TagNumber(3) - set height($core.double v) { $_setFloat(2, v); } + set height($core.double v) { + $_setFloat(2, v); + } + @$pb.TagNumber(3) $core.bool hasHeight() => $_has(2); @$pb.TagNumber(3) @@ -99,13 +114,16 @@ class CenterBox extends $pb.GeneratedMessage { @$pb.TagNumber(4) $core.double get width => $_getN(3); @$pb.TagNumber(4) - set width($core.double v) { $_setFloat(3, v); } + set width($core.double v) { + $_setFloat(3, v); + } + @$pb.TagNumber(4) $core.bool hasWidth() => $_has(3); @$pb.TagNumber(4) void clearWidth() => clearField(4); } - const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); +const _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/box.pbenum.dart b/mobile/apps/photos/lib/generated/protos/ente/common/box.pbenum.dart index 7310e57a03..4148fda29e 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/box.pbenum.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/box.pbenum.dart @@ -8,4 +8,3 @@ // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import - diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/box.pbjson.dart b/mobile/apps/photos/lib/generated/protos/ente/common/box.pbjson.dart index 6c9ab3cb27..4c4a41442f 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/box.pbjson.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/box.pbjson.dart @@ -35,4 +35,3 @@ final $typed_data.Uint8List centerBoxDescriptor = $convert.base64Decode( 'CglDZW50ZXJCb3gSEQoBeBgBIAEoAkgAUgF4iAEBEhEKAXkYAiABKAJIAVIBeYgBARIbCgZoZW' 'lnaHQYAyABKAJIAlIGaGVpZ2h0iAEBEhkKBXdpZHRoGAQgASgCSANSBXdpZHRoiAEBQgQKAl94' 'QgQKAl95QgkKB19oZWlnaHRCCAoGX3dpZHRo'); - diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/box.pbserver.dart b/mobile/apps/photos/lib/generated/protos/ente/common/box.pbserver.dart index 1e8625388d..79d3c2c86f 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/box.pbserver.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/box.pbserver.dart @@ -11,4 +11,3 @@ // ignore_for_file: unnecessary_import, unnecessary_this, unused_import export 'box.pb.dart'; - diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/point.pb.dart b/mobile/apps/photos/lib/generated/protos/ente/common/point.pb.dart index 47f9b87ce3..be82db12db 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/point.pb.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/point.pb.dart @@ -29,25 +29,30 @@ class EPoint extends $pb.GeneratedMessage { return $result; } EPoint._() : super(); - factory EPoint.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory EPoint.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory EPoint.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory EPoint.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EPoint', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), createEmptyInstance: create) + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'EPoint', + package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), + createEmptyInstance: create) ..a<$core.double>(1, _omitFieldNames ? '' : 'x', $pb.PbFieldType.OF) ..a<$core.double>(2, _omitFieldNames ? '' : 'y', $pb.PbFieldType.OF) - ..hasRequiredFields = false - ; + ..hasRequiredFields = false; - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') EPoint clone() => EPoint()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - EPoint copyWith(void Function(EPoint) updates) => super.copyWith((message) => updates(message as EPoint)) as EPoint; + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + EPoint copyWith(void Function(EPoint) updates) => + super.copyWith((message) => updates(message as EPoint)) as EPoint; $pb.BuilderInfo get info_ => _i; @@ -56,13 +61,17 @@ class EPoint extends $pb.GeneratedMessage { EPoint createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static EPoint getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static EPoint getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static EPoint? _defaultInstance; @$pb.TagNumber(1) $core.double get x => $_getN(0); @$pb.TagNumber(1) - set x($core.double v) { $_setFloat(0, v); } + set x($core.double v) { + $_setFloat(0, v); + } + @$pb.TagNumber(1) $core.bool hasX() => $_has(0); @$pb.TagNumber(1) @@ -71,13 +80,16 @@ class EPoint extends $pb.GeneratedMessage { @$pb.TagNumber(2) $core.double get y => $_getN(1); @$pb.TagNumber(2) - set y($core.double v) { $_setFloat(1, v); } + set y($core.double v) { + $_setFloat(1, v); + } + @$pb.TagNumber(2) $core.bool hasY() => $_has(1); @$pb.TagNumber(2) void clearY() => clearField(2); } - const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); +const _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/point.pbenum.dart b/mobile/apps/photos/lib/generated/protos/ente/common/point.pbenum.dart index 3c242a2fcd..8de70fe0e7 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/point.pbenum.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/point.pbenum.dart @@ -8,4 +8,3 @@ // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import - diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/point.pbjson.dart b/mobile/apps/photos/lib/generated/protos/ente/common/point.pbjson.dart index 44d2d0712a..aeb17b4a2c 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/point.pbjson.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/point.pbjson.dart @@ -30,4 +30,3 @@ const EPoint$json = { final $typed_data.Uint8List ePointDescriptor = $convert.base64Decode( 'CgZFUG9pbnQSEQoBeBgBIAEoAkgAUgF4iAEBEhEKAXkYAiABKAJIAVIBeYgBAUIECgJfeEIECg' 'JfeQ=='); - diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/point.pbserver.dart b/mobile/apps/photos/lib/generated/protos/ente/common/point.pbserver.dart index 66728e123a..490cae6a97 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/point.pbserver.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/point.pbserver.dart @@ -11,4 +11,3 @@ // ignore_for_file: unnecessary_import, unnecessary_this, unused_import export 'point.pb.dart'; - diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pb.dart b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pb.dart index 44aa7d7485..1b66675202 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pb.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pb.dart @@ -26,24 +26,29 @@ class EVector extends $pb.GeneratedMessage { return $result; } EVector._() : super(); - factory EVector.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory EVector.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory EVector.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory EVector.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EVector', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), createEmptyInstance: create) + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'EVector', + package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.common'), + createEmptyInstance: create) ..p<$core.double>(1, _omitFieldNames ? '' : 'values', $pb.PbFieldType.KD) - ..hasRequiredFields = false - ; + ..hasRequiredFields = false; - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') EVector clone() => EVector()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - EVector copyWith(void Function(EVector) updates) => super.copyWith((message) => updates(message as EVector)) as EVector; + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + EVector copyWith(void Function(EVector) updates) => + super.copyWith((message) => updates(message as EVector)) as EVector; $pb.BuilderInfo get info_ => _i; @@ -52,13 +57,14 @@ class EVector extends $pb.GeneratedMessage { EVector createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static EVector getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static EVector getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static EVector? _defaultInstance; @$pb.TagNumber(1) $core.List<$core.double> get values => $_getList(0); } - const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); +const _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbenum.dart b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbenum.dart index c88d2648a1..e0d964fe0f 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbenum.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbenum.dart @@ -8,4 +8,3 @@ // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import - diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbjson.dart b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbjson.dart index 1aff5cb290..8afe4568e0 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbjson.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbjson.dart @@ -22,6 +22,5 @@ const EVector$json = { }; /// Descriptor for `EVector`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List eVectorDescriptor = $convert.base64Decode( - 'CgdFVmVjdG9yEhYKBnZhbHVlcxgBIAMoAVIGdmFsdWVz'); - +final $typed_data.Uint8List eVectorDescriptor = + $convert.base64Decode('CgdFVmVjdG9yEhYKBnZhbHVlcxgBIAMoAVIGdmFsdWVz'); diff --git a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbserver.dart b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbserver.dart index dbf5ac36fa..2ffc744d6c 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbserver.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/common/vector.pbserver.dart @@ -11,4 +11,3 @@ // ignore_for_file: unnecessary_import, unnecessary_this, unused_import export 'vector.pb.dart'; - diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pb.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pb.dart index 55d512b664..050bcf1955 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pb.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pb.dart @@ -31,25 +31,32 @@ class Detection extends $pb.GeneratedMessage { return $result; } Detection._() : super(); - factory Detection.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory Detection.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory Detection.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory Detection.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Detection', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create) - ..aOM<$0.CenterBox>(1, _omitFieldNames ? '' : 'box', subBuilder: $0.CenterBox.create) - ..aOM<$1.EPoint>(2, _omitFieldNames ? '' : 'landmarks', subBuilder: $1.EPoint.create) - ..hasRequiredFields = false - ; + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'Detection', + package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), + createEmptyInstance: create) + ..aOM<$0.CenterBox>(1, _omitFieldNames ? '' : 'box', + subBuilder: $0.CenterBox.create) + ..aOM<$1.EPoint>(2, _omitFieldNames ? '' : 'landmarks', + subBuilder: $1.EPoint.create) + ..hasRequiredFields = false; - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') Detection clone() => Detection()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - Detection copyWith(void Function(Detection) updates) => super.copyWith((message) => updates(message as Detection)) as Detection; + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Detection copyWith(void Function(Detection) updates) => + super.copyWith((message) => updates(message as Detection)) as Detection; $pb.BuilderInfo get info_ => _i; @@ -58,13 +65,17 @@ class Detection extends $pb.GeneratedMessage { Detection createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static Detection getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Detection getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Detection? _defaultInstance; @$pb.TagNumber(1) $0.CenterBox get box => $_getN(0); @$pb.TagNumber(1) - set box($0.CenterBox v) { setField(1, v); } + set box($0.CenterBox v) { + setField(1, v); + } + @$pb.TagNumber(1) $core.bool hasBox() => $_has(0); @$pb.TagNumber(1) @@ -75,7 +86,10 @@ class Detection extends $pb.GeneratedMessage { @$pb.TagNumber(2) $1.EPoint get landmarks => $_getN(1); @$pb.TagNumber(2) - set landmarks($1.EPoint v) { setField(2, v); } + set landmarks($1.EPoint v) { + setField(2, v); + } + @$pb.TagNumber(2) $core.bool hasLandmarks() => $_has(1); @$pb.TagNumber(2) @@ -103,26 +117,33 @@ class Face extends $pb.GeneratedMessage { return $result; } Face._() : super(); - factory Face.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory Face.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory Face.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory Face.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Face', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create) + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'Face', + package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), + createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'id') - ..aOM(2, _omitFieldNames ? '' : 'detection', subBuilder: Detection.create) - ..a<$core.double>(3, _omitFieldNames ? '' : 'confidence', $pb.PbFieldType.OF) - ..hasRequiredFields = false - ; + ..aOM(2, _omitFieldNames ? '' : 'detection', + subBuilder: Detection.create) + ..a<$core.double>( + 3, _omitFieldNames ? '' : 'confidence', $pb.PbFieldType.OF) + ..hasRequiredFields = false; - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') Face clone() => Face()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - Face copyWith(void Function(Face) updates) => super.copyWith((message) => updates(message as Face)) as Face; + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Face copyWith(void Function(Face) updates) => + super.copyWith((message) => updates(message as Face)) as Face; $pb.BuilderInfo get info_ => _i; @@ -131,13 +152,17 @@ class Face extends $pb.GeneratedMessage { Face createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static Face getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Face getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Face? _defaultInstance; @$pb.TagNumber(1) $core.String get id => $_getSZ(0); @$pb.TagNumber(1) - set id($core.String v) { $_setString(0, v); } + set id($core.String v) { + $_setString(0, v); + } + @$pb.TagNumber(1) $core.bool hasId() => $_has(0); @$pb.TagNumber(1) @@ -146,7 +171,10 @@ class Face extends $pb.GeneratedMessage { @$pb.TagNumber(2) Detection get detection => $_getN(1); @$pb.TagNumber(2) - set detection(Detection v) { setField(2, v); } + set detection(Detection v) { + setField(2, v); + } + @$pb.TagNumber(2) $core.bool hasDetection() => $_has(1); @$pb.TagNumber(2) @@ -157,13 +185,16 @@ class Face extends $pb.GeneratedMessage { @$pb.TagNumber(3) $core.double get confidence => $_getN(2); @$pb.TagNumber(3) - set confidence($core.double v) { $_setFloat(2, v); } + set confidence($core.double v) { + $_setFloat(2, v); + } + @$pb.TagNumber(3) $core.bool hasConfidence() => $_has(2); @$pb.TagNumber(3) void clearConfidence() => clearField(3); } - const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); +const _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbenum.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbenum.dart index 2eefe1f447..9691e4bb9d 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbenum.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbenum.dart @@ -8,4 +8,3 @@ // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import - diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbjson.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbjson.dart index 5aa614a8b8..59e6d41b14 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbjson.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbjson.dart @@ -17,8 +17,26 @@ import 'dart:typed_data' as $typed_data; const Detection$json = { '1': 'Detection', '2': [ - {'1': 'box', '3': 1, '4': 1, '5': 11, '6': '.ente.common.CenterBox', '9': 0, '10': 'box', '17': true}, - {'1': 'landmarks', '3': 2, '4': 1, '5': 11, '6': '.ente.common.EPoint', '9': 1, '10': 'landmarks', '17': true}, + { + '1': 'box', + '3': 1, + '4': 1, + '5': 11, + '6': '.ente.common.CenterBox', + '9': 0, + '10': 'box', + '17': true + }, + { + '1': 'landmarks', + '3': 2, + '4': 1, + '5': 11, + '6': '.ente.common.EPoint', + '9': 1, + '10': 'landmarks', + '17': true + }, ], '8': [ {'1': '_box'}, @@ -37,8 +55,25 @@ const Face$json = { '1': 'Face', '2': [ {'1': 'id', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'id', '17': true}, - {'1': 'detection', '3': 2, '4': 1, '5': 11, '6': '.ente.ml.Detection', '9': 1, '10': 'detection', '17': true}, - {'1': 'confidence', '3': 3, '4': 1, '5': 2, '9': 2, '10': 'confidence', '17': true}, + { + '1': 'detection', + '3': 2, + '4': 1, + '5': 11, + '6': '.ente.ml.Detection', + '9': 1, + '10': 'detection', + '17': true + }, + { + '1': 'confidence', + '3': 3, + '4': 1, + '5': 2, + '9': 2, + '10': 'confidence', + '17': true + }, ], '8': [ {'1': '_id'}, @@ -52,4 +87,3 @@ final $typed_data.Uint8List faceDescriptor = $convert.base64Decode( 'CgRGYWNlEhMKAmlkGAEgASgJSABSAmlkiAEBEjUKCWRldGVjdGlvbhgCIAEoCzISLmVudGUubW' 'wuRGV0ZWN0aW9uSAFSCWRldGVjdGlvbogBARIjCgpjb25maWRlbmNlGAMgASgCSAJSCmNvbmZp' 'ZGVuY2WIAQFCBQoDX2lkQgwKCl9kZXRlY3Rpb25CDQoLX2NvbmZpZGVuY2U='); - diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbserver.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbserver.dart index a2cd6ff853..9983bc998d 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbserver.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/face.pbserver.dart @@ -11,4 +11,3 @@ // ignore_for_file: unnecessary_import, unnecessary_this, unused_import export 'face.pb.dart'; - diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pb.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pb.dart index 853f89bac4..b717748ccb 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pb.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pb.dart @@ -31,25 +31,30 @@ class FileML extends $pb.GeneratedMessage { return $result; } FileML._() : super(); - factory FileML.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory FileML.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory FileML.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory FileML.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FileML', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create) + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'FileML', + package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), + createEmptyInstance: create) ..aInt64(1, _omitFieldNames ? '' : 'id') ..p<$core.double>(2, _omitFieldNames ? '' : 'clip', $pb.PbFieldType.KD) - ..hasRequiredFields = false - ; + ..hasRequiredFields = false; - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') FileML clone() => FileML()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - FileML copyWith(void Function(FileML) updates) => super.copyWith((message) => updates(message as FileML)) as FileML; + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FileML copyWith(void Function(FileML) updates) => + super.copyWith((message) => updates(message as FileML)) as FileML; $pb.BuilderInfo get info_ => _i; @@ -58,13 +63,17 @@ class FileML extends $pb.GeneratedMessage { FileML createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static FileML getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FileML getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static FileML? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get id => $_getI64(0); @$pb.TagNumber(1) - set id($fixnum.Int64 v) { $_setInt64(0, v); } + set id($fixnum.Int64 v) { + $_setInt64(0, v); + } + @$pb.TagNumber(1) $core.bool hasId() => $_has(0); @$pb.TagNumber(1) @@ -101,28 +110,34 @@ class FileFaces extends $pb.GeneratedMessage { return $result; } FileFaces._() : super(); - factory FileFaces.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory FileFaces.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory FileFaces.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory FileFaces.fromJson($core.String i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FileFaces', package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), createEmptyInstance: create) - ..pc<$2.Face>(1, _omitFieldNames ? '' : 'faces', $pb.PbFieldType.PM, subBuilder: $2.Face.create) + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'FileFaces', + package: const $pb.PackageName(_omitMessageNames ? '' : 'ente.ml'), + createEmptyInstance: create) + ..pc<$2.Face>(1, _omitFieldNames ? '' : 'faces', $pb.PbFieldType.PM, + subBuilder: $2.Face.create) ..a<$core.int>(2, _omitFieldNames ? '' : 'height', $pb.PbFieldType.O3) ..a<$core.int>(3, _omitFieldNames ? '' : 'width', $pb.PbFieldType.O3) ..a<$core.int>(4, _omitFieldNames ? '' : 'version', $pb.PbFieldType.O3) ..aOS(5, _omitFieldNames ? '' : 'error') - ..hasRequiredFields = false - ; + ..hasRequiredFields = false; - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') FileFaces clone() => FileFaces()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - FileFaces copyWith(void Function(FileFaces) updates) => super.copyWith((message) => updates(message as FileFaces)) as FileFaces; + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FileFaces copyWith(void Function(FileFaces) updates) => + super.copyWith((message) => updates(message as FileFaces)) as FileFaces; $pb.BuilderInfo get info_ => _i; @@ -131,7 +146,8 @@ class FileFaces extends $pb.GeneratedMessage { FileFaces createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static FileFaces getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FileFaces getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static FileFaces? _defaultInstance; @$pb.TagNumber(1) @@ -140,7 +156,10 @@ class FileFaces extends $pb.GeneratedMessage { @$pb.TagNumber(2) $core.int get height => $_getIZ(1); @$pb.TagNumber(2) - set height($core.int v) { $_setSignedInt32(1, v); } + set height($core.int v) { + $_setSignedInt32(1, v); + } + @$pb.TagNumber(2) $core.bool hasHeight() => $_has(1); @$pb.TagNumber(2) @@ -149,7 +168,10 @@ class FileFaces extends $pb.GeneratedMessage { @$pb.TagNumber(3) $core.int get width => $_getIZ(2); @$pb.TagNumber(3) - set width($core.int v) { $_setSignedInt32(2, v); } + set width($core.int v) { + $_setSignedInt32(2, v); + } + @$pb.TagNumber(3) $core.bool hasWidth() => $_has(2); @$pb.TagNumber(3) @@ -158,7 +180,10 @@ class FileFaces extends $pb.GeneratedMessage { @$pb.TagNumber(4) $core.int get version => $_getIZ(3); @$pb.TagNumber(4) - set version($core.int v) { $_setSignedInt32(3, v); } + set version($core.int v) { + $_setSignedInt32(3, v); + } + @$pb.TagNumber(4) $core.bool hasVersion() => $_has(3); @$pb.TagNumber(4) @@ -167,13 +192,16 @@ class FileFaces extends $pb.GeneratedMessage { @$pb.TagNumber(5) $core.String get error => $_getSZ(4); @$pb.TagNumber(5) - set error($core.String v) { $_setString(4, v); } + set error($core.String v) { + $_setString(4, v); + } + @$pb.TagNumber(5) $core.bool hasError() => $_has(4); @$pb.TagNumber(5) void clearError() => clearField(5); } - const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); +const _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbenum.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbenum.dart index 71d796efe9..3ced4ad5f4 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbenum.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbenum.dart @@ -8,4 +8,3 @@ // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import - diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbjson.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbjson.dart index 824741733e..314d85226b 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbjson.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbjson.dart @@ -34,10 +34,25 @@ final $typed_data.Uint8List fileMLDescriptor = $convert.base64Decode( const FileFaces$json = { '1': 'FileFaces', '2': [ - {'1': 'faces', '3': 1, '4': 3, '5': 11, '6': '.ente.ml.Face', '10': 'faces'}, + { + '1': 'faces', + '3': 1, + '4': 3, + '5': 11, + '6': '.ente.ml.Face', + '10': 'faces' + }, {'1': 'height', '3': 2, '4': 1, '5': 5, '9': 0, '10': 'height', '17': true}, {'1': 'width', '3': 3, '4': 1, '5': 5, '9': 1, '10': 'width', '17': true}, - {'1': 'version', '3': 4, '4': 1, '5': 5, '9': 2, '10': 'version', '17': true}, + { + '1': 'version', + '3': 4, + '4': 1, + '5': 5, + '9': 2, + '10': 'version', + '17': true + }, {'1': 'error', '3': 5, '4': 1, '5': 9, '9': 3, '10': 'error', '17': true}, ], '8': [ @@ -54,4 +69,3 @@ final $typed_data.Uint8List fileFacesDescriptor = $convert.base64Decode( 'dodBgCIAEoBUgAUgZoZWlnaHSIAQESGQoFd2lkdGgYAyABKAVIAVIFd2lkdGiIAQESHQoHdmVy' 'c2lvbhgEIAEoBUgCUgd2ZXJzaW9uiAEBEhkKBWVycm9yGAUgASgJSANSBWVycm9yiAEBQgkKB1' '9oZWlnaHRCCAoGX3dpZHRoQgoKCF92ZXJzaW9uQggKBl9lcnJvcg=='); - diff --git a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbserver.dart b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbserver.dart index 4cb208d271..aff0b1e960 100644 --- a/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbserver.dart +++ b/mobile/apps/photos/lib/generated/protos/ente/ml/fileml.pbserver.dart @@ -11,4 +11,3 @@ // ignore_for_file: unnecessary_import, unnecessary_this, unused_import export 'fileml.pb.dart'; - diff --git a/mobile/apps/photos/lib/l10n/intl_ar.arb b/mobile/apps/photos/lib/l10n/intl_ar.arb index e6363c83ec..521b19360e 100644 --- a/mobile/apps/photos/lib/l10n/intl_ar.arb +++ b/mobile/apps/photos/lib/l10n/intl_ar.arb @@ -1735,15 +1735,23 @@ "peopleWidgetDesc": "حدد الأشخاص الذين ترغب في ظهورهم على شاشتك الرئيسية.", "albumsWidgetDesc": "حدد الألبومات التي تريد ظهورها على شاشتك الرئيسية.", "memoriesWidgetDesc": "اختر نوع الذكريات التي ترغب في رؤيتها على شاشتك الرئيسية.", + "smartMemories": "ذكريات ذكية", + "pastYearsMemories": "ذكريات السنوات الماضية", "deleteMultipleAlbumDialog": "هل تريد أيضًا حذف الصور (والمقاطع) الموجودة في هذه الألبومات {count} من كافة الألبومات الأخرى التي تشترك فيها؟", "addParticipants": "إضافة مشاركين", "selectedAlbums": "{count} تم تحديد", "actionNotSupportedOnFavouritesAlbum": "الإجراء غير مدعوم في ألبوم المفضلة", + "onThisDayMemories": "ذكريات هذا اليوم", "onThisDay": "في هذا اليوم", + "lookBackOnYourMemories": "استرجع ذكرياتك 🌄", "newPhotosEmoji": " جديد 📸", + "sorryWeHadToPauseYourBackups": "عذراً، لقد اضطررنا إلى إيقاف النسخ الاحتياطي الخاصة بك", "clickToInstallOurBestVersionYet": "انقر لتثبيت أفضل إصدار لنا حتى الآن", "onThisDayNotificationExplanation": "تلقي تذكيرات حول ذكريات مثل اليوم في السنوات السابقة.", + "addMemoriesWidgetPrompt": "أضف أداة ذكريات إلى شاشتك الرئيسية، ثم عد إلى هنا لتخصيصها.", + "addAlbumWidgetPrompt": "أضف أداة ألبوم إلى شاشتك الرئيسية، ثم عد إلى هنا لتخصيصها.", "addPeopleWidgetPrompt": "أضف عنصر واجهة الأشخاص إلى شاشتك الرئيسية ثم عد إلى هنا لتخصيصه.", + "birthdayNotifications": "إشعارات عيد الميلاد", "receiveRemindersOnBirthdays": "استلم تذكيرات عندما يحين عيد ميلاد أحدهم. النقر على الإشعار سينقلك إلى صور الشخص المحتفل بعيد ميلاده.", "happyBirthday": "عيد ميلاد سعيد! 🥳", "birthdays": "أعياد الميلاد", @@ -1758,14 +1766,59 @@ "ignore": "تجاهل", "merge": "دمج", "reset": "إعادة تعيين", + "areYouSureYouWantToIgnoreThisPerson": "هل أنت متأكد من أنك تريد تجاهل هذا الشخص؟", + "areYouSureYouWantToIgnoreThesePersons": "هل أنت متأكد أنك تريد تجاهل هؤلاء الأشخاص؟", "thePersonGroupsWillNotBeDisplayed": "لن تظهر مجموعات الأشخاص في قسم الأشخاص بعد الآن. ستظل الصور دون تغيير.", "thePersonWillNotBeDisplayed": "لن يتم عرض هذا الشخص في قسم الأشخاص بعد الآن. الصور ستبقى كما هي دون تغيير.", "areYouSureYouWantToMergeThem": "هل أنت متأكد من رغبتك في دمجهم؟", "allUnnamedGroupsWillBeMergedIntoTheSelectedPerson": "سيتم دمج جميع المجموعات غير المسماة مع الشخص المحدد. يمكن التراجع عن هذا الإجراء لاحقًا من خلال نظرة عامة على سجل الاقتراحات التابع لهذا الشخص.", "yesIgnore": "نعم، تجاهل", + "same": "نفس", + "different": "مختلف", + "sameperson": "نفس الشخص؟", + "cLTitle1": "محرر الصور المتقدم", + "cLDesc1": "نحن بصدد إطلاق محرر صور جديد ومتقدم يضيف المزيد من إطارات الاقتصاص، والإعدادات المسبقة للفلاتر من أجل تعديلات سريعة، وخيارات الضبط الدقيق التي تشمل التشبع، والتباين، والسطوع، ودرجة الحرارة، وغير ذلك الكثير. يتضمن المحرر الجديد أيضا القدرة على الرسم على صورك وإضافة الرموز التعبيرية كملصقات.", + "cLTitle2": "ألبومات ذكية", + "cLTitle3": "معرض محسن", + "cLTitle4": "تمرير أسرع", "thisWeek": "هذا الأسبوع", "lastWeek": "الأسبوع الماضي", "thisMonth": "هذا الشهر", "thisYear": "هذه السنة", - "day": "اليوم" + "groupBy": "تجميع حسب", + "faceThumbnailGenerationFailed": "تعذر إنشاء الصور المصغرة للوجه", + "fileAnalysisFailed": "تعذر تحليل الملف", + "editAutoAddPeople": "تحرير إضافة الأشخاص التلقائية", + "autoAddPeople": "إضافة الأشخاص التلقائية", + "autoAddToAlbum": "إضافة تلقائية إلى الألبوم", + "addingPhotos": "جاري إضافة الصور", + "gettingReady": "جاري الإعداد", + "addSomePhotosDesc2": "وجوه مألوفة", + "addSomePhotosDesc3": "\nللبدء بـ", + "ignorePerson": "تجاهل الشخص", + "analysis": "تحليل", + "doesGroupContainMultiplePeople": "هل هذه المجموعة تحتوي على أشخاص متعددين؟", + "automaticallyAnalyzeAndSplitGrouping": "سنقوم تلقائيا بتحليل المجموعة لتحديد ما إذا كان هناك عدة أشخاص، وفصلهم مرة أخرى. قد يستغرق هذا بضع ثوان.", + "layout": "التخطيط", + "day": "اليوم", + "peopleAutoAddDesc": "حدد الأشخاص الذين تريد إضافتهم تلقائيا إلى الألبوم", + "undo": "تراجع", + "redo": "إعادة", + "filter": "فلتر", + "adjust": "تعديل", + "draw": "رسم", + "sticker": "ملصق", + "brushColor": "لون الفرشاة", + "font": "الخط", + "background": "خلفية", + "align": "محاذاة", + "addedToAlbums": "{count, plural, =1{تمت الإضافة إلى ألبوم واحد بنجاح} other{تم الإضافة إلى {count} ألبومات بنجاح}}", + "@addedToAlbums": { + "description": "Message shown when items are added to albums", + "placeholders": { + "count": { + "type": "int" + } + } + } } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_de.arb b/mobile/apps/photos/lib/l10n/intl_de.arb index 82240e31b2..8849255874 100644 --- a/mobile/apps/photos/lib/l10n/intl_de.arb +++ b/mobile/apps/photos/lib/l10n/intl_de.arb @@ -1776,6 +1776,14 @@ "same": "Gleich", "different": "Verschieden", "sameperson": "Dieselbe Person?", + "cLTitle1": "Erweiterte Bildbearbeitung", + "cLDesc1": "Wir veröffentlichen eine neue und erweiterte Bildbearbeitung, die mehr Bildzuschnitte ermöglicht, vordefinierte Filter für schnelleres Bearbeiten bietet, sowie die Feinabstimmung von Sättigung, Kontrast, Helligkeit und vielem mehr erlaubt. Der neue Editor erlaubt außerdem das Zeichnen auf den Fotos oder das Hinzufügen von Emojis als Sticker.", + "cLTitle2": "Intelligente Alben", + "cLDesc2": "Du kannst jetzt automatisch Fotos von ausgewählten Personen zu jedem Album hinzufügen. Öffne einfach das Album und wähle \"Personen automatisch hinzufügen\" aus dem Menü. Zusammen mit einem geteilten Album kannst Du Fotos mit null Klicks teilen.", + "cLTitle3": "Verbesserte Galerie", + "cLDesc3": "Wir haben die Möglichkeit hinzugefügt, Alben nach Wochen, Monaten und Jahren zu gruppieren. Du kannst jetzt die Galerie mit diesen neuen Gruppierungs-Optionen so anpassen, dass sie genau so aussieht, wie Du möchtest, zusammen mit angepassten Rastern", + "cLTitle4": "Schnelleres Scrollen", + "cLDesc4": "Zusammen mit einem Schwung Änderungen unter der Haube, um das Erlebnis beim Scrollen der Galerie zu verbessern, haben wir außerdem den Scrollbalken mit Markern neu gestaltet, um es Dir zu ermöglichen, schnell in der Zeitleiste zu springen.", "indexingPausedStatusDescription": "Die Indizierung ist pausiert. Sie wird automatisch fortgesetzt, wenn das Gerät bereit ist. Das Gerät wird als bereit angesehen, wenn sich der Akkustand, die Akkugesundheit und der thermische Zustand in einem gesunden Bereich befinden.", "thisWeek": "Diese Woche", "lastWeek": "Letzte Woche", @@ -1800,5 +1808,24 @@ "automaticallyAnalyzeAndSplitGrouping": "Wir analysieren die Gruppierung automatisch, um festzustellen, ob mehrere Personen vorhanden sind, und trennen sie erneut. Dies kann ein paar Sekunden dauern.", "layout": "Layout", "day": "Tag", - "peopleAutoAddDesc": "Wähle die Personen, die du automatisch zum Album hinzufügen möchtest" + "peopleAutoAddDesc": "Wähle die Personen, die du automatisch zum Album hinzufügen möchtest", + "undo": "Rückgängig", + "redo": "Wiederherstellen", + "filter": "Filter", + "adjust": "Anpassen", + "draw": "Zeichnen", + "sticker": "Sticker", + "brushColor": "Pinselfarbe", + "font": "Schriftart", + "background": "Hintergrund", + "align": "Ausrichten", + "addedToAlbums": "{count, plural, =1{Erfolgreich zu einem Album hinzugefügt} other{Erfolgreich zu {count} Alben hinzugefügt}}", + "@addedToAlbums": { + "description": "Message shown when items are added to albums", + "placeholders": { + "count": { + "type": "int" + } + } + } } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_fr.arb b/mobile/apps/photos/lib/l10n/intl_fr.arb index 8f73c4baa1..7bdb63cbd4 100644 --- a/mobile/apps/photos/lib/l10n/intl_fr.arb +++ b/mobile/apps/photos/lib/l10n/intl_fr.arb @@ -1758,7 +1758,7 @@ "wishThemAHappyBirthday": "Souhaitez à {name} un joyeux anniversaire ! 🎉", "areYouSureRemoveThisFaceFromPerson": "Êtes-vous sûr de vouloir retirer ce visage de cette personne ?", "otherDetectedFaces": "Autres visages détectés", - "areThey": "Vraiment", + "areThey": "S'agit-il de ", "questionmark": "?", "saveAsAnotherPerson": "Enregistrer comme une autre personne", "showLessFaces": "Afficher moins de visages", @@ -1776,7 +1776,56 @@ "same": "Identique", "different": "Différent(e)", "sameperson": "Même personne ?", + "cLTitle1": "Éditeur d'image avancé", + "cLDesc1": "Nous déployons un nouvel éditeur d'image avancé qui ajoute plus d'options de rognage, des filtres, des préréglages pour des modifications rapides ainsi que des options de réglage fin (la saturation, le contraste, la luminosité, la température et beaucoup plus). Le nouvel éditeur inclut également la possibilité de dessiner sur vos photos et d'ajouter des emojis en tant qu'autocollants.", + "cLTitle2": "Albums Intelligents", + "cLDesc2": "Vous pouvez maintenant ajouter automatiquement des photos de personnes sélectionnées à n'importe quel album. Allez simplement à l'album et sélectionnez \"Ajouter automatiquement des personnes\" dans le menu déroulant. Couplé avec un album partagé, vous pouvez partager des photos en zéro clic.", + "cLTitle3": "Galerie améliorée", + "cLDesc3": "Nous avons ajouté la possibilité de regrouper votre galerie par semaines, mois et années. Vous pouvez maintenant personnaliser votre galerie pour qu'elle soit exactement comme vous le souhaitez avec ces nouvelles options de regroupement, ainsi que des grilles personnalisées", + "cLTitle4": "Défilement plus rapide", + "cLDesc4": "En plus des quelques améliorations pour améliorer l'expérience de défilement de la galerie, nous avons également redessiné la barre de défilement pour afficher des marqueurs, ce qui vous permet de sauter rapidement dans la chronologie.", "indexingPausedStatusDescription": "L'indexation est en pause. Elle reprendra automatiquement lorsque l'appareil sera prêt. Celui-ci est considéré comme prêt lorsque le niveau de batterie, sa santé et son état thermique sont dans une plage saine.", + "thisWeek": "Cette semaine", + "lastWeek": "La semaine dernière", + "thisMonth": "Ce mois", + "thisYear": "Cette année", + "groupBy": "Grouper par", "faceThumbnailGenerationFailed": "Impossible de créer des miniatures de visage", - "fileAnalysisFailed": "Impossible d'analyser le fichier" + "fileAnalysisFailed": "Impossible d'analyser le fichier", + "editAutoAddPeople": "Modifier les personnes auto-ajoutées", + "autoAddPeople": "Ajouter automatiquement des personnes", + "autoAddToAlbum": "Ajouter automatiquement à l'album", + "shouldRemoveFilesSmartAlbumsDesc": "Les fichiers liés à la personne qui ont été précédemment sélectionnés dans les albums intelligents doivent-ils être supprimés ?", + "addingPhotos": "Ajout des photos", + "gettingReady": "Préparation", + "addSomePhotosDesc1": "Ajoutez quelques photos ou choisissez des ", + "addSomePhotosDesc2": "visages familiers", + "addSomePhotosDesc3": "\npour commencer", + "ignorePerson": "Ignorer la personne", + "mixedGrouping": "Plusieurs personnes?", + "analysis": "Analyse", + "doesGroupContainMultiplePeople": "Ce groupement contient-il plusieurs personnes ?", + "automaticallyAnalyzeAndSplitGrouping": "Nous analyserons automatiquement le regroupement pour déterminer s'il y a plusieurs personnes présentes et nous les séparerons à nouveau si tel est le cas. Cela peut prendre quelques secondes.", + "layout": "Disposition", + "day": "Jour", + "peopleAutoAddDesc": "Sélectionnez les personnes que vous souhaitez ajouter automatiquement à l'album", + "undo": "Annuler", + "redo": "Rétablir", + "filter": "Filtres", + "adjust": "Ajuster", + "draw": "Dessiner", + "sticker": "Autocollant", + "brushColor": "Couleur du pinceau", + "font": "Police", + "background": "Arrière-plan", + "align": "Aligner", + "addedToAlbums": "{count, plural, one {}=1{Ajouté avec succès à 1 album} other{Ajouté avec succès à {count} albums}}", + "@addedToAlbums": { + "description": "Message shown when items are added to albums", + "placeholders": { + "count": { + "type": "int" + } + } + } } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_lt.arb b/mobile/apps/photos/lib/l10n/intl_lt.arb index 20266b1cc2..ae339750e2 100644 --- a/mobile/apps/photos/lib/l10n/intl_lt.arb +++ b/mobile/apps/photos/lib/l10n/intl_lt.arb @@ -1776,6 +1776,14 @@ "same": "Tas pats", "different": "Skirtingas", "sameperson": "Tas pats asmuo?", + "cLTitle1": "Pažangi vaizdų rengyklė", + "cLDesc1": "Mes išleidžiame naują ir pažangią vaizdų rengyklę, kurioje yra daugiau apkirpimo rėmelių, filtro nustatymų sparčiams redagavimams, tikslaus sureguliavimo parinkčių, įskaitant sodrumą, kontrastą, skaistį, temperatūrą ir daug daugiau. Naujoji rengyklė taip pat suteikia galimybę piešti ant nuotraukų ir pridėti jaustukus kaip lipdukus.", + "cLTitle2": "Išmanieji albumai", + "cLDesc2": "Dabar galite automatiškai įtraukti pasirinktų asmenų nuotraukas į bet kurį albumą. Tiesiog eikite į albumą ir iš išskleidžiamojo meniu pasirinkite „Automatiškai įtraukti asmenis“. Jei naudojama kartu su bendrinimu albumu, nuotraukas galite bendrinti be jokių paspaudimų.", + "cLTitle3": "Patobulinta galerija", + "cLDesc3": "Pridėjome galimybę sugrupuoti galeriją pagal savaites, mėnesius ir metus. Dabar galite pritaikyti galeriją taip, kad ji atrodytų būtent taip, kaip norite su šiomis naujomis grupavimo parinktimis ir pasirinktiniais tinkleliais.", + "cLTitle4": "Spartesnis slinkimas", + "cLDesc4": "Kartu su daugybe vidinių patobulinimų pagerinti galerijos slinkimo patirtį, mes taip pat pertvarkėme slinkties juostą, kad joje būtų rodomi žymekliai, leidžiantys sparčiai pereiti per laiko juostą.", "indexingPausedStatusDescription": "Indeksavimas pristabdytas. Jis bus automatiškai tęsiamas, kai įrenginys bus parengtas. Įrenginys laikomas parengtu, kai jo akumuliatoriaus įkrovos lygis, akumuliatoriaus būklė ir terminė būklė yra normos ribose.", "thisWeek": "Šią savaitę", "lastWeek": "Praėjusią savaitę", @@ -1784,8 +1792,31 @@ "groupBy": "Grupuoti pagal", "faceThumbnailGenerationFailed": "Nepavyksta sugeneruoti veido miniatiūrų.", "fileAnalysisFailed": "Nepavyksta išanalizuoti failo.", + "editAutoAddPeople": "Redaguoti automatiškai įtrauktus asmenis", + "autoAddPeople": "Automatiškai įtraukti asmenis", + "autoAddToAlbum": "Automatiškai įtraukti į albumą", + "shouldRemoveFilesSmartAlbumsDesc": "Ar reikia pašalinti failus, susijusius su asmeniu, kuris anksčiau buvo atrinktas išmaniuosiuose albumuose?", + "addingPhotos": "Įtraukiamos nuotraukos", + "gettingReady": "Pasirengiama", + "addSomePhotosDesc1": "Įtraukite šiek tiek nuotraukų arba pasirinkite ", + "addSomePhotosDesc2": "pažįstamus veidus", + "addSomePhotosDesc3": "\niš pradžių.", "ignorePerson": "Ignoruoti asmenį", + "mixedGrouping": "Sumaišytas grupavimas?", "analysis": "Analizė", + "doesGroupContainMultiplePeople": "Ar šiame grupavime yra keli asmenys?", + "automaticallyAnalyzeAndSplitGrouping": "Mes automatiškai išanalizuosime grupavimą, kad nustatytume, ar yra keli asmenys, ir vėl juos atskirsime. Tai gali užtrukti keletą sekundžių.", "layout": "Išdėstymas", - "day": "Diena" + "day": "Diena", + "peopleAutoAddDesc": "Pasirinkite asmenis, kuriuos norite automatiškai įtraukti į albumą.", + "undo": "Anuliuoti", + "redo": "Grąžinti", + "filter": "Filtruoti", + "adjust": "Priderinti", + "draw": "Piešti", + "sticker": "Lipdukas", + "brushColor": "Teptuko spalva", + "font": "Šriftas", + "background": "Fonas", + "align": "Lygiuoti" } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_nn.arb b/mobile/apps/photos/lib/l10n/intl_nn.arb new file mode 100644 index 0000000000..1d48d2df40 --- /dev/null +++ b/mobile/apps/photos/lib/l10n/intl_nn.arb @@ -0,0 +1,313 @@ +{ + "@@locale ": "en", + "enterYourEmailAddress": "Skriv inn e-postadressa di", + "enterYourNewEmailAddress": "Skriv inn den nye e-postadressa di", + "accountWelcomeBack": "Velkommen tilbake!", + "emailAlreadyRegistered": "E-postadressa er registrert frå før.", + "emailNotRegistered": "E-postadressa er ikkje registrert.", + "email": "E-post", + "cancel": "Avbryt", + "verify": "Stadfest", + "invalidEmailAddress": "Ugyldig e-postadresse", + "enterValidEmail": "Skriv inn ei gyldig e-postadresse.", + "deleteAccount": "Slett konto", + "askDeleteReason": "Kva er hovudgrunnen til at du vil sletta kontoen din?", + "feedback": "Tilbakemelding", + "confirmDeletePrompt": "Ja, eg vil sletta denne kontoen og alle tilhøyrande data frå alle appar permanent.", + "confirmAccountDeletion": "Stadfest sletting av konto", + "deleteAccountPermanentlyButton": "Slett konto permanent", + "yourAccountHasBeenDeleted": "Kontoen er sletta", + "sendEmail": "Send e-post", + "entePhotosPerm": "Ente treng løyve til å kunna ta vare på fotoa dine", + "ok": "OK", + "createAccount": "Opprett konto", + "createNewAccount": "Opprett konto", + "password": "Passord", + "confirmPassword": "Stadfest passord", + "activeSessions": "Aktive økter", + "oops": "Uff då", + "somethingWentWrongPleaseTryAgain": "Det oppstod ein feil. Prøv på nytt.", + "thisWillLogYouOutOfThisDevice": "Dette loggar deg ut frå denne eininga.", + "thisWillLogYouOutOfTheFollowingDevice": "Dette loggar deg ut frå dei følgjande einingane:", + "terminateSession": "Avslutta økt?", + "terminate": "Avslutt", + "thisDevice": "Denne eininga", + "recoverButton": "Gjenopprett", + "recoverySuccessful": "Gjenoppretting var vellukka.", + "decrypting": "Dekrypterer …", + "incorrectRecoveryKeyTitle": "Gjenopprettingsnøkkelen er feil", + "incorrectRecoveryKeyBody": "Gjenopprettingsnøkkelen som du skreiv inn er feil", + "forgotPassword": "Gløymt passordet", + "enterYourRecoveryKey": "Skriv inn gjenopprettingsnøkkelen", + "noRecoveryKey": "Ingen gjenopprettingsnøkkel?", + "sorry": "Orsak", + "verifyEmail": "Stadfest e-postadresse", + "resendEmail": "Send e-posten på nytt", + "weHaveSendEmailTo": "Vi har sendt ein e-post til {email} ", + "@weHaveSendEmailTo": { + "description": "Text to indicate that we have sent a mail to the user", + "placeholders": { + "email": { + "description": "The email address of the user", + "type": "String", + "example": "example@ente.io" + } + } + }, + "setPasswordTitle": "Vel passord", + "changePasswordTitle": "Endra passord", + "resetPasswordTitle": "Tilbakestill passord", + "encryptionKeys": "Krypteringsnøklar", + "passwordWarning": "Vi lagrar ikkje dette passordet, så dersom du gløymer det kan vi ikkje dekryptera dataa dine", + "enterPasswordToEncrypt": "Skriv inn eit passord me kan kryptera dataa dine med", + "enterNewPasswordToEncrypt": "Skriv inn eit nytt passord me kan kryptera dataa dine med", + "weakStrength": "Svakt", + "strongStrength": "Sterkt", + "moderateStrength": "Middels sterkt", + "passwordStrength": "Passordstyrke: {passwordStrengthValue}", + "@passwordStrength": { + "description": "Text to indicate the password strength", + "placeholders": { + "passwordStrengthValue": { + "description": "The strength of the password as a string", + "type": "String", + "example": "Weak or Moderate or Strong" + } + }, + "message": "Password Strength: {passwordStrengthText}" + }, + "passwordChangedSuccessfully": "Passordet er endra", + "generatingEncryptionKeys": "Lagar krypteringsnøklar …", + "pleaseWait": "Vent litt …", + "continueLabel": "Fortsett", + "insecureDevice": "Usikker eining", + "sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Klarte ikkje laga tryggleiksnøklar på denne eininga.\n\nBruk ei anna eining for å registrera deg.", + "howItWorks": "Slik fungerer det", + "encryption": "Kryptering", + "ackPasswordLostWarning": "Eg forstår at dersom eg gløymer passordet mitt kan alle dataa mine gå tapt, fordi dei er ende-til-ende-krypterte.", + "privacyPolicyTitle": "Personvernerklæring", + "termsOfServicesTitle": "Vilkår", + "signUpTerms": "Eg godtek tenestevilkåra og personvernerklæringa", + "logInLabel": "Logg på", + "changeEmail": "Endra e-postadresse", + "enterYourPassword": "Skriv inn passordet ditt", + "welcomeBack": "Velkommen tilbake!", + "incorrectPasswordTitle": "Ugyldig passord", + "pleaseTryAgain": "Prøv på nytt", + "recreatePasswordTitle": "Opprett passord på nytt", + "useRecoveryKey": "Bruk gjenopprettingsnøkkel", + "recreatePasswordBody": "Den gjeldande eininga er ikkje kraftig nok til å kunna stadfesta passordet ditt, men me kan laga det på nytt ved å bruka ein metode som vil fungere på alle einingar.\n\nLogg på ved å bruka gjenopprettingsnøkkelen din og lag passordet på nytt (du kan gjenbruka passordet viss du vil).", + "verifyPassword": "Stadfest passord", + "recoveryKey": "Gjenopprettingsnøkkel", + "recoveryKeyOnForgotPassword": "Viss du gløymer passordet, er det berre ved å bruka denne nøkkelen at du kan gjenoppretta dataa dine.", + "recoveryKeySaveDescription": "Me tek ikkje vare på denne nøkkelen. Denne nøkkelen på 24 ord må du oppbevara på ein trygg stad.", + "doThisLater": "Gjer dette seinare", + "saveKey": "Lagra nøkkel", + "recoveryKeyCopiedToClipboard": "Gjenopprettingsnøkkel kopiert til utklippstavla", + "recoverAccount": "Gjenopprett konto", + "recover": "Gjenopprett", + "dropSupportEmail": "Send ein e-post til {supportEmail} frå e-postadressa du registrerte deg med", + "@dropSupportEmail": { + "placeholders": { + "supportEmail": { + "description": "The support email address", + "type": "String", + "example": "support@ente.io" + } + } + }, + "twofactorSetup": "Oppsett av tofaktor", + "enterCode": "Skriv inn kode", + "scanCode": "Skann kode", + "codeCopiedToClipboard": "Kode kopiert til utklippstavla", + "copypasteThisCodentoYourAuthenticatorApp": "Kopier og lim inn koden\ni autentikator-appen", + "tapToCopy": "trykk for å kopiera", + "scanThisBarcodeWithnyourAuthenticatorApp": "Skann denne strekkoden med\nautentikator-appen", + "enterThe6digitCodeFromnyourAuthenticatorApp": "Skriv inn den seks-sifra koden\nfrå autentikator-appen", + "confirm": "Stadfest", + "setupComplete": "Oppsettet er fullført", + "saveYourRecoveryKeyIfYouHaventAlready": "Lagra gjenopprettingsnøkkelen viss du ikkje alt har gjort det", + "twofactorAuthenticationPageTitle": "Tofaktorautentisering", + "verifyingRecoveryKey": "Stadfestar gjenopprettingsnøkkel …", + "recoveryKeyVerified": "Gjenopprettingsnøkkelen er stadfesta", + "recoveryKeySuccessBody": "Flott! Gjenopprettingsnøkkelen er gyldig. Takk for at du stadfesta han.\n\nHugs å oppbevara gjenopprettingsnøkkelen på ein trygg stad.", + "invalidRecoveryKey": "Gjenopprettingsnøkkelen er ikkje gyldig. Pass på at han inneheld 24 ord og er stava riktig.\n\nViss du skreiv inn ein eldre gjenopprettingskode, pass på at han inneheld 64 teikn.", + "invalidKey": "Ugyldig nøkkel", + "tryAgain": "Prøv på nytt", + "viewRecoveryKey": "Vis gjenopprettingsnøkkel", + "confirmRecoveryKey": "Stadfest gjenopprettingsnøkkel", + "recoveryKeyVerifyReason": "Viss du gløymer passordet, er det berre ved å bruka gjenopprettingsnøkkelen at du kan gjenoppretta fotoa dine. Vel «Konto» frå «Innstillingar»-menyen for å finna gjenopprettingsnøkkelen.\n\nSkriv inn gjenopprettingsnøkkelen her for å stadfesta at du har lagra han på riktig måte.", + "confirmYourRecoveryKey": "Stadfest gjenopprettingsnøkkelen din", + "addANewEmail": "Legg til ei ny e-postadresse", + "enterEmail": "Skriv inn e-postadresse", + "albumOwner": "Eigar", + "@albumOwner": { + "description": "Role of the album owner" + }, + "you": "Deg", + "enterPassword": "Skriv inn passord", + "removeLink": "Fjern lenkje", + "manageLink": "Handsam lenkje", + "done": "Ferdig", + "details": "Detaljar", + "faq": "Spørsmål og svar", + "help": "Hjelp", + "oopsSomethingWentWrong": "Uff då. Noko gjekk gale.", + "addingToFavorites": "Legger til i favorittar …", + "removingFromFavorites": "Fjernar frå favorittar …", + "sorryCouldNotAddToFavorites": "Klarte ikkje leggja til i favorittar.", + "sorryCouldNotRemoveFromFavorites": "Klarte ikkje fjerna frå favorittar.", + "archive": "Arkiv", + "createAlbumActionHint": "Trykk lenge for å velja foto, og trykk på pluss-ikonet for å oppretta eit album", + "importing": "Importerer …", + "failedToLoadAlbums": "Feil ved lasting av album", + "hidden": "Gøymde", + "authToViewYourHiddenFiles": "Autentiser deg for å visa gøymde filer", + "authToViewTrashedFiles": "Autentiser deg for å visa filer i papirkorga", + "trash": "Papirkorg", + "uncategorized": "Ikkje-kategoriserte", + "videoSmallCase": "video", + "photoSmallCase": "foto", + "deleteFromBoth": "Slett frå begge", + "newAlbum": "Nytt album", + "albums": "Albums", + "memoryCount": "{count, plural, =0{ingen minne} one{{formattedCount} minne} other{{formattedCount} minne}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, + "selectedPhotos": "{count} valde", + "@selectedPhotos": { + "description": "Display the number of selected photos", + "type": "text", + "placeholders": { + "count": { + "example": "5", + "type": "int" + } + } + }, + "selectedPhotosWithYours": "{count} valde ({yourCount} av desse er dine)", + "@selectedPhotosWithYours": { + "description": "Display the number of selected photos, including the number of selected photos owned by the user", + "type": "text", + "placeholders": { + "count": { + "example": "12", + "type": "int" + }, + "yourCount": { + "example": "2", + "type": "int" + } + } + }, + "advancedSettings": "Avansert", + "@advancedSettings": { + "description": "The text to display in the advanced settings section" + }, + "discover_babies": "Babyar", + "discover_pets": "Kjæledyr", + "discover_selfies": "Selfiar", + "discover_food": "Mat", + "discover_celebrations": "Feiringar", + "discover_sunset": "Solnedgang", + "discover_hills": "Bakkar", + "loadingModel": "Lastar ned modellar  …", + "waitingForWifi": "Ventar på Wi-Fi …", + "status": "Status", + "indexedItems": "Indekserte element", + "selectedFoldersWillBeEncryptedAndBackedUp": "Dei valde mappene vert krypterte og reservekopierte", + "unselectAll": "Fjern all merking", + "selectAll": "Merk alle", + "skip": "Hopp over", + "backupSettings": "Innstillingar for reservekopiering", + "backupStatus": "Status for reservekopiering", + "backupStatusDescription": "Reservekopierte element vert viste her", + "backupOverMobileData": "Ta reservekopi via mobildata", + "backupVideos": "Ta reservekopi av videoar", + "youAreOnTheLatestVersion": "Du har siste versjon", + "account": "Konto", + "manageSubscription": "Handsam abonnement", + "authToChangeYourEmail": "Autentiser for å endra e-postadresse", + "changePassword": "Endra passord", + "authToChangeYourPassword": "Autentiser for å endra passord", + "exportYourData": "Eksporter dataa dine", + "logout": "Logg ut", + "areYouSureYouWantToLogout": "Er du sikker på at du vil logga ut?", + "yesLogout": "Ja, logg ut", + "aNewVersionOfEnteIsAvailable": "Ein ny versjon av Ente er tilgjengeleg.", + "update": "Oppdater", + "installManually": "Installer manuelt", + "criticalUpdateAvailable": "Kritisk oppdatering tilgjengeleg", + "updateAvailable": "Oppdatering tilgjengeleg", + "ignoreUpdate": "Ignorer", + "downloading": "Lastar ned …", + "cannotDeleteSharedFiles": "Kan ikkje sletta delte filer", + "theDownloadCouldNotBeCompleted": "Klarte ikkje fullføra nedlastinga", + "retry": "Prøv på nytt", + "backup": "Reservekopiering", + "freeUpDeviceSpace": "Frigjer plass på eininga", + "freeUpDeviceSpaceDesc": "Frigjer plass på eininga ved å fjerna filer som allereie er reservekopierte.", + "removeDuplicates": "Fjern duplikat", + "removeDuplicatesDesc": "Sjå gjennom og fjern duplikate filer.", + "viewLargeFiles": "Store filer", + "viewLargeFilesDesc": "Vis filer som tek opp mest plass.", + "youHaveSuccessfullyFreedUp": "Du har frigjort {storageSaved}!", + "@youHaveSuccessfullyFreedUp": { + "description": "The text to display when the user has successfully freed up storage", + "type": "text", + "placeholders": { + "storageSaved": { + "example": "1.2 GB", + "type": "String" + } + } + }, + "advanced": "Avansert", + "general": "Generelt", + "security": "Tryggleik", + "faqs": "Spørsmål og svar", + "subscription": "Abonnement", + "startBackup": "Start reservekopiering", + "privateBackups": "Private reservekopiar", + "backupFailed": "Feil ved reservekopiering", + "sorryBackupFailedDesc": "Klarte ikkje reservekopiera fila. Me prøver på nytt seinare.", + "couldNotBackUpTryLater": "Klarte ikkje reservekopiera dataa dine.\nMe prøver på nytt seinare.", + "renameAlbum": "Endra namn på album", + "rename": "Endra namn", + "noExifData": "Ingen Exif-data", + "thisImageHasNoExifData": "Biletet har ingen exif-data", + "exif": "Exif", + "encryptingBackup": "Krypterer reservekopi …", + "renameFile": "Endra namn på fil", + "rotateLeft": "Roter til venstre", + "flip": "Spegelvend", + "rotateRight": "Roter til høgre", + "saveCopy": "Lagra kopi", + "fileInfoAddDescHint": "Legg til skildring …", + "androidCancelButton": "Avbryt", + "@androidCancelButton": { + "description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters." + }, + "crop": "Skjer av", + "rotate": "Roter", + "next": "Neste", + "noFacesFound": "Fann ingen ansikt", + "selectDate": "Vel dato", + "areThey": "Er dette ", + "filter": "Filter", + "adjust": "Juster", + "draw": "Klistremerke", + "brushColor": "Penselfarge" +} \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_no.arb b/mobile/apps/photos/lib/l10n/intl_no.arb index a0003c7bf4..4dbf2967c0 100644 --- a/mobile/apps/photos/lib/l10n/intl_no.arb +++ b/mobile/apps/photos/lib/l10n/intl_no.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "Skriv inn e-postadressen din", + "enterYourNewEmailAddress": "Skriv inn den nye e-postadressen din", "accountWelcomeBack": "Velkommen tilbake!", "emailAlreadyRegistered": "E-postadressen er allerede registrert.", "emailNotRegistered": "E-postadressen er ikke registrert.", @@ -721,6 +722,7 @@ "type": "text" }, "backupFailed": "Sikkerhetskopiering mislyktes", + "sorryBackupFailedDesc": "Beklager, vi kunne ikke sikkerhetskopiere denne filen akkurat nå, vil vi prøve på nytt senere.", "couldNotBackUpTryLater": "Vi kunne ikke sikkerhetskopiere dine data.\nVi vil prøve på nytt senere.", "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Ente kan bare kryptere og bevare filer hvis du gir tilgang til dem", "pleaseGrantPermissions": "Vennligst gi tillatelser", @@ -897,6 +899,7 @@ "authToViewYourMemories": "Vennligst autentiser deg for å se minnene dine", "unlock": "Lås opp", "freeUpSpace": "Frigjør lagringsplass", + "freeUpSpaceSaving": "{count, plural, =1 {Det kan slettes fra enheten for å frigi {formattedSize}} other {De kan slettes fra enheten for å frigjøre {formattedSize}}}", "filesBackedUpInAlbum": "{count, plural, one {1 fil} other {{formattedNumber} filer}} I dette albumet har blitt sikkerhetskopiert", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", @@ -927,6 +930,18 @@ } } }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, + "freeUpAccessPostDelete": "Du kan fortsatt få tilgang til {count, plural, =1 {det} other {dem}} på Ente så lenge du har et aktivt abonnement", + "@freeUpAccessPostDelete": { + "placeholders": { + "count": { + "example": "1", + "type": "int" + } + } + }, "freeUpAmount": "Frigjør {sizeInMBorGB}", "thisEmailIsAlreadyInUse": "Denne e-postadressen er allerede i bruk", "incorrectCode": "Feil kode", @@ -1016,6 +1031,7 @@ "didYouKnow": "Visste du at?", "loadingMessage": "Laster bildene dine...", "loadMessage1": "Du kan dele abonnementet med familien din", + "loadMessage2": "Vi har bevart over 200 millioner minner så langt", "loadMessage3": "Vi beholder 3 kopier av dine data, en i en underjordisk bunker", "loadMessage4": "Alle våre apper har åpen kildekode", "loadMessage5": "Vår kildekode og kryptografi har blitt revidert eksternt", @@ -1253,6 +1269,8 @@ "description": "Subtitle to indicate that the user can find people quickly by name" }, "findPeopleByName": "Finn folk raskt med navn", + "addViewers": "{count, plural, =0 {Legg til seer} =1 {Legg til seer} other {Legg til seere}}", + "addCollaborators": "{count, plural, =0 {Legg til samarbeidspartner} =1 {Legg til samarbeidspartner} other {Legg til samarbeidspartnere}}", "longPressAnEmailToVerifyEndToEndEncryption": "Trykk og hold på en e-post for å bekrefte ende-til-ende-kryptering.", "developerSettingsWarning": "Er du sikker på at du vil endre utviklerinnstillingene?", "developerSettings": "Utviklerinnstillinger", @@ -1264,6 +1282,8 @@ "createCollaborativeLink": "Samarbeidslenke", "search": "Søk", "enterPersonName": "Angi personnavn", + "editEmailAlreadyLinked": "Denne e-postadressen er allerede koblet til {name}.", + "viewPersonToUnlink": "Vis {name} for å fjerne koblingen", "enterName": "Angi navn", "savePerson": "Lagre person", "editPerson": "Rediger person", @@ -1383,6 +1403,16 @@ "enableMachineLearningBanner": "Aktiver maskinlæring for magisk søk og ansiktsgjenkjenning", "searchDiscoverEmptySection": "Bilder vil vises her når behandlingen og synkronisering er fullført", "searchPersonsEmptySection": "Folk vil vises her når behandling og synkronisering er fullført", + "viewersSuccessfullyAdded": "{count, plural, =0 {La til 0 tilskuere} =1 {La til 1 tilskuer} other {La til {count} tilskuer}}", + "@viewersSuccessfullyAdded": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + }, + "description": "Number of viewers that were successfully added to an album." + }, "collaboratorsSuccessfullyAdded": "{count, plural, =0 {La til 0 samarbeidspartner} =1 {La til 1 samarbeidspartner} other {Lagt til {count} samarbeidspartnere}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { @@ -1458,6 +1488,15 @@ }, "currentlyRunning": "Kjører for øyeblikket", "ignored": "ignorert", + "photosCount": "{count, plural, =0 {0 bilder} =1 {1 bilde} other {{count} bilder}}", + "@photosCount": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, "file": "Fil", "searchSectionsLengthMismatch": "Uoverensstemmelse i seksjonslengde: {snapshotLength} != {searchLength}", "@searchSectionsLengthMismatch": { @@ -1623,6 +1662,7 @@ "@linkPersonCaption": { "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." }, + "videoStreaming": "Strømbare videoer", "processingVideos": "Behandler videoer", "streamDetails": "Strømmedetaljer", "processing": "Behandler", @@ -1688,5 +1728,13 @@ "moon": "I månelyset", "onTheRoad": "På veien igjen", "food": "Kulinær glede", - "pets": "Pelsvenner" + "pets": "Pelsvenner", + "curatedMemories": "Kuraterte minner", + "widgets": "Moduler", + "memories": "Minner", + "peopleWidgetDesc": "Velg folkene du ønsker å se på din hjemskjerm.", + "albumsWidgetDesc": "Velg albumene du ønsker å se på din hjemskjerm.", + "memoriesWidgetDesc": "Velg typen minner du ønsker å se på din hjemskjerm.", + "smartMemories": "Smarte minner", + "pastYearsMemories": "Tidligere års minner" } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_pl.arb b/mobile/apps/photos/lib/l10n/intl_pl.arb index 836add0ac0..d6c9af626c 100644 --- a/mobile/apps/photos/lib/l10n/intl_pl.arb +++ b/mobile/apps/photos/lib/l10n/intl_pl.arb @@ -372,6 +372,21 @@ "deleteFromBoth": "Usuń z obu", "newAlbum": "Nowy album", "albums": "Albumy", + "memoryCount": "{count, plural, =0{brak wspomnień} one{{formattedCount} wspomnienie} few{{formattedCount} wspomnienia} many{{formattedCount} wspomnień} other{{formattedCount} wspomnień}}", + "@memoryCount": { + "description": "The text to display the number of memories", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "formattedCount": { + "type": "String", + "example": "11.513, 11,511" + } + } + }, "selectedPhotos": "Wybrano {count}", "@selectedPhotos": { "description": "Display the number of selected photos", @@ -779,6 +794,14 @@ "share": "Udostępnij", "unhideToAlbum": "Odkryj do albumu", "restoreToAlbum": "Przywróć do albumu", + "moveItem": "{count, plural, =1 {Przenieś element} few {Przenieś elementy} many {Przenieś elementów} other {Przenieś elementów}}", + "@moveItem": { + "description": "Page title while moving one or more items to an album" + }, + "addItem": "{count, plural, =1 {Dodaj element} few {Dodaj elementy} many {Dodaj elementów} other {Dodaj elementów}}", + "@addItem": { + "description": "Page title while adding one or more items to album" + }, "createOrSelectAlbum": "Utwórz lub wybierz album", "selectAlbum": "Wybierz album", "searchByAlbumNameHint": "Nazwa albumu", @@ -876,6 +899,7 @@ "authToViewYourMemories": "Prosimy uwierzytelnić się, aby wyświetlić swoje wspomnienia", "unlock": "Odblokuj", "freeUpSpace": "Zwolnij miejsce", + "freeUpSpaceSaving": "{count, plural, =1 {Może zostać usunięty z urządzenia, aby zwolnić {formattedSize}} many {Może być usuniętych z urządzenia, aby zwolnić {formattedSize}} other {Mogą być usunięte z urządzenia, aby zwolnić {formattedSize}}}", "filesBackedUpInAlbum": "{count, plural, one {1 plikowi} other {{formattedNumber} plikom}} w tym albumie została bezpiecznie utworzona kopia zapasowa", "@filesBackedUpInAlbum": { "description": "Text to tell user how many files have been backed up in the album", @@ -906,6 +930,18 @@ } } }, + "@freeUpSpaceSaving": { + "description": "Text to tell user how much space they can free up by deleting items from the device" + }, + "freeUpAccessPostDelete": "Nadal możesz mieć dostęp {count, plural, =1 {do tego} other {do tych}} na Ente tak długo, jak masz aktywną subskrypcję", + "@freeUpAccessPostDelete": { + "placeholders": { + "count": { + "example": "1", + "type": "int" + } + } + }, "freeUpAmount": "Zwolnij {sizeInMBorGB}", "thisEmailIsAlreadyInUse": "Ten e-mail jest już używany", "incorrectCode": "Nieprawidłowy kod", @@ -1233,6 +1269,8 @@ "description": "Subtitle to indicate that the user can find people quickly by name" }, "findPeopleByName": "Szybko szukaj osób po imieniu", + "addViewers": "{count, plural, =0 {Dodaj widza} =1 {Dodaj widza} other {Dodaj widzów}}", + "addCollaborators": "{count, plural, =0 {Dodaj współuczestnika} =1 {Dodaj współuczestnika} other {Dodaj współuczestników}}", "longPressAnEmailToVerifyEndToEndEncryption": "Naciśnij i przytrzymaj e-mail, aby zweryfikować szyfrowanie end-to-end.", "developerSettingsWarning": "Czy na pewno chcesz zmodyfikować ustawienia programisty?", "developerSettings": "Ustawienia dla programistów", @@ -1365,6 +1403,16 @@ "enableMachineLearningBanner": "Włącz nauczanie maszynowe dla magicznego wyszukiwania i rozpoznawania twarzy", "searchDiscoverEmptySection": "Obrazy będą wyświetlane tutaj po zakończeniu przetwarzania i synchronizacji", "searchPersonsEmptySection": "Osoby będą wyświetlane tutaj po zakończeniu przetwarzania i synchronizacji", + "viewersSuccessfullyAdded": "{count, plural, =0 {Dodano 0 widzów} =1 {Dodano 1 widza} other {Dodano {count} widzów}}", + "@viewersSuccessfullyAdded": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + }, + "description": "Number of viewers that were successfully added to an album." + }, "collaboratorsSuccessfullyAdded": "{count, plural, =0 {Dodano 0 współuczestników} =1 {Dodano 1 współuczestnika} other {Dodano {count} współuczestników}}", "@collaboratorsSuccessfullyAdded": { "placeholders": { @@ -1440,6 +1488,15 @@ }, "currentlyRunning": "aktualnie uruchomiony", "ignored": "ignorowane", + "photosCount": "{count, plural, =0 {0 zdjęć} =1 {1 zdjęcie} few {{count} zdjęcia} many {{count} zdjęć} other {{count} zdjęć}}", + "@photosCount": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, "file": "Plik", "searchSectionsLengthMismatch": "Niezgodność długości sekcji: {snapshotLength} != {searchLength}", "@searchSectionsLengthMismatch": { @@ -1539,6 +1596,7 @@ "joinAlbumSubtextViewer": "aby dodać to do udostępnionych albumów", "join": "Dołącz", "linkEmail": "Połącz adres e-mail", + "link": "Połącz", "noEnteAccountExclamation": "Brak konta Ente!", "orPickFromYourContacts": "lub wybierz ze swoich kontaktów", "emailDoesNotHaveEnteAccount": "{email} nie posiada konta Ente.", @@ -1559,6 +1617,7 @@ } } }, + "reassignMe": "Przypisz \"Mnie\" ponownie", "me": "Ja", "linkEmailToContactBannerCaption": "aby szybciej udostępniać", "@linkEmailToContactBannerCaption": { @@ -1586,6 +1645,7 @@ } }, "selectYourFace": "Wybierz swoją twarz", + "reassigningLoading": "Ponowne przypisywanie...", "reassignedToName": "Ponownie przypisano cię do {name}", "@reassignedToName": { "placeholders": { @@ -1597,12 +1657,19 @@ "saveChangesBeforeLeavingQuestion": "Zapisać zmiany przed wyjściem?", "dontSave": "Nie zapisuj", "thisIsMeExclamation": "To ja!", + "linkPerson": "Połącz osobę", + "linkPersonCaption": "dla lepszych doświadczeń podczas udostępniania", + "@linkPersonCaption": { + "description": "Caption for the 'Link person' title. It should be a continuation of the 'Link person' title. Just like how 'Link person' + 'for better sharing experience' forms a proper sentence in English, the combination of these two strings should also be a proper sentence in other languages." + }, "videoStreaming": "Streamowalne wideo", "processingVideos": "Przetwarzanie wideo", + "streamDetails": "Szczegóły transmisji", "processing": "Przetwarzanie", "queued": "W kolejce", "ineligible": "Nie kwalifikuje się", "failed": "Nie powiodło się", + "playStream": "Odtwórz transmisję", "playOriginal": "Odtwórz oryginał", "joinAlbumConfirmationDialogBody": "Dołączenie do albumu sprawi, że Twój e-mail będzie widoczny dla jego uczestników.", "pleaseWaitThisWillTakeAWhile": "Prosimy czekać, to może zająć chwilę.", @@ -1619,13 +1686,25 @@ "moveSelectedPhotosToOneDate": "Przenieś wybrane zdjęcia na jedną datę", "shiftDatesAndTime": "Zmień daty i czas", "photosKeepRelativeTimeDifference": "Zdjęcia zachowują względną różnicę czasu", + "photocountPhotos": "{count, plural, =0 {Brak zdjęć} =1 {1 zdjęcie} few {{count} zdjęcia} many {{count} zdjęć} other {{count} zdjęć}}", + "@photocountPhotos": { + "placeholders": { + "count": { + "type": "int", + "example": "2" + } + } + }, "appIcon": "Ikona aplikacji", "notThisPerson": "Nie ta osoba?", "selectedItemsWillBeRemovedFromThisPerson": "Wybrane elementy zostaną usunięte z tej osoby, ale nie zostaną usunięte z Twojej biblioteki.", "throughTheYears": "{dateFormat} przez lata", "thisWeekThroughTheYears": "Ten tydzień przez lata", + "thisWeekXYearsAgo": "{count, plural, =1 {W tym tygodniu, {count} rok temu} few {W tym tygodniu, {count} lata temu} many {W tym tygodniu, {count} lat temu} other {W tym tygodniu, {count} lat temu}}", "youAndThem": "Ty i {name}", "admiringThem": "Podziwianie {name}", + "embracingThem": "Obejmowanie {name}", + "partyWithThem": "Impreza z {name}", "hikingWithThem": "Wędrówka z {name}", "feastingWithThem": "Ucztowanie z {name}", "selfiesWithThem": "Selfie z {name}", @@ -1638,6 +1717,7 @@ "personIsAge": "{name} ma {age} lat!", "personTurningAge": "{name} wkrótce będzie mieć {age} lat", "lastTimeWithThem": "Ostatnio z {name}", + "tripToLocation": "Wyjazd do {location}", "tripInYear": "Podróż w {year}", "lastYearsTrip": "Zeszłoroczna podróż", "sunrise": "Na horyzoncie", @@ -1655,6 +1735,7 @@ "peopleWidgetDesc": "Wybierz osoby, które chcesz zobaczyć na ekranie głównym.", "albumsWidgetDesc": "Wybierz albumy, które chcesz zobaczyć na ekranie głównym.", "memoriesWidgetDesc": "Wybierz rodzaj wspomnień, które chcesz zobaczyć na ekranie głównym.", + "smartMemories": "Inteligentne wspomnienia", "pastYearsMemories": "Wspomnienia z ubiegłych lat", "deleteMultipleAlbumDialog": "Usunąć również zdjęcia (i filmy) obecne w tych albumach {count} z wszystkich innych albumów, których są częścią?", "addParticipants": "Dodaj uczestników", @@ -1695,7 +1776,56 @@ "same": "Identyczne", "different": "Inne", "sameperson": "Ta sama osoba?", + "cLTitle1": "Zaawansowany Edytor Obrazów", + "cLDesc1": "Wydajemy nowy i zaawansowany edytor obrazów, który dodaje więcej klatek przycinania, filtry dla szybkich edycji, precyzyjne opcje dostrajania, w tym nasycenie, kontrast, jasność, temperatura i wiele więcej. Nowy edytor zawiera również możliwość rysowania zdjęć i dodawania emotikonów jako naklejki.", + "cLTitle2": "Inteligentne Albumy", + "cLDesc2": "Teraz możesz automatycznie dodawać zdjęcia wybranych osób do dowolnego albumu. Po prostu przejdź do albumu i wybierz \"automatycznie dodaj osoby\" z menu przepełnienia. Jeśli używane razem z udostępnionym albumem, możesz udostępniać zdjęcia bez żadnych kliknięć.", + "cLTitle3": "Ulepszona Galeria", + "cLDesc3": "Dodaliśmy możliwość grupowania Twojej galerii po tygodniach, miesiącach i latach. Możesz teraz spersonalizować swoją galerię, aby dokładnie wyglądać w ten sposób z nowymi opcjami grupowania, wraz z niestandardowymi siatkami", + "cLTitle4": "Szybsze Przewijanie", + "cLDesc4": "Wraz z kilkoma ulepszeniami w celu poprawy doświadczenia galerii, przeprojektowaliśmy również pasek przewijania, aby pokazywać znaczniki, umożliwiając szybki skok po osi czasu.", "indexingPausedStatusDescription": "Indeksowanie zostało wstrzymane. Zostanie automatycznie wznowione, gdy urządzenie będzie gotowe. Urządzenie uznaje się za gotowe, gdy poziom baterii, stan jej zdrowia oraz status termiczny znajdują się w bezpiecznym zakresie.", + "thisWeek": "Ten tydzień", + "lastWeek": "Zeszły tydzień", + "thisMonth": "Ten miesiąc", + "thisYear": "Ten rok", + "groupBy": "Grupuj według", "faceThumbnailGenerationFailed": "Nie można wygenerować miniaturek twarzy", - "fileAnalysisFailed": "Nie można przeanalizować pliku" + "fileAnalysisFailed": "Nie można przeanalizować pliku", + "editAutoAddPeople": "Edytuj automatyczne dodawanie osób", + "autoAddPeople": "Automatycznie dodaj osoby", + "autoAddToAlbum": "Automatycznie dodaj do albumu", + "shouldRemoveFilesSmartAlbumsDesc": "Czy pliki związane z osobą, które zostały wcześniej wybrane w inteligentnych albumach, powinny zostać usunięte?", + "addingPhotos": "Dodawanie zdjęć", + "gettingReady": "Przygotowywanie", + "addSomePhotosDesc1": "Dodaj jakieś zdjęcia lub wybierz ", + "addSomePhotosDesc2": "znane twarze", + "addSomePhotosDesc3": "\nzaczynając od", + "ignorePerson": "Ignoruj osobę", + "mixedGrouping": "Grupowanie mieszane?", + "analysis": "Analiza", + "doesGroupContainMultiplePeople": "Czy ta grupa zawiera wiele osób?", + "automaticallyAnalyzeAndSplitGrouping": "Automatycznie przeanalizujemy grupę, aby ustalić, czy jest wiele osób i oddzielimy ich ponownie. Może to potrwać kilka sekund.", + "layout": "Układ", + "day": "Dzień", + "peopleAutoAddDesc": "Wybierz osoby, które chcesz automatycznie dodać do albumu", + "undo": "Cofnij", + "redo": "Ponów", + "filter": "Filtruj", + "adjust": "Dostosuj", + "draw": "Rysuj", + "sticker": "Naklejka", + "brushColor": "Kolor Pędzla", + "font": "Czcionka", + "background": "Tło", + "align": "Wyrównaj", + "addedToAlbums": "{count, plural, =1{Pomyślnie dodano do 1 albumu} other{Pomyślnie dodano do {count} albumów}}", + "@addedToAlbums": { + "description": "Message shown when items are added to albums", + "placeholders": { + "count": { + "type": "int" + } + } + } } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_ru.arb b/mobile/apps/photos/lib/l10n/intl_ru.arb index 7378594bf4..d3bc0d412a 100644 --- a/mobile/apps/photos/lib/l10n/intl_ru.arb +++ b/mobile/apps/photos/lib/l10n/intl_ru.arb @@ -1778,5 +1778,12 @@ "sameperson": "Тот же человек?", "indexingPausedStatusDescription": "Индексирование приостановлено. Оно автоматически возобновится, когда устройство будет готово. Устройство считается готовым, когда уровень заряда батареи, её состояние и температура находятся в пределах нормы.", "faceThumbnailGenerationFailed": "Не удалось создать миниатюры лиц", - "fileAnalysisFailed": "Не удалось проанализировать файл" + "fileAnalysisFailed": "Не удалось проанализировать файл", + "addingPhotos": "Добавление фото", + "gettingReady": "Идет подготовка", + "addSomePhotosDesc2": "знакомые лица", + "analysis": "Анализ", + "day": "День", + "filter": "Фильтр", + "font": "Шрифт" } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_sr.arb b/mobile/apps/photos/lib/l10n/intl_sr.arb index e875286038..52f1bd951d 100644 --- a/mobile/apps/photos/lib/l10n/intl_sr.arb +++ b/mobile/apps/photos/lib/l10n/intl_sr.arb @@ -141,6 +141,66 @@ "enterThe6digitCodeFromnyourAuthenticatorApp": "Унесите 6-цифрени кôд из\nапликације за аутентификацију", "confirm": "Потврди", "setupComplete": "Постављање завршено", + "saveYourRecoveryKeyIfYouHaventAlready": "Уколико већ нисте, сачувајте кључ за опоравак", + "thisCanBeUsedToRecoverYourAccountIfYou": "Може се користити за опоравак рачуна уколико заборавите други ниво провере идентитета", + "twofactorAuthenticationPageTitle": "Двострука провера идентитета", + "lostDevice": "Изгубили сте уређај?", + "verifyingRecoveryKey": "Проверавам кључ за опоравак...", + "recoveryKeyVerified": "Кључ за опоравак је потврђен", + "recoveryKeySuccessBody": "Сјајно! Ваш кључ за опоравак је исправан. Хвала за потврду.\n\nНе заборавите да овај кључ чувате на сигурном месту.", + "invalidRecoveryKey": "Кључ за опоравак који сте унели није исправан. Постарајте се да садржи 24 речи, и проверите да ли сте их правилно уписали.\n\nУколико сте унели стари формат кључа, постарајте се да садржи 64 карактера и додатно проверите да ли је сваки исправно уписан.", + "invalidKey": "Неисправан кључ", + "tryAgain": "Покушај поново", + "viewRecoveryKey": "Погледај кључ за опоравак", + "confirmRecoveryKey": "Потврди кључ за опоравак", + "recoveryKeyVerifyReason": "Кључ за опоравак рачуна је једини начин да повратите фотографије ако заборавите лозинку. Можете га пронаћи под Подешавања > Рачун.\n\nУнесите ваш кључ за опоравак рачуна како бисмо били сигурни да сте га правилно сачували.", + "confirmYourRecoveryKey": "Потврдите кључ за опоравак", + "addViewer": "Додај посматрача", + "addCollaborator": "Додај сарадника", + "addANewEmail": "Додај нови имејл", + "orPickAnExistingOne": "Или изабери већ постојећи", + "collaboratorsCanAddPhotosAndVideosToTheSharedAlbum": "Сарадници могу додати фотографије и клипове у заједнички албум.", + "enterEmail": "Унеси имејл", + "albumOwner": "Власник", + "@albumOwner": { + "description": "Role of the album owner" + }, + "you": "Ти", + "collaborator": "Сарадник", + "addMore": "Додај још", + "@addMore": { + "description": "Button text to add more collaborators/viewers" + }, + "viewer": "Посматрач", + "remove": "Уклони", + "removeParticipant": "Уклони учесника", + "@removeParticipant": { + "description": "menuSectionTitle for removing a participant" + }, + "manage": "Управљај", + "addedAs": "Додат као", + "changePermissions": "Измените дозволе?", + "yesConvertToViewer": "Да, претвори у посматрача", + "cannotAddMorePhotosAfterBecomingViewer": "{user} неће више моћи да додаје фотографије у овај албум\nИ даље ће моћи да уклони фотографије које је претходно додао", + "allowAddingPhotos": "Дозволи додавање фотографија", + "@allowAddingPhotos": { + "description": "Switch button to enable uploading photos to a public link" + }, + "allowAddPhotosDescription": "Дозволи људима са линком да додају фотографије у заједнички албум.", + "passwordLock": "Закључај помоћу лозинке", + "canNotOpenTitle": "Не могу да отворим овај албум", + "canNotOpenBody": "Жао ми је, овај албум се не може отворити у апликацији.", + "disableDownloadWarningTitle": "Молим, обратите пажњу", + "disableDownloadWarningBody": "Људи и даље могу да направе снимак екрана или да скину ваше фотографије користећи друге апликације", + "allowDownloads": "Дозволи преузимање", + "linkExpiry": "Рок важења линка", + "linkExpired": "Истекао", + "linkEnabled": "Омогућено", + "linkNeverExpires": "Никада", + "expiredLinkInfo": "Линк је истекао. Поставите ново време за престанак важности линка или онемогућите његово истицање.", + "setAPassword": "Постави лозинку", + "lockButtonLabel": "Закључај", + "enterPassword": "Унеси лозинку", "removeLink": "Уклони везу", "manageLink": "Управљај везом", "linkExpiresOn": "Веза ће истећи {expiryTime}", @@ -219,6 +279,49 @@ "codeChangeLimitReached": "Жао нам је, достигли сте максимум броја промена кôда.", "onlyFamilyAdminCanChangeCode": "Молимо вас да контактирате {familyAdminEmail} да бисте променили свој код.", "storageInGB": "{storageAmountInGB} ГБ", + "claimed": "Освојено", + "@claimed": { + "description": "Used to indicate storage claimed, like 10GB Claimed" + }, + "details": "Више детаља", + "claimMore": "Освоји још!", + "theyAlsoGetXGb": "Они ће такође добити {storageAmountInGB} ГБ", + "freeStorageOnReferralSuccess": "{storageAmountInGB} ГБ сваки пут када се неко претплати на неку од наших понуда и при том унесе ваш код", + "claimFreeStorage": "Освоји бесплатан простор на диску", + "inviteYourFriends": "Позови своје пријатеље", + "referralStep1": "1. Дај овај код својим пријатељима", + "referralStep2": "2. Они се претплате на понуду која се плаћа", + "referralStep3": "3. Обоје добијате {storageInGB} ГБ* бесплатно", + "referralsAreCurrentlyPaused": "Препоручивање је тренутно паузирано", + "youCanAtMaxDoubleYourStorage": "* У најбољем случају можете удвостручити ваш простор", + "faq": "Честа питања", + "help": "Помоћ", + "oopsSomethingWentWrong": "Упс, дошло је до грешке", + "peopleUsingYourCode": "Људи који користе ваш позивни код", + "total": "укупно", + "codeUsedByYou": "Код који ви користите", + "freeStorageClaimed": "Освојен бесплатан простор", + "freeStorageUsable": "Бесплатан простор који је могуће искористити", + "removeFromAlbumTitle": "Уклони из албума?", + "removeFromAlbum": "Уклони из албума", + "itemsWillBeRemovedFromAlbum": "Изабране ставке ће бити уклоњене из овог албума", + "addingToFavorites": "Додајем у омиљене", + "removingFromFavorites": "Уклањам из омиљених", + "sorryCouldNotAddToFavorites": "Извини, није додато у омиљене!", + "sorryCouldNotRemoveFromFavorites": "Извини, није уклоњено из омиљених!", + "subscribe": "Претплати се", + "deleteSharedAlbum": "Иѕбриши дељени албум?", + "deleteAlbum": "Избриши албум", + "deleteSharedAlbumDialogBody": "Албум ће бити обрисан за све", + "yesRemove": "Да, уклони", + "creatingLink": "Креирам линк...", + "removeWithQuestionMark": "Уклони?", + "removeParticipantBody": "{userEmail} ће бити уклоњен из овог дељеног албума.\n\nСве фотографије које су они додали ће такође бити уклоњене", + "keepPhotos": "Задржи фотографије", + "deletePhotos": "Обриши фотгорафије", + "inviteToEnte": "Позови у Енте", + "disableLinkMessage": "Ово ће уклонити јавни линк за приступ \"{albumName}\".", + "sharing": "Делим...", "youCannotShareWithYourself": "Не можеш делити сам са собом", "archive": "Архивирај", "createAlbumActionHint": "Дуго притисните да бисте изабрали фотографије и кликните на + да бисте направили албум", @@ -286,5 +389,536 @@ "advancedSettings": "Напредно", "@advancedSettings": { "description": "The text to display in the advanced settings section" + }, + "photoGridSize": "Величина мреже за приказ фотографија", + "manageDeviceStorage": "Управљај кеш меморијом уређаја", + "manageDeviceStorageDesc": "Прегледај и очисти локалну кеш меморију.", + "machineLearning": "Машинско учење", + "mlConsent": "Омогући машинско учење", + "mlConsentTitle": "Омогући машинско учење?", + "mlConsentPrivacy": "Кликните како бисте сазнали више о овоме у нашим правилима приватности", + "mlConsentConfirmation": "Разумем, и желим да укључим машинско учење", + "magicSearch": "Магична претрага", + "discover": "Истражи", + "@discover": { + "description": "The text to display for the discover section under which we show receipts, screenshots, sunsets, greenery, etc." + }, + "discover_identity": "Идентитет", + "discover_screenshots": "Снимци екрана", + "discover_receipts": "Признанице", + "discover_notes": "Белешке", + "discover_memes": "Мимови", + "discover_visiting_cards": "Разгледнице", + "discover_babies": "Бебе", + "discover_pets": "Љубимци", + "discover_selfies": "Селфији", + "discover_wallpapers": "Позадине", + "discover_food": "Храна", + "discover_celebrations": "Прославе", + "discover_sunset": "Заласци сунца", + "discover_hills": "Брда", + "discover_greenery": "Зеленило", + "waitingForWifi": "Чекам на бежичну мрежу...", + "status": "Статус", + "indexedItems": "Индексиране ставке", + "pendingItems": "На чекању", + "clearIndexes": "Очисти индексе", + "selectFoldersForBackup": "Изабери фолдере за копирање", + "selectedFoldersWillBeEncryptedAndBackedUp": "Иѕабрани фолдери ће бити енкриптовани и сигурно похрањени", + "unselectAll": "Деселектуј све", + "selectAll": "Означи све", + "skip": "Прескочи", + "updatingFolderSelection": "Освежавам избор фолдера...", + "duplicateItemsGroup": "{count} фајлова, {formattedSize} сваки", + "@duplicateItemsGroup": { + "description": "Display the number of duplicate files and their size", + "type": "text", + "placeholders": { + "count": { + "example": "12", + "type": "int" + }, + "formattedSize": { + "example": "2.3 MB", + "type": "String" + } + } + }, + "showMemories": "Прикажи успомене", + "yearsAgo": "{count, plural, one{{count} година уназад} few {{count} године уназад} other{{count} година уназад}}", + "backupStatus": "Статус резервних копија", + "backupOverMobileData": "Копирај користећи мобилни интернет", + "backupVideos": "Копирај видео снимке", + "disableAutoLock": "Онемогући закључавање екрана", + "about": "О нама", + "privacy": "Приватност", + "terms": "Услови", + "checkForUpdates": "Провери да ли постоје новине", + "checkStatus": "Провери статус", + "checking": "Проверавам...", + "youAreOnTheLatestVersion": "Користите најновију верзију", + "account": "Рачун", + "manageSubscription": "Управљај претплатом", + "changePassword": "Измени лозинку", + "authToChangeYourPassword": "Потврдите идентитет како бисте променили лозинку", + "emailVerificationToggle": "Провера имејла", + "exportYourData": "Извези своје податке", + "logout": "Одјави се", + "authToInitiateAccountDeletion": "Потврдите идентитет како бисте покренули брисање рачуна", + "areYouSureYouWantToLogout": "Да ли сигурно желите да се одјавите?", + "yesLogout": "Да, одјави ме", + "aNewVersionOfEnteIsAvailable": "Нова Енте верзија је доступна.", + "update": "Ажурирај", + "installManually": "Инсталирај ручно", + "criticalUpdateAvailable": "Критично ажурирање је доступно", + "updateAvailable": "Ажурирање доступно", + "ignoreUpdate": "Игнориши", + "cannotDeleteSharedFiles": "Не могу да обришем дељене фајлове", + "retry": "Покушај поново", + "freeUpDeviceSpace": "Ослободи простор на уређају", + "allClear": "✨ Све је чисто", + "noDeviceThatCanBeDeleted": "Не постоје фајлови на овом уређају који би могли бити обрисани", + "removeDuplicates": "Уклони дупликате", + "removeDuplicatesDesc": "Прегледај и уклони фајлове који су дупликати.", + "viewLargeFiles": "Велики фајлови", + "viewLargeFilesDesc": "Погледај фајлове који заузимају највише простора.", + "noDuplicates": "✨ Нема дупликата", + "youveNoDuplicateFilesThatCanBeCleared": "Немаш дупликата које бисмо могли да обришемо", + "rateUs": "Оцени нас", + "youHaveSuccessfullyFreedUp": "Успешно сте ослободили {storageSaved}!", + "@youHaveSuccessfullyFreedUp": { + "description": "The text to display when the user has successfully freed up storage", + "type": "text", + "placeholders": { + "storageSaved": { + "example": "1.2 GB", + "type": "String" + } + } + }, + "duplicateFileCountWithStorageSaved": "Обрисали сте {count, plural, one{{count} дупликат} few {{count} дупликата} other{{count} дупликата}}, ослобађам ({storageSaved}!)", + "@duplicateFileCountWithStorageSaved": { + "description": "The text to display when the user has successfully cleaned up duplicate files", + "type": "text", + "placeholders": { + "count": { + "example": "1", + "type": "int" + }, + "storageSaved": { + "example": "1.2 GB", + "type": "String" + } + } + }, + "familyPlans": "Породичне понуде", + "referrals": "Препоруке", + "notifications": "Обавештења", + "sharedPhotoNotifications": "Нове дељене фотографије", + "sharedPhotoNotificationsExplanation": "Добиј обавештење када неко дода фотографију у албум у којем ви учествујете", + "advanced": "Напредно", + "general": "Опште", + "security": "Сигурност", + "no": "Не", + "yes": "Да", + "rateUsOnStore": "Оцени нас на {storeName}", + "blog": "Блог", + "merchandise": "Роба", + "twitter": "Твитер", + "mastodon": "Мастодон", + "matrix": "Матрикс", + "discord": "Дискорд", + "reddit": "Редит", + "yourStorageDetailsCouldNotBeFetched": "Подаци о вашем простору на диску нису могли бити освежени", + "reportABug": "Пријави грешку", + "reportBug": "Пријави грешку", + "suggestFeatures": "Предложи нову функционалност", + "support": "Подршка", + "theme": "Тема", + "lightTheme": "Светла", + "darkTheme": "Тамна", + "systemTheme": "Системска", + "freeTrial": "Бесплатна проба", + "selectYourPlan": "Изабери пакет", + "enteSubscriptionPitch": "Енте чува твоје успомене тако да су увек са тобом, чак и ако изгубиш уређај.", + "enteSubscriptionShareWithFamily": "Можеш додати и породицу у оквиру овог пакета.", + "currentUsageIs": "Тренутно искоришћено", + "@currentUsageIs": { + "description": "This text is followed by storage usage", + "examples": { + "0": "Current usage is 1.2 GB" + }, + "type": "text" + }, + "faqs": "Често постављана питања", + "renewsOn": "Претплата се обнавља {endDate}", + "freeTrialValidTill": "Бесплатан пробни период важи до {endDate}", + "validTill": "Важи до {endDate}", + "addOnValidTill": "Ваш {storageAmount} додатак важи до {endDate}", + "playStoreFreeTrialValidTill": "Бесплатни пробни период важи до {endDate}.\nМожете изабрати неки од планова након тога.", + "subWillBeCancelledOn": "Ваша претплата ће бити отказана {endDate}", + "subscription": "Претплата", + "paymentDetails": "Детаљи плаћања", + "manageFamily": "Управљај породицом", + "renewSubscription": "Однови претплату", + "cancelSubscription": "Откажи претплату", + "areYouSureYouWantToRenew": "Да ли сте сигурни да желите да обновите претплату?", + "yesRenew": "Да, обнови претплату", + "areYouSureYouWantToCancel": "Да ли сте сигурни да желите да откажете?", + "yesCancel": "Да, откажи", + "failedToCancel": "Неуспешно отказивање", + "twoMonthsFreeOnYearlyPlans": "2 месеца гратис уз годишњу претплату", + "monthly": "Месечно", + "@monthly": { + "description": "The text to display for monthly plans", + "type": "text" + }, + "yearly": "Годишње", + "@yearly": { + "description": "The text to display for yearly plans", + "type": "text" + }, + "confirmPlanChange": "Потврди промену пакета", + "areYouSureYouWantToChangeYourPlan": "Да ли сигурно желиш да промениш пакет?", + "youCannotDowngradeToThisPlan": "Не можете изабрати овај пакет", + "cancelOtherSubscription": "Молимо, прво откажите претплау на {paymentProvider}", + "@cancelOtherSubscription": { + "description": "The text to display when the user has an existing subscription from a different payment provider", + "type": "text", + "placeholders": { + "paymentProvider": { + "example": "Apple", + "type": "String" + } + } + }, + "optionalAsShortAsYouLike": "Опционо, коико год кратко желите...", + "send": "Пошаљи", + "askCancelReason": "Отказали сте претплату. Да ли бисте нам рекли разлог?", + "thankYouForSubscribing": "Хвала што сте се претплатили!", + "yourPurchaseWasSuccessful": "Куповина успешно закључена", + "yourPlanWasSuccessfullyUpgraded": "Успешно сте прешли на јачи пакет", + "yourPlanWasSuccessfullyDowngraded": "Успешно сте прешли на слабији пакет", + "yourSubscriptionWasUpdatedSuccessfully": "Претплата успешно ажурирана", + "googlePlayId": "Гугл плеј идентификација", + "appleId": "Епл идентификација", + "playstoreSubscription": "Претплата путем Гугл продавнице", + "appstoreSubscription": "Претплата путем Епл продавнице", + "visitWebToManage": "Претплатом можете управљати на страници web.ente.io", + "couldNotUpdateSubscription": "Неуспешно ажурирање претплате", + "pleaseContactSupportAndWeWillBeHappyToHelp": "Контактирајте подршку на support@ente.io и радо ћемо вам помоћи!", + "paymentFailed": "Неуспела уплата", + "continueOnFreeTrial": "Настави бесплатни пробни период", + "areYouSureYouWantToExit": "Сигурно желите да изађете?", + "thankYou": "Хвала вам", + "pleaseWaitForSometimeBeforeRetrying": "Мало сачекајте пре него што покушате поново", + "youAreOnAFamilyPlan": "Ви сте на породичном пакету!", + "leaveFamily": "Напусти породицу", + "areYouSureThatYouWantToLeaveTheFamily": "Да ли заиста желиш да напустиш породични пакет?", + "leave": "Напусти", + "rateTheApp": "Оцените апликацију", + "startBackup": "Започни сигурносно копирање", + "preserveMore": "Сачувај још", + "grantFullAccessPrompt": "Дозволите приступ свим фотографијама у подешавањима уређаја", + "allowPermTitle": "Дозволи приступ фотографијама", + "openSettings": "Отвори подешавања", + "selectMorePhotos": "Изабери још фотографија", + "existingUser": "Постојећи корисник", + "privateBackups": "Приватни бекапи", + "forYourMemories": "за твоје успомене", + "safelyStored": "Сигурно похрањено", + "atAFalloutShelter": "у подземном бункеру", + "designedToOutlive": "Направљено да надживи", + "available": "Доступно", + "everywhere": "свуда", + "newToEnte": "Нови на Енте", + "pleaseLoginAgain": "Молимо, улогујте се поново", + "autoLogoutMessage": "Излоговани сте услед техничке грешке. Извињавамо се за непријатност.", + "yourSubscriptionHasExpired": "Ваша претплата је истекла", + "storageLimitExceeded": "Расположив простор је прекорачен", + "upgrade": "Ажурирај", + "raiseTicket": "Пошаљи упит", + "@raiseTicket": { + "description": "Button text for raising a support tickets in case of unhandled errors during backup", + "type": "text" + }, + "backupFailed": "Неуспешна израда резервне копије", + "sorryBackupFailedDesc": "Извините, нисмо успели да копирамо овај фајл тренутно. Покушаћемо касније.", + "couldNotBackUpTryLater": "Нисмо могли да бекапујемо ваше податке.\nПокушаћемо касније.", + "enteCanEncryptAndPreserveFilesOnlyIfYouGrant": "Енте може да екриптује и сачува фајлове једино ако дозволите приступ њима", + "pleaseGrantPermissions": "Молимо, дозволите приступ", + "grantPermission": "Дозволите приступ", + "privateSharing": "Приватно дељење", + "shareOnlyWithThePeopleYouWant": "Дели само са људима са којима желиш", + "usePublicLinksForPeopleNotOnEnte": "Користи јавне линкове за људима који нису на Енте", + "allowPeopleToAddPhotos": "Дозволи људима да додају фотографије", + "shareAnAlbumNow": "Подели албум сада", + "collectEventPhotos": "Прикупи фотографије са догађаја", + "@onDevice": { + "description": "The text displayed above folders/albums stored on device", + "type": "text" + }, + "onDevice": "На уређају", + "@onEnte": { + "description": "The text displayed above albums backed up to Ente", + "type": "text" + }, + "onEnte": "У Енте", + "name": "Име", + "newest": "Најновије", + "lastUpdated": "Последње ажурирано", + "deleteEmptyAlbums": "Избриши празне албуме", + "deleteEmptyAlbumsWithQuestionMark": "Обриши празне албуме?", + "permanentlyDelete": "Трајно избриши", + "canOnlyCreateLinkForFilesOwnedByYou": "Можете направити линк само за фајлове који су ваше власништво", + "linkCopiedToClipboard": "Линк је копиран у меморију", + "restore": "Поврати", + "@restore": { + "description": "Display text for an action which triggers a restore of item from trash", + "type": "text" + }, + "moveToAlbum": "Премести у албум", + "unarchive": "Врати из архиве", + "createCollage": "Направи колаж", + "saveCollage": "Сачувај колаж", + "addToEnte": "Додај у Енте", + "addToAlbum": "Додај у албум", + "delete": "Обриши", + "hide": "Сакриј", + "share": "Подели", + "searchByAlbumNameHint": "Име албума", + "albumTitle": "Наслов албума", + "enterAlbumName": "Унесите име албума", + "movingFilesToAlbum": "Премештам фајлове у албум...", + "addedSuccessfullyTo": "Успешно додато у {albumName}", + "movedSuccessfullyTo": "Успешно премештено у {albumName}", + "thisAlbumAlreadyHDACollaborativeLink": "Овај албум већ има линк за сарадњу", + "collaborativeLinkCreatedFor": "Линк за сарадњу креиран за {albumName}", + "askYourLovedOnesToShare": "Замолите ваше вољене да деле", + "invite": "Позови", + "shareYourFirstAlbum": "Подели твој први албум", + "sharedWith": "Подељено са {emailIDs}", + "sharedWithMe": "Подељено са мном", + "sharedByMe": "Ја поделио", + "doubleYourStorage": "Удвостручи простор", + "referFriendsAnd2xYourPlan": "Препоручи пријатељима и удвостручи тренутни пакет", + "rename": "Преименуј", + "thisEmailIsAlreadyInUse": "Имејл је већ у употреби", + "yourVerificationCodeHasExpired": "Ваш код ѕа верификацију је истекао", + "emailChangedTo": "Имејл промењен у {newEmail}", + "allMemoriesPreserved": "Све успомене су сачуване", + "loadingGallery": "Учитавам галерију", + "syncing": "Синхронизујем...", + "syncStopped": "Синхронизација прекинута", + "archiving": "Архивирам...", + "unarchiving": "Премештам из архиве...", + "successfullyArchived": "Успешно архивирано", + "successfullyUnarchived": "Успешно премештено из архиве", + "renameFile": "Преименуј фајл", + "enterFileName": "Именуј фајл", + "filesDeleted": "Обрисани фајлови", + "permanentlyDeleteFromDevice": "Трајно обриши са уређаја?", + "language": "Језик", + "selectLanguage": "Изабери језик", + "locationName": "Назив локације", + "addLocation": "Додај локацију", + "groupNearbyPhotos": "Групиши околне фотографије", + "kiloMeterUnit": "км", + "addLocationButton": "Додај", + "radius": "Пречник", + "save": "Сачувај", + "centerPoint": "Централна тачка", + "pickCenterPoint": "Изабери централну тачку", + "useSelectedPhoto": "Корисити изабрану фотографију", + "edit": "Измени", + "deleteLocation": "Обриши локацију", + "rotateLeft": "Заротирај у лево", + "flip": "Обрни у огледалу", + "rotateRight": "Заротирај у десно", + "saveCopy": "Сачувај копију", + "light": "Осветљење", + "color": "Боја", + "yesDiscardChanges": "Да, одбаци измене", + "doYouWantToDiscardTheEditsYouHaveMade": "Да ли желиш да одбациш направљене измене?", + "saving": "Чувам...", + "editsSaved": "Измене сачуване", + "distanceInKMUnit": "км", + "@distanceInKMUnit": { + "description": "Unit for distance in km" + }, + "dayToday": "Данас", + "dayYesterday": "Јуче", + "usedSpace": "Искоришћен простор", + "storageBreakupFamily": "Породица", + "storageBreakupYou": "Ти", + "@storageBreakupYou": { + "description": "Label to indicate how much storage you are using when you are part of a family plan" + }, + "fileInfoAddDescHint": "Додај опис", + "editLocationTagTitle": "Измени локацију", + "setRadius": "Задај пречник", + "map": "Мапа", + "@map": { + "description": "Label for the map view" + }, + "maps": "Мапе", + "enableMaps": "Омогући мапе", + "addPhotos": "Додај фотографије", + "zoomOutToSeePhotos": "Одзумирај да видиш фотографије", + "inviteYourFriendsToEnte": "Позови твоје пријатеље на Енте", + "addToHiddenAlbum": "Додај у тајни албум", + "viewAddOnButton": "Погледај додатке", + "addOns": "Додаци", + "addOnPageSubtitle": "Детаљи додатака", + "yourMap": "Твоја мапа", + "searchHint4": "Локација", + "faces": "Лица", + "people": "Људи", + "contacts": "Контакти", + "signOutFromOtherDevices": "Излогујте се са осталих уређаја", + "signOutOtherDevices": "Излогуј друге уређаје", + "selectALocation": "Изабери локацију", + "selectALocationFirst": "Прво изабери локацију", + "changeLocationOfSelectedItems": "Измени локацију изабраних ставки?", + "playOnTv": "Гледај албум на телевизору", + "pair": "Упари", + "deviceNotFound": "Уређај није пронађен", + "joinDiscord": "Прикључи се Дискорду", + "locations": "Локације", + "developerSettings": "с", + "rotate": "Ротирај", + "left": "Лево", + "right": "Десно", + "whatsNew": "Шта је ново", + "useAsCover": "Користи за позадину", + "notPersonLabel": "Није {name}?", + "@notPersonLabel": { + "description": "Label to indicate that the person in the photo is not the person whose name is mentioned", + "placeholders": { + "name": { + "content": "{name}", + "type": "String" + } + } + }, + "panorama": "Панорама", + "reenterPassword": "Поново унеси лозинку", + "reenterPin": "Поново унеси пин", + "deviceLock": "Закључавање уређаја", + "setNewPassword": "Постави нову лозинку", + "enterPin": "Унеси пин", + "setNewPin": "Постави нови пин", + "appLock": "Закључавање апликације", + "tapToUnlock": "Додирните за откључавање", + "tooManyIncorrectAttempts": "Превише погрешних покушаја", + "autoLock": "Аутоматско закључавање", + "immediately": "Одмах", + "hideContent": "Сакриј садржај", + "nameTheAlbum": "Именуј албум", + "showPerson": "Покажи особу", + "sort": "Сортирај", + "mostRecent": "Најновије", + "mostRelevant": "Најрелевантније", + "personName": "Име особе", + "addNewPerson": "Додај нову особу", + "addNameOrMerge": "Додај име или споји", + "mergeWithExisting": "Споји са постојећом", + "newPerson": "Нова особа", + "addName": "Додај име", + "add": "Додај", + "localIndexing": "Локално индексирање", + "resetPerson": "Уклони", + "month": "месец", + "yearShort": "год", + "@yearShort": { + "description": "Appears in pricing page (/yr)" + }, + "allow": "Дозволи", + "acceptTrustInvite": "Прихвати позивницу", + "declineTrustInvite": "Одбиј позивницу", + "legacy": "Наслеђе", + "trustedContacts": "Контакти од поверења", + "warning": "Упозорење", + "proceed": "Настави", + "gallery": "Галерија", + "linkEmail": "Повежи имејл", + "me": "Ја", + "thisIsMeExclamation": "Ово сам ја!", + "playOriginal": "Пусти оригинал", + "selectTime": "Изабери време", + "selectDate": "Изабери датум", + "appIcon": "Иконица апликације", + "notThisPerson": "То није та особа?", + "throughTheYears": "{dateFormat} кроз године", + "thisWeekThroughTheYears": "Тренутна недеља кроз године", + "youAndThem": "Ти и {name}", + "partyWithThem": "Журка са {name}", + "hikingWithThem": "Походништво са {name}", + "selfiesWithThem": "Селфији са {name}", + "posingWithThem": "Позирање са {name}", + "backgroundWithThem": "Прелепи призори са {name}", + "sportsWithThem": "Спорт са {name}", + "roadtripWithThem": "Путовање са {name}", + "spotlightOnYourself": "Сва светла на теби", + "spotlightOnThem": "Сва светла на {name}", + "personTurningAge": "{name} ускоро навршава {age}", + "lastTimeWithThem": "Последњи пут са {name}", + "tripToLocation": "Пут у {location}", + "tripInYear": "Пут из {year}", + "lastYearsTrip": "Прошлогодишње путовање", + "sunrise": "На хирозонту", + "mountains": "Преко брда", + "greenery": "Зеленило", + "beach": "Песак и море", + "city": "У граду", + "moon": "Под светлом Месеца", + "onTheRoad": "На путу", + "food": "Кулинарски ужици", + "pets": "Чупави другари", + "curatedMemories": "Пробране успомене", + "widgets": "Виџети", + "memories": "Успомене", + "pastYearsMemories": "Прошлогодишње успомене", + "addParticipants": "Додај учеснике", + "onThisDayMemories": "Успомене на данашњи дан", + "onThisDay": "На данашњи дан", + "birthdayNotifications": "Обавешења о рођенданима", + "happyBirthday": "Срећан рођендан! 🥳", + "birthdays": "Рођендани", + "wishThemAHappyBirthday": "Пожели {name} срећан рођендан! 🎉", + "otherDetectedFaces": "Друга препозната лица", + "areThey": "Да ли је то", + "questionmark": "?", + "saveAsAnotherPerson": "Сачувај као другу особу", + "showLessFaces": "Прикажи мање лица", + "showMoreFaces": "Прикажи још лица", + "ignore": "Игнориши", + "merge": "Споји", + "reset": "Ресетуј", + "areYouSureYouWantToMergeThem": "Да ли си сигуран да желиш да их спојиш?", + "addSomePhotosDesc1": "Додај фотографије или изабери", + "addSomePhotosDesc2": "позната лица", + "addSomePhotosDesc3": "за почетак", + "ignorePerson": "Игнориши особу", + "analysis": "Анализа", + "layout": "Распоред", + "day": "Дан", + "peopleAutoAddDesc": "Изабери људе за које желиш да буду аутоматски додати у албум", + "filter": "Филтер", + "adjust": "Прилагоди", + "draw": "Нацртај", + "sticker": "Налепница", + "brushColor": "Боја четкице", + "font": "Фонт", + "background": "Позадина", + "align": "Поравнај", + "addedToAlbums": "{count, plural, =1{Успешно додано у 1 албум} other{Успешно додано у {count} албума}}", + "@addedToAlbums": { + "description": "Message shown when items are added to albums", + "placeholders": { + "count": { + "type": "int" + } + } } } \ No newline at end of file diff --git a/mobile/apps/photos/lib/l10n/intl_sv.arb b/mobile/apps/photos/lib/l10n/intl_sv.arb index ccc0d6f882..2d4c753d42 100644 --- a/mobile/apps/photos/lib/l10n/intl_sv.arb +++ b/mobile/apps/photos/lib/l10n/intl_sv.arb @@ -1,6 +1,7 @@ { "@@locale ": "en", "enterYourEmailAddress": "Ange din e-postadress", + "enterYourNewEmailAddress": "Ange din nya e-postadress", "accountWelcomeBack": "Välkommen tillbaka!", "emailAlreadyRegistered": "E-postadress redan registrerad.", "emailNotRegistered": "E-postadressen är inte registrerad.", @@ -345,8 +346,20 @@ "keepPhotos": "Behåll foton", "deletePhotos": "Radera foton", "inviteToEnte": "Bjud in till Ente", + "removePublicLink": "Ta bort publik länk", + "sharing": "Delar...", + "youCannotShareWithYourself": "Du kan inte dela med dig själv", + "archive": "Arkiv", + "importing": "Importerar....", + "failedToLoadAlbums": "Det gick inte att läsa in album", + "hidden": "Dold", + "authToViewYourHiddenFiles": "Vänligen autentisera för att visa dina dolda filer", + "authToViewTrashedFiles": "Vänligen autentisera för att se dina kastade filer", "trash": "Papperskorg", + "uncategorized": "Okategoriserade", + "videoSmallCase": "video", "photoSmallCase": "foto", + "singleFileDeleteHighlight": "Det kommer att tas bort från alla album.", "yesDelete": "Ja, radera", "deleteFromDevice": "Radera från enhet", "newAlbum": "Nytt album", diff --git a/mobile/apps/photos/lib/l10n/intl_vi.arb b/mobile/apps/photos/lib/l10n/intl_vi.arb index 8d64a0f3f6..6392a8957d 100644 --- a/mobile/apps/photos/lib/l10n/intl_vi.arb +++ b/mobile/apps/photos/lib/l10n/intl_vi.arb @@ -15,13 +15,13 @@ "deleteAccountFeedbackPrompt": "Chúng tôi rất tiếc khi thấy bạn rời đi. Vui lòng chia sẻ phản hồi của bạn để giúp chúng tôi cải thiện.", "feedback": "Phản hồi", "kindlyHelpUsWithThisInformation": "Mong bạn giúp chúng tôi thông tin này", - "confirmDeletePrompt": "Có, tôi muốn xóa vĩnh viễn tài khoản này và tất cả dữ liệu của nó.", + "confirmDeletePrompt": "Có, tôi muốn xóa vĩnh viễn tài khoản này và tất cả dữ liệu.", "confirmAccountDeletion": "Xác nhận xóa tài khoản", "deleteAccountPermanentlyButton": "Xóa tài khoản vĩnh viễn", "yourAccountHasBeenDeleted": "Tài khoản của bạn đã bị xóa", "selectReason": "Chọn lý do", "deleteReason1": "Nó thiếu một tính năng quan trọng mà tôi cần", - "deleteReason2": "Ứng dụng hoặc một tính năng nhất định không hoạt động như tôi muốn", + "deleteReason2": "Ứng dụng hoặc một tính năng không hoạt động như tôi muốn", "deleteReason3": "Tôi tìm thấy một dịch vụ khác mà tôi thích hơn", "deleteReason4": "Lý do không có trong danh sách", "sendEmail": "Gửi email", @@ -241,7 +241,7 @@ "linkHasExpired": "Liên kết đã hết hạn", "publicLinkEnabled": "Liên kết công khai đã được bật", "shareALink": "Chia sẻ một liên kết", - "sharedAlbumSectionDescription": "Tạo album chia sẻ và cộng tác với người dùng Ente khác, bao gồm cả người dùng các gói miễn phí.", + "sharedAlbumSectionDescription": "Tạo album chia sẻ và cộng tác với người dùng Ente khác, bao gồm người dùng gói miễn phí.", "shareWithPeopleSectionTitle": "{numberOfPeople, plural, =0 {Chia sẻ với những người cụ thể} =1 {Chia sẻ với 1 người} other {Chia sẻ với {numberOfPeople} người}}", "@shareWithPeopleSectionTitle": { "placeholders": { @@ -293,7 +293,7 @@ "theyAlsoGetXGb": "Họ cũng nhận được {storageAmountInGB} GB", "freeStorageOnReferralSuccess": "{storageAmountInGB} GB mỗi khi ai đó đăng ký gói trả phí và áp dụng mã của bạn", "shareTextReferralCode": "Mã giới thiệu Ente: {referralCode} \n\nÁp dụng nó trong Cài đặt → Chung → Giới thiệu để nhận thêm {referralStorageInGB} GB miễn phí sau khi bạn đăng ký gói trả phí\n\nhttps://ente.io", - "claimFreeStorage": "Nhận thêm dung lượng miễn phí", + "claimFreeStorage": "Nhận thêm dung lượng", "inviteYourFriends": "Mời bạn bè của bạn", "failedToFetchReferralDetails": "Không thể lấy thông tin giới thiệu. Vui lòng thử lại sau.", "referralStep1": "1. Đưa mã này cho bạn bè của bạn", @@ -562,7 +562,7 @@ "referrals": "Giới thiệu", "notifications": "Thông báo", "sharedPhotoNotifications": "Ảnh chia sẻ mới", - "sharedPhotoNotificationsExplanation": "Nhận thông báo khi ai đó thêm ảnh vào album chia sẻ mà bạn tham gia", + "sharedPhotoNotificationsExplanation": "Nhận thông báo khi ai đó thêm ảnh vào album chia sẻ mà bạn tham gia.", "advanced": "Nâng cao", "general": "Chung", "security": "Bảo mật", @@ -822,8 +822,8 @@ "sharedWith": "Chia sẻ với {emailIDs}", "sharedWithMe": "Chia sẻ với tôi", "sharedByMe": "Chia sẻ bởi tôi", - "doubleYourStorage": "Gấp đôi dung lượng lưu trữ của bạn", - "referFriendsAnd2xYourPlan": "Giới thiệu bạn bè và ×2 gói của bạn", + "doubleYourStorage": "Nhân đôi dung lượng", + "referFriendsAnd2xYourPlan": "Giới thiệu bạn bè để được ×2 dung lượng gói của bạn", "shareAlbumHint": "Mở album và nhấn nút chia sẻ ở góc trên bên phải để chia sẻ.", "itemsShowTheNumberOfDaysRemainingBeforePermanentDeletion": "Trên các mục là số ngày còn lại trước khi xóa vĩnh viễn", "trashDaysLeft": "{count, plural, =0 {Sắp xóa} =1 {1 ngày} other {{count} ngày}}", @@ -1330,7 +1330,7 @@ }, "enable": "Bật", "enabled": "Bật", - "moreDetails": "Thêm chi tiết", + "moreDetails": "Thông tin thêm", "enableMLIndexingDesc": "Ente hỗ trợ học máy trên-thiết-bị nhằm nhận diện khuôn mặt, tìm kiếm vi diệu và các tính năng tìm kiếm nâng cao khác", "magicSearchHint": "Tìm kiếm vi diệu cho phép tìm ảnh theo nội dung của chúng, ví dụ: 'xe hơi', 'xe hơi đỏ', 'Ferrari'", "panorama": "Panorama", @@ -1752,7 +1752,7 @@ "addAlbumWidgetPrompt": "Thêm tiện ích album vào màn hình chính và quay lại đây để tùy chỉnh.", "addPeopleWidgetPrompt": "Thêm tiện ích người vào màn hình chính và quay lại đây để tùy chỉnh.", "birthdayNotifications": "Thông báo sinh nhật", - "receiveRemindersOnBirthdays": "Nhắc khi đến sinh nhật của ai đó. Chạm vào thông báo sẽ đưa bạn đến ảnh của người sinh nhật.", + "receiveRemindersOnBirthdays": "Nhắc khi đến sinh nhật của ai đó. Nhấn vào thông báo sẽ đưa bạn đến ảnh của người sinh nhật.", "happyBirthday": "Chúc mừng sinh nhật! 🥳", "birthdays": "Sinh nhật", "wishThemAHappyBirthday": "Chúc {name} sinh nhật vui vẻ! 🎉", diff --git a/mobile/apps/photos/lib/l10n/intl_zh.arb b/mobile/apps/photos/lib/l10n/intl_zh.arb index bb6219ced3..5ddb76d98f 100644 --- a/mobile/apps/photos/lib/l10n/intl_zh.arb +++ b/mobile/apps/photos/lib/l10n/intl_zh.arb @@ -1776,7 +1776,56 @@ "same": "相同", "different": "不同", "sameperson": "是同一个人?", + "cLTitle1": "高级图像编辑器", + "cLDesc1": "我们正在发布一款全新且高级的图像编辑器,新增更多裁剪框架、快速编辑的滤镜预设,以及包括饱和度、对比度、亮度、色温等在内的精细调整选项。新的编辑器还支持在照片上绘制和添加表情符号作为贴纸。", + "cLTitle2": "智能相册", + "cLDesc2": "您现在可以将所选人物的照片自动添加到任何相册。只需进入相册,从溢出菜单中选择“自动添加人物”。如果与共享相册一起使用,您可以零点击分享照片。", + "cLTitle3": "改进的相册", + "cLDesc3": "我们新增了按周、月、年对图库进行分组的功能。您现在可以通过这些新的分组选项以及自定义网格,定制图库的外观,完全按照您的喜好进行设置", + "cLTitle4": "更快滚动", + "cLDesc4": "除了多项后台改进以提升图库滚动体验外,我们还重新设计了滚动条,添加了标记功能,让您可以快速跳转到时间轴上的不同位置。", "indexingPausedStatusDescription": "索引已暂停。待设备准备就绪后,索引将自动恢复。当设备的电池电量、电池健康度和温度状态处于健康范围内时,设备即被视为准备就绪。", + "thisWeek": "本周", + "lastWeek": "上周", + "thisMonth": "本月", + "thisYear": "今年", + "groupBy": "分组依据", "faceThumbnailGenerationFailed": "无法生成人脸缩略图", - "fileAnalysisFailed": "无法分析文件" + "fileAnalysisFailed": "无法分析文件", + "editAutoAddPeople": "编辑自动添加人物", + "autoAddPeople": "自动添加人物", + "autoAddToAlbum": "自动添加到相册", + "shouldRemoveFilesSmartAlbumsDesc": "应该移除之前在智能相册中选择的与该人相关的文件吗?", + "addingPhotos": "正在添加照片", + "gettingReady": "准备就绪", + "addSomePhotosDesc1": "添加一些照片或者选择 ", + "addSomePhotosDesc2": "熟悉的面孔", + "addSomePhotosDesc3": "首先", + "ignorePerson": "忽略此人", + "mixedGrouping": "混合分组?", + "analysis": "分析", + "doesGroupContainMultiplePeople": "这个分组包含多个人吗?", + "automaticallyAnalyzeAndSplitGrouping": "我们将自动分析分组以确定是否有多人在场,并再次将他们分开。这可能需要几秒钟。", + "layout": "布局", + "day": "日", + "peopleAutoAddDesc": "选择您想要自动添加到相册的人", + "undo": "撤销", + "redo": "重做", + "filter": "筛选", + "adjust": "调整", + "draw": "绘制", + "sticker": "贴纸", + "brushColor": "笔刷颜色", + "font": "字体", + "background": "背景", + "align": "对齐", + "addedToAlbums": "{count, plural, =1{已成功添加到 1 个相册} other{已成功添加到 {count} 个相册}}", + "@addedToAlbums": { + "description": "Message shown when items are added to albums", + "placeholders": { + "count": { + "type": "int" + } + } + } } \ No newline at end of file diff --git a/mobile/apps/photos/lib/main.dart b/mobile/apps/photos/lib/main.dart index e7e24e2ffc..db7aa5d1b8 100644 --- a/mobile/apps/photos/lib/main.dart +++ b/mobile/apps/photos/lib/main.dart @@ -43,6 +43,7 @@ import 'package:photos/services/sync/remote_sync_service.dart'; import "package:photos/services/sync/sync_service.dart"; import "package:photos/services/video_preview_service.dart"; import "package:photos/services/wake_lock_service.dart"; +import "package:photos/src/rust/frb_generated.dart"; import 'package:photos/ui/tools/app_lock.dart'; import 'package:photos/ui/tools/lock_screen.dart'; import "package:photos/utils/email_util.dart"; @@ -65,6 +66,7 @@ bool _stopHearBeat = false; void main() async { debugRepaintRainbowEnabled = false; + await RustLib.init(); WidgetsFlutterBinding.ensureInitialized(); MediaKit.ensureInitialized(); diff --git a/mobile/apps/photos/lib/models/api/user/srp.dart b/mobile/apps/photos/lib/models/api/user/srp.dart index 1456052947..56b19c1317 100644 --- a/mobile/apps/photos/lib/models/api/user/srp.dart +++ b/mobile/apps/photos/lib/models/api/user/srp.dart @@ -5,7 +5,6 @@ class SetupSRPRequest { final String srpA; final bool isUpdate; - SetupSRPRequest({ required this.srpUserID, required this.srpSalt, @@ -82,6 +81,7 @@ class CompleteSRPSetupRequest { ); } } + class SrpAttributes { final String srpUserID; final String srpSalt; diff --git a/mobile/apps/photos/lib/models/memories/memories_cache.dart b/mobile/apps/photos/lib/models/memories/memories_cache.dart index f45282d30c..f49a1a1014 100644 --- a/mobile/apps/photos/lib/models/memories/memories_cache.dart +++ b/mobile/apps/photos/lib/models/memories/memories_cache.dart @@ -9,14 +9,12 @@ import "package:photos/models/memories/smart_memory.dart"; import "package:photos/models/memories/smart_memory_constants.dart"; import "package:photos/models/memories/trip_memory.dart"; -const kPersonShowTimeout = Duration(days: 7 * 10); -const kPersonAndTypeShowTimeout = Duration(days: 7 * 26); -const kClipShowTimeout = Duration(days: 3 * 10); -const kTripShowTimeout = Duration(days: 7 * 25); +const kPersonShowTimeout = Duration(days: 16 * kMemoriesUpdateFrequencyDays); +const kClipShowTimeout = Duration(days: 10 * kMemoriesUpdateFrequencyDays); +const kTripShowTimeout = Duration(days: 50 * kMemoriesUpdateFrequencyDays); final maxShowTimeout = [ kPersonShowTimeout, - kPersonAndTypeShowTimeout, kTripShowTimeout, ].reduce((value, element) => value > element ? value : element) * 3; diff --git a/mobile/apps/photos/lib/models/memories/smart_memory_constants.dart b/mobile/apps/photos/lib/models/memories/smart_memory_constants.dart index 2d9885f90e..35a8b4130c 100644 --- a/mobile/apps/photos/lib/models/memories/smart_memory_constants.dart +++ b/mobile/apps/photos/lib/models/memories/smart_memory_constants.dart @@ -1,4 +1,5 @@ // Constants for computing smart memories -const kMemoriesUpdateFrequency = Duration(days: 3); +const kMemoriesUpdateFrequencyDays = 3; +const kMemoriesUpdateFrequency = Duration(days: kMemoriesUpdateFrequencyDays); const kMemoriesMargin = Duration(days: 1); const kDayItself = Duration(days: 1); diff --git a/mobile/apps/photos/lib/models/selected_files.dart b/mobile/apps/photos/lib/models/selected_files.dart index e37368a89c..cdc37ce76f 100644 --- a/mobile/apps/photos/lib/models/selected_files.dart +++ b/mobile/apps/photos/lib/models/selected_files.dart @@ -79,8 +79,10 @@ class SelectedFiles extends ChangeNotifier { return false; } - void clearAll() { - Bus.instance.fire(ClearSelectionsEvent()); + void clearAll({bool fireEvent = true}) { + if (fireEvent) { + Bus.instance.fire(ClearSelectionsEvent()); + } lastSelectionOperationFiles.addAll(files); files.clear(); notifyListeners(); diff --git a/mobile/apps/photos/lib/models/similar_files.dart b/mobile/apps/photos/lib/models/similar_files.dart new file mode 100644 index 0000000000..ee946c499a --- /dev/null +++ b/mobile/apps/photos/lib/models/similar_files.dart @@ -0,0 +1,32 @@ +import "package:photos/models/file/file.dart"; + +class SimilarFiles { + final List files; + final Set fileIds; + final double furthestDistance; + + SimilarFiles( + this.files, + this.furthestDistance, + ) : fileIds = files.map((file) => file.uploadedFileID!).toSet(); + + int get totalSize => + files.fold(0, (sum, file) => sum + (file.fileSize ?? 0)); + + bool get isEmpty => files.isEmpty; + + int get length => files.length; + + @override + String toString() => + 'SimilarFiles(files: $files, size: $totalSize, distance: $furthestDistance)'; + + void removeFile(EnteFile file) { + files.remove(file); + fileIds.remove(file.uploadedFileID); + } + + bool containsFile(EnteFile file) { + return fileIds.contains(file.uploadedFileID); + } +} diff --git a/mobile/apps/photos/lib/services/machine_learning/ml_computer.dart b/mobile/apps/photos/lib/services/machine_learning/ml_computer.dart index 0adf68eebd..7eb58d401c 100644 --- a/mobile/apps/photos/lib/services/machine_learning/ml_computer.dart +++ b/mobile/apps/photos/lib/services/machine_learning/ml_computer.dart @@ -1,5 +1,8 @@ import 'dart:async'; +import "dart:typed_data" show Float32List; +import "package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart" + show Uint64List; import "package:logging/logging.dart"; import "package:photos/models/ml/vector.dart"; import "package:photos/services/machine_learning/ml_constants.dart"; @@ -32,6 +35,40 @@ class MLComputer extends SuperIsolate { static final MLComputer instance = MLComputer._privateConstructor(); factory MLComputer() => instance; + Future<(List, List)> bulkVectorSearch( + List clipFloat32, + bool exact, + ) async { + try { + final result = await runInIsolate(IsolateOperation.bulkVectorSearch, { + "clipFloat32": clipFloat32, + "exact": exact, + }); + return result; + } catch (e, s) { + _logger.severe("Could not run bulk vector search in MLComputer", e, s); + rethrow; + } + } + + Future<(Uint64List, List, List)> + bulkVectorSearchWithKeys( + Uint64List potentialKeys, + bool exact, + ) async { + try { + final result = + await runInIsolate(IsolateOperation.bulkVectorSearchWithKeys, { + "potentialKeys": potentialKeys, + "exact": exact, + }); + return result; + } catch (e, s) { + _logger.severe("Could not run bulk vector search in MLComputer", e, s); + rethrow; + } + } + Future> runClipText(String query) async { try { await _ensureLoadedClipTextModel(); diff --git a/mobile/apps/photos/lib/services/machine_learning/ml_constants.dart b/mobile/apps/photos/lib/services/machine_learning/ml_constants.dart index 424cf584fc..19b9844af2 100644 --- a/mobile/apps/photos/lib/services/machine_learning/ml_constants.dart +++ b/mobile/apps/photos/lib/services/machine_learning/ml_constants.dart @@ -1 +1 @@ -const imageEmbeddingsKey = "imageEmbeddings"; \ No newline at end of file +const imageEmbeddingsKey = "imageEmbeddings"; diff --git a/mobile/apps/photos/lib/services/machine_learning/ml_exceptions.dart b/mobile/apps/photos/lib/services/machine_learning/ml_exceptions.dart index 224be2fd6f..3c056b9514 100644 --- a/mobile/apps/photos/lib/services/machine_learning/ml_exceptions.dart +++ b/mobile/apps/photos/lib/services/machine_learning/ml_exceptions.dart @@ -1,4 +1,3 @@ - class GeneralFaceMlException implements Exception { final String message; @@ -26,4 +25,4 @@ class CouldNotRunFaceDetector implements Exception {} class CouldNotWarpAffine implements Exception {} -class CouldNotRunFaceEmbeddor implements Exception {} \ No newline at end of file +class CouldNotRunFaceEmbeddor implements Exception {} diff --git a/mobile/apps/photos/lib/services/machine_learning/semantic_search/query_result.dart b/mobile/apps/photos/lib/services/machine_learning/semantic_search/query_result.dart index aa48ab9f85..9e0d6e5455 100644 --- a/mobile/apps/photos/lib/services/machine_learning/semantic_search/query_result.dart +++ b/mobile/apps/photos/lib/services/machine_learning/semantic_search/query_result.dart @@ -3,4 +3,4 @@ class QueryResult { final double score; QueryResult(this.id, this.score); -} \ No newline at end of file +} diff --git a/mobile/apps/photos/lib/services/machine_learning/semantic_search/semantic_search_service.dart b/mobile/apps/photos/lib/services/machine_learning/semantic_search/semantic_search_service.dart index cf3930a782..032c21b777 100644 --- a/mobile/apps/photos/lib/services/machine_learning/semantic_search/semantic_search_service.dart +++ b/mobile/apps/photos/lib/services/machine_learning/semantic_search/semantic_search_service.dart @@ -1,6 +1,4 @@ import "dart:async" show Timer, unawaited; -import "dart:developer" as dev show log; -import "dart:math" show min; import "dart:ui" show Image; import "package:flutter/foundation.dart"; @@ -149,11 +147,13 @@ class SemanticSearchService { }, ); final queryResults = similarityResults[query]!; - // print query for top ten scores - for (int i = 0; i < min(10, queryResults.length); i++) { - final result = queryResults[i]; - dev.log("Query: $query, Score: ${result.score}, index $i"); - } + // Uncomment if needed for debugging: print query for top ten scores + // if (kDebugMode) { + // for (int i = 0; i < min(10, queryResults.length); i++) { + // final result = queryResults[i]; + // dev.log("Query: $query, Score: ${result.score}, index $i"); + // } + // } final Map fileIDToScoreMap = {}; for (final result in queryResults) { @@ -265,10 +265,19 @@ class SemanticSearchService { required Map minimumSimilarityMap, }) async { final startTime = DateTime.now(); + // Uncomment if needed for debugging: print query embeddings + // if (kDebugMode) { + // for (final queryText in textQueryToEmbeddingMap.keys) { + // final embedding = textQueryToEmbeddingMap[queryText]!; + // dev.log("CLIPTEXT Query: $queryText, embedding: $embedding"); + // } + // } await _cacheClipVectors(); - final Map> queryResults = await MLComputer - .instance - .computeBulkSimilarities(textQueryToEmbeddingMap, minimumSimilarityMap); + final Map> queryResults = + await MLComputer.instance.computeBulkSimilarities( + textQueryToEmbeddingMap, + minimumSimilarityMap, + ); final endTime = DateTime.now(); _logger.info( "computingSimilarities took for ${textQueryToEmbeddingMap.length} queries " + diff --git a/mobile/apps/photos/lib/services/machine_learning/similar_images_service.dart b/mobile/apps/photos/lib/services/machine_learning/similar_images_service.dart new file mode 100644 index 0000000000..fd1b0e9d1c --- /dev/null +++ b/mobile/apps/photos/lib/services/machine_learning/similar_images_service.dart @@ -0,0 +1,148 @@ +import "dart:math" show max; + +import "package:flutter/foundation.dart" show kDebugMode; +import "package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart" + show Uint64List; +import 'package:logging/logging.dart'; +import "package:photos/db/ml/db.dart"; +import "package:photos/extensions/stop_watch.dart"; +import 'package:photos/models/file/file.dart'; +import "package:photos/models/file/file_type.dart"; +import "package:photos/models/similar_files.dart"; +import "package:photos/services/machine_learning/ml_computer.dart"; +import "package:photos/services/machine_learning/ml_result.dart"; +import "package:photos/services/search_service.dart"; + +class SimilarImagesService { + final _logger = Logger("SimilarImagesService"); + + SimilarImagesService._privateConstructor(); + static final SimilarImagesService instance = + SimilarImagesService._privateConstructor(); + + /// Returns a list of SimilarFiles, where each SimilarFiles object contains + /// a list of files that are perceptually similar + Future> getSimilarFiles( + double distanceThreshold, { + bool exact = false, + }) async { + try { + final now = DateTime.now(); + final List result = + await _getSimilarFiles(distanceThreshold, exact); + final duration = DateTime.now().difference(now); + _logger.info( + "Found ${result.length} similar files in ${duration.inSeconds} seconds for threshold $distanceThreshold and exact $exact", + ); + return result; + } catch (e, s) { + _logger.severe("failed to get similar files", e, s); + rethrow; + } + } + + Future> _getSimilarFiles( + double distanceThreshold, + bool exact, + ) async { + final w = (kDebugMode ? EnteWatch('getSimilarFiles') : null)?..start(); + final mlDataDB = MLDataDB.instance; + _logger.info("Checking migration and filling clip vector DB"); + await mlDataDB.checkMigrateFillClipVectorDB(); + w?.log("checkMigrateFillClipVectorDB"); + + // Get all files, and all potential embedding IDs, and create a map of fileID to file + final allFiles = Set.from( + await SearchService.instance.getAllFilesForSearch(), + ); + final allFileIdsToFile = {}; + final fileIDs = []; + for (final file in allFiles) { + if (file.uploadedFileID != null && file.fileType != FileType.video) { + allFileIdsToFile[file.uploadedFileID!] = file; + fileIDs.add(file.uploadedFileID!); + } + } + final Uint64List potentialKeys = Uint64List.fromList(fileIDs); + w?.log("getAllFilesForSearch"); + + // Get mapping of fileIDs to corresponding personIDs + final fileIDToPersonIDs = >{}; + final dbPersonClusterInfo = await mlDataDB.getPersonToClusterIdToFaceIds(); + for (final personID in dbPersonClusterInfo.keys) { + final clusterInfo = dbPersonClusterInfo[personID]!; + for (final faceIDs in clusterInfo.values) { + for (final faceID in faceIDs) { + final fileID = getFileIdFromFaceId(faceID); + if (allFileIdsToFile.containsKey(fileID)) { + fileIDToPersonIDs + .putIfAbsent(fileID, () => {}) + .add(personID); + } + } + } + } + w?.log("getFileIDToPersonIDs"); + + // Run bulk vector search + final (keys, vectorKeys, distances) = + await MLComputer.instance.bulkVectorSearchWithKeys( + potentialKeys, + exact, + ); + w?.log("bulkSearchVectors"); + + // Run through the vector search results and create SimilarFiles objects + final alreadyUsedFileIDs = {}; + final allSimilarFiles = []; + for (int i = 0; i < keys.length; i++) { + final fileID = keys[i].toInt(); + if (alreadyUsedFileIDs.contains(fileID)) continue; + final firstLoopFile = allFileIdsToFile[fileID]; + if (firstLoopFile == null || firstLoopFile.uploadedFileID == null) { + continue; + } + final otherFileIDs = vectorKeys[i]; + final distancesToFiles = distances[i]; + final similarFilesList = []; + final personIDs = fileIDToPersonIDs[fileID] ?? {}; + double furthestDistance = 0.0; + for (int j = 0; j < otherFileIDs.length; j++) { + final otherFileID = otherFileIDs[j].toInt(); + if (otherFileID == fileID) continue; + if (alreadyUsedFileIDs.contains(otherFileID)) continue; + final distance = distancesToFiles[j]; + if (distance > distanceThreshold) break; + final otherFile = allFileIdsToFile[otherFileID]; + if (otherFile == null || otherFile.uploadedFileID == null) { + continue; + } + final otherPersonIDs = fileIDToPersonIDs[otherFileID] ?? {}; + if (!setsAreEqual(personIDs, otherPersonIDs)) continue; + similarFilesList.add(otherFile); + furthestDistance = max(furthestDistance, distance); + } + if (similarFilesList.isNotEmpty) { + similarFilesList.add(firstLoopFile); + for (final file in similarFilesList) { + alreadyUsedFileIDs.add(file.uploadedFileID!); + } + similarFilesList.sort((a, b) { + return a.displayName.length.compareTo(b.displayName.length); + }); + final similarFiles = SimilarFiles( + similarFilesList, + furthestDistance, + ); + allSimilarFiles.add(similarFiles); + } + } + w?.log("going through files"); + + return allSimilarFiles; + } +} + +bool setsAreEqual(Set set1, Set set2) { + return set1.length == set2.length && set1.containsAll(set2); +} diff --git a/mobile/apps/photos/lib/services/smart_memories_service.dart b/mobile/apps/photos/lib/services/smart_memories_service.dart index ce20f14cd2..117f334253 100644 --- a/mobile/apps/photos/lib/services/smart_memories_service.dart +++ b/mobile/apps/photos/lib/services/smart_memories_service.dart @@ -35,9 +35,9 @@ import "package:photos/services/collections_service.dart"; import "package:photos/services/language_service.dart"; import "package:photos/services/location_service.dart"; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; -import "package:photos/services/machine_learning/ml_computer.dart"; import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/services/search_service.dart"; +import "package:photos/utils/text_embeddings_util.dart"; class MemoriesResult { final List memories; @@ -103,24 +103,18 @@ class SmartMemoriesService { 'allImageEmbeddings has ${allImageEmbeddings.length} entries $t', ); - const String clipPositiveQuery = - 'Photo of a precious and nostalgic memory radiating warmth, vibrant energy, or quiet beauty — alive with color, light, or emotion'; - final clipPositiveTextVector = Vector.fromList( - await MLComputer.instance.runClipText(clipPositiveQuery), - ); - final Map clipPeopleActivityVectors = {}; - for (final peopleActivity in PeopleActivity.values) { - clipPeopleActivityVectors[peopleActivity] ??= Vector.fromList( - await MLComputer.instance.runClipText(activityQuery(peopleActivity)), + // Load pre-computed text embeddings from assets + final textEmbeddings = await loadTextEmbeddingsFromAssets(); + if (textEmbeddings == null) { + _logger.severe('Failed to load pre-computed text embeddings'); + throw Exception( + 'Failed to load pre-computed text embeddings', ); } - final Map clipMemoryTypeVectors = {}; - for (final clipMemoryType in ClipMemoryType.values) { - clipMemoryTypeVectors[clipMemoryType] ??= Vector.fromList( - await MLComputer.instance.runClipText(clipQuery(clipMemoryType)), - ); - } - _logger.info('clipPositiveTextVector and clipPeopleActivityVectors $t'); + _logger.info('Using pre-computed text embeddings from assets'); + final clipPositiveTextVector = textEmbeddings.clipPositiveVector; + final clipPeopleActivityVectors = textEmbeddings.peopleActivityVectors; + final clipMemoryTypeVectors = textEmbeddings.clipMemoryTypeVectors; final local = await getLocale(); final languageCode = local?.languageCode ?? "en"; @@ -422,6 +416,7 @@ class SmartMemoriesService { .map((p) => p.remoteID) .toList(); orderedImportantPersonsID.shuffle(Random()); + final amountOfPersons = orderedImportantPersonsID.length; w?.log('orderedImportantPersonsID setup'); // Check if the user has assignmed "me" @@ -709,6 +704,14 @@ class SmartMemoriesService { w?.log('relevancy setup'); // Loop through the people (and memory types) and add based on rotation + final shownPersonTimeout = Duration( + days: min( + kPersonShowTimeout.inDays, + max(1, amountOfPersons) * kMemoriesUpdateFrequencyDays, + ), + ); + final shownPersonAndTypeTimeout = + Duration(days: shownPersonTimeout.inDays * 2); peopleRotationLoop: for (final personID in orderedImportantPersonsID) { for (final memory in memoryResults) { @@ -721,11 +724,13 @@ class SmartMemoriesService { final shownDate = DateTime.fromMicrosecondsSinceEpoch(shownLog.lastTimeShown); final bool seenPersonRecently = - currentTime.difference(shownDate) < kPersonShowTimeout; + currentTime.difference(shownDate) < shownPersonTimeout; if (seenPersonRecently) continue peopleRotationLoop; } if (personToMemories[personID] == null) continue peopleRotationLoop; int added = 0; + final amountOfMemoryTypesForPerson = personToMemories[personID]!.length; + final bool manyMemoryTypes = amountOfMemoryTypesForPerson > 2; potentialMemoryLoop: for (final memoriesForCategory in personToMemories[personID]!.values) { PeopleMemory potentialMemory = memoriesForCategory.first; @@ -748,8 +753,10 @@ class SmartMemoriesService { final shownTypeDate = DateTime.fromMicrosecondsSinceEpoch(shownLog.lastTimeShown); final bool seenPersonTypeRecently = - currentTime.difference(shownTypeDate) < kPersonAndTypeShowTimeout; - if (seenPersonTypeRecently) continue potentialMemoryLoop; + currentTime.difference(shownTypeDate) < shownPersonAndTypeTimeout; + if (manyMemoryTypes && seenPersonTypeRecently) { + continue potentialMemoryLoop; + } } memoryResults.add(potentialMemory); added++; diff --git a/mobile/apps/photos/lib/src/rust/api/simple.dart b/mobile/apps/photos/lib/src/rust/api/simple.dart new file mode 100644 index 0000000000..a6a07cfa68 --- /dev/null +++ b/mobile/apps/photos/lib/src/rust/api/simple.dart @@ -0,0 +1,12 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: require_trailing_commas + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +import 'package:photos/src/rust/frb_generated.dart'; + +String greet({required String name}) => + RustLib.instance.api.crateApiSimpleGreet(name: name); diff --git a/mobile/apps/photos/lib/src/rust/api/usearch_api.dart b/mobile/apps/photos/lib/src/rust/api/usearch_api.dart new file mode 100644 index 0000000000..118cb1b38c --- /dev/null +++ b/mobile/apps/photos/lib/src/rust/api/usearch_api.dart @@ -0,0 +1,57 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: require_trailing_commas + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +import 'package:photos/src/rust/frb_generated.dart'; + +// These functions are ignored because they are not marked as `pub`: `ensure_capacity`, `save_index` + +// Rust type: RustOpaqueMoi> +abstract class VectorDb implements RustOpaqueInterface { + Future addVector({required BigInt key, required List vector}); + + Future bulkAddVectors( + {required Uint64List keys, required List vectors}); + + Future> bulkGetVectors({required Uint64List keys}); + + Future bulkRemoveVectors({required Uint64List keys}); + + Future<(Uint64List, List, List)> bulkSearchKeys( + {required Uint64List potentialKeys, + required BigInt count, + required bool exact}); + + Future<(List, List)> bulkSearchVectors( + {required List queries, + required BigInt count, + required bool exact}); + + /// Check if a vector with the given key exists in the index. + /// `true` if the index contains the vector with the given key, `false` otherwise. + Future containsVector({required BigInt key}); + + Future deleteIndex(); + + Future<(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt)> + getIndexStats(); + + Future getVector({required BigInt key}); + + factory VectorDb({required String filePath, required BigInt dimensions}) => + RustLib.instance.api.crateApiUsearchApiVectorDbNew( + filePath: filePath, dimensions: dimensions); + + Future removeVector({required BigInt key}); + + Future resetIndex(); + + Future<(Uint64List, Float32List)> searchVectors( + {required List query, + required BigInt count, + required bool exact}); +} diff --git a/mobile/apps/photos/lib/src/rust/frb_generated.dart b/mobile/apps/photos/lib/src/rust/frb_generated.dart new file mode 100644 index 0000000000..931d5ffb3a --- /dev/null +++ b/mobile/apps/photos/lib/src/rust/frb_generated.dart @@ -0,0 +1,1244 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: require_trailing_commas + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +import 'package:photos/src/rust/api/simple.dart'; +import 'package:photos/src/rust/api/usearch_api.dart'; +import 'package:photos/src/rust/frb_generated.dart'; +import 'package:photos/src/rust/frb_generated.io.dart' + if (dart.library.js_interop) 'frb_generated.web.dart'; + +/// Main entrypoint of the Rust API +class RustLib extends BaseEntrypoint { + @internal + static final instance = RustLib._(); + + RustLib._(); + + /// Initialize flutter_rust_bridge + static Future init({ + RustLibApi? api, + BaseHandler? handler, + ExternalLibrary? externalLibrary, + bool forceSameCodegenVersion = true, + }) async { + await instance.initImpl( + api: api, + handler: handler, + externalLibrary: externalLibrary, + forceSameCodegenVersion: forceSameCodegenVersion, + ); + } + + /// Initialize flutter_rust_bridge in mock mode. + /// No libraries for FFI are loaded. + static void initMock({ + required RustLibApi api, + }) { + instance.initMockImpl( + api: api, + ); + } + + /// Dispose flutter_rust_bridge + /// + /// The call to this function is optional, since flutter_rust_bridge (and everything else) + /// is automatically disposed when the app stops. + static void dispose() => instance.disposeImpl(); + + @override + ApiImplConstructor get apiImplConstructor => + RustLibApiImpl.new; + + @override + WireConstructor get wireConstructor => + RustLibWire.fromExternalLibrary; + + @override + Future executeRustInitializers() async { + await api.crateApiSimpleInitApp(); + } + + @override + ExternalLibraryLoaderConfig get defaultExternalLibraryLoaderConfig => + kDefaultExternalLibraryLoaderConfig; + + @override + String get codegenVersion => '2.11.1'; + + @override + int get rustContentHash => 1360671619; + + static const kDefaultExternalLibraryLoaderConfig = + ExternalLibraryLoaderConfig( + stem: 'rust_lib_photos', + ioDirectory: 'rust/target/release/', + webPrefix: 'pkg/', + ); +} + +abstract class RustLibApi extends BaseApi { + Future crateApiUsearchApiVectorDbAddVector( + {required VectorDb that, + required BigInt key, + required List vector}); + + Future crateApiUsearchApiVectorDbBulkAddVectors( + {required VectorDb that, + required Uint64List keys, + required List vectors}); + + Future> crateApiUsearchApiVectorDbBulkGetVectors( + {required VectorDb that, required Uint64List keys}); + + Future crateApiUsearchApiVectorDbBulkRemoveVectors( + {required VectorDb that, required Uint64List keys}); + + Future<(Uint64List, List, List)> + crateApiUsearchApiVectorDbBulkSearchKeys( + {required VectorDb that, + required Uint64List potentialKeys, + required BigInt count, + required bool exact}); + + Future<(List, List)> + crateApiUsearchApiVectorDbBulkSearchVectors( + {required VectorDb that, + required List queries, + required BigInt count, + required bool exact}); + + Future crateApiUsearchApiVectorDbContainsVector( + {required VectorDb that, required BigInt key}); + + Future crateApiUsearchApiVectorDbDeleteIndex({required VectorDb that}); + + Future<(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt)> + crateApiUsearchApiVectorDbGetIndexStats({required VectorDb that}); + + Future crateApiUsearchApiVectorDbGetVector( + {required VectorDb that, required BigInt key}); + + VectorDb crateApiUsearchApiVectorDbNew( + {required String filePath, required BigInt dimensions}); + + Future crateApiUsearchApiVectorDbRemoveVector( + {required VectorDb that, required BigInt key}); + + Future crateApiUsearchApiVectorDbResetIndex({required VectorDb that}); + + Future<(Uint64List, Float32List)> crateApiUsearchApiVectorDbSearchVectors( + {required VectorDb that, + required List query, + required BigInt count, + required bool exact}); + + String crateApiSimpleGreet({required String name}); + + Future crateApiSimpleInitApp(); + + RustArcIncrementStrongCountFnType + get rust_arc_increment_strong_count_VectorDb; + + RustArcDecrementStrongCountFnType + get rust_arc_decrement_strong_count_VectorDb; + + CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_VectorDbPtr; +} + +class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { + RustLibApiImpl({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @override + Future crateApiUsearchApiVectorDbAddVector( + {required VectorDb that, + required BigInt key, + required List vector}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_u_64(key, serializer); + sse_encode_list_prim_f_32_loose(vector, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 1, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbAddVectorConstMeta, + argValues: [that, key, vector], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbAddVectorConstMeta => + const TaskConstMeta( + debugName: "VectorDb_add_vector", + argNames: ["that", "key", "vector"], + ); + + @override + Future crateApiUsearchApiVectorDbBulkAddVectors( + {required VectorDb that, + required Uint64List keys, + required List vectors}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_list_prim_u_64_strict(keys, serializer); + sse_encode_list_list_prim_f_32_strict(vectors, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 2, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbBulkAddVectorsConstMeta, + argValues: [that, keys, vectors], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbBulkAddVectorsConstMeta => + const TaskConstMeta( + debugName: "VectorDb_bulk_add_vectors", + argNames: ["that", "keys", "vectors"], + ); + + @override + Future> crateApiUsearchApiVectorDbBulkGetVectors( + {required VectorDb that, required Uint64List keys}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_list_prim_u_64_strict(keys, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 3, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_list_prim_f_32_strict, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbBulkGetVectorsConstMeta, + argValues: [that, keys], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbBulkGetVectorsConstMeta => + const TaskConstMeta( + debugName: "VectorDb_bulk_get_vectors", + argNames: ["that", "keys"], + ); + + @override + Future crateApiUsearchApiVectorDbBulkRemoveVectors( + {required VectorDb that, required Uint64List keys}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_list_prim_u_64_strict(keys, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 4, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_usize, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbBulkRemoveVectorsConstMeta, + argValues: [that, keys], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbBulkRemoveVectorsConstMeta => + const TaskConstMeta( + debugName: "VectorDb_bulk_remove_vectors", + argNames: ["that", "keys"], + ); + + @override + Future<(Uint64List, List, List)> + crateApiUsearchApiVectorDbBulkSearchKeys( + {required VectorDb that, + required Uint64List potentialKeys, + required BigInt count, + required bool exact}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_list_prim_u_64_strict(potentialKeys, serializer); + sse_encode_usize(count, serializer); + sse_encode_bool(exact, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 5, port: port_); + }, + codec: SseCodec( + decodeSuccessData: + sse_decode_record_list_prim_u_64_strict_list_list_prim_u_64_strict_list_list_prim_f_32_strict, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbBulkSearchKeysConstMeta, + argValues: [that, potentialKeys, count, exact], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbBulkSearchKeysConstMeta => + const TaskConstMeta( + debugName: "VectorDb_bulk_search_keys", + argNames: ["that", "potentialKeys", "count", "exact"], + ); + + @override + Future<(List, List)> + crateApiUsearchApiVectorDbBulkSearchVectors( + {required VectorDb that, + required List queries, + required BigInt count, + required bool exact}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_list_list_prim_f_32_strict(queries, serializer); + sse_encode_usize(count, serializer); + sse_encode_bool(exact, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 6, port: port_); + }, + codec: SseCodec( + decodeSuccessData: + sse_decode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbBulkSearchVectorsConstMeta, + argValues: [that, queries, count, exact], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbBulkSearchVectorsConstMeta => + const TaskConstMeta( + debugName: "VectorDb_bulk_search_vectors", + argNames: ["that", "queries", "count", "exact"], + ); + + @override + Future crateApiUsearchApiVectorDbContainsVector( + {required VectorDb that, required BigInt key}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_u_64(key, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 7, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_bool, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbContainsVectorConstMeta, + argValues: [that, key], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbContainsVectorConstMeta => + const TaskConstMeta( + debugName: "VectorDb_contains_vector", + argNames: ["that", "key"], + ); + + @override + Future crateApiUsearchApiVectorDbDeleteIndex({required VectorDb that}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 8, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbDeleteIndexConstMeta, + argValues: [that], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbDeleteIndexConstMeta => + const TaskConstMeta( + debugName: "VectorDb_delete_index", + argNames: ["that"], + ); + + @override + Future<(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt)> + crateApiUsearchApiVectorDbGetIndexStats({required VectorDb that}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 9, port: port_); + }, + codec: SseCodec( + decodeSuccessData: + sse_decode_record_usize_usize_usize_usize_usize_usize_usize, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbGetIndexStatsConstMeta, + argValues: [that], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbGetIndexStatsConstMeta => + const TaskConstMeta( + debugName: "VectorDb_get_index_stats", + argNames: ["that"], + ); + + @override + Future crateApiUsearchApiVectorDbGetVector( + {required VectorDb that, required BigInt key}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_u_64(key, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 10, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_prim_f_32_strict, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbGetVectorConstMeta, + argValues: [that, key], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbGetVectorConstMeta => + const TaskConstMeta( + debugName: "VectorDb_get_vector", + argNames: ["that", "key"], + ); + + @override + VectorDb crateApiUsearchApiVectorDbNew( + {required String filePath, required BigInt dimensions}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(filePath, serializer); + sse_encode_usize(dimensions, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 11)!; + }, + codec: SseCodec( + decodeSuccessData: + sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbNewConstMeta, + argValues: [filePath, dimensions], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbNewConstMeta => + const TaskConstMeta( + debugName: "VectorDb_new", + argNames: ["filePath", "dimensions"], + ); + + @override + Future crateApiUsearchApiVectorDbRemoveVector( + {required VectorDb that, required BigInt key}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_u_64(key, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 12, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_usize, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbRemoveVectorConstMeta, + argValues: [that, key], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbRemoveVectorConstMeta => + const TaskConstMeta( + debugName: "VectorDb_remove_vector", + argNames: ["that", "key"], + ); + + @override + Future crateApiUsearchApiVectorDbResetIndex({required VectorDb that}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 13, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbResetIndexConstMeta, + argValues: [that], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbResetIndexConstMeta => + const TaskConstMeta( + debugName: "VectorDb_reset_index", + argNames: ["that"], + ); + + @override + Future<(Uint64List, Float32List)> crateApiUsearchApiVectorDbSearchVectors( + {required VectorDb that, + required List query, + required BigInt count, + required bool exact}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + that, serializer); + sse_encode_list_prim_f_32_loose(query, serializer); + sse_encode_usize(count, serializer); + sse_encode_bool(exact, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 14, port: port_); + }, + codec: SseCodec( + decodeSuccessData: + sse_decode_record_list_prim_u_64_strict_list_prim_f_32_strict, + decodeErrorData: null, + ), + constMeta: kCrateApiUsearchApiVectorDbSearchVectorsConstMeta, + argValues: [that, query, count, exact], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiUsearchApiVectorDbSearchVectorsConstMeta => + const TaskConstMeta( + debugName: "VectorDb_search_vectors", + argNames: ["that", "query", "count", "exact"], + ); + + @override + String crateApiSimpleGreet({required String name}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(name, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 15)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiSimpleGreetConstMeta, + argValues: [name], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiSimpleGreetConstMeta => const TaskConstMeta( + debugName: "greet", + argNames: ["name"], + ); + + @override + Future crateApiSimpleInitApp() { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 16, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: null, + ), + constMeta: kCrateApiSimpleInitAppConstMeta, + argValues: [], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiSimpleInitAppConstMeta => const TaskConstMeta( + debugName: "init_app", + argNames: [], + ); + + RustArcIncrementStrongCountFnType + get rust_arc_increment_strong_count_VectorDb => wire + .rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB; + + RustArcDecrementStrongCountFnType + get rust_arc_decrement_strong_count_VectorDb => wire + .rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB; + + @protected + VectorDb + dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return VectorDbImpl.frbInternalDcoDecode(raw as List); + } + + @protected + VectorDb + dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return VectorDbImpl.frbInternalDcoDecode(raw as List); + } + + @protected + VectorDb + dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return VectorDbImpl.frbInternalDcoDecode(raw as List); + } + + @protected + String dco_decode_String(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as String; + } + + @protected + bool dco_decode_bool(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as bool; + } + + @protected + double dco_decode_f_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as double; + } + + @protected + List dco_decode_list_list_prim_f_32_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List) + .map(dco_decode_list_prim_f_32_strict) + .toList(); + } + + @protected + List dco_decode_list_list_prim_u_64_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List) + .map(dco_decode_list_prim_u_64_strict) + .toList(); + } + + @protected + List dco_decode_list_prim_f_32_loose(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as List; + } + + @protected + Float32List dco_decode_list_prim_f_32_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as Float32List; + } + + @protected + Uint64List dco_decode_list_prim_u_64_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dcoDecodeUint64List(raw); + } + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as Uint8List; + } + + @protected + (List, List) + dco_decode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 2) { + throw Exception('Expected 2 elements, got ${arr.length}'); + } + return ( + dco_decode_list_list_prim_u_64_strict(arr[0]), + dco_decode_list_list_prim_f_32_strict(arr[1]), + ); + } + + @protected + ( + Uint64List, + List, + List + ) dco_decode_record_list_prim_u_64_strict_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 3) { + throw Exception('Expected 3 elements, got ${arr.length}'); + } + return ( + dco_decode_list_prim_u_64_strict(arr[0]), + dco_decode_list_list_prim_u_64_strict(arr[1]), + dco_decode_list_list_prim_f_32_strict(arr[2]), + ); + } + + @protected + ( + Uint64List, + Float32List + ) dco_decode_record_list_prim_u_64_strict_list_prim_f_32_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 2) { + throw Exception('Expected 2 elements, got ${arr.length}'); + } + return ( + dco_decode_list_prim_u_64_strict(arr[0]), + dco_decode_list_prim_f_32_strict(arr[1]), + ); + } + + @protected + (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) + dco_decode_record_usize_usize_usize_usize_usize_usize_usize(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 7) { + throw Exception('Expected 7 elements, got ${arr.length}'); + } + return ( + dco_decode_usize(arr[0]), + dco_decode_usize(arr[1]), + dco_decode_usize(arr[2]), + dco_decode_usize(arr[3]), + dco_decode_usize(arr[4]), + dco_decode_usize(arr[5]), + dco_decode_usize(arr[6]), + ); + } + + @protected + BigInt dco_decode_u_64(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dcoDecodeU64(raw); + } + + @protected + int dco_decode_u_8(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as int; + } + + @protected + void dco_decode_unit(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return; + } + + @protected + BigInt dco_decode_usize(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dcoDecodeU64(raw); + } + + @protected + VectorDb + sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return VectorDbImpl.frbInternalSseDecode( + sse_decode_usize(deserializer), sse_decode_i_32(deserializer)); + } + + @protected + VectorDb + sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return VectorDbImpl.frbInternalSseDecode( + sse_decode_usize(deserializer), sse_decode_i_32(deserializer)); + } + + @protected + VectorDb + sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return VectorDbImpl.frbInternalSseDecode( + sse_decode_usize(deserializer), sse_decode_i_32(deserializer)); + } + + @protected + String sse_decode_String(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final inner = sse_decode_list_prim_u_8_strict(deserializer); + return utf8.decoder.convert(inner); + } + + @protected + bool sse_decode_bool(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8() != 0; + } + + @protected + double sse_decode_f_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getFloat32(); + } + + @protected + List sse_decode_list_list_prim_f_32_strict( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + final len_ = sse_decode_i_32(deserializer); + final ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_list_prim_f_32_strict(deserializer)); + } + return ans_; + } + + @protected + List sse_decode_list_list_prim_u_64_strict( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + final len_ = sse_decode_i_32(deserializer); + final ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_list_prim_u_64_strict(deserializer)); + } + return ans_; + } + + @protected + List sse_decode_list_prim_f_32_loose(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getFloat32List(len_); + } + + @protected + Float32List sse_decode_list_prim_f_32_strict(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getFloat32List(len_); + } + + @protected + Uint64List sse_decode_list_prim_u_64_strict(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getUint64List(len_); + } + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getUint8List(len_); + } + + @protected + (List, List) + sse_decode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_field0 = sse_decode_list_list_prim_u_64_strict(deserializer); + final var_field1 = sse_decode_list_list_prim_f_32_strict(deserializer); + return (var_field0, var_field1); + } + + @protected + ( + Uint64List, + List, + List + ) sse_decode_record_list_prim_u_64_strict_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_field0 = sse_decode_list_prim_u_64_strict(deserializer); + final var_field1 = sse_decode_list_list_prim_u_64_strict(deserializer); + final var_field2 = sse_decode_list_list_prim_f_32_strict(deserializer); + return (var_field0, var_field1, var_field2); + } + + @protected + (Uint64List, Float32List) + sse_decode_record_list_prim_u_64_strict_list_prim_f_32_strict( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_field0 = sse_decode_list_prim_u_64_strict(deserializer); + final var_field1 = sse_decode_list_prim_f_32_strict(deserializer); + return (var_field0, var_field1); + } + + @protected + (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) + sse_decode_record_usize_usize_usize_usize_usize_usize_usize( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + final var_field0 = sse_decode_usize(deserializer); + final var_field1 = sse_decode_usize(deserializer); + final var_field2 = sse_decode_usize(deserializer); + final var_field3 = sse_decode_usize(deserializer); + final var_field4 = sse_decode_usize(deserializer); + final var_field5 = sse_decode_usize(deserializer); + final var_field6 = sse_decode_usize(deserializer); + return ( + var_field0, + var_field1, + var_field2, + var_field3, + var_field4, + var_field5, + var_field6 + ); + } + + @protected + BigInt sse_decode_u_64(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getBigUint64(); + } + + @protected + int sse_decode_u_8(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8(); + } + + @protected + void sse_decode_unit(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + BigInt sse_decode_usize(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getBigUint64(); + } + + @protected + int sse_decode_i_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getInt32(); + } + + @protected + void + sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + VectorDb self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_usize( + (self as VectorDbImpl).frbInternalSseEncode(move: true), serializer); + } + + @protected + void + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + VectorDb self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_usize( + (self as VectorDbImpl).frbInternalSseEncode(move: false), serializer); + } + + @protected + void + sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + VectorDb self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_usize( + (self as VectorDbImpl).frbInternalSseEncode(move: null), serializer); + } + + @protected + void sse_encode_String(String self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); + } + + @protected + void sse_encode_bool(bool self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self ? 1 : 0); + } + + @protected + void sse_encode_f_32(double self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putFloat32(self); + } + + @protected + void sse_encode_list_list_prim_f_32_strict( + List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_list_prim_f_32_strict(item, serializer); + } + } + + @protected + void sse_encode_list_list_prim_u_64_strict( + List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_list_prim_u_64_strict(item, serializer); + } + } + + @protected + void sse_encode_list_prim_f_32_loose( + List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putFloat32List( + self is Float32List ? self : Float32List.fromList(self)); + } + + @protected + void sse_encode_list_prim_f_32_strict( + Float32List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putFloat32List(self); + } + + @protected + void sse_encode_list_prim_u_64_strict( + Uint64List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putUint64List(self); + } + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putUint8List(self); + } + + @protected + void sse_encode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + (List, List) self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_list_prim_u_64_strict(self.$1, serializer); + sse_encode_list_list_prim_f_32_strict(self.$2, serializer); + } + + @protected + void + sse_encode_record_list_prim_u_64_strict_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + (Uint64List, List, List) self, + SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_prim_u_64_strict(self.$1, serializer); + sse_encode_list_list_prim_u_64_strict(self.$2, serializer); + sse_encode_list_list_prim_f_32_strict(self.$3, serializer); + } + + @protected + void sse_encode_record_list_prim_u_64_strict_list_prim_f_32_strict( + (Uint64List, Float32List) self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_prim_u_64_strict(self.$1, serializer); + sse_encode_list_prim_f_32_strict(self.$2, serializer); + } + + @protected + void sse_encode_record_usize_usize_usize_usize_usize_usize_usize( + (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) self, + SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_usize(self.$1, serializer); + sse_encode_usize(self.$2, serializer); + sse_encode_usize(self.$3, serializer); + sse_encode_usize(self.$4, serializer); + sse_encode_usize(self.$5, serializer); + sse_encode_usize(self.$6, serializer); + sse_encode_usize(self.$7, serializer); + } + + @protected + void sse_encode_u_64(BigInt self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putBigUint64(self); + } + + @protected + void sse_encode_u_8(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self); + } + + @protected + void sse_encode_unit(void self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + void sse_encode_usize(BigInt self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putBigUint64(self); + } + + @protected + void sse_encode_i_32(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putInt32(self); + } +} + +@sealed +class VectorDbImpl extends RustOpaque implements VectorDb { + // Not to be used by end users + VectorDbImpl.frbInternalDcoDecode(List wire) + : super.frbInternalDcoDecode(wire, _kStaticData); + + // Not to be used by end users + VectorDbImpl.frbInternalSseDecode(BigInt ptr, int externalSizeOnNative) + : super.frbInternalSseDecode(ptr, externalSizeOnNative, _kStaticData); + + static final _kStaticData = RustArcStaticData( + rustArcIncrementStrongCount: + RustLib.instance.api.rust_arc_increment_strong_count_VectorDb, + rustArcDecrementStrongCount: + RustLib.instance.api.rust_arc_decrement_strong_count_VectorDb, + rustArcDecrementStrongCountPtr: + RustLib.instance.api.rust_arc_decrement_strong_count_VectorDbPtr, + ); + + Future addVector({required BigInt key, required List vector}) => + RustLib.instance.api.crateApiUsearchApiVectorDbAddVector( + that: this, key: key, vector: vector); + + Future bulkAddVectors( + {required Uint64List keys, required List vectors}) => + RustLib.instance.api.crateApiUsearchApiVectorDbBulkAddVectors( + that: this, keys: keys, vectors: vectors); + + Future> bulkGetVectors({required Uint64List keys}) => + RustLib.instance.api + .crateApiUsearchApiVectorDbBulkGetVectors(that: this, keys: keys); + + Future bulkRemoveVectors({required Uint64List keys}) => + RustLib.instance.api + .crateApiUsearchApiVectorDbBulkRemoveVectors(that: this, keys: keys); + + Future<(Uint64List, List, List)> bulkSearchKeys( + {required Uint64List potentialKeys, + required BigInt count, + required bool exact}) => + RustLib.instance.api.crateApiUsearchApiVectorDbBulkSearchKeys( + that: this, potentialKeys: potentialKeys, count: count, exact: exact); + + Future<(List, List)> bulkSearchVectors( + {required List queries, + required BigInt count, + required bool exact}) => + RustLib.instance.api.crateApiUsearchApiVectorDbBulkSearchVectors( + that: this, queries: queries, count: count, exact: exact); + + /// Check if a vector with the given key exists in the index. + /// `true` if the index contains the vector with the given key, `false` otherwise. + Future containsVector({required BigInt key}) => RustLib.instance.api + .crateApiUsearchApiVectorDbContainsVector(that: this, key: key); + + Future deleteIndex() => + RustLib.instance.api.crateApiUsearchApiVectorDbDeleteIndex( + that: this, + ); + + Future<(BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt)> + getIndexStats() => + RustLib.instance.api.crateApiUsearchApiVectorDbGetIndexStats( + that: this, + ); + + Future getVector({required BigInt key}) => RustLib.instance.api + .crateApiUsearchApiVectorDbGetVector(that: this, key: key); + + Future removeVector({required BigInt key}) => RustLib.instance.api + .crateApiUsearchApiVectorDbRemoveVector(that: this, key: key); + + Future resetIndex() => + RustLib.instance.api.crateApiUsearchApiVectorDbResetIndex( + that: this, + ); + + Future<(Uint64List, Float32List)> searchVectors( + {required List query, + required BigInt count, + required bool exact}) => + RustLib.instance.api.crateApiUsearchApiVectorDbSearchVectors( + that: this, query: query, count: count, exact: exact); +} diff --git a/mobile/apps/photos/lib/src/rust/frb_generated.io.dart b/mobile/apps/photos/lib/src/rust/frb_generated.io.dart new file mode 100644 index 0000000000..f7b687f7d8 --- /dev/null +++ b/mobile/apps/photos/lib/src/rust/frb_generated.io.dart @@ -0,0 +1,315 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: require_trailing_commas + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi' as ffi; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; +import 'package:photos/src/rust/api/simple.dart'; +import 'package:photos/src/rust/api/usearch_api.dart'; +import 'package:photos/src/rust/frb_generated.dart'; + +abstract class RustLibApiImplPlatform extends BaseApiImpl { + RustLibApiImplPlatform({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_VectorDbPtr => wire + ._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr; + + @protected + VectorDb + dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + dynamic raw); + + @protected + VectorDb + dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + dynamic raw); + + @protected + VectorDb + dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + dynamic raw); + + @protected + String dco_decode_String(dynamic raw); + + @protected + bool dco_decode_bool(dynamic raw); + + @protected + double dco_decode_f_32(dynamic raw); + + @protected + List dco_decode_list_list_prim_f_32_strict(dynamic raw); + + @protected + List dco_decode_list_list_prim_u_64_strict(dynamic raw); + + @protected + List dco_decode_list_prim_f_32_loose(dynamic raw); + + @protected + Float32List dco_decode_list_prim_f_32_strict(dynamic raw); + + @protected + Uint64List dco_decode_list_prim_u_64_strict(dynamic raw); + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + + @protected + (List, List) + dco_decode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + dynamic raw); + + @protected + ( + Uint64List, + List, + List + ) dco_decode_record_list_prim_u_64_strict_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + dynamic raw); + + @protected + ( + Uint64List, + Float32List + ) dco_decode_record_list_prim_u_64_strict_list_prim_f_32_strict(dynamic raw); + + @protected + (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) + dco_decode_record_usize_usize_usize_usize_usize_usize_usize(dynamic raw); + + @protected + BigInt dco_decode_u_64(dynamic raw); + + @protected + int dco_decode_u_8(dynamic raw); + + @protected + void dco_decode_unit(dynamic raw); + + @protected + BigInt dco_decode_usize(dynamic raw); + + @protected + VectorDb + sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + SseDeserializer deserializer); + + @protected + VectorDb + sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + SseDeserializer deserializer); + + @protected + VectorDb + sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + SseDeserializer deserializer); + + @protected + String sse_decode_String(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + double sse_decode_f_32(SseDeserializer deserializer); + + @protected + List sse_decode_list_list_prim_f_32_strict( + SseDeserializer deserializer); + + @protected + List sse_decode_list_list_prim_u_64_strict( + SseDeserializer deserializer); + + @protected + List sse_decode_list_prim_f_32_loose(SseDeserializer deserializer); + + @protected + Float32List sse_decode_list_prim_f_32_strict(SseDeserializer deserializer); + + @protected + Uint64List sse_decode_list_prim_u_64_strict(SseDeserializer deserializer); + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + + @protected + (List, List) + sse_decode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + SseDeserializer deserializer); + + @protected + ( + Uint64List, + List, + List + ) sse_decode_record_list_prim_u_64_strict_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + SseDeserializer deserializer); + + @protected + (Uint64List, Float32List) + sse_decode_record_list_prim_u_64_strict_list_prim_f_32_strict( + SseDeserializer deserializer); + + @protected + (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) + sse_decode_record_usize_usize_usize_usize_usize_usize_usize( + SseDeserializer deserializer); + + @protected + BigInt sse_decode_u_64(SseDeserializer deserializer); + + @protected + int sse_decode_u_8(SseDeserializer deserializer); + + @protected + void sse_decode_unit(SseDeserializer deserializer); + + @protected + BigInt sse_decode_usize(SseDeserializer deserializer); + + @protected + int sse_decode_i_32(SseDeserializer deserializer); + + @protected + void + sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + VectorDb self, SseSerializer serializer); + + @protected + void + sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + VectorDb self, SseSerializer serializer); + + @protected + void + sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + VectorDb self, SseSerializer serializer); + + @protected + void sse_encode_String(String self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); + + @protected + void sse_encode_f_32(double self, SseSerializer serializer); + + @protected + void sse_encode_list_list_prim_f_32_strict( + List self, SseSerializer serializer); + + @protected + void sse_encode_list_list_prim_u_64_strict( + List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_f_32_loose( + List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_f_32_strict( + Float32List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_64_strict( + Uint64List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, SseSerializer serializer); + + @protected + void sse_encode_record_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + (List, List) self, SseSerializer serializer); + + @protected + void + sse_encode_record_list_prim_u_64_strict_list_list_prim_u_64_strict_list_list_prim_f_32_strict( + (Uint64List, List, List) self, + SseSerializer serializer); + + @protected + void sse_encode_record_list_prim_u_64_strict_list_prim_f_32_strict( + (Uint64List, Float32List) self, SseSerializer serializer); + + @protected + void sse_encode_record_usize_usize_usize_usize_usize_usize_usize( + (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) self, + SseSerializer serializer); + + @protected + void sse_encode_u_64(BigInt self, SseSerializer serializer); + + @protected + void sse_encode_u_8(int self, SseSerializer serializer); + + @protected + void sse_encode_unit(void self, SseSerializer serializer); + + @protected + void sse_encode_usize(BigInt self, SseSerializer serializer); + + @protected + void sse_encode_i_32(int self, SseSerializer serializer); +} + +// Section: wire_class + +class RustLibWire implements BaseWire { + factory RustLibWire.fromExternalLibrary(ExternalLibrary lib) => + RustLibWire(lib.ffiDynamicLibrary); + + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + RustLibWire(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; + + void + rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + ffi.Pointer ptr, + ) { + return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + ptr, + ); + } + + late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr = + _lookup)>>( + 'frbgen_photos_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB'); + late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB = + _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr + .asFunction)>(); + + void + rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + ffi.Pointer ptr, + ) { + return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + ptr, + ); + } + + late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr = + _lookup)>>( + 'frbgen_photos_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB'); + late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB = + _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDBPtr + .asFunction)>(); +} diff --git a/mobile/apps/photos/lib/ui/components/bottom_of_title_bar_widget.dart b/mobile/apps/photos/lib/ui/components/bottom_of_title_bar_widget.dart index 6d4a5d962f..be03babc47 100644 --- a/mobile/apps/photos/lib/ui/components/bottom_of_title_bar_widget.dart +++ b/mobile/apps/photos/lib/ui/components/bottom_of_title_bar_widget.dart @@ -18,8 +18,9 @@ class BottomOfTitleBarWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( - mainAxisAlignment: showCloseButton ? MainAxisAlignment.spaceBetween : - MainAxisAlignment.start, + mainAxisAlignment: showCloseButton + ? MainAxisAlignment.spaceBetween + : MainAxisAlignment.start, children: [ Flexible( child: Padding( diff --git a/mobile/apps/photos/lib/ui/extents_page_view.dart b/mobile/apps/photos/lib/ui/extents_page_view.dart index 1ed3572c9e..25f9200639 100644 --- a/mobile/apps/photos/lib/ui/extents_page_view.dart +++ b/mobile/apps/photos/lib/ui/extents_page_view.dart @@ -100,7 +100,7 @@ class ExtentsPageView extends StatefulWidget { int? itemCount, this.dragStartBehavior = DragStartBehavior.start, this.openDrawer, - }) : childrenDelegate = SliverChildBuilderDelegate( + }) : childrenDelegate = SliverChildBuilderDelegate( itemBuilder, childCount: itemCount, addAutomaticKeepAlives: false, @@ -198,7 +198,7 @@ class ExtentsPageView extends StatefulWidget { required this.childrenDelegate, this.dragStartBehavior = DragStartBehavior.start, this.openDrawer, - }) : extents = 0; + }) : extents = 0; /// The number of pages to build off screen. /// diff --git a/mobile/apps/photos/lib/ui/home/header_error_widget.dart b/mobile/apps/photos/lib/ui/home/header_error_widget.dart index 381d1c1a95..aab3aa91ba 100644 --- a/mobile/apps/photos/lib/ui/home/header_error_widget.dart +++ b/mobile/apps/photos/lib/ui/home/header_error_widget.dart @@ -9,8 +9,7 @@ import "package:photos/utils/navigation_util.dart"; class HeaderErrorWidget extends StatelessWidget { final Error? _error; - const HeaderErrorWidget({super.key, required Error? error}) - : _error = error; + const HeaderErrorWidget({super.key, required Error? error}) : _error = error; @override Widget build(BuildContext context) { diff --git a/mobile/apps/photos/lib/ui/settings/backup/free_space_options.dart b/mobile/apps/photos/lib/ui/settings/backup/free_space_options.dart index 6d42e2040c..95f61344b8 100644 --- a/mobile/apps/photos/lib/ui/settings/backup/free_space_options.dart +++ b/mobile/apps/photos/lib/ui/settings/backup/free_space_options.dart @@ -22,6 +22,7 @@ import "package:photos/ui/notification/toast.dart"; import "package:photos/ui/tools/debug/app_storage_viewer.dart"; import "package:photos/ui/tools/deduplicate_page.dart"; import "package:photos/ui/tools/free_space_page.dart"; +import "package:photos/ui/tools/similar_images_page.dart"; import "package:photos/ui/viewer/gallery/large_files_page.dart"; import "package:photos/utils/dialog_util.dart"; import 'package:photos/utils/navigation_util.dart'; @@ -187,6 +188,41 @@ class _FreeUpSpaceOptionsScreenState extends State { const SizedBox( height: 24, ), + if (flagService.enableVectorDb) + MenuItemWidget( + captionedTextWidget: + const CaptionedTextWidget( + title: + "Similar images", // TODO: lau: extract string + ), + menuItemColor: colorScheme.fillFaint, + trailingWidget: Icon( + Icons.chevron_right_outlined, + color: colorScheme.strokeBase, + ), + singleBorderRadius: 8, + alignCaptionedTextToLeft: true, + trailingIconIsMuted: true, + showOnlyLoadingState: true, + onTap: () async { + await routeToPage( + context, + const SimilarImagesPage(), + ); + }, + ), + if (flagService.enableVectorDb) + const Align( + alignment: Alignment.centerLeft, + child: MenuSectionDescriptionWidget( + content: + "Use AI to find images that look similar to each other.", // TODO: lau: extract string + ), + ), + if (flagService.enableVectorDb) + const SizedBox( + height: 24, + ), MenuItemWidget( captionedTextWidget: CaptionedTextWidget( title: S.of(context).viewLargeFiles, diff --git a/mobile/apps/photos/lib/ui/settings/debug/ml_debug_section_widget.dart b/mobile/apps/photos/lib/ui/settings/debug/ml_debug_section_widget.dart index fd83bcc7e0..b905228ee8 100644 --- a/mobile/apps/photos/lib/ui/settings/debug/ml_debug_section_widget.dart +++ b/mobile/apps/photos/lib/ui/settings/debug/ml_debug_section_widget.dart @@ -1,11 +1,20 @@ import "dart:async"; +import "dart:math" show Random; +import "dart:typed_data" show Float32List; +import "package:flutter/foundation.dart" show kDebugMode; import 'package:flutter/material.dart'; +import "package:flutter_rust_bridge/flutter_rust_bridge.dart"; import "package:logging/logging.dart"; +import "package:ml_linalg/linalg.dart"; +import "package:path_provider/path_provider.dart"; import "package:photos/core/constants.dart"; import "package:photos/core/event_bus.dart"; +import "package:photos/db/ml/clip_vector_db.dart"; import "package:photos/db/ml/db.dart"; import "package:photos/events/people_changed_event.dart"; +import "package:photos/extensions/stop_watch.dart"; +import "package:photos/generated/protos/ente/common/vector.pb.dart"; import "package:photos/models/ml/face/person.dart"; import "package:photos/models/search/generic_search_result.dart"; import "package:photos/service_locator.dart"; @@ -15,6 +24,8 @@ import 'package:photos/services/machine_learning/ml_service.dart'; import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart"; import "package:photos/services/notification_service.dart"; import "package:photos/services/search_service.dart"; +import "package:photos/src/rust/api/simple.dart"; +import "package:photos/src/rust/api/usearch_api.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/captioned_text_widget.dart'; import 'package:photos/ui/components/expandable_menu_item_widget.dart'; @@ -184,6 +195,382 @@ class _MLDebugSectionWidgetState extends State { }, ), sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Do some basic usearch", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + // randomly generate some vectors and keys + final random = Random(); + final tenEmbeddings = List.generate( + 10, + (index) { + final randomList = List.generate( + 192, + (_) => random.nextDouble(), // Values between 0 and 1 + ); + final randomVector = Vector.fromList(randomList).normalize(); + return Float32List.fromList(randomVector.toList()); + }, + ); + final tenKeys = Uint64List.fromList( + List.generate( + tenEmbeddings.length, + (index) => BigInt.from(index + 1), + ), + ); + final embedDimensions = BigInt.from(tenEmbeddings.first.length); + final indexPath = (await getApplicationSupportDirectory()).path + + "/ml/test/vector_db_index.usearch"; + final rustVectorDB = VectorDb( + filePath: indexPath, + dimensions: embedDimensions, + ); + await rustVectorDB.resetIndex(); + final stats = await rustVectorDB.getIndexStats(); + logger.info("vector_db stats: $stats"); + await rustVectorDB.bulkAddVectors( + keys: tenKeys, + vectors: tenEmbeddings, + ); + final statsAgain = await rustVectorDB.getIndexStats(); + logger.info("vector_db stats again: $statsAgain"); + final size = statsAgain.$1; + final capacity = statsAgain.$2; + final dimensions = statsAgain.$3; + showShortToast( + context, + "Size: $size, Capacity: $capacity, Dimensions: $dimensions", + ); + await rustVectorDB.deleteIndex(); + } catch (e, s) { + logger.warning('Rust bridge failed ', e, s); + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Fill ClipVectorDB", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + final allClip = await MLDataDB.instance.getAllClipVectors(); + final allClipSmall = allClip.sublist(0, 15000); + showShortToast(context, "Got all embeddings"); + logger.info("Got all embeddings"); + + final clipVectorDB = ClipVectorDB.instance; + await clipVectorDB.deleteAllEmbeddings(); + logger.info("Clean vector DB"); + final stats = await clipVectorDB.getIndexStats(); + logger.info(stats.toString()); + showShortToast(context, stats.toString()); + + final fileIDs = allClipSmall.map((e) => e.fileID).toList(); + final embeddings = allClipSmall + .map((e) => Float32List.fromList(e.vector.toList())) + .toList(); + showShortToast(context, "Reshaped embeddings data"); + logger.info("Reshaped embeddings data"); + + final now = DateTime.now(); + await clipVectorDB.bulkInsertEmbeddings( + fileIDs: fileIDs, + embeddings: embeddings, + ); + final duration = DateTime.now().difference(now); + logger.info( + "ClipVectorDB bulk insert took ${duration.inMilliseconds} ms for ${fileIDs.length} embeddings", + ); + final statsAfter = await clipVectorDB.getIndexStats(); + logger.info(statsAfter.toString()); + showShortToast(context, statsAfter.toString()); + } catch (e, s) { + logger.warning('ClipVectorDB migration failed ', e, s); + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Migrate to ClipVectorDB", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + await MLDataDB.instance.checkMigrateFillClipVectorDB(); + showShortToast(context, "Migration done!"); + } catch (e, s) { + logger.warning('ClipVectorDB migration failed ', e, s); + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Show ClipVectorDB stats", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + final clipVectorDB = ClipVectorDB.instance; + final stats = await clipVectorDB.getIndexStats(); + logger.info(stats.toString()); + showShortToast(context, stats.toString()); + } catch (e, s) { + logger.warning('ClipVectorDB stats failed ', e, s); + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Delete/Empty ClipVectorDB", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + final clipVectorDB = ClipVectorDB.instance; + await clipVectorDB.deleteIndex(); + } catch (e, s) { + logger.warning('ClipVectorDB cleanup failed ', e, s); + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Benchmark Vector DB Face", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + final w = (kDebugMode ? EnteWatch('MLDebugSectionWidget') : null) + ?..start(); + final persons = await PersonService.instance.getPersons(); + w?.log('get all persons for ${persons.length} persons'); + String laurensID = ''; + for (final person in persons) { + if (person.data.name.toLowerCase().contains('laurens')) { + laurensID = person.remoteID; + } + } + if (laurensID.isEmpty) { + throw Exception('Laurens not found'); + } + final laurensFaceIDs = + await MLDataDB.instance.getFaceIDsForPerson(laurensID); + w?.log( + 'getting all face ids for laurens (${laurensFaceIDs.length} faces)', + ); + final laurensFaceIdToEmbeddingData = await MLDataDB.instance + .getFaceEmbeddingMapForFaces(laurensFaceIDs); + + // Fill the vector DB with all embeddings + final laurensFaceIdToFloat32 = laurensFaceIdToEmbeddingData.map( + (key, value) => MapEntry( + key, + Float32List.fromList(EVector.fromBuffer(value).values), + ), + ); + final keys = Uint64List.fromList( + List.generate( + laurensFaceIdToFloat32.length, + (index) => BigInt.from(index + 1), + ), + ); + final vectorDB = VectorDb( + filePath: (await getApplicationSupportDirectory()).path + + "/ml/test/vector_db_face_index.usearch", + dimensions: BigInt.from( + laurensFaceIdToFloat32.values.first.length, + ), + ); + await vectorDB.resetIndex(); + await vectorDB.bulkAddVectors( + keys: keys, + vectors: laurensFaceIdToFloat32.values.toList(), + ); + + // Benchmarking the vector DB + final queries = laurensFaceIdToFloat32.values.toList(); + final count = BigInt.from(10); + w?.reset(); + final (vectorKeys, distances) = await vectorDB.bulkSearchVectors( + queries: queries, + count: count, + exact: false, + ); + + w?.log( + 'Done with ${queries.length * queries.length} (${queries.length} x ${queries.length}}) embeddings comparisons in vector DB', + ); + logger.info( + 'vector db results: ${vectorKeys.length} results, first: ${vectorKeys.first}, hundredth: ${vectorKeys[99]}', + ); + + // Benchmarking our own vector comparisons + final laurensFaceIdToEmbeddingVectors = + laurensFaceIdToEmbeddingData.map( + (key, value) => MapEntry( + key, + Vector.fromList(EVector.fromBuffer(value).values), + ), + ); + final faceVectors = laurensFaceIdToEmbeddingVectors.values; + w?.reset(); + for (final faceVector in faceVectors) { + for (final otherFaceVector in faceVectors) { + final _ = 1 - faceVector.dot(otherFaceVector); + } + } + + w?.log( + 'Done with ${faceVectors.length * faceVectors.length} (${faceVectors.length} x ${faceVectors.length}}) embeddings comparisons in own method', + ); + await vectorDB.deleteIndex(); + } catch (e, s) { + logger.warning('vector DB search failed ', e, s); + + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Benchmark Vector DB CLIP", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + final w = (kDebugMode ? EnteWatch('MLDebugSectionWidget') : null) + ?..start(); + final clipEmbeddings = await mlDataDB.getAllClipVectors(); + w?.log( + 'getting all clip embeddings (${clipEmbeddings.length} embeddings)', + ); + + // Fill the vector DB with all embeddings + final clipFloat32 = clipEmbeddings + .map( + (value) => Float32List.fromList(value.vector.toList()), + ) + .toList(); + final keys = Uint64List.fromList( + List.generate( + clipFloat32.length, + (index) => BigInt.from(index + 1), + ), + ); + final vectorDB = VectorDb( + filePath: (await getApplicationSupportDirectory()).path + + "/ml/test/vector_db_clip_index.usearch", + dimensions: BigInt.from( + clipFloat32.first.length, + ), + ); + await vectorDB.resetIndex(); + await vectorDB.bulkAddVectors( + keys: keys, + vectors: clipFloat32, + ); + + // Benchmarking the vector DB + final count = BigInt.from(10); + w?.reset(); + final (vectorKeys, distances) = await vectorDB.bulkSearchVectors( + queries: clipFloat32, + count: count, + exact: false, + ); + + w?.log( + 'Done with ${clipFloat32.length * clipFloat32.length} (${clipFloat32.length} x ${clipFloat32.length}}) embeddings comparisons in vector DB', + ); + logger.info( + 'vector db results: ${vectorKeys.length} results, first: ${vectorKeys.first} with distances ${distances.first}, hundredth: ${vectorKeys[99]} with distances ${distances[99]}', + ); + + // // Benchmarking our own vector comparisons + // final clipVectors = clipEmbeddings + // .map( + // (value) => value.vector, + // ) + // .toList(); + // w?.reset(); + // int compared = 0; + // int ms = DateTime.now().millisecondsSinceEpoch; + // for (final faceVector in clipVectors) { + // for (final otherFaceVector in clipVectors) { + // final _ = 1 - faceVector.dot(otherFaceVector); + // } + // compared++; + // if (compared % 100 == 0) { + // final now = DateTime.now().millisecondsSinceEpoch; + // logger.info( + // 'Compared next 100 in ${now - ms} ms, progress: ($compared / ${clipVectors.length})', + // ); + // ms = now; + // } + // } + // w?.log( + // 'Done with ${clipVectors.length * clipVectors.length} (${clipVectors.length} x ${clipVectors.length}}) embeddings comparisons in own method', + // ); + + await vectorDB.deleteIndex(); + } catch (e, s) { + logger.warning('vector DB search failed ', e, s); + + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, + MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Test rust bridge (without vectorDB)", + ), + pressedColor: getEnteColorScheme(context).fillFaint, + trailingIcon: Icons.chevron_right_outlined, + trailingIconIsMuted: true, + onTap: () async { + try { + final String greetings = greet(name: "Tom"); + const String expected = "Hello, Tom!"; + assert(greetings == expected); + debugPrint("String from rust: $greetings"); + showShortToast(context, greetings); + } catch (e, s) { + logger.warning('Rust bridge failed ', e, s); + await showGenericErrorDialog(context: context, error: e); + } + }, + ), + sectionOptionSpacing, MenuItemWidget( captionedTextWidget: FutureBuilder( future: getIndexStatus(), diff --git a/mobile/apps/photos/lib/ui/settings/ml/ml_user_dev_screen.dart b/mobile/apps/photos/lib/ui/settings/ml/ml_user_dev_screen.dart index 07a46131e1..db9e7a7964 100644 --- a/mobile/apps/photos/lib/ui/settings/ml/ml_user_dev_screen.dart +++ b/mobile/apps/photos/lib/ui/settings/ml/ml_user_dev_screen.dart @@ -57,57 +57,69 @@ class _MLUserDeveloperOptionsState extends State { ), ), const SizedBox(height: 48), - widget.mlIsEnabled ? ButtonWidget( - buttonType: ButtonType.neutral, - labelText: "Purge empty indices", - onTap: () async { - await deleteEmptyIndices(context); - }, - ) : const SizedBox(), - widget.mlIsEnabled ? const SizedBox(height: 24) : const SizedBox(), - widget.mlIsEnabled ? ButtonWidget( - buttonType: ButtonType.neutral, - labelText: "Reset all local ML", - onTap: () async { - await deleteAllLocalML(context); - }, - ) : const SizedBox(), - widget.mlIsEnabled ? const SizedBox(height: 24) : const SizedBox(), - widget.mlIsEnabled ? MenuItemWidget( - captionedTextWidget: const CaptionedTextWidget( - title: "Remote fetch", - ), - menuItemColor: colorScheme.fillFaint, - trailingWidget: ToggleSwitchWidget( - value: () => localSettings.remoteFetchEnabled, - onChanged: () async { - try { - await localSettings.toggleRemoteFetch(); - _logger.info( - 'Remote fetch is turned ${localSettings.remoteFetchEnabled ? 'on' : 'off'}', - ); - if (mounted) { - setState(() {}); - } - } catch (e, s) { - _logger.warning( - 'Remote fetch toggle failed ', - e, - s, - ); - await showGenericErrorDialog( - context: context, - error: e, - ); - } - }, - ), - singleBorderRadius: 8, - alignCaptionedTextToLeft: true, - isBottomBorderRadiusRemoved: true, - isGestureDetectorDisabled: true, - ) : const SizedBox(), - widget.mlIsEnabled ? const SizedBox(height: 24) : const SizedBox.shrink(), + widget.mlIsEnabled + ? ButtonWidget( + buttonType: ButtonType.neutral, + labelText: "Purge empty indices", + onTap: () async { + await deleteEmptyIndices(context); + }, + ) + : const SizedBox(), + widget.mlIsEnabled + ? const SizedBox(height: 24) + : const SizedBox(), + widget.mlIsEnabled + ? ButtonWidget( + buttonType: ButtonType.neutral, + labelText: "Reset all local ML", + onTap: () async { + await deleteAllLocalML(context); + }, + ) + : const SizedBox(), + widget.mlIsEnabled + ? const SizedBox(height: 24) + : const SizedBox(), + widget.mlIsEnabled + ? MenuItemWidget( + captionedTextWidget: const CaptionedTextWidget( + title: "Remote fetch", + ), + menuItemColor: colorScheme.fillFaint, + trailingWidget: ToggleSwitchWidget( + value: () => localSettings.remoteFetchEnabled, + onChanged: () async { + try { + await localSettings.toggleRemoteFetch(); + _logger.info( + 'Remote fetch is turned ${localSettings.remoteFetchEnabled ? 'on' : 'off'}', + ); + if (mounted) { + setState(() {}); + } + } catch (e, s) { + _logger.warning( + 'Remote fetch toggle failed ', + e, + s, + ); + await showGenericErrorDialog( + context: context, + error: e, + ); + } + }, + ), + singleBorderRadius: 8, + alignCaptionedTextToLeft: true, + isBottomBorderRadiusRemoved: true, + isGestureDetectorDisabled: true, + ) + : const SizedBox(), + widget.mlIsEnabled + ? const SizedBox(height: 24) + : const SizedBox.shrink(), ButtonWidget( buttonType: ButtonType.neutral, labelText: "Load face detection model", diff --git a/mobile/apps/photos/lib/ui/tools/collage/collage_item_widget.dart b/mobile/apps/photos/lib/ui/tools/collage/collage_item_widget.dart index 4351954d0b..66a45a55b7 100644 --- a/mobile/apps/photos/lib/ui/tools/collage/collage_item_widget.dart +++ b/mobile/apps/photos/lib/ui/tools/collage/collage_item_widget.dart @@ -1,4 +1,3 @@ - import "package:flutter/material.dart"; import 'package:photos/models/file/file.dart'; import "package:photos/ui/viewer/file/zoomable_image.dart"; diff --git a/mobile/apps/photos/lib/ui/tools/deduplicate_page.dart b/mobile/apps/photos/lib/ui/tools/deduplicate_page.dart index 09885f1a8d..81887b955f 100644 --- a/mobile/apps/photos/lib/ui/tools/deduplicate_page.dart +++ b/mobile/apps/photos/lib/ui/tools/deduplicate_page.dart @@ -29,8 +29,8 @@ class DeduplicatePage extends StatefulWidget { } class _DeduplicatePageState extends State { - static const crossAxisCount = 4; - static const crossAxisSpacing = 4.0; + static const crossAxisCount = 3; + static const crossAxisSpacing = 12.0; static const headerRowCount = 3; final Set selectedGrids = {}; @@ -277,7 +277,7 @@ class _DeduplicatePageState extends State { width: double.infinity, child: SafeArea( child: Padding( - padding: const EdgeInsets.symmetric(horizontal: crossAxisSpacing / 2), + padding: const EdgeInsets.symmetric(horizontal: crossAxisSpacing), child: TextButton( style: OutlinedButton.styleFrom( backgroundColor: @@ -375,7 +375,8 @@ class _DeduplicatePageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.fromLTRB(2, 4, 2, 12), + padding: const EdgeInsets.fromLTRB( + crossAxisSpacing, 4, crossAxisSpacing, 12,), child: GestureDetector( onTap: () { if (selectedGrids.contains(itemIndex)) { @@ -410,7 +411,7 @@ class _DeduplicatePageState extends State { ), ), Padding( - padding: const EdgeInsets.symmetric(horizontal: crossAxisSpacing / 2), + padding: const EdgeInsets.symmetric(horizontal: crossAxisSpacing), child: GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -475,7 +476,7 @@ class _DeduplicatePageState extends State { child: Hero( tag: "deduplicate_" + file.tag, child: ClipRRect( - borderRadius: BorderRadius.circular(4), + borderRadius: BorderRadius.circular(8), child: ThumbnailWidget( file, diskLoadDeferDuration: galleryThumbnailDiskLoadDeferDuration, diff --git a/mobile/apps/photos/lib/ui/tools/similar_images_page.dart b/mobile/apps/photos/lib/ui/tools/similar_images_page.dart new file mode 100644 index 0000000000..89d50f6a2d --- /dev/null +++ b/mobile/apps/photos/lib/ui/tools/similar_images_page.dart @@ -0,0 +1,871 @@ +import "dart:async"; + +import 'package:flutter/material.dart'; +import 'package:logging/logging.dart'; +import 'package:photos/core/constants.dart'; +import "package:photos/generated/l10n.dart"; + +import "package:photos/models/file/file.dart"; +import "package:photos/models/selected_files.dart"; +import "package:photos/models/similar_files.dart"; +import "package:photos/service_locator.dart"; +import "package:photos/services/collections_service.dart"; +import "package:photos/services/machine_learning/similar_images_service.dart"; +import 'package:photos/theme/ente_theme.dart'; +import "package:photos/ui/common/loading_widget.dart"; +import 'package:photos/ui/components/buttons/button_widget.dart'; +import "package:photos/ui/components/models/button_type.dart"; +import "package:photos/ui/components/toggle_switch_widget.dart"; +import "package:photos/ui/viewer/file/detail_page.dart"; +import "package:photos/ui/viewer/file/thumbnail_widget.dart"; +import "package:photos/utils/delete_file_util.dart"; +import "package:photos/utils/dialog_util.dart"; +import "package:photos/utils/navigation_util.dart"; +import "package:photos/utils/standalone/data.dart"; + +enum SimilarImagesPageState { + setup, + loading, + results, +} + +enum SortKey { + size, + distanceAsc, + distanceDesc, + count, +} + +class SimilarImagesPage extends StatefulWidget { + const SimilarImagesPage({super.key}); + + @override + State createState() => _SimilarImagesPageState(); +} + +class _SimilarImagesPageState extends State { + static const crossAxisCount = 3; + static const crossAxisSpacing = 12.0; + static const autoSelectDistanceThreshold = 0.01; + + final _logger = Logger("SimilarImagesPage"); + bool _isDisposed = false; + + SimilarImagesPageState _pageState = SimilarImagesPageState.setup; + double _distanceThreshold = 0.04; // Default value + List _similarFilesList = []; + SortKey _sortKey = SortKey.distanceAsc; + bool _exactSearch = false; + + late SelectedFiles _selectedFiles; + + @override + void initState() { + super.initState(); + _selectedFiles = SelectedFiles(); + } + + @override + void dispose() { + _isDisposed = true; + _selectedFiles.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 0, + title: const Text("Similar images"), // TODO: lau: extract string + actions: _pageState == SimilarImagesPageState.results + ? [_getSortMenu()] + : null, + ), + body: _getBody(), + ); + } + + Widget _getBody() { + switch (_pageState) { + case SimilarImagesPageState.setup: + return _getSetupView(); + case SimilarImagesPageState.loading: + return _getLoadingView(); + case SimilarImagesPageState.results: + return _getResultsView(); + } + } + + Widget _getSetupView() { + final colorScheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); + + return Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Icon( + Icons.auto_awesome_outlined, + size: 72, + color: colorScheme.primary500, + ), + const SizedBox(height: 32), + Text( + "Find similar images", // TODO: lau: extract string + style: textTheme.h3Bold, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Text( + "Use AI to find images that look similar to each other. Adjust the distance threshold below.", // TODO: lau: extract string + style: textTheme.body, + textAlign: TextAlign.center, + ), + const SizedBox(height: 48), + Text( + "Similarity threshold", // TODO: lau: extract string + style: textTheme.bodyBold, + ), + const SizedBox(height: 8), + Text( + "Lower values mean a closer match.", // TODO: lau: extract string + style: textTheme.miniMuted, + ), + const SizedBox(height: 16), + Row( + children: [ + Text( + "0.01", + style: textTheme.mini, + ), + Expanded( + child: Slider( + value: _distanceThreshold, + min: 0.01, + max: 0.15, + divisions: 14, + onChanged: (value) { + if (_isDisposed) return; + setState(() { + _distanceThreshold = (value * 100).round() / 100; + }); + }, + ), + ), + Text( + "0.15", + style: textTheme.mini, + ), + ], + ), + Text( + "Current: ${_distanceThreshold.toStringAsFixed(2)}", // TODO: lau: extract string + style: textTheme.body, + textAlign: TextAlign.center, + ), + const SizedBox(height: 48), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Exact search", // TODO: lau: extract string + style: textTheme.bodyBold, + ), + ToggleSwitchWidget( + value: () => _exactSearch, + onChanged: () async { + if (_isDisposed) return; + setState(() { + _exactSearch = !_exactSearch; + }); + }, + ), + ], + ), + const SizedBox(height: 32), + ButtonWidget( + labelText: "Find similar images", // TODO: lau: extract string + buttonType: ButtonType.primary, + onTap: () async { + await _findSimilarImages(); + }, + ), + ], + ), + ); + } + + Widget _getLoadingView() { + return const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + EnteLoadingWidget(), + SizedBox(height: 16), + Text("Analyzing images..."), // TODO: lau: extract string + ], + ), + ); + } + + Widget _getResultsView() { + final textTheme = getEnteTextTheme(context); + final colorScheme = getEnteColorScheme(context); + if (_similarFilesList.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.check_circle_outline, + size: 72, + color: colorScheme.primary500, + ), + const SizedBox(height: 16), + Text( + "No Similar Images Found", // TODO: lau: extract string + style: textTheme.h3Bold, + ), + const SizedBox(height: 8), + Text( + "Try adjusting the similarity threshold", // TODO: lau: extract string + style: textTheme.body, + ), + const SizedBox(height: 32), + ButtonWidget( + labelText: "Try Again", // TODO: lau: extract string + buttonType: ButtonType.secondary, + onTap: () async { + if (_isDisposed) return; + setState(() { + _pageState = SimilarImagesPageState.setup; + }); + }, + ), + ], + ), + ); + } + + return Column( + children: [ + Expanded( + child: ListView.builder( + itemCount: _similarFilesList.length + 1, // +1 for header + itemBuilder: (context, index) { + if (index == 0) { + // Header item + if (flagService.internalUser) { + return Container( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Text( + "(I) Found ${_similarFilesList.length} groups of similar images", // TODO: lau: extract string + style: textTheme.bodyBold, + ), + const SizedBox(height: 4), + Text( + "(I) Threshold: ${_distanceThreshold.toStringAsFixed(2)}", // TODO: lau: extract string + style: textTheme.miniMuted, + ), + ], + ), + ); + } else { + return const SizedBox.shrink(); + } + } + + // Similar files groups (index - 1 because first item is header) + final similarFiles = _similarFilesList[index - 1]; + return _buildSimilarFilesGroup(similarFiles); + }, + ), + ), + _getBottomActionButtons(), + ], + ); + } + + Widget _getBottomActionButtons() { + return ListenableBuilder( + listenable: _selectedFiles, + builder: (context, _) { + final selectedCount = _selectedFiles.files.length; + final hasSelectedFiles = selectedCount > 0; + + return AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + child: hasSelectedFiles + ? SafeArea( + child: Container( + key: const ValueKey('bottom_buttons'), + padding: const EdgeInsets.symmetric( + horizontal: crossAxisSpacing, + vertical: 8, + ), + decoration: BoxDecoration( + color: getEnteColorScheme(context).backgroundBase, + ), + child: Column( + children: [ + SizedBox( + width: double.infinity, + child: ButtonWidget( + labelText: + "Delete $selectedCount photos", // TODO: lau: extract string + buttonType: ButtonType.critical, + onTap: () async { + await _deleteFiles( + _selectedFiles.files, + showDialog: true, + ); + }, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: double.infinity, + child: ButtonWidget( + labelText: + "Unselect all", // TODO: lau: extract string + buttonType: ButtonType.secondary, + onTap: () async { + _selectedFiles.clearAll(fireEvent: false); + }, + ), + ), + ], + ), + ), + ) + : const SizedBox.shrink(key: ValueKey('empty')), + ); + }, + ); + } + + Future _findSimilarImages() async { + if (_isDisposed) return; + setState(() { + _pageState = SimilarImagesPageState.loading; + }); + + try { + // You can use _toggleValue here for advanced mode features + _logger.info("exact mode: $_exactSearch"); + + final similarFiles = await SimilarImagesService.instance + .getSimilarFiles(_distanceThreshold, exact: _exactSearch); + _logger.info( + "Found ${similarFiles.length} groups of similar images", + ); + + _similarFilesList = similarFiles; + _pageState = SimilarImagesPageState.results; + _sortSimilarFiles(); + _autoSelectSimilarFiles(); + + if (_isDisposed) return; + setState(() {}); + + return; + } catch (e, s) { + _logger.severe("Failed to get similar files", e, s); + if (_isDisposed) return; + if (flagService.internalUser) { + await showGenericErrorDialog(context: context, error: e); + } + if (_isDisposed) return; + setState(() { + _pageState = SimilarImagesPageState.setup; + }); + return; + } + } + + void _sortSimilarFiles() { + switch (_sortKey) { + case SortKey.size: + _similarFilesList.sort((a, b) => b.totalSize.compareTo(a.totalSize)); + break; + case SortKey.distanceAsc: + _similarFilesList + .sort((a, b) => a.furthestDistance.compareTo(b.furthestDistance)); + break; + case SortKey.distanceDesc: + _similarFilesList + .sort((a, b) => b.furthestDistance.compareTo(a.furthestDistance)); + break; + case SortKey.count: + _similarFilesList + .sort((a, b) => b.files.length.compareTo(a.files.length)); + break; + } + if (_isDisposed) return; + setState(() {}); + } + + void _autoSelectSimilarFiles() { + final filesToSelect = {}; + int groupsProcessed = 0; + int groupsAutoSelected = 0; + + for (final similarFilesGroup in _similarFilesList) { + groupsProcessed++; + if (similarFilesGroup.furthestDistance < autoSelectDistanceThreshold) { + groupsAutoSelected++; + // Skip the first file (keep it unselected) and select the rest + for (int i = 1; i < similarFilesGroup.files.length; i++) { + filesToSelect.add(similarFilesGroup.files[i]); + } + } + } + + if (filesToSelect.isNotEmpty) { + _selectedFiles.selectAll(filesToSelect); + _logger.info( + "Auto-selected ${filesToSelect.length} files from $groupsAutoSelected/$groupsProcessed groups (threshold: $autoSelectDistanceThreshold)", + ); + } else { + _logger.info( + "No files auto-selected from $groupsProcessed groups (threshold: $autoSelectDistanceThreshold)", + ); + } + } + + Widget _buildSimilarFilesGroup(SimilarFiles similarFiles) { + final textTheme = getEnteTextTheme(context); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: crossAxisSpacing), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "${similarFiles.files.length} similar images" + + (flagService.internalUser + ? " (I: d: ${similarFiles.furthestDistance.toStringAsFixed(3)})" + : ""), // TODO: lau: extract string + style: textTheme.smallMuted.copyWith( + fontWeight: FontWeight.w600, + ), + ), + SizedBox( + height: 34, + child: ListenableBuilder( + listenable: _selectedFiles, + builder: (context, _) { + final groupSelectedFiles = similarFiles.files + .where((file) => _selectedFiles.isFileSelected(file)) + .toSet(); + final bool allFilesFromGroupSelected = + groupSelectedFiles.length == similarFiles.length; + final hasAnySelection = _selectedFiles.files.isNotEmpty; + final allGroupFilesSelected = similarFiles.files.every( + (file) => _selectedFiles.isFileSelected(file), + ); + + if (groupSelectedFiles.isNotEmpty) { + return _getSmallDeleteButton( + groupSelectedFiles, + allFilesFromGroupSelected, + ); + } else if (hasAnySelection) { + return _getSmallSelectButton(allGroupFilesSelected, () { + if (allGroupFilesSelected) { + // Unselect all files in this group + _selectedFiles.unSelectAll( + similarFiles.files.toSet(), + ); + } else { + // Select all files in this group + _selectedFiles.selectAll( + similarFiles.files.sublist(1).toSet(), + ); + } + }); + } + return const SizedBox.shrink(); + }, + ), + ), + ], + ), + const SizedBox(height: 16), + GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return _buildFile( + context, + similarFiles.files[index], + similarFiles.files, + index, + ); + }, + itemCount: similarFiles.files.length, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + crossAxisSpacing: crossAxisSpacing, + childAspectRatio: 0.70, + ), + padding: const EdgeInsets.all(0), + ), + const SizedBox(height: 16), // Add spacing between groups + ], + ), + ); + } + + Widget _buildFile( + BuildContext context, + EnteFile file, + List allFiles, + int index, + ) { + final textTheme = getEnteTextTheme(context); + return ListenableBuilder( + listenable: _selectedFiles, + builder: (context, _) { + final bool isSelected = _selectedFiles.isFileSelected(file); + final bool hasAnySelection = _selectedFiles.files.isNotEmpty; + + return GestureDetector( + onTap: () { + if (hasAnySelection) { + // If files are selected, tap should toggle selection + _selectedFiles.toggleSelection(file); + } else { + // If no files selected, tap opens detail page + routeToPage( + context, + DetailPage( + DetailPageConfiguration( + allFiles, + index, + "similar_images_", + mode: DetailPageMode.minimalistic, + ), + ), + ); + } + }, + onLongPress: () { + if (hasAnySelection) { + // If files are selected, long press opens detail page + routeToPage( + context, + DetailPage( + DetailPageConfiguration( + allFiles, + index, + "similar_images_", + mode: DetailPageMode.minimalistic, + ), + ), + ); + } else { + // If no files selected, long press starts selection + _selectedFiles.toggleSelection(file); + } + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Stack( + children: [ + Hero( + tag: "similar_images_" + file.tag, + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: isSelected + ? ColorFiltered( + colorFilter: ColorFilter.mode( + Colors.black.withAlpha((0.4 * 255).toInt()), + BlendMode.darken, + ), + child: ThumbnailWidget( + file, + diskLoadDeferDuration: + galleryThumbnailDiskLoadDeferDuration, + serverLoadDeferDuration: + galleryThumbnailServerLoadDeferDuration, + shouldShowLivePhotoOverlay: true, + key: Key("similar_images_" + file.tag), + ), + ) + : ThumbnailWidget( + file, + diskLoadDeferDuration: + galleryThumbnailDiskLoadDeferDuration, + serverLoadDeferDuration: + galleryThumbnailServerLoadDeferDuration, + shouldShowLivePhotoOverlay: true, + key: Key("similar_images_" + file.tag), + ), + ), + ), + Positioned( + top: 5, + right: 5, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + child: isSelected + ? const Icon( + Icons.check_circle_rounded, + color: Colors.white, + size: 22, + ) + : null, + ), + ), + ], + ), + ), + const SizedBox(height: 6), + Text( + file.displayName, + style: textTheme.small, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 2), + Text( + formatBytes(file.fileSize!), + style: textTheme.miniMuted, + ), + const SizedBox(height: 16), + ], + ), + ); + }, + ); + } + + Widget _getSmallDeleteButton(Set files, bool showDialog) { + final colorScheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); + + if (files.isEmpty) { + return const SizedBox.shrink(); + } + + return GestureDetector( + onTap: () async { + await _deleteFiles(files, showDialog: showDialog); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + decoration: BoxDecoration( + color: colorScheme.warning500.withAlpha((0.1 * 255).toInt()), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.delete_outline, + size: 12, + color: colorScheme.warning500, + ), + const SizedBox(width: 4), + Text( + "Delete (${files.length})", // TODO: lau: extract string + style: textTheme.smallBold.copyWith( + color: colorScheme.warning500, + ), + ), + ], + ), + ), + ); + } + + Future _deleteFiles( + Set filesToDelete, { + bool showDialog = true, + }) async { + if (filesToDelete.isEmpty) return; + if (showDialog) { + final _ = await showChoiceActionSheet( + context, + title: "Delete files", // TODO: lau: extract string + body: + "Are you sure you want to delete these files?", // TODO: lau: extract string + firstButtonLabel: S.of(context).delete, + isCritical: true, + firstButtonOnTap: () async { + try { + await _deleteFilesLogic(filesToDelete, true); + } catch (e, s) { + _logger.severe("Failed to delete files", e, s); + if (flagService.internalUser) { + await showGenericErrorDialog(context: context, error: e); + } + } + }, + ); + } else { + await _deleteFilesLogic(filesToDelete, true); + } + } + + Future _deleteFilesLogic( + Set filesToDelete, + bool createSymlink, + ) async { + if (filesToDelete.isEmpty) { + return; + } + final Map> collectionToFilesToAddMap = {}; + final allDeleteFiles = {}; + final groupsToRemove = {}; + for (final similarGroup in _similarFilesList) { + final groupDeleteFiles = {}; + for (final file in filesToDelete) { + if (similarGroup.containsFile(file)) { + similarGroup.removeFile(file); + groupDeleteFiles.add(file); + allDeleteFiles.add(file); + if (similarGroup.isEmpty) { + break; + } + } + } + if (similarGroup.files.length <= 1) { + groupsToRemove.add(similarGroup); + } + if (groupDeleteFiles.isNotEmpty) { + filesToDelete.removeAll(groupDeleteFiles); + } + if (!similarGroup.isEmpty && createSymlink) { + final filesToKeep = similarGroup.files; + final collectionIDs = + filesToKeep.map((file) => file.collectionID).toSet(); + for (final deletedFile in groupDeleteFiles) { + final collectionID = deletedFile.collectionID; + if (collectionIDs.contains(collectionID) || collectionID == null) { + continue; + } + if (!collectionToFilesToAddMap.containsKey(collectionID)) { + collectionToFilesToAddMap[collectionID] = []; + } + collectionToFilesToAddMap[collectionID]!.addAll(filesToKeep); + } + } + } + for (final group in groupsToRemove) { + _similarFilesList.remove(group); + } + + if (createSymlink) { + for (final collectionID in collectionToFilesToAddMap.keys) { + await CollectionsService.instance.addSilentlyToCollection( + collectionID, + collectionToFilesToAddMap[collectionID]!, + ); + } + } + + _selectedFiles.unSelectAll(allDeleteFiles); + setState(() {}); + await deleteFilesFromRemoteOnly(context, allDeleteFiles.toList()); + } + + Widget _getSmallSelectButton(bool unselectAll, void Function() onTap) { + final colorScheme = getEnteColorScheme(context); + final textTheme = getEnteTextTheme(context); + + return GestureDetector( + onTap: onTap, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 8, + ), + decoration: BoxDecoration( + color: unselectAll + ? getEnteColorScheme(context).primary500 + : getEnteColorScheme(context).strokeFaint, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + unselectAll + ? "Unselect all" // TODO: lau: extract string + : "Select extra", // TODO: lau: extract string + style: textTheme.smallMuted.copyWith( + color: unselectAll ? Colors.white : colorScheme.textMuted, + ), + ), + ), + ); + } + + Widget _getSortMenu() { + final textTheme = getEnteTextTheme(context); + final colorScheme = getEnteColorScheme(context); + Text sortOptionText(SortKey key) { + String text = key.toString(); + switch (key) { + case SortKey.size: + text = "Size"; // TODO: lau: extract string + break; + case SortKey.distanceAsc: + text = "Distance ascending"; // TODO: lau: extract string + break; + case SortKey.distanceDesc: + text = "Distance descending"; // TODO: lau: extract string + break; + case SortKey.count: + text = "Count"; // TODO: lau: extract string + break; + } + return Text( + text, + style: textTheme.miniBold, + ); + } + + return PopupMenuButton( + initialValue: _sortKey.index, + child: Padding( + padding: const EdgeInsets.fromLTRB(24, 6, 24, 6), + child: Icon( + Icons.sort, + color: colorScheme.strokeBase, + size: 20, + ), + ), + onSelected: (int index) { + if (_isDisposed) return; + setState(() { + _sortKey = SortKey.values[index]; + }); + _sortSimilarFiles(); + }, + itemBuilder: (context) { + return List.generate(SortKey.values.length, (index) { + return PopupMenuItem( + value: index, + child: Text( + sortOptionText(SortKey.values[index]).data!, + style: textTheme.miniBold, + ), + ); + }); + }, + ); + } +} diff --git a/mobile/apps/photos/lib/ui/viewer/date/date_time_picker.dart b/mobile/apps/photos/lib/ui/viewer/date/date_time_picker.dart index dfdb7a5c9d..25dfcc95c0 100644 --- a/mobile/apps/photos/lib/ui/viewer/date/date_time_picker.dart +++ b/mobile/apps/photos/lib/ui/viewer/date/date_time_picker.dart @@ -3,7 +3,8 @@ import "package:flutter/material.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/theme/ente_theme.dart"; -Future showDatePickerSheet(BuildContext context, { +Future showDatePickerSheet( + BuildContext context, { required DateTime initialDate, DateTime? maxDate, DateTime? minDate, diff --git a/mobile/apps/photos/lib/ui/viewer/file_details/creation_time_item_widget.dart b/mobile/apps/photos/lib/ui/viewer/file_details/creation_time_item_widget.dart index bc19247340..735b1ac07b 100644 --- a/mobile/apps/photos/lib/ui/viewer/file_details/creation_time_item_widget.dart +++ b/mobile/apps/photos/lib/ui/viewer/file_details/creation_time_item_widget.dart @@ -5,6 +5,7 @@ import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/components/info_item_widget.dart"; import "package:photos/ui/viewer/date/edit_date_sheet.dart"; import "package:photos/utils/standalone/date_time.dart"; + class CreationTimeItem extends StatefulWidget { final EnteFile file; final int currentUserID; diff --git a/mobile/apps/photos/lib/ui/viewer/people/people_util.dart b/mobile/apps/photos/lib/ui/viewer/people/people_util.dart index 55ac269a4d..1270f1d30a 100644 --- a/mobile/apps/photos/lib/ui/viewer/people/people_util.dart +++ b/mobile/apps/photos/lib/ui/viewer/people/people_util.dart @@ -1,18 +1,16 @@ - - import "package:photos/core/configuration.dart"; import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; Future isMeAssigned() async { - final personEntities = await PersonService.instance.getPersons(); - final currentUserEmail = Configuration.instance.getEmail(); + final personEntities = await PersonService.instance.getPersons(); + final currentUserEmail = Configuration.instance.getEmail(); - bool isAssigned = false; - for (final personEntity in personEntities) { - if (personEntity.data.email == currentUserEmail) { - isAssigned = true; - break; - } + bool isAssigned = false; + for (final personEntity in personEntities) { + if (personEntity.data.email == currentUserEmail) { + isAssigned = true; + break; } - return isAssigned; - } \ No newline at end of file + } + return isAssigned; +} diff --git a/mobile/apps/photos/lib/ui/viewer/people/person_gallery_suggestion.dart b/mobile/apps/photos/lib/ui/viewer/people/person_gallery_suggestion.dart index 7311e81de5..59aa4a869e 100644 --- a/mobile/apps/photos/lib/ui/viewer/people/person_gallery_suggestion.dart +++ b/mobile/apps/photos/lib/ui/viewer/people/person_gallery_suggestion.dart @@ -101,7 +101,9 @@ class _PersonGallerySuggestionState extends State } else { suggestions = await ClusterFeedbackService.instance .getAllLargePersonSuggestions(); - person = suggestions.first.person; + if (suggestions.isNotEmpty) { + person = suggestions.first.person; + } } if (suggestions.isNotEmpty && mounted) { @@ -122,8 +124,8 @@ class _PersonGallerySuggestionState extends State } if (mounted && _fadeController != null && _slideController != null) { - unawaited(_fadeController!.forward()); - unawaited(_slideController!.forward()); + unawaited(_fadeController?.forward()); + unawaited(_slideController?.forward()); } unawaited(_precomputeNextSuggestions()); @@ -383,8 +385,8 @@ class _PersonGallerySuggestionState extends State Future _animateIn() async { if (mounted && _fadeController != null && _slideController != null) { - _slideController!.reset(); - _fadeController!.reset(); + _slideController?.reset(); + _fadeController?.reset(); await Future.wait([ _fadeController!.forward(), _slideController!.forward(), diff --git a/mobile/apps/photos/lib/utils/file_uploader.dart b/mobile/apps/photos/lib/utils/file_uploader.dart index 890b167fea..52b627b1df 100644 --- a/mobile/apps/photos/lib/utils/file_uploader.dart +++ b/mobile/apps/photos/lib/utils/file_uploader.dart @@ -23,7 +23,7 @@ import "package:photos/events/file_uploaded_event.dart"; import 'package:photos/events/files_updated_event.dart'; import 'package:photos/events/local_photos_updated_event.dart'; import 'package:photos/events/subscription_purchased_event.dart'; -import 'package:photos/main.dart'; +import "package:photos/main.dart"; import "package:photos/models/api/metadata.dart"; import "package:photos/models/backup/backup_item.dart"; import "package:photos/models/backup/backup_item_status.dart"; diff --git a/mobile/apps/photos/lib/utils/isolate/isolate_operations.dart b/mobile/apps/photos/lib/utils/isolate/isolate_operations.dart index ae4e1e8851..6deba3d97a 100644 --- a/mobile/apps/photos/lib/utils/isolate/isolate_operations.dart +++ b/mobile/apps/photos/lib/utils/isolate/isolate_operations.dart @@ -1,6 +1,8 @@ -import 'dart:typed_data' show Uint8List; +import 'dart:typed_data' show Uint8List, Float32List; +import "package:flutter_rust_bridge/flutter_rust_bridge.dart" show Uint64List; import "package:ml_linalg/linalg.dart"; +import "package:photos/db/ml/clip_vector_db.dart"; import "package:photos/models/ml/face/box.dart"; import "package:photos/models/ml/vector.dart"; import "package:photos/services/machine_learning/face_ml/face_clustering/face_clustering_service.dart"; @@ -10,6 +12,7 @@ import "package:photos/services/machine_learning/ml_result.dart"; import "package:photos/services/machine_learning/semantic_search/clip/clip_text_encoder.dart"; import "package:photos/services/machine_learning/semantic_search/clip/clip_text_tokenizer.dart"; import "package:photos/services/machine_learning/semantic_search/query_result.dart"; +import "package:photos/src/rust/frb_generated.dart" show RustLib; import "package:photos/utils/image_ml_util.dart"; import "package:photos/utils/ml_util.dart"; @@ -40,6 +43,12 @@ enum IsolateOperation { /// [MLComputer] computeBulkSimilarities, + /// [MLComputer] + bulkVectorSearch, + + /// [MLComputer] + bulkVectorSearchWithKeys, + /// [FaceClusteringService] linearIncrementalClustering, @@ -57,6 +66,28 @@ Future isolateFunction( Map args, ) async { switch (function) { + case IsolateOperation.bulkVectorSearchWithKeys: + await _ensureRustLoaded(); + final potentialKeys = args["potentialKeys"] as Uint64List; + final exact = args["exact"] as bool; + + return ClipVectorDB.instance.bulkSearchWithKeys( + potentialKeys, + BigInt.from(100), + exact: exact, + ); + + case IsolateOperation.bulkVectorSearch: + await _ensureRustLoaded(); + final clipFloat32 = args["clipFloat32"] as List; + final exact = args["exact"] as bool; + + return ClipVectorDB.instance.bulkSearchVectors( + clipFloat32, + BigInt.from(100), + exact: exact, + ); + /// Cases for MLIndexingIsolate start here /// MLIndexingIsolate @@ -182,9 +213,26 @@ Future isolateFunction( /// Caching case IsolateOperation.clearAllIsolateCache: + _ensureRustDisposed(); _isolateCache.clear(); return true; /// Cases for Caching stop here } } + +Future _ensureRustLoaded() async { + final bool loaded = _isolateCache["rustLibLoaded"] as bool? ?? false; + if (!loaded) { + await RustLib.init(); + _isolateCache["rustLibLoaded"] = true; + } +} + +void _ensureRustDisposed() { + final bool loaded = _isolateCache["rustLibLoaded"] as bool? ?? false; + if (loaded) { + RustLib.dispose(); + _isolateCache.remove("rustLibLoaded"); + } +} diff --git a/mobile/apps/photos/lib/utils/text_embeddings_util.dart b/mobile/apps/photos/lib/utils/text_embeddings_util.dart new file mode 100644 index 0000000000..349c284ed4 --- /dev/null +++ b/mobile/apps/photos/lib/utils/text_embeddings_util.dart @@ -0,0 +1,172 @@ +import 'dart:convert'; +import "dart:developer" as dev show log; +import "dart:io" show File; + +import 'package:flutter/services.dart'; +import 'package:logging/logging.dart'; +import 'package:ml_linalg/vector.dart'; +import "package:path_provider/path_provider.dart" + show getExternalStorageDirectory; +import 'package:photos/models/memories/clip_memory.dart'; +import 'package:photos/models/memories/people_memory.dart'; +import "package:photos/services/machine_learning/ml_computer.dart" + show MLComputer; + +final _logger = Logger('TextEmbeddingsUtil'); + +/// Loads pre-computed text embeddings from assets +Future loadTextEmbeddingsFromAssets() async { + try { + _logger.info('Loading text embeddings from assets'); + final jsonString = + await rootBundle.loadString('assets/ml/text_embeddings.json'); + final data = json.decode(jsonString) as Map; + + final embeddings = data['embeddings'] as Map; + + // Parse clip positive embedding + Vector? clipPositiveVector; + final clipPositive = embeddings['clip_positive'] as Map; + final clipPositiveVectorData = + (clipPositive['vector'] as List).cast(); + if (clipPositiveVectorData.isNotEmpty) { + clipPositiveVector = Vector.fromList(clipPositiveVectorData); + } + + // Parse people activities embeddings + final Map peopleActivityVectors = {}; + final peopleActivities = + embeddings['people_activities'] as Map; + for (final activity in PeopleActivity.values) { + final activityName = activity.toString().split('.').last; + if (peopleActivities.containsKey(activityName)) { + final activityData = + peopleActivities[activityName] as Map; + final vector = (activityData['vector'] as List).cast(); + if (vector.isNotEmpty) { + peopleActivityVectors[activity] = Vector.fromList(vector); + } + } + } + + // Parse clip memory types embeddings + final Map clipMemoryTypeVectors = {}; + final clipMemoryTypes = + embeddings['clip_memory_types'] as Map; + for (final memoryType in ClipMemoryType.values) { + final typeName = memoryType.toString().split('.').last; + if (clipMemoryTypes.containsKey(typeName)) { + final typeData = clipMemoryTypes[typeName] as Map; + final vector = (typeData['vector'] as List).cast(); + if (vector.isNotEmpty) { + clipMemoryTypeVectors[memoryType] = Vector.fromList(vector); + } + } + } + + // Check if we have all required embeddings + if (clipPositiveVector == null) { + _logger.severe('Clip positive vector is missing'); + throw Exception('Clip positive vector is missing'); + } + + if (peopleActivityVectors.length != PeopleActivity.values.length) { + _logger.severe('Some people activity vectors are missing'); + throw Exception('Some people activity vectors are missing'); + } + + if (clipMemoryTypeVectors.length != ClipMemoryType.values.length) { + _logger.severe('Some clip memory type vectors are missing'); + throw Exception('Some clip memory type vectors are missing'); + } + + _logger.info('Text embeddings loaded successfully from JSON assets'); + return TextEmbeddings( + clipPositiveVector: clipPositiveVector, + peopleActivityVectors: peopleActivityVectors, + clipMemoryTypeVectors: clipMemoryTypeVectors, + ); + } catch (e, stackTrace) { + _logger.severe('Failed to load text embeddings from JSON', e, stackTrace); + return null; + } +} + +class TextEmbeddings { + final Vector clipPositiveVector; + final Map peopleActivityVectors; + final Map clipMemoryTypeVectors; + + const TextEmbeddings({ + required this.clipPositiveVector, + required this.peopleActivityVectors, + required this.clipMemoryTypeVectors, + }); +} + +/// Helper function to generate text embeddings and save them to a JSON file +/// Run this once to generate the embeddings, then copy the output +/// to assets/ml/text_embeddings.json +Future generateAndSaveTextEmbeddings() async { + final Map embeddingsData = { + 'version': '1.0.0', + 'embeddings': { + 'clip_positive': {}, + 'people_activities': {}, + 'clip_memory_types': {}, + }, + }; + + // Generate clip positive embedding + const String clipPositiveQuery = + 'Photo of a precious and nostalgic memory radiating warmth, vibrant energy, or quiet beauty — alive with color, light, or emotion'; + final clipPositiveVector = + await MLComputer.instance.runClipText(clipPositiveQuery); + embeddingsData['embeddings']['clip_positive'] = { + 'prompt': clipPositiveQuery, + 'vector': clipPositiveVector, + }; + + // Generate people activity embeddings + final peopleActivities = {}; + for (final activity in PeopleActivity.values) { + final activityName = activity.toString().split('.').last; + final prompt = activityQuery(activity); + final vector = await MLComputer.instance.runClipText(prompt); + peopleActivities[activityName] = { + 'prompt': prompt, + 'vector': vector, + }; + } + embeddingsData['embeddings']['people_activities'] = peopleActivities; + + // Generate clip memory type embeddings + final clipMemoryTypes = {}; + for (final memoryType in ClipMemoryType.values) { + final typeName = memoryType.toString().split('.').last; + final prompt = clipQuery(memoryType); + final vector = await MLComputer.instance.runClipText(prompt); + clipMemoryTypes[typeName] = { + 'prompt': prompt, + 'vector': vector, + }; + } + embeddingsData['embeddings']['clip_memory_types'] = clipMemoryTypes; + + // Convert to JSON and log it + final jsonString = const JsonEncoder.withIndent(' ').convert(embeddingsData); + dev.log( + '_generateAndSaveTextEmbeddings: Generated text embeddings JSON', + ); + + final tempDir = await getExternalStorageDirectory(); + final file = File('${tempDir!.path}/text_embeddings.json'); + await file.writeAsString(jsonString); + dev.log( + '_generateAndSaveTextEmbeddings: Saved text embeddings to ${file.path}', + ); + + dev.log( + '_generateAndSaveTextEmbeddings: Text embeddings generation complete! Copy the JSON output above to assets/ml/text_embeddings.json', + ); +} diff --git a/mobile/apps/photos/plugins/ente_feature_flag/lib/src/service.dart b/mobile/apps/photos/plugins/ente_feature_flag/lib/src/service.dart index 66fda0c674..2163d69144 100644 --- a/mobile/apps/photos/plugins/ente_feature_flag/lib/src/service.dart +++ b/mobile/apps/photos/plugins/ente_feature_flag/lib/src/service.dart @@ -58,6 +58,8 @@ class FlagService { bool get enableMobMultiPart => flags.enableMobMultiPart || internalUser; + bool get enableVectorDb => flags.internalUser; + String get castUrl => flags.castUrl; String get customDomain => flags.customDomain; diff --git a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/checksums/checksums.lock b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/checksums/checksums.lock index eda644daa6..4170ac40d0 100644 Binary files a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/checksums/checksums.lock and b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/checksums/checksums.lock differ diff --git a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/checksums/sha1-checksums.bin b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/checksums/sha1-checksums.bin new file mode 100644 index 0000000000..ce391d4fab Binary files /dev/null and b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/checksums/sha1-checksums.bin differ diff --git a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/fileHashes/fileHashes.lock b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/fileHashes/fileHashes.lock index 4e4d51aaa9..5d34963075 100644 Binary files a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/fileHashes/fileHashes.lock and b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/8.5/fileHashes/fileHashes.lock differ diff --git a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock index ca921a15e6..a77c685bd8 100644 Binary files a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/outputFiles.bin b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/outputFiles.bin index a49084dcd8..4455dbfbfe 100644 Binary files a/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/outputFiles.bin and b/mobile/apps/photos/plugins/onnx_dart/android/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index 6bcb6addc9..d9ef339a3a 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -170,6 +170,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.5.4" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + url: "https://pub.dev" + source: hosted + version: "2.1.0" build_config: dependency: transitive description: @@ -1027,6 +1035,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.28" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e" + url: "https://pub.dev" + source: hosted + version: "2.11.1" flutter_secure_storage: dependency: "direct main" description: @@ -2141,6 +2157,13 @@ packages: url: "https://github.com/KasemJaffer/receive_sharing_intent.git" source: git version: "1.8.1" + rust_lib_photos: + dependency: "direct main" + description: + path: rust_builder + relative: true + source: path + version: "0.0.1" rxdart: dependency: transitive description: diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index e9315cc414..63db0d4076 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -16,7 +16,7 @@ version: 1.2.1+1205 publish_to: none environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.3.0 <4.0.0" dependencies: adaptive_theme: ^3.1.0 @@ -95,6 +95,7 @@ dependencies: flutter_map: ^7.0.2 flutter_map_marker_cluster: ^1.3.6 flutter_password_strength: ^0.1.6 + flutter_rust_bridge: 2.11.1 # Do not upgrade this package unless this issue is resolved: # https://github.com/juliansteenbakker/flutter_secure_storage/issues/870 # On v9.2.4, keys related to lockscreen persist even after reintsall. For context see: @@ -178,6 +179,8 @@ dependencies: git: url: https://github.com/KasemJaffer/receive_sharing_intent.git ref: 2cea396 + rust_lib_photos: + path: rust_builder screenshot: ^3.0.0 scrollable_positioned_list: ^0.3.5 sentry: ^8.14.1 @@ -344,6 +347,7 @@ flutter: - assets/image-editor/ - assets/icons/ - assets/launcher_icon/ + - assets/ml/ fonts: - family: Inter fonts: diff --git a/mobile/apps/photos/rust/.gitignore b/mobile/apps/photos/rust/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/mobile/apps/photos/rust/.gitignore @@ -0,0 +1 @@ +/target diff --git a/mobile/apps/photos/rust/Cargo.lock b/mobile/apps/photos/rust/Cargo.lock new file mode 100644 index 0000000000..e091b5defd --- /dev/null +++ b/mobile/apps/photos/rust/Cargo.lock @@ -0,0 +1,1012 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allo-isolate" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449e356a4864c017286dbbec0e12767ea07efba29e3b7d984194c2a7ff3c4550" +dependencies = [ + "anyhow", + "atomic", + "backtrace", +] + +[[package]] +name = "android_log-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" + +[[package]] +name = "android_logger" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" +dependencies = [ + "android_log-sys", + "env_filter", + "log", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "build-target" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cxx" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df" +dependencies = [ + "cc", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "dart-sys" +version = "4.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57967e4b200d767d091b961d6ab42cc7d0cc14fe9e052e75d0d3cf9eb732d895" +dependencies = [ + "cc", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "delegate-attr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51aac4c99b2e6775164b412ea33ae8441b2fde2dbf05a20bc0052a63d08c475b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "flutter_rust_bridge" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde126295b2acc5f0a712e265e91b6fdc0ed38767496483e592ae7134db83725" +dependencies = [ + "allo-isolate", + "android_logger", + "anyhow", + "build-target", + "bytemuck", + "byteorder", + "console_error_panic_hook", + "dart-sys", + "delegate-attr", + "flutter_rust_bridge_macros", + "futures", + "js-sys", + "lazy_static", + "log", + "oslog", + "portable-atomic", + "threadpool", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "flutter_rust_bridge_macros" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f0420326b13675321b194928bb7830043b68cf8b810e1c651285c747abb080" +dependencies = [ + "hex", + "md-5", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown 0.15.4", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "link-cplusplus" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" +dependencies = [ + "cc", +] + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "oslog" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d2043d1f61d77cb2f4b1f7b7b2295f40507f5f8e9d1c8bf10a1ca5f97a3969" +dependencies = [ + "cc", + "dashmap", + "log", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8af0dde094006011e6a740d4879319439489813bd0bcdc7d821beaeeff48ec" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rust_lib_photos" +version = "0.1.0" +dependencies = [ + "flutter_rust_bridge", + "usearch", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scratch" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tokio" +version = "1.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +dependencies = [ + "backtrace", + "num_cpus", + "pin-project-lite", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "usearch" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa869be4baf62146b39700da30b235b06f58d2c03b7e073a8e2b57e0f511aa9" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/mobile/apps/photos/rust/Cargo.toml b/mobile/apps/photos/rust/Cargo.toml new file mode 100644 index 0000000000..2a861a57c5 --- /dev/null +++ b/mobile/apps/photos/rust/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rust_lib_photos" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "staticlib"] + +[dependencies] +flutter_rust_bridge = "=2.11.1" +usearch = "2.19.1" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] } diff --git a/mobile/apps/photos/rust/src/api/mod.rs b/mobile/apps/photos/rust/src/api/mod.rs new file mode 100644 index 0000000000..3f601e97bc --- /dev/null +++ b/mobile/apps/photos/rust/src/api/mod.rs @@ -0,0 +1,2 @@ +pub mod simple; +pub mod usearch_api; \ No newline at end of file diff --git a/mobile/apps/photos/rust/src/api/simple.rs b/mobile/apps/photos/rust/src/api/simple.rs new file mode 100644 index 0000000000..4360c82ae0 --- /dev/null +++ b/mobile/apps/photos/rust/src/api/simple.rs @@ -0,0 +1,10 @@ +#[flutter_rust_bridge::frb(sync)] // Synchronous mode for simplicity of the demo +pub fn greet(name: String) -> String { + format!("Hello, {name}!") +} + +#[flutter_rust_bridge::frb(init)] +pub fn init_app() { + // Default utilities - feel free to customize + flutter_rust_bridge::setup_default_user_utils(); +} diff --git a/mobile/apps/photos/rust/src/api/usearch_api.rs b/mobile/apps/photos/rust/src/api/usearch_api.rs new file mode 100644 index 0000000000..49e8301375 --- /dev/null +++ b/mobile/apps/photos/rust/src/api/usearch_api.rs @@ -0,0 +1,238 @@ +use flutter_rust_bridge::frb; +use usearch::{Index, IndexOptions, MetricKind, ScalarKind}; + +use std::path::PathBuf; + +#[frb(opaque)] +pub struct VectorDB { + index: Index, + path: PathBuf, +} + +impl VectorDB { + #[frb(sync)] + pub fn new(file_path: &str, dimensions: usize) -> Self { + let path = PathBuf::from(file_path); + let file_exists = path.try_exists().unwrap_or(false); + + let mut options = IndexOptions::default(); + options.dimensions = dimensions; + options.metric = MetricKind::IP; + options.quantization = ScalarKind::F32; + options.connectivity = 0; // auto + options.expansion_add = 0; // auto + options.expansion_search = 0; // auto + + let index = Index::new(&options).expect("Failed to create index"); + index + .reserve(1000) + .expect("Failed to reserve space in index"); + + let db = Self { index, path }; + + if file_exists { + println!("Loading index from disk."); + db.index.load(file_path).expect("Failed to load index"); + } else { + println!("Creating new index."); + db.save_index(); + } + db + } + + fn save_index(&self) { + // Ensure directory exists + if let Some(parent) = self.path.parent() { + std::fs::create_dir_all(parent).expect("Failed to create directory"); + } + self.index + .save(self.path.to_str().expect("Invalid path")) + .expect("Failed to save index"); + } + + fn ensure_capacity(&self, margin: usize) { + let current_size = self.index.size(); + let capacity = self.index.capacity(); + if current_size + margin + 1000 >= capacity { + self.index + .reserve(current_size + margin) + .expect("Failed to reserve space in index"); + } + } + + pub fn add_vector(&self, key: u64, vector: &[f32]) { + if self.contains_vector(key) { + self.remove_vector(key); + } else { + self.ensure_capacity(1); + } + self.index.add(key, vector).expect("Failed to add vector"); + self.save_index(); + } + + pub fn bulk_add_vectors(&self, keys: Vec, vectors: &Vec>) { + self.ensure_capacity(keys.len()); + for (key, vector) in keys.iter().zip(vectors.iter()) { + if self.contains_vector(*key) { + self.remove_vector(*key); + } + self.index + .add(*key, vector) + .expect("Failed to (bulk) add vector"); + } + self.save_index(); + } + + pub fn search_vectors(&self, query: &[f32], count: usize, exact: bool) -> (Vec, Vec) { + let matches = if exact { + self.index + .exact_search(query, count) + .expect("Failed to exact search vectors") + } else { + self.index + .search(query, count) + .expect("Failed to search vectors") + }; + (matches.keys, matches.distances) + } + + pub fn bulk_search_vectors( + &self, + queries: &Vec>, + count: usize, + exact: bool, + ) -> (Vec>, Vec>) { + let mut keys = Vec::new(); + let mut distances = Vec::new(); + + for query in queries { + let (keys_result, distances_result) = self.search_vectors(query, count, exact); + keys.push(keys_result); + distances.push(distances_result); + } + (keys, distances) + } + + pub fn bulk_search_keys( + &self, + potential_keys: &Vec, + count: usize, + exact: bool, + ) -> (Vec, Vec>, Vec>) { + let dimensions = self.index.dimensions(); + let mut embedding_data = vec![0.0f32; potential_keys.len() * dimensions]; + let mut contained_keys = Vec::with_capacity(potential_keys.len()); + let mut actual_query_count = 0; + + // Fill embeddings directly into flat storage using slices + for key in potential_keys { + if self.index.contains(*key) { + let start_idx = actual_query_count * dimensions; + let end_idx = start_idx + dimensions; + let embedding_slice = &mut embedding_data[start_idx..end_idx]; + + self.index + .get(*key, embedding_slice) + .expect("Failed to get vector"); + contained_keys.push(*key); + actual_query_count += 1; + } + } + embedding_data.truncate(actual_query_count * dimensions); + + let max_result_size = std::cmp::min(self.index.size(), count); + let mut closeby_keys = vec![Vec::with_capacity(max_result_size); actual_query_count]; + let mut distances = vec![Vec::with_capacity(max_result_size); actual_query_count]; + + // Search using slices and fill pre-allocated containers + for i in 0..actual_query_count { + let start_idx = i * dimensions; + let end_idx = start_idx + dimensions; + let query_slice = &embedding_data[start_idx..end_idx]; + let (keys_result, distances_result) = self.search_vectors(query_slice, count, exact); + closeby_keys[i] = keys_result; + distances[i] = distances_result; + } + + (contained_keys, closeby_keys, distances) + } + + /// Check if a vector with the given key exists in the index. + /// `true` if the index contains the vector with the given key, `false` otherwise. + pub fn contains_vector(&self, key: u64) -> bool { + self.index.contains(key) + } + + pub fn get_vector(&self, key: u64) -> Vec { + let mut vector: Vec = vec![0.0; self.index.dimensions()]; + self.index + .get(key, &mut vector) + .expect("Failed to get vector"); + vector + } + + pub fn bulk_get_vectors(&self, keys: Vec) -> Vec> { + let mut vectors = Vec::new(); + for key in keys { + let vector = self.get_vector(key); + vectors.push(vector); + } + vectors + } + + pub fn remove_vector(&self, key: u64) -> usize { + let removed_count = self.index.remove(key).expect("Failed to remove vector"); + self.save_index(); + removed_count + } + + pub fn bulk_remove_vectors(&self, keys: Vec) -> usize { + let mut removed_count = 0; + for key in keys { + removed_count += self + .index + .remove(key) + .expect("Failed to (bulk) remove vector"); + } + self.save_index(); + removed_count + } + + pub fn reset_index(&self) { + self.index.reset().expect("Failed to reset index"); + self.index + .reserve(1000) + .expect("Failed to reserve space in index"); + self.save_index(); + } + + pub fn delete_index(self) { + if self.path.exists() { + std::fs::remove_file(&self.path).expect("Failed to delete index file"); + } else { + println!("Index file does not exist."); + } + } + + pub fn get_index_stats(&self) -> (usize, usize, usize, usize, usize, usize, usize) { + let size = self.index.size(); + let capacity = self.index.capacity(); + let dimensions = self.index.dimensions(); + + let file_size = self.index.serialized_length(); + let memory_usage = self.index.memory_usage(); + + let expansion_add = self.index.expansion_add(); + let expansion_search = self.index.expansion_search(); + + ( + size, + capacity, + dimensions, + file_size, + memory_usage, + expansion_add, + expansion_search, + ) + } +} diff --git a/mobile/apps/photos/rust/src/frb_generated.rs b/mobile/apps/photos/rust/src/frb_generated.rs new file mode 100644 index 0000000000..8ccbd11c20 --- /dev/null +++ b/mobile/apps/photos/rust/src/frb_generated.rs @@ -0,0 +1,1348 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +#![allow( + non_camel_case_types, + unused, + non_snake_case, + clippy::needless_return, + clippy::redundant_closure_call, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::unused_unit, + clippy::double_parens, + clippy::let_and_return, + clippy::too_many_arguments, + clippy::match_single_binding, + clippy::clone_on_copy, + clippy::let_unit_value, + clippy::deref_addrof, + clippy::explicit_auto_deref, + clippy::borrow_deref_ref, + clippy::needless_borrow +)] + +// Section: imports + +use crate::api::usearch_api::*; +use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; +use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; +use flutter_rust_bridge::{Handler, IntoIntoDart}; + +// Section: boilerplate + +flutter_rust_bridge::frb_generated_boilerplate!( + default_stream_sink_codec = SseCodec, + default_rust_opaque = RustOpaqueMoi, + default_rust_auto_opaque = RustAutoOpaqueMoi, +); +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1"; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1360671619; + +// Section: executor + +flutter_rust_bridge::frb_generated_default_handler!(); + +// Section: wire_funcs + +fn wire__crate__api__usearch_api__VectorDb_add_vector_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_add_vector", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_key = ::sse_decode(&mut deserializer); + let api_vector = >::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok({ + crate::api::usearch_api::VectorDB::add_vector( + &*api_that_guard, + api_key, + &api_vector, + ); + })?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_bulk_add_vectors_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_bulk_add_vectors", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_keys = >::sse_decode(&mut deserializer); + let api_vectors = >>::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok({ + crate::api::usearch_api::VectorDB::bulk_add_vectors( + &*api_that_guard, + api_keys, + &api_vectors, + ); + })?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_bulk_get_vectors_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_bulk_get_vectors", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_keys = >::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = + Result::<_, ()>::Ok(crate::api::usearch_api::VectorDB::bulk_get_vectors( + &*api_that_guard, + api_keys, + ))?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_bulk_remove_vectors_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_bulk_remove_vectors", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_keys = >::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok( + crate::api::usearch_api::VectorDB::bulk_remove_vectors( + &*api_that_guard, + api_keys, + ), + )?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_bulk_search_keys_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_bulk_search_keys", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_potential_keys = >::sse_decode(&mut deserializer); + let api_count = ::sse_decode(&mut deserializer); + let api_exact = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = + Result::<_, ()>::Ok(crate::api::usearch_api::VectorDB::bulk_search_keys( + &*api_that_guard, + &api_potential_keys, + api_count, + api_exact, + ))?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_bulk_search_vectors_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_bulk_search_vectors", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_queries = >>::sse_decode(&mut deserializer); + let api_count = ::sse_decode(&mut deserializer); + let api_exact = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok( + crate::api::usearch_api::VectorDB::bulk_search_vectors( + &*api_that_guard, + &api_queries, + api_count, + api_exact, + ), + )?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_contains_vector_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_contains_vector", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_key = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = + Result::<_, ()>::Ok(crate::api::usearch_api::VectorDB::contains_vector( + &*api_that_guard, + api_key, + ))?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_delete_index_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_delete_index", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok({ + crate::api::usearch_api::VectorDB::delete_index(api_that); + })?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_get_index_stats_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_get_index_stats", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok( + crate::api::usearch_api::VectorDB::get_index_stats(&*api_that_guard), + )?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_get_vector_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_get_vector", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_key = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok( + crate::api::usearch_api::VectorDB::get_vector(&*api_that_guard, api_key), + )?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_new_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_new", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_file_path = ::sse_decode(&mut deserializer); + let api_dimensions = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::usearch_api::VectorDB::new( + &api_file_path, + api_dimensions, + ))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_remove_vector_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_remove_vector", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_key = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok( + crate::api::usearch_api::VectorDB::remove_vector(&*api_that_guard, api_key), + )?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_reset_index_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_reset_index", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = Result::<_, ()>::Ok({ + crate::api::usearch_api::VectorDB::reset_index(&*api_that_guard); + })?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__usearch_api__VectorDb_search_vectors_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "VectorDb_search_vectors", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_that = , + >>::sse_decode(&mut deserializer); + let api_query = >::sse_decode(&mut deserializer); + let api_count = ::sse_decode(&mut deserializer); + let api_exact = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let mut api_that_guard = None; + let decode_indices_ = + flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![ + flutter_rust_bridge::for_generated::LockableOrderInfo::new( + &api_that, 0, false, + ), + ]); + for i in decode_indices_ { + match i { + 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()), + _ => unreachable!(), + } + } + let api_that_guard = api_that_guard.unwrap(); + let output_ok = + Result::<_, ()>::Ok(crate::api::usearch_api::VectorDB::search_vectors( + &*api_that_guard, + &api_query, + api_count, + api_exact, + ))?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__simple__greet_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "greet", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_name = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::simple::greet(api_name))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__simple__init_app_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "init_app", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok({ + crate::api::simple::init_app(); + })?; + Ok(output_ok) + })()) + } + }, + ) +} + +// Section: related_funcs + +flutter_rust_bridge::frb_generated_moi_arc_impl_value!( + flutter_rust_bridge::for_generated::RustAutoOpaqueInner +); + +// Section: dart2rust + +impl SseDecode for VectorDB { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = , + >>::sse_decode(deserializer); + return flutter_rust_bridge::for_generated::rust_auto_opaque_decode_owned(inner); + } +} + +impl SseDecode + for RustOpaqueMoi> +{ + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = ::sse_decode(deserializer); + return decode_rust_opaque_moi(inner); + } +} + +impl SseDecode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = >::sse_decode(deserializer); + return String::from_utf8(inner).unwrap(); + } +} + +impl SseDecode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() != 0 + } +} + +impl SseDecode for f32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_f32::().unwrap() + } +} + +impl SseDecode for Vec> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(>::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(>::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for (Vec>, Vec>) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_field0 = >>::sse_decode(deserializer); + let mut var_field1 = >>::sse_decode(deserializer); + return (var_field0, var_field1); + } +} + +impl SseDecode for (Vec, Vec>, Vec>) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_field0 = >::sse_decode(deserializer); + let mut var_field1 = >>::sse_decode(deserializer); + let mut var_field2 = >>::sse_decode(deserializer); + return (var_field0, var_field1, var_field2); + } +} + +impl SseDecode for (Vec, Vec) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_field0 = >::sse_decode(deserializer); + let mut var_field1 = >::sse_decode(deserializer); + return (var_field0, var_field1); + } +} + +impl SseDecode for (usize, usize, usize, usize, usize, usize, usize) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_field0 = ::sse_decode(deserializer); + let mut var_field1 = ::sse_decode(deserializer); + let mut var_field2 = ::sse_decode(deserializer); + let mut var_field3 = ::sse_decode(deserializer); + let mut var_field4 = ::sse_decode(deserializer); + let mut var_field5 = ::sse_decode(deserializer); + let mut var_field6 = ::sse_decode(deserializer); + return ( + var_field0, var_field1, var_field2, var_field3, var_field4, var_field5, var_field6, + ); + } +} + +impl SseDecode for u64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u64::().unwrap() + } +} + +impl SseDecode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() + } +} + +impl SseDecode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} +} + +impl SseDecode for usize { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u64::().unwrap() as _ + } +} + +impl SseDecode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i32::().unwrap() + } +} + +fn pde_ffi_dispatcher_primary_impl( + func_id: i32, + port: flutter_rust_bridge::for_generated::MessagePort, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + 1 => wire__crate__api__usearch_api__VectorDb_add_vector_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 2 => wire__crate__api__usearch_api__VectorDb_bulk_add_vectors_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 3 => wire__crate__api__usearch_api__VectorDb_bulk_get_vectors_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 4 => wire__crate__api__usearch_api__VectorDb_bulk_remove_vectors_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 5 => wire__crate__api__usearch_api__VectorDb_bulk_search_keys_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 6 => wire__crate__api__usearch_api__VectorDb_bulk_search_vectors_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 7 => wire__crate__api__usearch_api__VectorDb_contains_vector_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 8 => wire__crate__api__usearch_api__VectorDb_delete_index_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 9 => wire__crate__api__usearch_api__VectorDb_get_index_stats_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 10 => wire__crate__api__usearch_api__VectorDb_get_vector_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 12 => wire__crate__api__usearch_api__VectorDb_remove_vector_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 13 => wire__crate__api__usearch_api__VectorDb_reset_index_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 14 => wire__crate__api__usearch_api__VectorDb_search_vectors_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 16 => wire__crate__api__simple__init_app_impl(port, ptr, rust_vec_len, data_len), + _ => unreachable!(), + } +} + +fn pde_ffi_dispatcher_sync_impl( + func_id: i32, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + 11 => wire__crate__api__usearch_api__VectorDb_new_impl(ptr, rust_vec_len, data_len), + 15 => wire__crate__api__simple__greet_impl(ptr, rust_vec_len, data_len), + _ => unreachable!(), + } +} + +// Section: rust2dart + +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for FrbWrapper { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self.0) + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for FrbWrapper {} + +impl flutter_rust_bridge::IntoIntoDart> for VectorDB { + fn into_into_dart(self) -> FrbWrapper { + self.into() + } +} + +impl SseEncode for VectorDB { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >>::sse_encode(flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self), serializer); + } +} + +impl SseEncode + for RustOpaqueMoi> +{ + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + let (ptr, size) = self.sse_encode_raw(); + ::sse_encode(ptr, serializer); + ::sse_encode(size, serializer); + } +} + +impl SseEncode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.into_bytes(), serializer); + } +} + +impl SseEncode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self as _).unwrap(); + } +} + +impl SseEncode for f32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_f32::(self).unwrap(); + } +} + +impl SseEncode for Vec> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + >::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + >::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for (Vec>, Vec>) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >>::sse_encode(self.0, serializer); + >>::sse_encode(self.1, serializer); + } +} + +impl SseEncode for (Vec, Vec>, Vec>) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.0, serializer); + >>::sse_encode(self.1, serializer); + >>::sse_encode(self.2, serializer); + } +} + +impl SseEncode for (Vec, Vec) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.0, serializer); + >::sse_encode(self.1, serializer); + } +} + +impl SseEncode for (usize, usize, usize, usize, usize, usize, usize) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.0, serializer); + ::sse_encode(self.1, serializer); + ::sse_encode(self.2, serializer); + ::sse_encode(self.3, serializer); + ::sse_encode(self.4, serializer); + ::sse_encode(self.5, serializer); + ::sse_encode(self.6, serializer); + } +} + +impl SseEncode for u64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u64::(self).unwrap(); + } +} + +impl SseEncode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self).unwrap(); + } +} + +impl SseEncode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} +} + +impl SseEncode for usize { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer + .cursor + .write_u64::(self as _) + .unwrap(); + } +} + +impl SseEncode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_i32::(self).unwrap(); + } +} + +#[cfg(not(target_family = "wasm"))] +mod io { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.11.1. + + // Section: imports + + use super::*; + use crate::api::usearch_api::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_io!(); + + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_photos_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + ptr: *const std::ffi::c_void, + ) { + MoiArc::>::increment_strong_count(ptr as _); + } + + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_photos_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVectorDB( + ptr: *const std::ffi::c_void, + ) { + MoiArc::>::decrement_strong_count(ptr as _); + } +} +#[cfg(not(target_family = "wasm"))] +pub use io::*; diff --git a/mobile/apps/photos/rust/src/lib.rs b/mobile/apps/photos/rust/src/lib.rs new file mode 100644 index 0000000000..cbb071f8bf --- /dev/null +++ b/mobile/apps/photos/rust/src/lib.rs @@ -0,0 +1,2 @@ +pub mod api; +mod frb_generated; diff --git a/mobile/apps/photos/rust_builder/.gitignore b/mobile/apps/photos/rust_builder/.gitignore new file mode 100644 index 0000000000..ac5aa9893e --- /dev/null +++ b/mobile/apps/photos/rust_builder/.gitignore @@ -0,0 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ diff --git a/mobile/apps/photos/rust_builder/README.md b/mobile/apps/photos/rust_builder/README.md new file mode 100644 index 0000000000..922615f9c1 --- /dev/null +++ b/mobile/apps/photos/rust_builder/README.md @@ -0,0 +1 @@ +Please ignore this folder, which is just glue to build Rust with Flutter. \ No newline at end of file diff --git a/mobile/apps/photos/rust_builder/android/.gitignore b/mobile/apps/photos/rust_builder/android/.gitignore new file mode 100644 index 0000000000..161bdcdaf8 --- /dev/null +++ b/mobile/apps/photos/rust_builder/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/mobile/apps/photos/rust_builder/android/build.gradle b/mobile/apps/photos/rust_builder/android/build.gradle new file mode 100644 index 0000000000..5239261a2e --- /dev/null +++ b/mobile/apps/photos/rust_builder/android/build.gradle @@ -0,0 +1,56 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + +group 'com.flutter_rust_bridge.rust_lib_photos' +version '1.0' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. + classpath 'com.android.tools.build:gradle:7.3.0' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' + +android { + if (project.android.hasProperty("namespace")) { + namespace 'com.flutter_rust_bridge.rust_lib_photos' + } + + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. + compileSdkVersion 33 + + // Use the NDK version + // declared in /android/app/build.gradle file of the Flutter project. + // Replace it with a version number if this plugin requires a specfic NDK version. + // (e.g. ndkVersion "23.1.7779620") + ndkVersion android.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 19 + } +} + +apply from: "../cargokit/gradle/plugin.gradle" +cargokit { + manifestDir = "../../rust" + libname = "rust_lib_photos" +} diff --git a/mobile/apps/photos/rust_builder/android/settings.gradle b/mobile/apps/photos/rust_builder/android/settings.gradle new file mode 100644 index 0000000000..48e7a64ca7 --- /dev/null +++ b/mobile/apps/photos/rust_builder/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'rust_lib_photos' diff --git a/mobile/apps/photos/rust_builder/android/src/main/AndroidManifest.xml b/mobile/apps/photos/rust_builder/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..b80e4df687 --- /dev/null +++ b/mobile/apps/photos/rust_builder/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/mobile/apps/photos/rust_builder/cargokit/.gitignore b/mobile/apps/photos/rust_builder/cargokit/.gitignore new file mode 100644 index 0000000000..cf7bb868c0 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/.gitignore @@ -0,0 +1,4 @@ +target +.dart_tool +*.iml +!pubspec.lock diff --git a/mobile/apps/photos/rust_builder/cargokit/LICENSE b/mobile/apps/photos/rust_builder/cargokit/LICENSE new file mode 100644 index 0000000000..d33a5fea52 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/LICENSE @@ -0,0 +1,42 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +Copyright 2022 Matej Knopp + +================================================================================ + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +================================================================================ + +APACHE LICENSE, VERSION 2.0 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/mobile/apps/photos/rust_builder/cargokit/README b/mobile/apps/photos/rust_builder/cargokit/README new file mode 100644 index 0000000000..398474dbc8 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/README @@ -0,0 +1,11 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +Experimental repository to provide glue for seamlessly integrating cargo build +with flutter plugins and packages. + +See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/ +for a tutorial on how to use Cargokit. + +Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin. + diff --git a/mobile/apps/photos/rust_builder/cargokit/build_pod.sh b/mobile/apps/photos/rust_builder/cargokit/build_pod.sh new file mode 100755 index 0000000000..ed0e0d987d --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_pod.sh @@ -0,0 +1,58 @@ +#!/bin/sh +set -e + +BASEDIR=$(dirname "$0") + +# Workaround for https://github.com/dart-lang/pub/issues/4010 +BASEDIR=$(cd "$BASEDIR" ; pwd -P) + +# Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project +NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"` + +export PATH=${NEW_PATH%?} # remove trailing : + +env + +# Platform name (macosx, iphoneos, iphonesimulator) +export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME + +# Arctive architectures (arm64, armv7, x86_64), space separated. +export CARGOKIT_DARWIN_ARCHS=$ARCHS + +# Current build configuration (Debug, Release) +export CARGOKIT_CONFIGURATION=$CONFIGURATION + +# Path to directory containing Cargo.toml. +export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1 + +# Temporary directory for build artifacts. +export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR + +# Output directory for final artifacts. +export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME + +# Directory to store built tool artifacts. +export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool + +# Directory inside root project. Not necessarily the top level directory of root project. +export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT + +FLUTTER_EXPORT_BUILD_ENVIRONMENT=( + "$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS + "$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS +) + +for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}" +do + if [[ -f "$path" ]]; then + source "$path" + fi +done + +sh "$BASEDIR/run_build_tool.sh" build-pod "$@" + +# Make a symlink from built framework to phony file, which will be used as input to +# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate +# attribute on custom build phase) +ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony" +ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out" diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/README.md b/mobile/apps/photos/rust_builder/cargokit/build_tool/README.md new file mode 100644 index 0000000000..a878c27964 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/README.md @@ -0,0 +1,5 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/analysis_options.yaml b/mobile/apps/photos/rust_builder/cargokit/build_tool/analysis_options.yaml new file mode 100644 index 0000000000..0e16a8b092 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/analysis_options.yaml @@ -0,0 +1,34 @@ +# This is copied from Cargokit (which is the official way to use it currently) +# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +linter: + rules: + - prefer_relative_imports + - directives_ordering + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/bin/build_tool.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/bin/build_tool.dart new file mode 100644 index 0000000000..268eb524dc --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/bin/build_tool.dart @@ -0,0 +1,8 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'package:build_tool/build_tool.dart' as build_tool; + +void main(List arguments) { + build_tool.runMain(arguments); +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/build_tool.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/build_tool.dart new file mode 100644 index 0000000000..7c1bb750a4 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/build_tool.dart @@ -0,0 +1,8 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'src/build_tool.dart' as build_tool; + +Future runMain(List args) async { + return build_tool.runMain(args); +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/android_environment.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/android_environment.dart new file mode 100644 index 0000000000..15fc9eedac --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/android_environment.dart @@ -0,0 +1,195 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math' as math; + +import 'package:collection/collection.dart'; +import 'package:path/path.dart' as path; +import 'package:version/version.dart'; + +import 'target.dart'; +import 'util.dart'; + +class AndroidEnvironment { + AndroidEnvironment({ + required this.sdkPath, + required this.ndkVersion, + required this.minSdkVersion, + required this.targetTempDir, + required this.target, + }); + + static void clangLinkerWrapper(List args) { + final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG']; + if (clang == null) { + throw Exception( + "cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var"); + } + final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET']; + if (target == null) { + throw Exception( + "cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var"); + } + + runCommand(clang, [ + target, + ...args, + ]); + } + + /// Full path to Android SDK. + final String sdkPath; + + /// Full version of Android NDK. + final String ndkVersion; + + /// Minimum supported SDK version. + final int minSdkVersion; + + /// Target directory for build artifacts. + final String targetTempDir; + + /// Target being built. + final Target target; + + bool ndkIsInstalled() { + final ndkPath = path.join(sdkPath, 'ndk', ndkVersion); + final ndkPackageXml = File(path.join(ndkPath, 'package.xml')); + return ndkPackageXml.existsSync(); + } + + void installNdk({ + required String javaHome, + }) { + final sdkManagerExtension = Platform.isWindows ? '.bat' : ''; + final sdkManager = path.join( + sdkPath, + 'cmdline-tools', + 'latest', + 'bin', + 'sdkmanager$sdkManagerExtension', + ); + + log.info('Installing NDK $ndkVersion'); + runCommand(sdkManager, [ + '--install', + 'ndk;$ndkVersion', + ], environment: { + 'JAVA_HOME': javaHome, + }); + } + + Future> buildEnvironment() async { + final hostArch = Platform.isMacOS + ? "darwin-x86_64" + : (Platform.isLinux ? "linux-x86_64" : "windows-x86_64"); + + final ndkPath = path.join(sdkPath, 'ndk', ndkVersion); + final toolchainPath = path.join( + ndkPath, + 'toolchains', + 'llvm', + 'prebuilt', + hostArch, + 'bin', + ); + + final minSdkVersion = + math.max(target.androidMinSdkVersion!, this.minSdkVersion); + + final exe = Platform.isWindows ? '.exe' : ''; + + final arKey = 'AR_${target.rust}'; + final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe'] + .map((e) => path.join(toolchainPath, e)) + .firstWhereOrNull((element) => File(element).existsSync()); + if (arValue == null) { + throw Exception('Failed to find ar for $target in $toolchainPath'); + } + + final targetArg = '--target=${target.rust}$minSdkVersion'; + + final ccKey = 'CC_${target.rust}'; + final ccValue = path.join(toolchainPath, 'clang$exe'); + final cfFlagsKey = 'CFLAGS_${target.rust}'; + final cFlagsValue = targetArg; + + final cxxKey = 'CXX_${target.rust}'; + final cxxValue = path.join(toolchainPath, 'clang++$exe'); + final cxxFlagsKey = 'CXXFLAGS_${target.rust}'; + final cxxFlagsValue = targetArg; + + final linkerKey = + 'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase(); + + final ranlibKey = 'RANLIB_${target.rust}'; + final ranlibValue = path.join(toolchainPath, 'llvm-ranlib$exe'); + + final ndkVersionParsed = Version.parse(ndkVersion); + final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS'; + final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed); + + final runRustTool = + Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh'; + + final packagePath = (await Isolate.resolvePackageUri( + Uri.parse('package:build_tool/buildtool.dart')))! + .toFilePath(); + final selfPath = path.canonicalize(path.join( + packagePath, + '..', + '..', + '..', + runRustTool, + )); + + // Make sure that run_build_tool is working properly even initially launched directly + // through dart run. + final toolTempDir = + Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir; + + return { + arKey: arValue, + ccKey: ccValue, + cfFlagsKey: cFlagsValue, + cxxKey: cxxValue, + cxxFlagsKey: cxxFlagsValue, + ranlibKey: ranlibValue, + rustFlagsKey: rustFlagsValue, + linkerKey: selfPath, + // Recognized by main() so we know when we're acting as a wrapper + '_CARGOKIT_NDK_LINK_TARGET': targetArg, + '_CARGOKIT_NDK_LINK_CLANG': ccValue, + 'CARGOKIT_TOOL_TEMP_DIR': toolTempDir, + }; + } + + // Workaround for libgcc missing in NDK23, inspired by cargo-ndk + String _libGccWorkaround(String buildDir, Version ndkVersion) { + final workaroundDir = path.join( + buildDir, + 'cargokit', + 'libgcc_workaround', + '${ndkVersion.major}', + ); + Directory(workaroundDir).createSync(recursive: true); + if (ndkVersion.major >= 23) { + File(path.join(workaroundDir, 'libgcc.a')) + .writeAsStringSync('INPUT(-lunwind)'); + } else { + // Other way around, untested, forward libgcc.a from libunwind once Rust + // gets updated for NDK23+. + File(path.join(workaroundDir, 'libunwind.a')) + .writeAsStringSync('INPUT(-lgcc)'); + } + + var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? ''; + if (rustFlags.isNotEmpty) { + rustFlags = '$rustFlags\x1f'; + } + rustFlags = '$rustFlags-L\x1f$workaroundDir'; + return rustFlags; + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart new file mode 100644 index 0000000000..e608cece73 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart @@ -0,0 +1,266 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:http/http.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'builder.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'rustup.dart'; +import 'target.dart'; + +class Artifact { + /// File system location of the artifact. + final String path; + + /// Actual file name that the artifact should have in destination folder. + final String finalFileName; + + AritifactType get type { + if (finalFileName.endsWith('.dll') || + finalFileName.endsWith('.dll.lib') || + finalFileName.endsWith('.pdb') || + finalFileName.endsWith('.so') || + finalFileName.endsWith('.dylib')) { + return AritifactType.dylib; + } else if (finalFileName.endsWith('.lib') || finalFileName.endsWith('.a')) { + return AritifactType.staticlib; + } else { + throw Exception('Unknown artifact type for $finalFileName'); + } + } + + Artifact({ + required this.path, + required this.finalFileName, + }); +} + +final _log = Logger('artifacts_provider'); + +class ArtifactProvider { + ArtifactProvider({ + required this.environment, + required this.userOptions, + }); + + final BuildEnvironment environment; + final CargokitUserOptions userOptions; + + Future>> getArtifacts(List targets) async { + final result = await _getPrecompiledArtifacts(targets); + + final pendingTargets = List.of(targets); + pendingTargets.removeWhere((element) => result.containsKey(element)); + + if (pendingTargets.isEmpty) { + return result; + } + + final rustup = Rustup(); + for (final target in targets) { + final builder = RustBuilder(target: target, environment: environment); + builder.prepare(rustup); + _log.info('Building ${environment.crateInfo.packageName} for $target'); + final targetDir = await builder.build(); + // For local build accept both static and dynamic libraries. + final artifactNames = { + ...getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + aritifactType: AritifactType.dylib, + remote: false, + ), + ...getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + aritifactType: AritifactType.staticlib, + remote: false, + ) + }; + final artifacts = artifactNames + .map((artifactName) => Artifact( + path: path.join(targetDir, artifactName), + finalFileName: artifactName, + )) + .where((element) => File(element.path).existsSync()) + .toList(); + result[target] = artifacts; + } + return result; + } + + Future>> _getPrecompiledArtifacts( + List targets) async { + if (userOptions.usePrecompiledBinaries == false) { + _log.info('Precompiled binaries are disabled'); + return {}; + } + if (environment.crateOptions.precompiledBinaries == null) { + _log.fine('Precompiled binaries not enabled for this crate'); + return {}; + } + + final start = Stopwatch()..start(); + final crateHash = CrateHash.compute(environment.manifestDir, + tempStorage: environment.targetTempDir); + _log.fine( + 'Computed crate hash $crateHash in ${start.elapsedMilliseconds}ms'); + + final downloadedArtifactsDir = + path.join(environment.targetTempDir, 'precompiled', crateHash); + Directory(downloadedArtifactsDir).createSync(recursive: true); + + final res = >{}; + + for (final target in targets) { + final requiredArtifacts = getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + remote: true, + ); + final artifactsForTarget = []; + + for (final artifact in requiredArtifacts) { + final fileName = PrecompileBinaries.fileName(target, artifact); + final downloadedPath = path.join(downloadedArtifactsDir, fileName); + if (!File(downloadedPath).existsSync()) { + final signatureFileName = + PrecompileBinaries.signatureFileName(target, artifact); + await _tryDownloadArtifacts( + crateHash: crateHash, + fileName: fileName, + signatureFileName: signatureFileName, + finalPath: downloadedPath, + ); + } + if (File(downloadedPath).existsSync()) { + artifactsForTarget.add(Artifact( + path: downloadedPath, + finalFileName: artifact, + )); + } else { + break; + } + } + + // Only provide complete set of artifacts. + if (artifactsForTarget.length == requiredArtifacts.length) { + _log.fine('Found precompiled artifacts for $target'); + res[target] = artifactsForTarget; + } + } + + return res; + } + + static Future _get(Uri url, {Map? headers}) async { + int attempt = 0; + const maxAttempts = 10; + while (true) { + try { + return await get(url, headers: headers); + } on SocketException catch (e) { + // Try to detect reset by peer error and retry. + if (attempt++ < maxAttempts && + (e.osError?.errorCode == 54 || e.osError?.errorCode == 10054)) { + _log.severe( + 'Failed to download $url: $e, attempt $attempt of $maxAttempts, will retry...'); + await Future.delayed(Duration(seconds: 1)); + continue; + } else { + rethrow; + } + } + } + } + + Future _tryDownloadArtifacts({ + required String crateHash, + required String fileName, + required String signatureFileName, + required String finalPath, + }) async { + final precompiledBinaries = environment.crateOptions.precompiledBinaries!; + final prefix = precompiledBinaries.uriPrefix; + final url = Uri.parse('$prefix$crateHash/$fileName'); + final signatureUrl = Uri.parse('$prefix$crateHash/$signatureFileName'); + _log.fine('Downloading signature from $signatureUrl'); + final signature = await _get(signatureUrl); + if (signature.statusCode == 404) { + _log.warning( + 'Precompiled binaries not available for crate hash $crateHash ($fileName)'); + return; + } + if (signature.statusCode != 200) { + _log.severe( + 'Failed to download signature $signatureUrl: status ${signature.statusCode}'); + return; + } + _log.fine('Downloading binary from $url'); + final res = await _get(url); + if (res.statusCode != 200) { + _log.severe('Failed to download binary $url: status ${res.statusCode}'); + return; + } + if (verify( + precompiledBinaries.publicKey, res.bodyBytes, signature.bodyBytes)) { + File(finalPath).writeAsBytesSync(res.bodyBytes); + } else { + _log.shout('Signature verification failed! Ignoring binary.'); + } + } +} + +enum AritifactType { + staticlib, + dylib, +} + +AritifactType artifactTypeForTarget(Target target) { + if (target.darwinPlatform != null) { + return AritifactType.staticlib; + } else { + return AritifactType.dylib; + } +} + +List getArtifactNames({ + required Target target, + required String libraryName, + required bool remote, + AritifactType? aritifactType, +}) { + aritifactType ??= artifactTypeForTarget(target); + if (target.darwinArch != null) { + if (aritifactType == AritifactType.staticlib) { + return ['lib$libraryName.a']; + } else { + return ['lib$libraryName.dylib']; + } + } else if (target.rust.contains('-windows-')) { + if (aritifactType == AritifactType.staticlib) { + return ['$libraryName.lib']; + } else { + return [ + '$libraryName.dll', + '$libraryName.dll.lib', + if (!remote) '$libraryName.pdb' + ]; + } + } else if (target.rust.contains('-linux-')) { + if (aritifactType == AritifactType.staticlib) { + return ['lib$libraryName.a']; + } else { + return ['lib$libraryName.so']; + } + } else { + throw Exception("Unsupported target: ${target.rust}"); + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_cmake.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_cmake.dart new file mode 100644 index 0000000000..6f3b2a4ec1 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_cmake.dart @@ -0,0 +1,40 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; + +class BuildCMake { + final CargokitUserOptions userOptions; + + BuildCMake({required this.userOptions}); + + Future build() async { + final targetPlatform = Environment.targetPlatform; + final target = Target.forFlutterName(Environment.targetPlatform); + if (target == null) { + throw Exception("Unknown target platform: $targetPlatform"); + } + + final environment = BuildEnvironment.fromEnvironment(isAndroid: false); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts([target]); + + final libs = artifacts[target]!; + + for (final lib in libs) { + if (lib.type == AritifactType.dylib) { + File(lib.path) + .copySync(path.join(Environment.outputDir, lib.finalFileName)); + } + } + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_gradle.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_gradle.dart new file mode 100644 index 0000000000..7e61fcbb7c --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_gradle.dart @@ -0,0 +1,49 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; + +final log = Logger('build_gradle'); + +class BuildGradle { + BuildGradle({required this.userOptions}); + + final CargokitUserOptions userOptions; + + Future build() async { + final targets = Environment.targetPlatforms.map((arch) { + final target = Target.forFlutterName(arch); + if (target == null) { + throw Exception( + "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); + } + return target; + }).toList(); + + final environment = BuildEnvironment.fromEnvironment(isAndroid: true); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts(targets); + + for (final target in targets) { + final libs = artifacts[target]!; + final outputDir = path.join(Environment.outputDir, target.android!); + Directory(outputDir).createSync(recursive: true); + + for (final lib in libs) { + if (lib.type == AritifactType.dylib) { + File(lib.path).copySync(path.join(outputDir, lib.finalFileName)); + } + } + } + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_pod.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_pod.dart new file mode 100644 index 0000000000..8a9c0db5de --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_pod.dart @@ -0,0 +1,89 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; +import 'util.dart'; + +class BuildPod { + BuildPod({required this.userOptions}); + + final CargokitUserOptions userOptions; + + Future build() async { + final targets = Environment.darwinArchs.map((arch) { + final target = Target.forDarwin( + platformName: Environment.darwinPlatformName, darwinAarch: arch); + if (target == null) { + throw Exception( + "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); + } + return target; + }).toList(); + + final environment = BuildEnvironment.fromEnvironment(isAndroid: false); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts(targets); + + void performLipo(String targetFile, Iterable sourceFiles) { + runCommand("lipo", [ + '-create', + ...sourceFiles, + '-output', + targetFile, + ]); + } + + final outputDir = Environment.outputDir; + + Directory(outputDir).createSync(recursive: true); + + final staticLibs = artifacts.values + .expand((element) => element) + .where((element) => element.type == AritifactType.staticlib) + .toList(); + final dynamicLibs = artifacts.values + .expand((element) => element) + .where((element) => element.type == AritifactType.dylib) + .toList(); + + final libName = environment.crateInfo.packageName; + + // If there is static lib, use it and link it with pod + if (staticLibs.isNotEmpty) { + final finalTargetFile = path.join(outputDir, "lib$libName.a"); + performLipo(finalTargetFile, staticLibs.map((e) => e.path)); + } else { + // Otherwise try to replace bundle dylib with our dylib + final bundlePaths = [ + '$libName.framework/Versions/A/$libName', + '$libName.framework/$libName', + ]; + + for (final bundlePath in bundlePaths) { + final targetFile = path.join(outputDir, bundlePath); + if (File(targetFile).existsSync()) { + performLipo(targetFile, dynamicLibs.map((e) => e.path)); + + // Replace absolute id with @rpath one so that it works properly + // when moved to Frameworks. + runCommand("install_name_tool", [ + '-id', + '@rpath/$bundlePath', + targetFile, + ]); + return; + } + } + throw Exception('Unable to find bundle for dynamic library'); + } + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_tool.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_tool.dart new file mode 100644 index 0000000000..c8f36981b5 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/build_tool.dart @@ -0,0 +1,271 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:github/github.dart'; +import 'package:hex/hex.dart'; +import 'package:logging/logging.dart'; + +import 'android_environment.dart'; +import 'build_cmake.dart'; +import 'build_gradle.dart'; +import 'build_pod.dart'; +import 'logging.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'target.dart'; +import 'util.dart'; +import 'verify_binaries.dart'; + +final log = Logger('build_tool'); + +abstract class BuildCommand extends Command { + Future runBuildCommand(CargokitUserOptions options); + + @override + Future run() async { + final options = CargokitUserOptions.load(); + + if (options.verboseLogging || + Platform.environment['CARGOKIT_VERBOSE'] == '1') { + enableVerboseLogging(); + } + + await runBuildCommand(options); + } +} + +class BuildPodCommand extends BuildCommand { + @override + final name = 'build-pod'; + + @override + final description = 'Build cocoa pod library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildPod(userOptions: options); + await build.build(); + } +} + +class BuildGradleCommand extends BuildCommand { + @override + final name = 'build-gradle'; + + @override + final description = 'Build android library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildGradle(userOptions: options); + await build.build(); + } +} + +class BuildCMakeCommand extends BuildCommand { + @override + final name = 'build-cmake'; + + @override + final description = 'Build CMake library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildCMake(userOptions: options); + await build.build(); + } +} + +class GenKeyCommand extends Command { + @override + final name = 'gen-key'; + + @override + final description = 'Generate key pair for signing precompiled binaries'; + + @override + void run() { + final kp = generateKey(); + final private = HEX.encode(kp.privateKey.bytes); + final public = HEX.encode(kp.publicKey.bytes); + print("Private Key: $private"); + print("Public Key: $public"); + } +} + +class PrecompileBinariesCommand extends Command { + PrecompileBinariesCommand() { + argParser + ..addOption( + 'repository', + mandatory: true, + help: 'Github repository slug in format owner/name', + ) + ..addOption( + 'manifest-dir', + mandatory: true, + help: 'Directory containing Cargo.toml', + ) + ..addMultiOption('target', + help: 'Rust target triple of artifact to build.\n' + 'Can be specified multiple times or omitted in which case\n' + 'all targets for current platform will be built.') + ..addOption( + 'android-sdk-location', + help: 'Location of Android SDK (if available)', + ) + ..addOption( + 'android-ndk-version', + help: 'Android NDK version (if available)', + ) + ..addOption( + 'android-min-sdk-version', + help: 'Android minimum rquired version (if available)', + ) + ..addOption( + 'temp-dir', + help: 'Directory to store temporary build artifacts', + ) + ..addFlag( + "verbose", + abbr: "v", + defaultsTo: false, + help: "Enable verbose logging", + ); + } + + @override + final name = 'precompile-binaries'; + + @override + final description = 'Prebuild and upload binaries\n' + 'Private key must be passed through PRIVATE_KEY environment variable. ' + 'Use gen_key through generate priave key.\n' + 'Github token must be passed as GITHUB_TOKEN environment variable.\n'; + + @override + Future run() async { + final verbose = argResults!['verbose'] as bool; + if (verbose) { + enableVerboseLogging(); + } + + final privateKeyString = Platform.environment['PRIVATE_KEY']; + if (privateKeyString == null) { + throw ArgumentError('Missing PRIVATE_KEY environment variable'); + } + final githubToken = Platform.environment['GITHUB_TOKEN']; + if (githubToken == null) { + throw ArgumentError('Missing GITHUB_TOKEN environment variable'); + } + final privateKey = HEX.decode(privateKeyString); + if (privateKey.length != 64) { + throw ArgumentError('Private key must be 64 bytes long'); + } + final manifestDir = argResults!['manifest-dir'] as String; + if (!Directory(manifestDir).existsSync()) { + throw ArgumentError('Manifest directory does not exist: $manifestDir'); + } + String? androidMinSdkVersionString = + argResults!['android-min-sdk-version'] as String?; + int? androidMinSdkVersion; + if (androidMinSdkVersionString != null) { + androidMinSdkVersion = int.tryParse(androidMinSdkVersionString); + if (androidMinSdkVersion == null) { + throw ArgumentError( + 'Invalid android-min-sdk-version: $androidMinSdkVersionString'); + } + } + final targetStrigns = argResults!['target'] as List; + final targets = targetStrigns.map((target) { + final res = Target.forRustTriple(target); + if (res == null) { + throw ArgumentError('Invalid target: $target'); + } + return res; + }).toList(growable: false); + final precompileBinaries = PrecompileBinaries( + privateKey: PrivateKey(privateKey), + githubToken: githubToken, + manifestDir: manifestDir, + repositorySlug: RepositorySlug.full(argResults!['repository'] as String), + targets: targets, + androidSdkLocation: argResults!['android-sdk-location'] as String?, + androidNdkVersion: argResults!['android-ndk-version'] as String?, + androidMinSdkVersion: androidMinSdkVersion, + tempDir: argResults!['temp-dir'] as String?, + ); + + await precompileBinaries.run(); + } +} + +class VerifyBinariesCommand extends Command { + VerifyBinariesCommand() { + argParser.addOption( + 'manifest-dir', + mandatory: true, + help: 'Directory containing Cargo.toml', + ); + } + + @override + final name = "verify-binaries"; + + @override + final description = 'Verifies published binaries\n' + 'Checks whether there is a binary published for each targets\n' + 'and checks the signature.'; + + @override + Future run() async { + final manifestDir = argResults!['manifest-dir'] as String; + final verifyBinaries = VerifyBinaries( + manifestDir: manifestDir, + ); + await verifyBinaries.run(); + } +} + +Future runMain(List args) async { + try { + // Init logging before options are loaded + initLogging(); + + if (Platform.environment['_CARGOKIT_NDK_LINK_TARGET'] != null) { + return AndroidEnvironment.clangLinkerWrapper(args); + } + + final runner = CommandRunner('build_tool', 'Cargokit built_tool') + ..addCommand(BuildPodCommand()) + ..addCommand(BuildGradleCommand()) + ..addCommand(BuildCMakeCommand()) + ..addCommand(GenKeyCommand()) + ..addCommand(PrecompileBinariesCommand()) + ..addCommand(VerifyBinariesCommand()); + + await runner.run(args); + } on ArgumentError catch (e) { + stderr.writeln(e.toString()); + exit(1); + } catch (e, s) { + log.severe(kDoubleSeparator); + log.severe('Cargokit BuildTool failed with error:'); + log.severe(kSeparator); + log.severe(e); + // This tells user to install Rust, there's no need to pollute the log with + // stack trace. + if (e is! RustupNotFoundException) { + log.severe(kSeparator); + log.severe(s); + log.severe(kSeparator); + log.severe('BuildTool arguments: $args'); + } + log.severe(kDoubleSeparator); + exit(1); + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/builder.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/builder.dart new file mode 100644 index 0000000000..84c46e4f54 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/builder.dart @@ -0,0 +1,198 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'package:collection/collection.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'android_environment.dart'; +import 'cargo.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'rustup.dart'; +import 'target.dart'; +import 'util.dart'; + +final _log = Logger('builder'); + +enum BuildConfiguration { + debug, + release, + profile, +} + +extension on BuildConfiguration { + bool get isDebug => this == BuildConfiguration.debug; + String get rustName => switch (this) { + BuildConfiguration.debug => 'debug', + BuildConfiguration.release => 'release', + BuildConfiguration.profile => 'release', + }; +} + +class BuildException implements Exception { + final String message; + + BuildException(this.message); + + @override + String toString() { + return 'BuildException: $message'; + } +} + +class BuildEnvironment { + final BuildConfiguration configuration; + final CargokitCrateOptions crateOptions; + final String targetTempDir; + final String manifestDir; + final CrateInfo crateInfo; + + final bool isAndroid; + final String? androidSdkPath; + final String? androidNdkVersion; + final int? androidMinSdkVersion; + final String? javaHome; + + BuildEnvironment({ + required this.configuration, + required this.crateOptions, + required this.targetTempDir, + required this.manifestDir, + required this.crateInfo, + required this.isAndroid, + this.androidSdkPath, + this.androidNdkVersion, + this.androidMinSdkVersion, + this.javaHome, + }); + + static BuildConfiguration parseBuildConfiguration(String value) { + // XCode configuration adds the flavor to configuration name. + final firstSegment = value.split('-').first; + final buildConfiguration = BuildConfiguration.values.firstWhereOrNull( + (e) => e.name == firstSegment, + ); + if (buildConfiguration == null) { + _log.warning('Unknown build configuraiton $value, will assume release'); + return BuildConfiguration.release; + } + return buildConfiguration; + } + + static BuildEnvironment fromEnvironment({ + required bool isAndroid, + }) { + final buildConfiguration = + parseBuildConfiguration(Environment.configuration); + final manifestDir = Environment.manifestDir; + final crateOptions = CargokitCrateOptions.load( + manifestDir: manifestDir, + ); + final crateInfo = CrateInfo.load(manifestDir); + return BuildEnvironment( + configuration: buildConfiguration, + crateOptions: crateOptions, + targetTempDir: Environment.targetTempDir, + manifestDir: manifestDir, + crateInfo: crateInfo, + isAndroid: isAndroid, + androidSdkPath: isAndroid ? Environment.sdkPath : null, + androidNdkVersion: isAndroid ? Environment.ndkVersion : null, + androidMinSdkVersion: + isAndroid ? int.parse(Environment.minSdkVersion) : null, + javaHome: isAndroid ? Environment.javaHome : null, + ); + } +} + +class RustBuilder { + final Target target; + final BuildEnvironment environment; + + RustBuilder({ + required this.target, + required this.environment, + }); + + void prepare( + Rustup rustup, + ) { + final toolchain = _toolchain; + if (rustup.installedTargets(toolchain) == null) { + rustup.installToolchain(toolchain); + } + if (toolchain == 'nightly') { + rustup.installRustSrcForNightly(); + } + if (!rustup.installedTargets(toolchain)!.contains(target.rust)) { + rustup.installTarget(target.rust, toolchain: toolchain); + } + } + + CargoBuildOptions? get _buildOptions => + environment.crateOptions.cargo[environment.configuration]; + + String get _toolchain => _buildOptions?.toolchain.name ?? 'stable'; + + /// Returns the path of directory containing build artifacts. + Future build() async { + final extraArgs = _buildOptions?.flags ?? []; + final manifestPath = path.join(environment.manifestDir, 'Cargo.toml'); + runCommand( + 'rustup', + [ + 'run', + _toolchain, + 'cargo', + 'build', + ...extraArgs, + '--manifest-path', + manifestPath, + '-p', + environment.crateInfo.packageName, + if (!environment.configuration.isDebug) '--release', + '--target', + target.rust, + '--target-dir', + environment.targetTempDir, + ], + environment: await _buildEnvironment(), + ); + return path.join( + environment.targetTempDir, + target.rust, + environment.configuration.rustName, + ); + } + + Future> _buildEnvironment() async { + if (target.android == null) { + return {}; + } else { + final sdkPath = environment.androidSdkPath; + final ndkVersion = environment.androidNdkVersion; + final minSdkVersion = environment.androidMinSdkVersion; + if (sdkPath == null) { + throw BuildException('androidSdkPath is not set'); + } + if (ndkVersion == null) { + throw BuildException('androidNdkVersion is not set'); + } + if (minSdkVersion == null) { + throw BuildException('androidMinSdkVersion is not set'); + } + final env = AndroidEnvironment( + sdkPath: sdkPath, + ndkVersion: ndkVersion, + minSdkVersion: minSdkVersion, + targetTempDir: environment.targetTempDir, + target: target, + ); + if (!env.ndkIsInstalled() && environment.javaHome != null) { + env.installNdk(javaHome: environment.javaHome!); + } + return env.buildEnvironment(); + } + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/cargo.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/cargo.dart new file mode 100644 index 0000000000..0d8958ff2e --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/cargo.dart @@ -0,0 +1,48 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; +import 'package:toml/toml.dart'; + +class ManifestException { + ManifestException(this.message, {required this.fileName}); + + final String? fileName; + final String message; + + @override + String toString() { + if (fileName != null) { + return 'Failed to parse package manifest at $fileName: $message'; + } else { + return 'Failed to parse package manifest: $message'; + } + } +} + +class CrateInfo { + CrateInfo({required this.packageName}); + + final String packageName; + + static CrateInfo parseManifest(String manifest, {final String? fileName}) { + final toml = TomlDocument.parse(manifest); + final package = toml.toMap()['package']; + if (package == null) { + throw ManifestException('Missing package section', fileName: fileName); + } + final name = package['name']; + if (name == null) { + throw ManifestException('Missing package name', fileName: fileName); + } + return CrateInfo(packageName: name); + } + + static CrateInfo load(String manifestDir) { + final manifestFile = File(path.join(manifestDir, 'Cargo.toml')); + final manifest = manifestFile.readAsStringSync(); + return parseManifest(manifest, fileName: manifestFile.path); + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/crate_hash.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/crate_hash.dart new file mode 100644 index 0000000000..0c4d88d16b --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/crate_hash.dart @@ -0,0 +1,124 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:collection/collection.dart'; +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as path; + +class CrateHash { + /// Computes a hash uniquely identifying crate content. This takes into account + /// content all all .rs files inside the src directory, as well as Cargo.toml, + /// Cargo.lock, build.rs and cargokit.yaml. + /// + /// If [tempStorage] is provided, computed hash is stored in a file in that directory + /// and reused on subsequent calls if the crate content hasn't changed. + static String compute(String manifestDir, {String? tempStorage}) { + return CrateHash._( + manifestDir: manifestDir, + tempStorage: tempStorage, + )._compute(); + } + + CrateHash._({ + required this.manifestDir, + required this.tempStorage, + }); + + String _compute() { + final files = getFiles(); + final tempStorage = this.tempStorage; + if (tempStorage != null) { + final quickHash = _computeQuickHash(files); + final quickHashFolder = Directory(path.join(tempStorage, 'crate_hash')); + quickHashFolder.createSync(recursive: true); + final quickHashFile = File(path.join(quickHashFolder.path, quickHash)); + if (quickHashFile.existsSync()) { + return quickHashFile.readAsStringSync(); + } + final hash = _computeHash(files); + quickHashFile.writeAsStringSync(hash); + return hash; + } else { + return _computeHash(files); + } + } + + /// Computes a quick hash based on files stat (without reading contents). This + /// is used to cache the real hash, which is slower to compute since it involves + /// reading every single file. + String _computeQuickHash(List files) { + final output = AccumulatorSink(); + final input = sha256.startChunkedConversion(output); + + final data = ByteData(8); + for (final file in files) { + input.add(utf8.encode(file.path)); + final stat = file.statSync(); + data.setUint64(0, stat.size); + input.add(data.buffer.asUint8List()); + data.setUint64(0, stat.modified.millisecondsSinceEpoch); + input.add(data.buffer.asUint8List()); + } + + input.close(); + return base64Url.encode(output.events.single.bytes); + } + + String _computeHash(List files) { + final output = AccumulatorSink(); + final input = sha256.startChunkedConversion(output); + + void addTextFile(File file) { + // text Files are hashed by lines in case we're dealing with github checkout + // that auto-converts line endings. + final splitter = LineSplitter(); + if (file.existsSync()) { + final data = file.readAsStringSync(); + final lines = splitter.convert(data); + for (final line in lines) { + input.add(utf8.encode(line)); + } + } + } + + for (final file in files) { + addTextFile(file); + } + + input.close(); + final res = output.events.single; + + // Truncate to 128bits. + final hash = res.bytes.sublist(0, 16); + return hex.encode(hash); + } + + List getFiles() { + final src = Directory(path.join(manifestDir, 'src')); + final files = src + .listSync(recursive: true, followLinks: false) + .whereType() + .toList(); + files.sortBy((element) => element.path); + void addFile(String relative) { + final file = File(path.join(manifestDir, relative)); + if (file.existsSync()) { + files.add(file); + } + } + + addFile('Cargo.toml'); + addFile('Cargo.lock'); + addFile('build.rs'); + addFile('cargokit.yaml'); + return files; + } + + final String manifestDir; + final String? tempStorage; +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/environment.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/environment.dart new file mode 100644 index 0000000000..996483a180 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/environment.dart @@ -0,0 +1,68 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +extension on String { + String resolveSymlink() => File(this).resolveSymbolicLinksSync(); +} + +class Environment { + /// Current build configuration (debug or release). + static String get configuration => + _getEnv("CARGOKIT_CONFIGURATION").toLowerCase(); + + static bool get isDebug => configuration == 'debug'; + static bool get isRelease => configuration == 'release'; + + /// Temporary directory where Rust build artifacts are placed. + static String get targetTempDir => _getEnv("CARGOKIT_TARGET_TEMP_DIR"); + + /// Final output directory where the build artifacts are placed. + static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR'); + + /// Path to the crate manifest (containing Cargo.toml). + static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR'); + + /// Directory inside root project. Not necessarily root folder. Symlinks are + /// not resolved on purpose. + static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR'); + + // Pod + + /// Platform name (macosx, iphoneos, iphonesimulator). + static String get darwinPlatformName => + _getEnv("CARGOKIT_DARWIN_PLATFORM_NAME"); + + /// List of architectures to build for (arm64, armv7, x86_64). + static List get darwinArchs => + _getEnv("CARGOKIT_DARWIN_ARCHS").split(' '); + + // Gradle + static String get minSdkVersion => _getEnv("CARGOKIT_MIN_SDK_VERSION"); + static String get ndkVersion => _getEnv("CARGOKIT_NDK_VERSION"); + static String get sdkPath => _getEnvPath("CARGOKIT_SDK_DIR"); + static String get javaHome => _getEnvPath("CARGOKIT_JAVA_HOME"); + static List get targetPlatforms => + _getEnv("CARGOKIT_TARGET_PLATFORMS").split(','); + + // CMAKE + static String get targetPlatform => _getEnv("CARGOKIT_TARGET_PLATFORM"); + + static String _getEnv(String key) { + final res = Platform.environment[key]; + if (res == null) { + throw Exception("Missing environment variable $key"); + } + return res; + } + + static String _getEnvPath(String key) { + final res = _getEnv(key); + if (Directory(res).existsSync()) { + return res.resolveSymlink(); + } else { + return res; + } + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/logging.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/logging.dart new file mode 100644 index 0000000000..5edd4fd184 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/logging.dart @@ -0,0 +1,52 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:logging/logging.dart'; + +const String kSeparator = "--"; +const String kDoubleSeparator = "=="; + +bool _lastMessageWasSeparator = false; + +void _log(LogRecord rec) { + final prefix = '${rec.level.name}: '; + final out = rec.level == Level.SEVERE ? stderr : stdout; + if (rec.message == kSeparator) { + if (!_lastMessageWasSeparator) { + out.write(prefix); + out.writeln('-' * 80); + _lastMessageWasSeparator = true; + } + return; + } else if (rec.message == kDoubleSeparator) { + out.write(prefix); + out.writeln('=' * 80); + _lastMessageWasSeparator = true; + return; + } + out.write(prefix); + out.writeln(rec.message); + _lastMessageWasSeparator = false; +} + +void initLogging() { + Logger.root.level = Level.INFO; + Logger.root.onRecord.listen((LogRecord rec) { + final lines = rec.message.split('\n'); + for (final line in lines) { + if (line.isNotEmpty || lines.length == 1 || line != lines.last) { + _log(LogRecord( + rec.level, + line, + rec.loggerName, + )); + } + } + }); +} + +void enableVerboseLogging() { + Logger.root.level = Level.ALL; +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/options.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/options.dart new file mode 100644 index 0000000000..22aef1d371 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/options.dart @@ -0,0 +1,309 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:hex/hex.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; +import 'package:source_span/source_span.dart'; +import 'package:yaml/yaml.dart'; + +import 'builder.dart'; +import 'environment.dart'; +import 'rustup.dart'; + +final _log = Logger('options'); + +/// A class for exceptions that have source span information attached. +class SourceSpanException implements Exception { + // This is a getter so that subclasses can override it. + /// A message describing the exception. + String get message => _message; + final String _message; + + // This is a getter so that subclasses can override it. + /// The span associated with this exception. + /// + /// This may be `null` if the source location can't be determined. + SourceSpan? get span => _span; + final SourceSpan? _span; + + SourceSpanException(this._message, this._span); + + /// Returns a string representation of `this`. + /// + /// [color] may either be a [String], a [bool], or `null`. If it's a string, + /// it indicates an ANSI terminal color escape that should be used to + /// highlight the span's text. If it's `true`, it indicates that the text + /// should be highlighted using the default color. If it's `false` or `null`, + /// it indicates that the text shouldn't be highlighted. + @override + String toString({Object? color}) { + if (span == null) return message; + return 'Error on ${span!.message(message, color: color)}'; + } +} + +enum Toolchain { + stable, + beta, + nightly, +} + +class CargoBuildOptions { + final Toolchain toolchain; + final List flags; + + CargoBuildOptions({ + required this.toolchain, + required this.flags, + }); + + static Toolchain _toolchainFromNode(YamlNode node) { + if (node case YamlScalar(value: String name)) { + final toolchain = + Toolchain.values.firstWhereOrNull((element) => element.name == name); + if (toolchain != null) { + return toolchain; + } + } + throw SourceSpanException( + 'Unknown toolchain. Must be one of ${Toolchain.values.map((e) => e.name)}.', + node.span); + } + + static CargoBuildOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargo options must be a map', node.span); + } + Toolchain toolchain = Toolchain.stable; + List flags = []; + for (final MapEntry(:key, :value) in node.nodes.entries) { + if (key case YamlScalar(value: 'toolchain')) { + toolchain = _toolchainFromNode(value); + } else if (key case YamlScalar(value: 'extra_flags')) { + if (value case YamlList(nodes: List list)) { + if (list.every((element) { + if (element case YamlScalar(value: String _)) { + return true; + } + return false; + })) { + flags = list.map((e) => e.value as String).toList(); + continue; + } + } + throw SourceSpanException( + 'Extra flags must be a list of strings', value.span); + } else { + throw SourceSpanException( + 'Unknown cargo option type. Must be "toolchain" or "extra_flags".', + key.span); + } + } + return CargoBuildOptions(toolchain: toolchain, flags: flags); + } +} + +extension on YamlMap { + /// Map that extracts keys so that we can do map case check on them. + Map get valueMap => + nodes.map((key, value) => MapEntry(key.value, value)); +} + +class PrecompiledBinaries { + final String uriPrefix; + final PublicKey publicKey; + + PrecompiledBinaries({ + required this.uriPrefix, + required this.publicKey, + }); + + static PublicKey _publicKeyFromHex(String key, SourceSpan? span) { + final bytes = HEX.decode(key); + if (bytes.length != 32) { + throw SourceSpanException( + 'Invalid public key. Must be 32 bytes long.', span); + } + return PublicKey(bytes); + } + + static PrecompiledBinaries parse(YamlNode node) { + if (node case YamlMap(valueMap: Map map)) { + if (map + case { + 'url_prefix': YamlNode urlPrefixNode, + 'public_key': YamlNode publicKeyNode, + }) { + final urlPrefix = switch (urlPrefixNode) { + YamlScalar(value: String urlPrefix) => urlPrefix, + _ => throw SourceSpanException( + 'Invalid URL prefix value.', urlPrefixNode.span), + }; + final publicKey = switch (publicKeyNode) { + YamlScalar(value: String publicKey) => + _publicKeyFromHex(publicKey, publicKeyNode.span), + _ => throw SourceSpanException( + 'Invalid public key value.', publicKeyNode.span), + }; + return PrecompiledBinaries( + uriPrefix: urlPrefix, + publicKey: publicKey, + ); + } + } + throw SourceSpanException( + 'Invalid precompiled binaries value. ' + 'Expected Map with "url_prefix" and "public_key".', + node.span); + } +} + +/// Cargokit options specified for Rust crate. +class CargokitCrateOptions { + CargokitCrateOptions({ + this.cargo = const {}, + this.precompiledBinaries, + }); + + final Map cargo; + final PrecompiledBinaries? precompiledBinaries; + + static CargokitCrateOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargokit options must be a map', node.span); + } + final options = {}; + PrecompiledBinaries? precompiledBinaries; + + for (final entry in node.nodes.entries) { + if (entry + case MapEntry( + key: YamlScalar(value: 'cargo'), + value: YamlNode node, + )) { + if (node is! YamlMap) { + throw SourceSpanException('Cargo options must be a map', node.span); + } + for (final MapEntry(:YamlNode key, :value) in node.nodes.entries) { + if (key case YamlScalar(value: String name)) { + final configuration = BuildConfiguration.values + .firstWhereOrNull((element) => element.name == name); + if (configuration != null) { + options[configuration] = CargoBuildOptions.parse(value); + continue; + } + } + throw SourceSpanException( + 'Unknown build configuration. Must be one of ${BuildConfiguration.values.map((e) => e.name)}.', + key.span); + } + } else if (entry.key case YamlScalar(value: 'precompiled_binaries')) { + precompiledBinaries = PrecompiledBinaries.parse(entry.value); + } else { + throw SourceSpanException( + 'Unknown cargokit option type. Must be "cargo" or "precompiled_binaries".', + entry.key.span); + } + } + return CargokitCrateOptions( + cargo: options, + precompiledBinaries: precompiledBinaries, + ); + } + + static CargokitCrateOptions load({ + required String manifestDir, + }) { + final uri = Uri.file(path.join(manifestDir, "cargokit.yaml")); + final file = File.fromUri(uri); + if (file.existsSync()) { + final contents = loadYamlNode(file.readAsStringSync(), sourceUrl: uri); + return parse(contents); + } else { + return CargokitCrateOptions(); + } + } +} + +class CargokitUserOptions { + // When Rustup is installed always build locally unless user opts into + // using precompiled binaries. + static bool defaultUsePrecompiledBinaries() { + return Rustup.executablePath() == null; + } + + CargokitUserOptions({ + required this.usePrecompiledBinaries, + required this.verboseLogging, + }); + + CargokitUserOptions._() + : usePrecompiledBinaries = defaultUsePrecompiledBinaries(), + verboseLogging = false; + + static CargokitUserOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargokit options must be a map', node.span); + } + bool usePrecompiledBinaries = defaultUsePrecompiledBinaries(); + bool verboseLogging = false; + + for (final entry in node.nodes.entries) { + if (entry.key case YamlScalar(value: 'use_precompiled_binaries')) { + if (entry.value case YamlScalar(value: bool value)) { + usePrecompiledBinaries = value; + continue; + } + throw SourceSpanException( + 'Invalid value for "use_precompiled_binaries". Must be a boolean.', + entry.value.span); + } else if (entry.key case YamlScalar(value: 'verbose_logging')) { + if (entry.value case YamlScalar(value: bool value)) { + verboseLogging = value; + continue; + } + throw SourceSpanException( + 'Invalid value for "verbose_logging". Must be a boolean.', + entry.value.span); + } else { + throw SourceSpanException( + 'Unknown cargokit option type. Must be "use_precompiled_binaries" or "verbose_logging".', + entry.key.span); + } + } + return CargokitUserOptions( + usePrecompiledBinaries: usePrecompiledBinaries, + verboseLogging: verboseLogging, + ); + } + + static CargokitUserOptions load() { + String fileName = "cargokit_options.yaml"; + var userProjectDir = Directory(Environment.rootProjectDir); + + while (userProjectDir.parent.path != userProjectDir.path) { + final configFile = File(path.join(userProjectDir.path, fileName)); + if (configFile.existsSync()) { + final contents = loadYamlNode( + configFile.readAsStringSync(), + sourceUrl: configFile.uri, + ); + final res = parse(contents); + if (res.verboseLogging) { + _log.info('Found user options file at ${configFile.path}'); + } + return res; + } + userProjectDir = userProjectDir.parent; + } + return CargokitUserOptions._(); + } + + final bool usePrecompiledBinaries; + final bool verboseLogging; +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart new file mode 100644 index 0000000000..c27f4195dd --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart @@ -0,0 +1,202 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:github/github.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'cargo.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'rustup.dart'; +import 'target.dart'; + +final _log = Logger('precompile_binaries'); + +class PrecompileBinaries { + PrecompileBinaries({ + required this.privateKey, + required this.githubToken, + required this.repositorySlug, + required this.manifestDir, + required this.targets, + this.androidSdkLocation, + this.androidNdkVersion, + this.androidMinSdkVersion, + this.tempDir, + }); + + final PrivateKey privateKey; + final String githubToken; + final RepositorySlug repositorySlug; + final String manifestDir; + final List targets; + final String? androidSdkLocation; + final String? androidNdkVersion; + final int? androidMinSdkVersion; + final String? tempDir; + + static String fileName(Target target, String name) { + return '${target.rust}_$name'; + } + + static String signatureFileName(Target target, String name) { + return '${target.rust}_$name.sig'; + } + + Future run() async { + final crateInfo = CrateInfo.load(manifestDir); + + final targets = List.of(this.targets); + if (targets.isEmpty) { + targets.addAll([ + ...Target.buildableTargets(), + if (androidSdkLocation != null) ...Target.androidTargets(), + ]); + } + + _log.info('Precompiling binaries for $targets'); + + final hash = CrateHash.compute(manifestDir); + _log.info('Computed crate hash: $hash'); + + final String tagName = 'precompiled_$hash'; + + final github = GitHub(auth: Authentication.withToken(githubToken)); + final repo = github.repositories; + final release = await _getOrCreateRelease( + repo: repo, + tagName: tagName, + packageName: crateInfo.packageName, + hash: hash, + ); + + final tempDir = this.tempDir != null + ? Directory(this.tempDir!) + : Directory.systemTemp.createTempSync('precompiled_'); + + tempDir.createSync(recursive: true); + + final crateOptions = CargokitCrateOptions.load( + manifestDir: manifestDir, + ); + + final buildEnvironment = BuildEnvironment( + configuration: BuildConfiguration.release, + crateOptions: crateOptions, + targetTempDir: tempDir.path, + manifestDir: manifestDir, + crateInfo: crateInfo, + isAndroid: androidSdkLocation != null, + androidSdkPath: androidSdkLocation, + androidNdkVersion: androidNdkVersion, + androidMinSdkVersion: androidMinSdkVersion, + ); + + final rustup = Rustup(); + + for (final target in targets) { + final artifactNames = getArtifactNames( + target: target, + libraryName: crateInfo.packageName, + remote: true, + ); + + if (artifactNames.every((name) { + final fileName = PrecompileBinaries.fileName(target, name); + return (release.assets ?? []).any((e) => e.name == fileName); + })) { + _log.info("All artifacts for $target already exist - skipping"); + continue; + } + + _log.info('Building for $target'); + + final builder = + RustBuilder(target: target, environment: buildEnvironment); + builder.prepare(rustup); + final res = await builder.build(); + + final assets = []; + for (final name in artifactNames) { + final file = File(path.join(res, name)); + if (!file.existsSync()) { + throw Exception('Missing artifact: ${file.path}'); + } + + final data = file.readAsBytesSync(); + final create = CreateReleaseAsset( + name: PrecompileBinaries.fileName(target, name), + contentType: "application/octet-stream", + assetData: data, + ); + final signature = sign(privateKey, data); + final signatureCreate = CreateReleaseAsset( + name: signatureFileName(target, name), + contentType: "application/octet-stream", + assetData: signature, + ); + bool verified = verify(public(privateKey), data, signature); + if (!verified) { + throw Exception('Signature verification failed'); + } + assets.add(create); + assets.add(signatureCreate); + } + _log.info('Uploading assets: ${assets.map((e) => e.name)}'); + for (final asset in assets) { + // This seems to be failing on CI so do it one by one + int retryCount = 0; + while (true) { + try { + await repo.uploadReleaseAssets(release, [asset]); + break; + } on Exception catch (e) { + if (retryCount == 10) { + rethrow; + } + ++retryCount; + _log.shout( + 'Upload failed (attempt $retryCount, will retry): ${e.toString()}'); + await Future.delayed(Duration(seconds: 2)); + } + } + } + } + + _log.info('Cleaning up'); + tempDir.deleteSync(recursive: true); + } + + Future _getOrCreateRelease({ + required RepositoriesService repo, + required String tagName, + required String packageName, + required String hash, + }) async { + Release release; + try { + _log.info('Fetching release $tagName'); + release = await repo.getReleaseByTagName(repositorySlug, tagName); + } on ReleaseNotFound { + _log.info('Release not found - creating release $tagName'); + release = await repo.createRelease( + repositorySlug, + CreateRelease.from( + tagName: tagName, + name: 'Precompiled binaries ${hash.substring(0, 8)}', + targetCommitish: null, + isDraft: false, + isPrerelease: false, + body: 'Precompiled binaries for crate $packageName, ' + 'crate hash $hash.', + )); + } + return release; + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/rustup.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/rustup.dart new file mode 100644 index 0000000000..0ac8d08616 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/rustup.dart @@ -0,0 +1,136 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:path/path.dart' as path; + +import 'util.dart'; + +class _Toolchain { + _Toolchain( + this.name, + this.targets, + ); + + final String name; + final List targets; +} + +class Rustup { + List? installedTargets(String toolchain) { + final targets = _installedTargets(toolchain); + return targets != null ? List.unmodifiable(targets) : null; + } + + void installToolchain(String toolchain) { + log.info("Installing Rust toolchain: $toolchain"); + runCommand("rustup", ['toolchain', 'install', toolchain]); + _installedToolchains + .add(_Toolchain(toolchain, _getInstalledTargets(toolchain))); + } + + void installTarget( + String target, { + required String toolchain, + }) { + log.info("Installing Rust target: $target"); + runCommand("rustup", [ + 'target', + 'add', + '--toolchain', + toolchain, + target, + ]); + _installedTargets(toolchain)?.add(target); + } + + final List<_Toolchain> _installedToolchains; + + Rustup() : _installedToolchains = _getInstalledToolchains(); + + List? _installedTargets(String toolchain) => _installedToolchains + .firstWhereOrNull( + (e) => e.name == toolchain || e.name.startsWith('$toolchain-')) + ?.targets; + + static List<_Toolchain> _getInstalledToolchains() { + String extractToolchainName(String line) { + // ignore (default) after toolchain name + final parts = line.split(' '); + return parts[0]; + } + + final res = runCommand("rustup", ['toolchain', 'list']); + + // To list all non-custom toolchains, we need to filter out lines that + // don't start with "stable", "beta", or "nightly". + Pattern nonCustom = RegExp(r"^(stable|beta|nightly)"); + final lines = res.stdout + .toString() + .split('\n') + .where((e) => e.isNotEmpty && e.startsWith(nonCustom)) + .map(extractToolchainName) + .toList(growable: true); + + return lines + .map( + (name) => _Toolchain( + name, + _getInstalledTargets(name), + ), + ) + .toList(growable: true); + } + + static List _getInstalledTargets(String toolchain) { + final res = runCommand("rustup", [ + 'target', + 'list', + '--toolchain', + toolchain, + '--installed', + ]); + final lines = res.stdout + .toString() + .split('\n') + .where((e) => e.isNotEmpty) + .toList(growable: true); + return lines; + } + + bool _didInstallRustSrcForNightly = false; + + void installRustSrcForNightly() { + if (_didInstallRustSrcForNightly) { + return; + } + // Useful for -Z build-std + runCommand( + "rustup", + ['component', 'add', 'rust-src', '--toolchain', 'nightly'], + ); + _didInstallRustSrcForNightly = true; + } + + static String? executablePath() { + final envPath = Platform.environment['PATH']; + final envPathSeparator = Platform.isWindows ? ';' : ':'; + final home = Platform.isWindows + ? Platform.environment['USERPROFILE'] + : Platform.environment['HOME']; + final paths = [ + if (home != null) path.join(home, '.cargo', 'bin'), + if (envPath != null) ...envPath.split(envPathSeparator), + ]; + for (final p in paths) { + final rustup = Platform.isWindows ? 'rustup.exe' : 'rustup'; + final rustupPath = path.join(p, rustup); + if (File(rustupPath).existsSync()) { + return rustupPath; + } + } + return null; + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/target.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/target.dart new file mode 100644 index 0000000000..6fbc58b64f --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/target.dart @@ -0,0 +1,140 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; + +import 'util.dart'; + +class Target { + Target({ + required this.rust, + this.flutter, + this.android, + this.androidMinSdkVersion, + this.darwinPlatform, + this.darwinArch, + }); + + static final all = [ + Target( + rust: 'armv7-linux-androideabi', + flutter: 'android-arm', + android: 'armeabi-v7a', + androidMinSdkVersion: 16, + ), + Target( + rust: 'aarch64-linux-android', + flutter: 'android-arm64', + android: 'arm64-v8a', + androidMinSdkVersion: 21, + ), + Target( + rust: 'i686-linux-android', + flutter: 'android-x86', + android: 'x86', + androidMinSdkVersion: 16, + ), + Target( + rust: 'x86_64-linux-android', + flutter: 'android-x64', + android: 'x86_64', + androidMinSdkVersion: 21, + ), + Target( + rust: 'x86_64-pc-windows-msvc', + flutter: 'windows-x64', + ), + Target( + rust: 'x86_64-unknown-linux-gnu', + flutter: 'linux-x64', + ), + Target( + rust: 'aarch64-unknown-linux-gnu', + flutter: 'linux-arm64', + ), + Target( + rust: 'x86_64-apple-darwin', + darwinPlatform: 'macosx', + darwinArch: 'x86_64', + ), + Target( + rust: 'aarch64-apple-darwin', + darwinPlatform: 'macosx', + darwinArch: 'arm64', + ), + Target( + rust: 'aarch64-apple-ios', + darwinPlatform: 'iphoneos', + darwinArch: 'arm64', + ), + Target( + rust: 'aarch64-apple-ios-sim', + darwinPlatform: 'iphonesimulator', + darwinArch: 'arm64', + ), + Target( + rust: 'x86_64-apple-ios', + darwinPlatform: 'iphonesimulator', + darwinArch: 'x86_64', + ), + ]; + + static Target? forFlutterName(String flutterName) { + return all.firstWhereOrNull((element) => element.flutter == flutterName); + } + + static Target? forDarwin({ + required String platformName, + required String darwinAarch, + }) { + return all.firstWhereOrNull((element) => // + element.darwinPlatform == platformName && + element.darwinArch == darwinAarch); + } + + static Target? forRustTriple(String triple) { + return all.firstWhereOrNull((element) => element.rust == triple); + } + + static List androidTargets() { + return all + .where((element) => element.android != null) + .toList(growable: false); + } + + /// Returns buildable targets on current host platform ignoring Android targets. + static List buildableTargets() { + if (Platform.isLinux) { + // Right now we don't support cross-compiling on Linux. So we just return + // the host target. + final arch = runCommand('arch', []).stdout as String; + if (arch.trim() == 'aarch64') { + return [Target.forRustTriple('aarch64-unknown-linux-gnu')!]; + } else { + return [Target.forRustTriple('x86_64-unknown-linux-gnu')!]; + } + } + return all.where((target) { + if (Platform.isWindows) { + return target.rust.contains('-windows-'); + } else if (Platform.isMacOS) { + return target.darwinPlatform != null; + } + return false; + }).toList(growable: false); + } + + @override + String toString() { + return rust; + } + + final String? flutter; + final String rust; + final String? android; + final int? androidMinSdkVersion; + final String? darwinPlatform; + final String? darwinArch; +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/util.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/util.dart new file mode 100644 index 0000000000..8bb6a8724f --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/util.dart @@ -0,0 +1,172 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:convert'; +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'logging.dart'; +import 'rustup.dart'; + +final log = Logger("process"); + +class CommandFailedException implements Exception { + final String executable; + final List arguments; + final ProcessResult result; + + CommandFailedException({ + required this.executable, + required this.arguments, + required this.result, + }); + + @override + String toString() { + final stdout = result.stdout.toString().trim(); + final stderr = result.stderr.toString().trim(); + return [ + "External Command: $executable ${arguments.map((e) => '"$e"').join(' ')}", + "Returned Exit Code: ${result.exitCode}", + kSeparator, + "STDOUT:", + if (stdout.isNotEmpty) stdout, + kSeparator, + "STDERR:", + if (stderr.isNotEmpty) stderr, + ].join('\n'); + } +} + +class TestRunCommandArgs { + final String executable; + final List arguments; + final String? workingDirectory; + final Map? environment; + final bool includeParentEnvironment; + final bool runInShell; + final Encoding? stdoutEncoding; + final Encoding? stderrEncoding; + + TestRunCommandArgs({ + required this.executable, + required this.arguments, + this.workingDirectory, + this.environment, + this.includeParentEnvironment = true, + this.runInShell = false, + this.stdoutEncoding, + this.stderrEncoding, + }); +} + +class TestRunCommandResult { + TestRunCommandResult({ + this.pid = 1, + this.exitCode = 0, + this.stdout = '', + this.stderr = '', + }); + + final int pid; + final int exitCode; + final String stdout; + final String stderr; +} + +TestRunCommandResult Function(TestRunCommandArgs args)? testRunCommandOverride; + +ProcessResult runCommand( + String executable, + List arguments, { + String? workingDirectory, + Map? environment, + bool includeParentEnvironment = true, + bool runInShell = false, + Encoding? stdoutEncoding = systemEncoding, + Encoding? stderrEncoding = systemEncoding, +}) { + if (testRunCommandOverride != null) { + final result = testRunCommandOverride!(TestRunCommandArgs( + executable: executable, + arguments: arguments, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding, + )); + return ProcessResult( + result.pid, + result.exitCode, + result.stdout, + result.stderr, + ); + } + log.finer('Running command $executable ${arguments.join(' ')}'); + final res = Process.runSync( + _resolveExecutable(executable), + arguments, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stderrEncoding: stderrEncoding, + stdoutEncoding: stdoutEncoding, + ); + if (res.exitCode != 0) { + throw CommandFailedException( + executable: executable, + arguments: arguments, + result: res, + ); + } else { + return res; + } +} + +class RustupNotFoundException implements Exception { + @override + String toString() { + return [ + ' ', + 'rustup not found in PATH.', + ' ', + 'Maybe you need to install Rust? It only takes a minute:', + ' ', + if (Platform.isWindows) 'https://www.rust-lang.org/tools/install', + if (hasHomebrewRustInPath()) ...[ + '\$ brew unlink rust # Unlink homebrew Rust from PATH', + ], + if (!Platform.isWindows) + "\$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh", + ' ', + ].join('\n'); + } + + static bool hasHomebrewRustInPath() { + if (!Platform.isMacOS) { + return false; + } + final envPath = Platform.environment['PATH'] ?? ''; + final paths = envPath.split(':'); + return paths.any((p) { + return p.contains('homebrew') && File(path.join(p, 'rustc')).existsSync(); + }); + } +} + +String _resolveExecutable(String executable) { + if (executable == 'rustup') { + final resolved = Rustup.executablePath(); + if (resolved != null) { + return resolved; + } + throw RustupNotFoundException(); + } else { + return executable; + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart new file mode 100644 index 0000000000..2366b57bfd --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart @@ -0,0 +1,84 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:http/http.dart'; + +import 'artifacts_provider.dart'; +import 'cargo.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'target.dart'; + +class VerifyBinaries { + VerifyBinaries({ + required this.manifestDir, + }); + + final String manifestDir; + + Future run() async { + final crateInfo = CrateInfo.load(manifestDir); + + final config = CargokitCrateOptions.load(manifestDir: manifestDir); + final precompiledBinaries = config.precompiledBinaries; + if (precompiledBinaries == null) { + stdout.writeln('Crate does not support precompiled binaries.'); + } else { + final crateHash = CrateHash.compute(manifestDir); + stdout.writeln('Crate hash: $crateHash'); + + for (final target in Target.all) { + final message = 'Checking ${target.rust}...'; + stdout.write(message.padRight(40)); + stdout.flush(); + + final artifacts = getArtifactNames( + target: target, + libraryName: crateInfo.packageName, + remote: true, + ); + + final prefix = precompiledBinaries.uriPrefix; + + bool ok = true; + + for (final artifact in artifacts) { + final fileName = PrecompileBinaries.fileName(target, artifact); + final signatureFileName = + PrecompileBinaries.signatureFileName(target, artifact); + + final url = Uri.parse('$prefix$crateHash/$fileName'); + final signatureUrl = + Uri.parse('$prefix$crateHash/$signatureFileName'); + + final signature = await get(signatureUrl); + if (signature.statusCode != 200) { + stdout.writeln('MISSING'); + ok = false; + break; + } + final asset = await get(url); + if (asset.statusCode != 200) { + stdout.writeln('MISSING'); + ok = false; + break; + } + + if (!verify(precompiledBinaries.publicKey, asset.bodyBytes, + signature.bodyBytes)) { + stdout.writeln('INVALID SIGNATURE'); + ok = false; + } + } + + if (ok) { + stdout.writeln('OK'); + } + } + } + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/pubspec.lock b/mobile/apps/photos/rust_builder/cargokit/build_tool/pubspec.lock new file mode 100644 index 0000000000..343bdd3694 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/pubspec.lock @@ -0,0 +1,453 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" + source: hosted + version: "64.0.0" + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + args: + dependency: "direct main" + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + collection: + dependency: "direct main" + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: "direct main" + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" + source: hosted + version: "1.6.3" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + ed25519_edwards: + dependency: "direct main" + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + github: + dependency: "direct main" + description: + name: github + sha256: "9966bc13bf612342e916b0a343e95e5f046c88f602a14476440e9b75d2295411" + url: "https://pub.dev" + source: hosted + version: "9.17.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + hex: + dependency: "direct main" + description: + name: hex + sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + http: + dependency: "direct main" + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: "direct main" + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "2ad4cddff7f5cc0e2d13069f2a3f7a73ca18f66abd6f5ecf215219cdb3638edb" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: "direct main" + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "9b0dd8e36af4a5b1569029949d50a52cb2a2a2fdaa20cebb96e6603b9ae241f9" + url: "https://pub.dev" + source: hosted + version: "1.24.6" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + test_core: + dependency: transitive + description: + name: test_core + sha256: "4bef837e56375537055fdbbbf6dd458b1859881f4c7e6da936158f77d61ab265" + url: "https://pub.dev" + source: hosted + version: "0.5.6" + toml: + dependency: "direct main" + description: + name: toml + sha256: "157c5dca5160fced243f3ce984117f729c788bb5e475504f3dbcda881accee44" + url: "https://pub.dev" + source: hosted + version: "0.14.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + version: + dependency: "direct main" + description: + name: version + sha256: "2307e23a45b43f96469eeab946208ed63293e8afca9c28cd8b5241ff31c55f55" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0fae432c85c4ea880b33b497d32824b97795b04cdaa74d270219572a1f50268d" + url: "https://pub.dev" + source: hosted + version: "11.9.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + yaml: + dependency: "direct main" + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.0.0 <4.0.0" diff --git a/mobile/apps/photos/rust_builder/cargokit/build_tool/pubspec.yaml b/mobile/apps/photos/rust_builder/cargokit/build_tool/pubspec.yaml new file mode 100644 index 0000000000..18c61e3386 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/build_tool/pubspec.yaml @@ -0,0 +1,33 @@ +# This is copied from Cargokit (which is the official way to use it currently) +# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +name: build_tool +description: Cargokit build_tool. Facilitates the build of Rust crate during Flutter application build. +publish_to: none +version: 1.0.0 + +environment: + sdk: ">=3.0.0 <4.0.0" + +# Add regular dependencies here. +dependencies: + # these are pinned on purpose because the bundle_tool_runner doesn't have + # pubspec.lock. See run_build_tool.sh + logging: 1.2.0 + path: 1.8.0 + version: 3.0.0 + collection: 1.18.0 + ed25519_edwards: 0.3.1 + hex: 0.2.0 + yaml: 3.1.2 + source_span: 1.10.0 + github: 9.17.0 + args: 2.4.2 + crypto: 3.0.3 + convert: 3.1.1 + http: 1.1.0 + toml: 0.14.0 + +dev_dependencies: + lints: ^2.1.0 + test: ^1.24.0 diff --git a/mobile/apps/photos/rust_builder/cargokit/cmake/cargokit.cmake b/mobile/apps/photos/rust_builder/cargokit/cmake/cargokit.cmake new file mode 100644 index 0000000000..ddd05df9b4 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/cmake/cargokit.cmake @@ -0,0 +1,99 @@ +SET(cargokit_cmake_root "${CMAKE_CURRENT_LIST_DIR}/..") + +# Workaround for https://github.com/dart-lang/pub/issues/4010 +get_filename_component(cargokit_cmake_root "${cargokit_cmake_root}" REALPATH) + +if(WIN32) + # REALPATH does not properly resolve symlinks on windows :-/ + execute_process(COMMAND powershell -ExecutionPolicy Bypass -File "${CMAKE_CURRENT_LIST_DIR}/resolve_symlinks.ps1" "${cargokit_cmake_root}" OUTPUT_VARIABLE cargokit_cmake_root OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Arguments +# - target: CMAKE target to which rust library is linked +# - manifest_dir: relative path from current folder to directory containing cargo manifest +# - lib_name: cargo package name +# - any_symbol_name: name of any exported symbol from the library. +# used on windows to force linking with library. +function(apply_cargokit target manifest_dir lib_name any_symbol_name) + + set(CARGOKIT_LIB_NAME "${lib_name}") + set(CARGOKIT_LIB_FULL_NAME "${CMAKE_SHARED_MODULE_PREFIX}${CARGOKIT_LIB_NAME}${CMAKE_SHARED_MODULE_SUFFIX}") + if (CMAKE_CONFIGURATION_TYPES) + set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/$") + set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/$/${CARGOKIT_LIB_FULL_NAME}") + else() + set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/${CARGOKIT_LIB_FULL_NAME}") + endif() + set(CARGOKIT_TEMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/cargokit_build") + + if (FLUTTER_TARGET_PLATFORM) + set(CARGOKIT_TARGET_PLATFORM "${FLUTTER_TARGET_PLATFORM}") + else() + set(CARGOKIT_TARGET_PLATFORM "windows-x64") + endif() + + set(CARGOKIT_ENV + "CARGOKIT_CMAKE=${CMAKE_COMMAND}" + "CARGOKIT_CONFIGURATION=$" + "CARGOKIT_MANIFEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${manifest_dir}" + "CARGOKIT_TARGET_TEMP_DIR=${CARGOKIT_TEMP_DIR}" + "CARGOKIT_OUTPUT_DIR=${CARGOKIT_OUTPUT_DIR}" + "CARGOKIT_TARGET_PLATFORM=${CARGOKIT_TARGET_PLATFORM}" + "CARGOKIT_TOOL_TEMP_DIR=${CARGOKIT_TEMP_DIR}/tool" + "CARGOKIT_ROOT_PROJECT_DIR=${CMAKE_SOURCE_DIR}" + ) + + if (WIN32) + set(SCRIPT_EXTENSION ".cmd") + set(IMPORT_LIB_EXTENSION ".lib") + else() + set(SCRIPT_EXTENSION ".sh") + set(IMPORT_LIB_EXTENSION "") + execute_process(COMMAND chmod +x "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}") + endif() + + # Using generators in custom command is only supported in CMake 3.20+ + if (CMAKE_CONFIGURATION_TYPES AND ${CMAKE_VERSION} VERSION_LESS "3.20.0") + foreach(CONFIG IN LISTS CMAKE_CONFIGURATION_TYPES) + add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/${CARGOKIT_LIB_FULL_NAME}" + "${CMAKE_CURRENT_BINARY_DIR}/_phony_" + COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} + "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake + VERBATIM + ) + endforeach() + else() + add_custom_command( + OUTPUT + ${OUTPUT_LIB} + "${CMAKE_CURRENT_BINARY_DIR}/_phony_" + COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} + "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake + VERBATIM + ) + endif() + + + set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/_phony_" PROPERTIES SYMBOLIC TRUE) + + if (TARGET ${target}) + # If we have actual cmake target provided create target and make existing + # target depend on it + add_custom_target("${target}_cargokit" DEPENDS ${OUTPUT_LIB}) + add_dependencies("${target}" "${target}_cargokit") + target_link_libraries("${target}" PRIVATE "${OUTPUT_LIB}${IMPORT_LIB_EXTENSION}") + if(WIN32) + target_link_options(${target} PRIVATE "/INCLUDE:${any_symbol_name}") + endif() + else() + # Otherwise (FFI) just use ALL to force building always + add_custom_target("${target}_cargokit" ALL DEPENDS ${OUTPUT_LIB}) + endif() + + # Allow adding the output library to plugin bundled libraries + set("${target}_cargokit_lib" ${OUTPUT_LIB} PARENT_SCOPE) + +endfunction() diff --git a/mobile/apps/photos/rust_builder/cargokit/cmake/resolve_symlinks.ps1 b/mobile/apps/photos/rust_builder/cargokit/cmake/resolve_symlinks.ps1 new file mode 100644 index 0000000000..3d10d283c2 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/cmake/resolve_symlinks.ps1 @@ -0,0 +1,27 @@ +function Resolve-Symlinks { + [CmdletBinding()] + [OutputType([string])] + param( + [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [string] $Path + ) + + [string] $separator = '/' + [string[]] $parts = $Path.Split($separator) + + [string] $realPath = '' + foreach ($part in $parts) { + if ($realPath -and !$realPath.EndsWith($separator)) { + $realPath += $separator + } + $realPath += $part + $item = Get-Item $realPath + if ($item.Target) { + $realPath = $item.Target.Replace('\', '/') + } + } + $realPath +} + +$path=Resolve-Symlinks -Path $args[0] +Write-Host $path diff --git a/mobile/apps/photos/rust_builder/cargokit/gradle/plugin.gradle b/mobile/apps/photos/rust_builder/cargokit/gradle/plugin.gradle new file mode 100644 index 0000000000..d139d04f66 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/gradle/plugin.gradle @@ -0,0 +1,179 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import java.nio.file.Paths +import org.apache.tools.ant.taskdefs.condition.Os + +CargoKitPlugin.file = buildscript.sourceFile + +apply plugin: CargoKitPlugin + +class CargoKitExtension { + String manifestDir; // Relative path to folder containing Cargo.toml + String libname; // Library name within Cargo.toml. Must be a cdylib +} + +abstract class CargoKitBuildTask extends DefaultTask { + + @Input + String buildMode + + @Input + String buildDir + + @Input + String outputDir + + @Input + String ndkVersion + + @Input + String sdkDirectory + + @Input + int compileSdkVersion; + + @Input + int minSdkVersion; + + @Input + String pluginFile + + @Input + List targetPlatforms + + @TaskAction + def build() { + if (project.cargokit.manifestDir == null) { + throw new GradleException("Property 'manifestDir' must be set on cargokit extension"); + } + + if (project.cargokit.libname == null) { + throw new GradleException("Property 'libname' must be set on cargokit extension"); + } + + def executableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "run_build_tool.cmd" : "run_build_tool.sh" + def path = Paths.get(new File(pluginFile).parent, "..", executableName); + + def manifestDir = Paths.get(project.buildscript.sourceFile.parent, project.cargokit.manifestDir) + + def rootProjectDir = project.rootProject.projectDir + + if (!Os.isFamily(Os.FAMILY_WINDOWS)) { + project.exec { + commandLine 'chmod', '+x', path + } + } + + project.exec { + executable path + args "build-gradle" + environment "CARGOKIT_ROOT_PROJECT_DIR", rootProjectDir + environment "CARGOKIT_TOOL_TEMP_DIR", "${buildDir}/build_tool" + environment "CARGOKIT_MANIFEST_DIR", manifestDir + environment "CARGOKIT_CONFIGURATION", buildMode + environment "CARGOKIT_TARGET_TEMP_DIR", buildDir + environment "CARGOKIT_OUTPUT_DIR", outputDir + environment "CARGOKIT_NDK_VERSION", ndkVersion + environment "CARGOKIT_SDK_DIR", sdkDirectory + environment "CARGOKIT_COMPILE_SDK_VERSION", compileSdkVersion + environment "CARGOKIT_MIN_SDK_VERSION", minSdkVersion + environment "CARGOKIT_TARGET_PLATFORMS", targetPlatforms.join(",") + environment "CARGOKIT_JAVA_HOME", System.properties['java.home'] + } + } +} + +class CargoKitPlugin implements Plugin { + + static String file; + + private Plugin findFlutterPlugin(Project rootProject) { + _findFlutterPlugin(rootProject.childProjects) + } + + private Plugin _findFlutterPlugin(Map projects) { + for (project in projects) { + for (plugin in project.value.getPlugins()) { + if (plugin.class.name == "com.flutter.gradle.FlutterPlugin") { + return plugin; + } + } + def plugin = _findFlutterPlugin(project.value.childProjects); + if (plugin != null) { + return plugin; + } + } + return null; + } + + @Override + void apply(Project project) { + def plugin = findFlutterPlugin(project.rootProject); + + project.extensions.create("cargokit", CargoKitExtension) + + if (plugin == null) { + print("Flutter plugin not found, CargoKit plugin will not be applied.") + return; + } + + def cargoBuildDir = "${project.buildDir}/build" + + // Determine if the project is an application or library + def isApplication = plugin.project.plugins.hasPlugin('com.android.application') + def variants = isApplication ? plugin.project.android.applicationVariants : plugin.project.android.libraryVariants + + variants.all { variant -> + + final buildType = variant.buildType.name + + def cargoOutputDir = "${project.buildDir}/jniLibs/${buildType}"; + def jniLibs = project.android.sourceSets.maybeCreate(buildType).jniLibs; + jniLibs.srcDir(new File(cargoOutputDir)) + + def platforms = com.flutter.gradle.FlutterPluginUtils.getTargetPlatforms(project).collect() + + // Same thing addFlutterDependencies does in flutter.gradle + if (buildType == "debug") { + platforms.add("android-x86") + platforms.add("android-x64") + } + + // The task name depends on plugin properties, which are not available + // at this point + project.getGradle().afterProject { + def taskName = "cargokitCargoBuild${project.cargokit.libname.capitalize()}${buildType.capitalize()}"; + + if (project.tasks.findByName(taskName)) { + return + } + + if (plugin.project.android.ndkVersion == null) { + throw new GradleException("Please set 'android.ndkVersion' in 'app/build.gradle'.") + } + + def task = project.tasks.create(taskName, CargoKitBuildTask.class) { + buildMode = variant.buildType.name + buildDir = cargoBuildDir + outputDir = cargoOutputDir + ndkVersion = plugin.project.android.ndkVersion + sdkDirectory = plugin.project.android.sdkDirectory + minSdkVersion = plugin.project.android.defaultConfig.minSdkVersion.apiLevel as int + compileSdkVersion = plugin.project.android.compileSdkVersion.substring(8) as int + targetPlatforms = platforms + pluginFile = CargoKitPlugin.file + } + def onTask = { newTask -> + if (newTask.name == "merge${buildType.capitalize()}NativeLibs") { + newTask.dependsOn task + // Fix gradle 7.4.2 not picking up JNI library changes + newTask.outputs.upToDateWhen { false } + } + } + project.tasks.each onTask + project.tasks.whenTaskAdded onTask + } + } + } +} diff --git a/mobile/apps/photos/rust_builder/cargokit/run_build_tool.cmd b/mobile/apps/photos/rust_builder/cargokit/run_build_tool.cmd new file mode 100755 index 0000000000..c45d0aa8b5 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/run_build_tool.cmd @@ -0,0 +1,91 @@ +@echo off +setlocal + +setlocal ENABLEDELAYEDEXPANSION + +SET BASEDIR=%~dp0 + +if not exist "%CARGOKIT_TOOL_TEMP_DIR%" ( + mkdir "%CARGOKIT_TOOL_TEMP_DIR%" +) +cd /D "%CARGOKIT_TOOL_TEMP_DIR%" + +SET BUILD_TOOL_PKG_DIR=%BASEDIR%build_tool +SET DART=%FLUTTER_ROOT%\bin\cache\dart-sdk\bin\dart + +set BUILD_TOOL_PKG_DIR_POSIX=%BUILD_TOOL_PKG_DIR:\=/% + +( + echo name: build_tool_runner + echo version: 1.0.0 + echo publish_to: none + echo. + echo environment: + echo sdk: '^>=3.0.0 ^<4.0.0' + echo. + echo dependencies: + echo build_tool: + echo path: %BUILD_TOOL_PKG_DIR_POSIX% +) >pubspec.yaml + +if not exist bin ( + mkdir bin +) + +( + echo import 'package:build_tool/build_tool.dart' as build_tool; + echo void main^(List^ args^) ^{ + echo build_tool.runMain^(args^); + echo ^} +) >bin\build_tool_runner.dart + +SET PRECOMPILED=bin\build_tool_runner.dill + +REM To detect changes in package we compare output of DIR /s (recursive) +set PREV_PACKAGE_INFO=.dart_tool\package_info.prev +set CUR_PACKAGE_INFO=.dart_tool\package_info.cur + +DIR "%BUILD_TOOL_PKG_DIR%" /s > "%CUR_PACKAGE_INFO%_orig" + +REM Last line in dir output is free space on harddrive. That is bound to +REM change between invocation so we need to remove it +( + Set "Line=" + For /F "UseBackQ Delims=" %%A In ("%CUR_PACKAGE_INFO%_orig") Do ( + SetLocal EnableDelayedExpansion + If Defined Line Echo !Line! + EndLocal + Set "Line=%%A") +) >"%CUR_PACKAGE_INFO%" +DEL "%CUR_PACKAGE_INFO%_orig" + +REM Compare current directory listing with previous +FC /B "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" > nul 2>&1 + +If %ERRORLEVEL% neq 0 ( + REM Changed - copy current to previous and remove precompiled kernel + if exist "%PREV_PACKAGE_INFO%" ( + DEL "%PREV_PACKAGE_INFO%" + ) + MOVE /Y "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" + if exist "%PRECOMPILED%" ( + DEL "%PRECOMPILED%" + ) +) + +REM There is no CUR_PACKAGE_INFO it was renamed in previous step to %PREV_PACKAGE_INFO% +REM which means we need to do pub get and precompile +if not exist "%PRECOMPILED%" ( + echo Running pub get in "%cd%" + "%DART%" pub get --no-precompile + "%DART%" compile kernel bin/build_tool_runner.dart +) + +"%DART%" "%PRECOMPILED%" %* + +REM 253 means invalid snapshot version. +If %ERRORLEVEL% equ 253 ( + "%DART%" pub get --no-precompile + "%DART%" compile kernel bin/build_tool_runner.dart + "%DART%" "%PRECOMPILED%" %* +) diff --git a/mobile/apps/photos/rust_builder/cargokit/run_build_tool.sh b/mobile/apps/photos/rust_builder/cargokit/run_build_tool.sh new file mode 100755 index 0000000000..6e594a23d4 --- /dev/null +++ b/mobile/apps/photos/rust_builder/cargokit/run_build_tool.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + +set -e + +BASEDIR=$(dirname "$0") + +mkdir -p "$CARGOKIT_TOOL_TEMP_DIR" + +cd "$CARGOKIT_TOOL_TEMP_DIR" + +# Write a very simple bin package in temp folder that depends on build_tool package +# from Cargokit. This is done to ensure that we don't pollute Cargokit folder +# with .dart_tool contents. + +BUILD_TOOL_PKG_DIR="$BASEDIR/build_tool" + +if [[ -z $FLUTTER_ROOT ]]; then # not defined + DART=dart +else + DART="$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart" +fi + +cat << EOF > "pubspec.yaml" +name: build_tool_runner +version: 1.0.0 +publish_to: none + +environment: + sdk: '>=3.0.0 <4.0.0' + +dependencies: + build_tool: + path: "$BUILD_TOOL_PKG_DIR" +EOF + +mkdir -p "bin" + +cat << EOF > "bin/build_tool_runner.dart" +import 'package:build_tool/build_tool.dart' as build_tool; +void main(List args) { + build_tool.runMain(args); +} +EOF + +# Create alias for `shasum` if it does not exist and `sha1sum` exists +if ! [ -x "$(command -v shasum)" ] && [ -x "$(command -v sha1sum)" ]; then + shopt -s expand_aliases + alias shasum="sha1sum" +fi + +# Dart run will not cache any package that has a path dependency, which +# is the case for our build_tool_runner. So instead we precompile the package +# ourselves. +# To invalidate the cached kernel we use the hash of ls -LR of the build_tool +# package directory. This should be good enough, as the build_tool package +# itself is not meant to have any path dependencies. + +if [[ "$OSTYPE" == "darwin"* ]]; then + PACKAGE_HASH=$(ls -lTR "$BUILD_TOOL_PKG_DIR" | shasum) +else + PACKAGE_HASH=$(ls -lR --full-time "$BUILD_TOOL_PKG_DIR" | shasum) +fi + +PACKAGE_HASH_FILE=".package_hash" + +if [ -f "$PACKAGE_HASH_FILE" ]; then + EXISTING_HASH=$(cat "$PACKAGE_HASH_FILE") + if [ "$PACKAGE_HASH" != "$EXISTING_HASH" ]; then + rm "$PACKAGE_HASH_FILE" + fi +fi + +# Run pub get if needed. +if [ ! -f "$PACKAGE_HASH_FILE" ]; then + "$DART" pub get --no-precompile + "$DART" compile kernel bin/build_tool_runner.dart + echo "$PACKAGE_HASH" > "$PACKAGE_HASH_FILE" +fi + +set +e + +"$DART" bin/build_tool_runner.dill "$@" + +exit_code=$? + +# 253 means invalid snapshot version. +if [ $exit_code == 253 ]; then + "$DART" pub get --no-precompile + "$DART" compile kernel bin/build_tool_runner.dart + "$DART" bin/build_tool_runner.dill "$@" + exit_code=$? +fi + +exit $exit_code diff --git a/mobile/apps/photos/rust_builder/ios/Classes/dummy_file.c b/mobile/apps/photos/rust_builder/ios/Classes/dummy_file.c new file mode 100644 index 0000000000..e06dab9968 --- /dev/null +++ b/mobile/apps/photos/rust_builder/ios/Classes/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to force CocoaPods to create a framework. diff --git a/mobile/apps/photos/rust_builder/ios/rust_lib_photos.podspec b/mobile/apps/photos/rust_builder/ios/rust_lib_photos.podspec new file mode 100644 index 0000000000..16d34d0103 --- /dev/null +++ b/mobile/apps/photos/rust_builder/ios/rust_lib_photos.podspec @@ -0,0 +1,45 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint rust_lib_photos.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'rust_lib_photos' + s.version = '0.0.1' + s.summary = 'A new Flutter FFI plugin project.' + s.description = <<-DESC +A new Flutter FFI plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.platform = :ios, '11.0' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' + + s.script_phase = { + :name => 'Build Rust library', + # First argument is relative path to the `rust` folder, second is name of rust library + :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_photos', + :execution_position => :before_compile, + :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], + # Let XCode know that the static library referenced in -force_load below is + # created by this build step. + :output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_photos.a"], + } + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # Flutter.framework does not contain a i386 slice. + 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', + 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_photos.a -lc++', + } +end \ No newline at end of file diff --git a/mobile/apps/photos/rust_builder/linux/CMakeLists.txt b/mobile/apps/photos/rust_builder/linux/CMakeLists.txt new file mode 100644 index 0000000000..e6656c9227 --- /dev/null +++ b/mobile/apps/photos/rust_builder/linux/CMakeLists.txt @@ -0,0 +1,19 @@ +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. +cmake_minimum_required(VERSION 3.10) + +# Project-level configuration. +set(PROJECT_NAME "rust_lib_photos") +project(${PROJECT_NAME} LANGUAGES CXX) + +include("../cargokit/cmake/cargokit.cmake") +apply_cargokit(${PROJECT_NAME} ../../rust rust_lib_photos "") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(rust_lib_photos_bundled_libraries + "${${PROJECT_NAME}_cargokit_lib}" + PARENT_SCOPE +) diff --git a/mobile/apps/photos/rust_builder/macos/Classes/dummy_file.c b/mobile/apps/photos/rust_builder/macos/Classes/dummy_file.c new file mode 100644 index 0000000000..e06dab9968 --- /dev/null +++ b/mobile/apps/photos/rust_builder/macos/Classes/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to force CocoaPods to create a framework. diff --git a/mobile/apps/photos/rust_builder/macos/rust_lib_photos.podspec b/mobile/apps/photos/rust_builder/macos/rust_lib_photos.podspec new file mode 100644 index 0000000000..e929e5848e --- /dev/null +++ b/mobile/apps/photos/rust_builder/macos/rust_lib_photos.podspec @@ -0,0 +1,44 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint rust_lib_photos.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'rust_lib_photos' + s.version = '0.0.1' + s.summary = 'A new Flutter FFI plugin project.' + s.description = <<-DESC +A new Flutter FFI plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'FlutterMacOS' + + s.platform = :osx, '10.11' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.swift_version = '5.0' + + s.script_phase = { + :name => 'Build Rust library', + # First argument is relative path to the `rust` folder, second is name of rust library + :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_photos', + :execution_position => :before_compile, + :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], + # Let XCode know that the static library referenced in -force_load below is + # created by this build step. + :output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_photos.a"], + } + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # Flutter.framework does not contain a i386 slice. + 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', + 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_photos.a -lc++', + } +end \ No newline at end of file diff --git a/mobile/apps/photos/rust_builder/pubspec.yaml b/mobile/apps/photos/rust_builder/pubspec.yaml new file mode 100644 index 0000000000..2be7b960ab --- /dev/null +++ b/mobile/apps/photos/rust_builder/pubspec.yaml @@ -0,0 +1,34 @@ +name: rust_lib_photos +description: "Utility to build Rust code" +version: 0.0.1 +publish_to: none + +environment: + sdk: ">=3.3.0 <4.0.0" + flutter: ">=3.3.0" + +dependencies: + flutter: + sdk: flutter + plugin_platform_interface: ^2.0.2 + +dev_dependencies: + ffi: ^2.0.2 + ffigen: ^11.0.0 + flutter_lints: ^2.0.0 + flutter_test: + sdk: flutter + +flutter: + plugin: + platforms: + android: + ffiPlugin: true + ios: + ffiPlugin: true + linux: + ffiPlugin: true + macos: + ffiPlugin: true + windows: + ffiPlugin: true diff --git a/mobile/apps/photos/rust_builder/windows/.gitignore b/mobile/apps/photos/rust_builder/windows/.gitignore new file mode 100644 index 0000000000..b3eb2be169 --- /dev/null +++ b/mobile/apps/photos/rust_builder/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/mobile/apps/photos/rust_builder/windows/CMakeLists.txt b/mobile/apps/photos/rust_builder/windows/CMakeLists.txt new file mode 100644 index 0000000000..4640016d5c --- /dev/null +++ b/mobile/apps/photos/rust_builder/windows/CMakeLists.txt @@ -0,0 +1,20 @@ +# The Flutter tooling requires that developers have a version of Visual Studio +# installed that includes CMake 3.14 or later. You should not increase this +# version, as doing so will cause the plugin to fail to compile for some +# customers of the plugin. +cmake_minimum_required(VERSION 3.14) + +# Project-level configuration. +set(PROJECT_NAME "rust_lib_photos") +project(${PROJECT_NAME} LANGUAGES CXX) + +include("../cargokit/cmake/cargokit.cmake") +apply_cargokit(${PROJECT_NAME} ../../../../../../rust rust_lib_photos "") + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(rust_lib_photos_bundled_libraries + "${${PROJECT_NAME}_cargokit_lib}" + PARENT_SCOPE +) diff --git a/mobile/apps/photos/scripts/store_changes.txt b/mobile/apps/photos/scripts/store_changes.txt index e6c8911ffe..1d6ce14986 100644 --- a/mobile/apps/photos/scripts/store_changes.txt +++ b/mobile/apps/photos/scripts/store_changes.txt @@ -1,4 +1,5 @@ -- Added support for custom domain links +- Added similar images debug screen (Settings > Backup > Free up space > Similar images) +- Added support for custom domain links - Image editor fixes: - Fixed bottom navigation bar color in light theme - Resolved initial color issue in paint editor diff --git a/mobile/apps/photos/test_driver/integration_test.dart b/mobile/apps/photos/test_driver/integration_test.dart new file mode 100644 index 0000000000..b38629cca9 --- /dev/null +++ b/mobile/apps/photos/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/mobile/packages/lock_screen/lib/lock_screen_settings.dart b/mobile/packages/lock_screen/lib/lock_screen_settings.dart index 2c631bc931..33e230cfc0 100644 --- a/mobile/packages/lock_screen/lib/lock_screen_settings.dart +++ b/mobile/packages/lock_screen/lib/lock_screen_settings.dart @@ -95,7 +95,6 @@ class LockScreenSettings { Future setHideAppContent(bool hideContent) async { if (PlatformUtil.isDesktop()) return; - final bool isLightMode = _preferences.getBool(kIsLightMode) ?? true; !hideContent ? PrivacyScreen.instance.disable() : await PrivacyScreen.instance.enable( @@ -105,11 +104,8 @@ class LockScreenSettings { androidOptions: const PrivacyAndroidOptions( enableSecure: true, ), - backgroundColor: - isLightMode ? const Color(0xffffffff) : const Color(0xff000000), - blurEffect: isLightMode - ? PrivacyBlurEffect.extraLight - : PrivacyBlurEffect.extraLight, + backgroundColor: const Color(0xff000000), + blurEffect: PrivacyBlurEffect.extraLight, ); await _preferences.setBool(keyHideAppContent, hideContent); } diff --git a/web/apps/photos/src/components/Sidebar.tsx b/web/apps/photos/src/components/Sidebar.tsx index 27f6aca66c..f2b4cc7b12 100644 --- a/web/apps/photos/src/components/Sidebar.tsx +++ b/web/apps/photos/src/components/Sidebar.tsx @@ -14,6 +14,7 @@ import { DialogContent, Divider, IconButton, + Link, Skeleton, Stack, styled, @@ -54,7 +55,6 @@ import { useBaseContext } from "ente-base/context"; import { isHTTPErrorWithStatus } from "ente-base/http"; import { getLocaleInUse, - pt, setLocaleInUse, supportedLocales, ut, @@ -824,50 +824,43 @@ const Preferences: React.FC = ({ /> )} - { - /* TODO: CD */ process.env.NEXT_PUBLIC_ENTE_WIP_CD && ( - - - - - - - } - onClick={showDomainSettings} - /> - ) - } + + + + + + + } + onClick={showDomainSettings} + /> } label={t("map")} @@ -1024,17 +1017,15 @@ const DomainSettings: React.FC = ({ ); }; -// Separate component to reset state on back. +// Separate component to reset state on going back. const DomainSettingsContents: React.FC = () => { const { customDomain, customDomainCNAME } = useSettingsSnapshot(); @@ -1050,9 +1041,11 @@ const DomainSettingsContents: React.FC = () => { } catch (e) { log.error(`Failed to submit input ${domain}`, e); if (isHTTPErrorWithStatus(e, 400)) { - setValueFieldError(pt("Invalid domain")); + setValueFieldError(t("invalid_domain")); + } else if (isHTTPErrorWithStatus(e, 402)) { + setValueFieldError(t("sharing_disabled_for_free_accounts")); } else if (isHTTPErrorWithStatus(e, 409)) { - setValueFieldError(pt("Domain already linked by a user")); + setValueFieldError(t("already_linked_domain")); } else { setValueFieldError(t("generic_error")); } @@ -1060,11 +1053,9 @@ const DomainSettingsContents: React.FC = () => { }, }); - // TODO: CD: help - return ( - +
{ margin="dense" disabled={formik.isSubmitting} error={!!formik.errors.domain} - helperText={ - formik.errors.domain ?? - pt("Any domain or subdomain you own") - } - label={t("Domain")} + helperText={formik.errors.domain ?? t("domain_help")} + label={t("domain")} placeholder={ut("photos.example.org")} sx={{ mb: 2 }} /> @@ -1090,33 +1078,43 @@ const DomainSettingsContents: React.FC = () => { loading={formik.isSubmitting} color="accent" > - {customDomain ? pt("Update") : pt("Save")} + {customDomain ? t("update") : t("save")}
- + - On your DNS provider, add a CNAME from your domain to{" "} - - {customDomainCNAME} - - - - - - - Within 1 hour, your public albums will be accessible via - your domain! + + ), + }} + values={{ host: customDomainCNAME }} + /> - For more information, see - - {" help "} - + + ), + }} + />
@@ -1126,13 +1124,11 @@ const DomainSettingsContents: React.FC = () => { interface DomainSectionProps { title: string; ordinal: string; - isEmoji?: boolean; } const DomainItem: React.FC> = ({ title, ordinal, - isEmoji, children, }) => ( @@ -1140,7 +1136,7 @@ const DomainItem: React.FC> = ({ direction="row" sx={{ alignItems: "center", justifyContent: "space-between" }} > - {title} + {title} {{host}}", + "custom_domains_help": "For more information, see help", + "num_1": "1", + "num_2": "2" } diff --git a/web/packages/base/locales/es-ES/translation.json b/web/packages/base/locales/es-ES/translation.json index 1d3d91cf93..15fd1bfbd9 100644 --- a/web/packages/base/locales/es-ES/translation.json +++ b/web/packages/base/locales/es-ES/translation.json @@ -685,5 +685,17 @@ "person_favorites": "Los favoritos de {{name}}", "shared_favorites": "Favoritos compartidos", "added_by_name": "Añadido por {{name}}", - "unowned_files_not_processed": "Los archivos añadidos por otros usuarios no han sido procesados" + "unowned_files_not_processed": "Los archivos añadidos por otros usuarios no han sido procesados", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/et-EE/translation.json b/web/packages/base/locales/et-EE/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/et-EE/translation.json +++ b/web/packages/base/locales/et-EE/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/fa-IR/translation.json b/web/packages/base/locales/fa-IR/translation.json index b1956bcf24..c626e82841 100644 --- a/web/packages/base/locales/fa-IR/translation.json +++ b/web/packages/base/locales/fa-IR/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/fi-FI/translation.json b/web/packages/base/locales/fi-FI/translation.json index 70a7dc4a9b..23b9a09ff6 100644 --- a/web/packages/base/locales/fi-FI/translation.json +++ b/web/packages/base/locales/fi-FI/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/fr-FR/translation.json b/web/packages/base/locales/fr-FR/translation.json index 564cd4528b..11b5a723c4 100644 --- a/web/packages/base/locales/fr-FR/translation.json +++ b/web/packages/base/locales/fr-FR/translation.json @@ -162,7 +162,7 @@ "ok": "Ok", "success": "Parfait", "error": "Erreur", - "note": "", + "note": "Note", "offline_message": "Vous êtes hors ligne, les souvenirs en cache sont affichés", "install": "Installer", "install_mobile_app": "Installez notre application Android or iOS pour sauvegarder automatiquement toutes vos photos", @@ -685,5 +685,17 @@ "person_favorites": "Favoris de {{name}}", "shared_favorites": "Favoris partagés", "added_by_name": "Ajouté par {{name}}", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "Les fichiers ajoutés par d'autres utilisateurs n'ont pas été traités", + "custom_domains": "Domaines personnalisés", + "custom_domains_desc": "Utiliser votre propre domaine lors du partage", + "link_your_domain": "Lier votre domaine", + "domain": "Domaine", + "domain_help": "N'importe quel domaine ou sous-domaine que vous possédez", + "invalid_domain": "Domaine non valide", + "already_linked_domain": "Le domaine déjà lié par un utilisateur", + "add_dns_entry": "Ajouter l'entrée DNS", + "add_dns_entry_hint": "Chez votre fournisseur DNS, ajoutez un CNAME de votre domaine {{host}}", + "custom_domains_help": "Pour plus d'informations, voir l'help", + "num_1": "1", + "num_2": "2" } diff --git a/web/packages/base/locales/gu-IN/translation.json b/web/packages/base/locales/gu-IN/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/gu-IN/translation.json +++ b/web/packages/base/locales/gu-IN/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/hi-IN/translation.json b/web/packages/base/locales/hi-IN/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/hi-IN/translation.json +++ b/web/packages/base/locales/hi-IN/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/hu-HU/translation.json b/web/packages/base/locales/hu-HU/translation.json index 43a3f09dc5..28cff66abb 100644 --- a/web/packages/base/locales/hu-HU/translation.json +++ b/web/packages/base/locales/hu-HU/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/id-ID/translation.json b/web/packages/base/locales/id-ID/translation.json index a6338d7cc7..b174f2f2ea 100644 --- a/web/packages/base/locales/id-ID/translation.json +++ b/web/packages/base/locales/id-ID/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/is-IS/translation.json b/web/packages/base/locales/is-IS/translation.json index 1eb86e3776..c1330d2ebc 100644 --- a/web/packages/base/locales/is-IS/translation.json +++ b/web/packages/base/locales/is-IS/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/it-IT/translation.json b/web/packages/base/locales/it-IT/translation.json index 0dbe77e990..0d537b7e25 100644 --- a/web/packages/base/locales/it-IT/translation.json +++ b/web/packages/base/locales/it-IT/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ja-JP/translation.json b/web/packages/base/locales/ja-JP/translation.json index c99792db1b..420e96c069 100644 --- a/web/packages/base/locales/ja-JP/translation.json +++ b/web/packages/base/locales/ja-JP/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/km-KH/translation.json b/web/packages/base/locales/km-KH/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/km-KH/translation.json +++ b/web/packages/base/locales/km-KH/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ko-KR/translation.json b/web/packages/base/locales/ko-KR/translation.json index c149854bde..fb420c812a 100644 --- a/web/packages/base/locales/ko-KR/translation.json +++ b/web/packages/base/locales/ko-KR/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/lt-LT/translation.json b/web/packages/base/locales/lt-LT/translation.json index b26aebb96d..91d3494e06 100644 --- a/web/packages/base/locales/lt-LT/translation.json +++ b/web/packages/base/locales/lt-LT/translation.json @@ -685,5 +685,17 @@ "person_favorites": "{{name}} mėgstami", "shared_favorites": "Bendrinami mėgstami", "added_by_name": "Įtraukė {{name}}", - "unowned_files_not_processed": "Kiti naudotojai pridėti failai nebuvo apdoroti" + "unowned_files_not_processed": "Kiti naudotojai pridėti failai nebuvo apdoroti", + "custom_domains": "Pasirinktiniai domenai", + "custom_domains_desc": "Naudokite savo domeną, kai bendrinate.", + "link_your_domain": "Susieti savo domeną", + "domain": "Domenas", + "domain_help": "Bet kuris jūsų turimas domenas arba subdomenas", + "invalid_domain": "Netinkamas domenas.", + "already_linked_domain": "Domenas jau susietas su naudotoju.", + "add_dns_entry": "Pridėti DNS elementą", + "add_dns_entry_hint": "Savo DNS teikėjoje pridėkite „CNAME“ iš savo domeno į {{host}}.", + "custom_domains_help": "Dėl daugiau informacijos žiūrėkite pagalbą.", + "num_1": "1", + "num_2": "2" } diff --git a/web/packages/base/locales/lv-LV/translation.json b/web/packages/base/locales/lv-LV/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/lv-LV/translation.json +++ b/web/packages/base/locales/lv-LV/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ml-IN/translation.json b/web/packages/base/locales/ml-IN/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/ml-IN/translation.json +++ b/web/packages/base/locales/ml-IN/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ms-BN/translation.json b/web/packages/base/locales/ms-BN/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/ms-BN/translation.json +++ b/web/packages/base/locales/ms-BN/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ms-MY/translation.json b/web/packages/base/locales/ms-MY/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/ms-MY/translation.json +++ b/web/packages/base/locales/ms-MY/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/nl-NL/translation.json b/web/packages/base/locales/nl-NL/translation.json index 5f93685250..44b4f47d3f 100644 --- a/web/packages/base/locales/nl-NL/translation.json +++ b/web/packages/base/locales/nl-NL/translation.json @@ -685,5 +685,17 @@ "person_favorites": "Favorieten van {{name}}", "shared_favorites": "Gedeelde favorieten", "added_by_name": "Toegevoegd door {{name}}", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/pl-PL/translation.json b/web/packages/base/locales/pl-PL/translation.json index 064add62dc..bdae07f1a1 100644 --- a/web/packages/base/locales/pl-PL/translation.json +++ b/web/packages/base/locales/pl-PL/translation.json @@ -685,5 +685,17 @@ "person_favorites": "Ulubione użytkownika {{name}}", "shared_favorites": "Udostępnione ulubione", "added_by_name": "Dodane przez {{name}}", - "unowned_files_not_processed": "Pliki dodane przez innych użytkowników nie były przetwarzane" + "unowned_files_not_processed": "Pliki dodane przez innych użytkowników nie były przetwarzane", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/pt-BR/translation.json b/web/packages/base/locales/pt-BR/translation.json index ffb09b5b4a..9852b1f35d 100644 --- a/web/packages/base/locales/pt-BR/translation.json +++ b/web/packages/base/locales/pt-BR/translation.json @@ -685,5 +685,17 @@ "person_favorites": "Favoritos de {{name}}", "shared_favorites": "Favoritos compartilhados", "added_by_name": "Adicionado por {{name}}", - "unowned_files_not_processed": "Não processou os arquivos adicionados por outros usuários" + "unowned_files_not_processed": "Não processou os arquivos adicionados por outros usuários", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/pt-PT/translation.json b/web/packages/base/locales/pt-PT/translation.json index 4a85e90c62..446f8319fe 100644 --- a/web/packages/base/locales/pt-PT/translation.json +++ b/web/packages/base/locales/pt-PT/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ro-RO/translation.json b/web/packages/base/locales/ro-RO/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/ro-RO/translation.json +++ b/web/packages/base/locales/ro-RO/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ru-RU/translation.json b/web/packages/base/locales/ru-RU/translation.json index 39401daefc..fe0728c1f1 100644 --- a/web/packages/base/locales/ru-RU/translation.json +++ b/web/packages/base/locales/ru-RU/translation.json @@ -685,5 +685,17 @@ "person_favorites": "{{name}} избранных", "shared_favorites": "Общие избранные", "added_by_name": "Добавлено {{name}}", - "unowned_files_not_processed": "Файлы, добавленные другими пользователями, не были обработаны" + "unowned_files_not_processed": "Файлы, добавленные другими пользователями, не были обработаны", + "custom_domains": "Пользовательские домены", + "custom_domains_desc": "Используйте свой собственный домен при публикации", + "link_your_domain": "Привязать ваш домен", + "domain": "Домен", + "domain_help": "Любой домен или поддомен, которым вы владеете", + "invalid_domain": "Неверный домен", + "already_linked_domain": "Домен уже связан пользователем", + "add_dns_entry": "Добавить DNS-запись", + "add_dns_entry_hint": "На стороне вашего DNS-провайдера добавьте CNAME из вашего домена в {{host}}", + "custom_domains_help": "Для получения дополнительной информации см. помощь", + "num_1": "1", + "num_2": "2" } diff --git a/web/packages/base/locales/sl-SI/translation.json b/web/packages/base/locales/sl-SI/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/sl-SI/translation.json +++ b/web/packages/base/locales/sl-SI/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/sr-SP/translation.json b/web/packages/base/locales/sr-SP/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/sr-SP/translation.json +++ b/web/packages/base/locales/sr-SP/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/sv-SE/translation.json b/web/packages/base/locales/sv-SE/translation.json index 3380397e3e..a8fde78805 100644 --- a/web/packages/base/locales/sv-SE/translation.json +++ b/web/packages/base/locales/sv-SE/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ta-IN/translation.json b/web/packages/base/locales/ta-IN/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/ta-IN/translation.json +++ b/web/packages/base/locales/ta-IN/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/te-IN/translation.json b/web/packages/base/locales/te-IN/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/te-IN/translation.json +++ b/web/packages/base/locales/te-IN/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/th-TH/translation.json b/web/packages/base/locales/th-TH/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/th-TH/translation.json +++ b/web/packages/base/locales/th-TH/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/ti-ER/translation.json b/web/packages/base/locales/ti-ER/translation.json index 23a6018ed0..1030b4dea7 100644 --- a/web/packages/base/locales/ti-ER/translation.json +++ b/web/packages/base/locales/ti-ER/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/tr-TR/translation.json b/web/packages/base/locales/tr-TR/translation.json index 627ac8aa91..c957b3906d 100644 --- a/web/packages/base/locales/tr-TR/translation.json +++ b/web/packages/base/locales/tr-TR/translation.json @@ -685,5 +685,17 @@ "person_favorites": "{{name}}'in favorileri", "shared_favorites": "Paylaşılan favoriler", "added_by_name": "{{name}} tarafından eklendi", - "unowned_files_not_processed": "Diğer kullanıcılar tarafından eklenen dosyalar işlenmedi" + "unowned_files_not_processed": "Diğer kullanıcılar tarafından eklenen dosyalar işlenmedi", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/uk-UA/translation.json b/web/packages/base/locales/uk-UA/translation.json index cc7ffca77a..ab3b64fb34 100644 --- a/web/packages/base/locales/uk-UA/translation.json +++ b/web/packages/base/locales/uk-UA/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/packages/base/locales/vi-VN/translation.json b/web/packages/base/locales/vi-VN/translation.json index fdd39566fb..af041df4a8 100644 --- a/web/packages/base/locales/vi-VN/translation.json +++ b/web/packages/base/locales/vi-VN/translation.json @@ -685,5 +685,17 @@ "person_favorites": "{{name}} đã thích", "shared_favorites": "Những mục thích đã chia sẻ", "added_by_name": "Được thêm bởi {{name}}", - "unowned_files_not_processed": "Các tệp được thêm bởi người dùng khác không được xử lý" + "unowned_files_not_processed": "Các tệp được thêm bởi người dùng khác không được xử lý", + "custom_domains": "Tùy chỉnh tên miền", + "custom_domains_desc": "Dùng tên miền của bạn khi chia sẻ", + "link_your_domain": "Liên kết với tên miền", + "domain": "Tên miền", + "domain_help": "Bất kỳ tên miền hoặc tên miền phụ nào của bạn", + "invalid_domain": "Tên miền không hợp lệ", + "already_linked_domain": "Tên miền đã được liên kết với người dùng khác", + "add_dns_entry": "Thêm entry DNS", + "add_dns_entry_hint": "Trên trình quản lý của nhà cung cấp DNS, thêm một CNAME từ tên miền của bạn đến {{host}}", + "custom_domains_help": "Để biết thêm chi tiết, xem trợ giúp", + "num_1": "1", + "num_2": "2" } diff --git a/web/packages/base/locales/zh-CN/translation.json b/web/packages/base/locales/zh-CN/translation.json index 0bfb3cce8e..16b109545f 100644 --- a/web/packages/base/locales/zh-CN/translation.json +++ b/web/packages/base/locales/zh-CN/translation.json @@ -1,5 +1,5 @@ { - "intro_slide_1_title": "私人备份
为您的回忆", + "intro_slide_1_title": "为您的回忆
私密备份", "intro_slide_1": "默认端到端加密", "intro_slide_2_title": "安全地存放
在一个掩护所中", "intro_slide_2": "经久耐用", @@ -685,5 +685,17 @@ "person_favorites": "{{name}}的收藏", "shared_favorites": "已共享的收藏", "added_by_name": "由{{name}}添加", - "unowned_files_not_processed": "由其他用户添加的文件未被处理" + "unowned_files_not_processed": "由其他用户添加的文件未被处理", + "custom_domains": "自定义域名", + "custom_domains_desc": "分享时使用您自己的域名", + "link_your_domain": "链接您的域名", + "domain": "域名", + "domain_help": "您拥有的任何域名或子域名", + "invalid_domain": "无效的域名", + "already_linked_domain": "域名已被其他用户链接", + "add_dns_entry": "添加 DNS 条目", + "add_dns_entry_hint": "在您的 DNS 提供商上,将您域中的 CNAME 添加到 {{host}}", + "custom_domains_help": "欲了解更多信息,请参阅 help", + "num_1": "1", + "num_2": "2" } diff --git a/web/packages/base/locales/zh-HK/translation.json b/web/packages/base/locales/zh-HK/translation.json index bdfed3f70f..bd35a6b091 100644 --- a/web/packages/base/locales/zh-HK/translation.json +++ b/web/packages/base/locales/zh-HK/translation.json @@ -685,5 +685,17 @@ "person_favorites": "", "shared_favorites": "", "added_by_name": "", - "unowned_files_not_processed": "" + "unowned_files_not_processed": "", + "custom_domains": "", + "custom_domains_desc": "", + "link_your_domain": "", + "domain": "", + "domain_help": "", + "invalid_domain": "", + "already_linked_domain": "", + "add_dns_entry": "", + "add_dns_entry_hint": "", + "custom_domains_help": "", + "num_1": "", + "num_2": "" } diff --git a/web/yarn.lock b/web/yarn.lock index 6553105924..622a5cd80a 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1227,7 +1227,7 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7" integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw== -"@types/react-dom@^19.1.1", "@types/react-dom@^19.1.6": +"@types/react-dom@^19.1.6": version "19.1.6" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.6.tgz#4af629da0e9f9c0f506fc4d1caa610399c595d64" integrity sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw== @@ -1244,7 +1244,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^19.1.0", "@types/react@^19.1.8": +"@types/react@*", "@types/react@^19.1.8": version "19.1.8" resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.8.tgz#ff8395f2afb764597265ced15f8dddb0720ae1c3" integrity sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==