Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75d1d21cc6 |
@@ -1,4 +1,4 @@
|
|||||||
ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:2ef23730ec68d8511ec8e6e0b82550ca728b256805d81f60ed890f3bfb21cfb9
|
ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:9791f4aa527774bc370c6bd2f6705ce5a686f1e6f204badd8dfaacce28c631ae
|
||||||
FROM ${BASEIMAGE}
|
FROM ${BASEIMAGE}
|
||||||
|
|
||||||
# Flutter SDK
|
# Flutter SDK
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
22.14.0
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
title: '[Feature] feature-name-goes-here'
|
title: "[Feature] feature-name-goes-here"
|
||||||
labels: ['feature']
|
labels: ["feature"]
|
||||||
|
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
@@ -13,7 +13,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: I have searched the existing feature requests, both open and closed, to make sure this is not a duplicate request.
|
label: I have searched the existing feature requests, both open and closed, to make sure this is not a duplicate request.
|
||||||
options:
|
options:
|
||||||
- label: 'Yes'
|
- label: "Yes"
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: I have searched the existing issues, both open and closed, to make sure this is not a duplicate report.
|
label: I have searched the existing issues, both open and closed, to make sure this is not a duplicate report.
|
||||||
options:
|
options:
|
||||||
- label: 'Yes'
|
- label: "Yes"
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: markdown
|
- type: markdown
|
||||||
@@ -84,7 +84,7 @@ body:
|
|||||||
id: repro
|
id: repro
|
||||||
attributes:
|
attributes:
|
||||||
label: Reproduction steps
|
label: Reproduction steps
|
||||||
description: 'How do you trigger this bug? Please walk us through it step by step.'
|
description: "How do you trigger this bug? Please walk us through it step by step."
|
||||||
value: |
|
value: |
|
||||||
1.
|
1.
|
||||||
2.
|
2.
|
||||||
@@ -97,13 +97,12 @@ body:
|
|||||||
id: logs
|
id: logs
|
||||||
attributes:
|
attributes:
|
||||||
label: Relevant log output
|
label: Relevant log output
|
||||||
description:
|
description: Please copy and paste any relevant logs below. (code formatting is
|
||||||
Please copy and paste any relevant logs below. (code formatting is
|
|
||||||
enabled, no need for backticks)
|
enabled, no need for backticks)
|
||||||
render: shell
|
render: shell
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Additional information
|
label: Additional information
|
||||||
|
|||||||
Generated
-28
@@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": ".github",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"devDependencies": {
|
|
||||||
"prettier": "^3.5.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/prettier": {
|
|
||||||
"version": "3.5.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
|
||||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"prettier": "bin/prettier.cjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"format": "prettier --check .",
|
|
||||||
"format:fix": "prettier --write ."
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"prettier": "^3.5.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+33
-33
@@ -1,33 +1,33 @@
|
|||||||
changelog:
|
changelog:
|
||||||
categories:
|
categories:
|
||||||
- title: 🚨 Breaking Changes
|
- title: 🚨 Breaking Changes
|
||||||
labels:
|
labels:
|
||||||
- changelog:breaking-change
|
- changelog:breaking-change
|
||||||
|
|
||||||
- title: 🫥 Deprecated Changes
|
- title: 🫥 Deprecated Changes
|
||||||
labels:
|
labels:
|
||||||
- changelog:deprecated
|
- changelog:deprecated
|
||||||
|
|
||||||
- title: 🔒 Security
|
- title: 🔒 Security
|
||||||
labels:
|
labels:
|
||||||
- changelog:security
|
- changelog:security
|
||||||
|
|
||||||
- title: 🚀 Features
|
- title: 🚀 Features
|
||||||
labels:
|
labels:
|
||||||
- changelog:feature
|
- changelog:feature
|
||||||
|
|
||||||
- title: 🌟 Enhancements
|
- title: 🌟 Enhancements
|
||||||
labels:
|
labels:
|
||||||
- changelog:enhancement
|
- changelog:enhancement
|
||||||
|
|
||||||
- title: 🐛 Bug fixes
|
- title: 🐛 Bug fixes
|
||||||
labels:
|
labels:
|
||||||
- changelog:bugfix
|
- changelog:bugfix
|
||||||
|
|
||||||
- title: 📚 Documentation
|
- title: 📚 Documentation
|
||||||
labels:
|
labels:
|
||||||
- changelog:documentation
|
- changelog:documentation
|
||||||
|
|
||||||
- title: 🌐 Translations
|
- title: 🌐 Translations
|
||||||
labels:
|
labels:
|
||||||
- changelog:translation
|
- changelog:translation
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ jobs:
|
|||||||
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
- id: found_paths
|
- id: found_paths
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
|
uses: dorny/paths-filter@v3
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
mobile:
|
mobile:
|
||||||
@@ -51,18 +51,18 @@ jobs:
|
|||||||
ref="${input_ref:-$github_ref}"
|
ref="${input_ref:-$github_ref}"
|
||||||
echo "ref=$ref" >> $GITHUB_OUTPUT
|
echo "ref=$ref" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ steps.get-ref.outputs.ref }}
|
ref: ${{ steps.get-ref.outputs.ref }}
|
||||||
|
|
||||||
- uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
- uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
cache: 'gradle'
|
cache: 'gradle'
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
|
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
|
||||||
|
|
||||||
- name: Publish Android Artifact
|
- name: Publish Android Artifact
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-apk-signed
|
name: release-apk-signed
|
||||||
path: mobile/build/app/outputs/flutter-apk/*.apk
|
path: mobile/build/app/outputs/flutter-apk/*.apk
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ on:
|
|||||||
- 'cli/**'
|
- 'cli/**'
|
||||||
- '.github/workflows/cli.yml'
|
- '.github/workflows/cli.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
paths:
|
paths:
|
||||||
- 'cli/**'
|
- 'cli/**'
|
||||||
- '.github/workflows/cli.yml'
|
- '.github/workflows/cli.yml'
|
||||||
@@ -28,9 +29,9 @@ jobs:
|
|||||||
working-directory: ./cli
|
working-directory: ./cli
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@v4
|
||||||
# Setup .npmrc file to publish to npm
|
# Setup .npmrc file to publish to npm
|
||||||
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
@@ -52,16 +53,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
uses: docker/setup-qemu-action@v3.6.0
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
uses: docker/setup-buildx-action@v3.10.0
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
@@ -76,7 +77,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate docker image tags
|
- name: Generate docker image tags
|
||||||
id: metadata
|
id: metadata
|
||||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=false
|
latest=false
|
||||||
@@ -87,7 +88,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
uses: docker/build-push-action@v6.15.0
|
||||||
with:
|
with:
|
||||||
file: cli/Dockerfile
|
file: cli/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
# the `language` matrix defined below to confirm you have the correct set of
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
# supported CodeQL languages.
|
# supported CodeQL languages.
|
||||||
#
|
#
|
||||||
name: 'CodeQL'
|
name: "CodeQL"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ['main']
|
branches: [ "main" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: ['main']
|
branches: [ "main" ]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '20 13 * * 1'
|
- cron: '20 13 * * 1'
|
||||||
|
|
||||||
@@ -36,42 +36,43 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
language: ['javascript', 'python']
|
language: [ 'javascript', 'python' ]
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
# By default, queries listed here will override any specified in a config file.
|
# By default, queries listed here will override any specified in a config file.
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||||
# queries: security-extended,security-and-quality
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@5f8171a638ada777af81d42b55959a643bb29017 # v3
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
# - run: |
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
# echo "Run, Build Application using script"
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
# ./location_of_script_within_repo/buildscript.sh
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
# - run: |
|
||||||
uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3
|
# echo "Run, Build Application using script"
|
||||||
with:
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
category: '/language:${{matrix.language}}'
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v3
|
||||||
|
with:
|
||||||
|
category: "/language:${{matrix.language}}"
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ jobs:
|
|||||||
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
- id: found_paths
|
- id: found_paths
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
|
uses: dorny/paths-filter@v3
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
server:
|
server:
|
||||||
@@ -49,23 +49,23 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
suffix: ['', '-cuda', '-rocm', '-openvino', '-armnn', '-rknn']
|
suffix: ["", "-cuda", "-openvino", "-armnn"]
|
||||||
steps:
|
steps:
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Re-tag image
|
- name: Re-tag image
|
||||||
run: |
|
run: |
|
||||||
REGISTRY_NAME="ghcr.io"
|
REGISTRY_NAME="ghcr.io"
|
||||||
REPOSITORY=${{ github.repository_owner }}/immich-machine-learning
|
REPOSITORY=${{ github.repository_owner }}/immich-machine-learning
|
||||||
TAG_OLD=main${{ matrix.suffix }}
|
TAG_OLD=main${{ matrix.suffix }}
|
||||||
TAG_PR=${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }}
|
TAG_PR=${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }}
|
||||||
TAG_COMMIT=commit-${{ github.event_name != 'pull_request' && github.sha || github.event.pull_request.head.sha }}${{ matrix.suffix }}
|
TAG_COMMIT=commit-${{ github.event_name != 'pull_request' && github.sha || github.event.pull_request.head.sha }}${{ matrix.suffix }}
|
||||||
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_PR $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
|
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_PR $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
|
||||||
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_COMMIT $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
|
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_COMMIT $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
|
||||||
|
|
||||||
retag_server:
|
retag_server:
|
||||||
name: Re-Tag Server
|
name: Re-Tag Server
|
||||||
@@ -74,10 +74,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
suffix: ['']
|
suffix: [""]
|
||||||
steps:
|
steps:
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
@@ -120,11 +120,6 @@ jobs:
|
|||||||
device: cuda
|
device: cuda
|
||||||
suffix: -cuda
|
suffix: -cuda
|
||||||
|
|
||||||
- platform: linux/amd64
|
|
||||||
runner: mich
|
|
||||||
device: rocm
|
|
||||||
suffix: -rocm
|
|
||||||
|
|
||||||
- platform: linux/amd64
|
- platform: linux/amd64
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
device: openvino
|
device: openvino
|
||||||
@@ -135,11 +130,6 @@ jobs:
|
|||||||
device: armnn
|
device: armnn
|
||||||
suffix: -armnn
|
suffix: -armnn
|
||||||
|
|
||||||
- platform: linux/arm64
|
|
||||||
runner: ubuntu-24.04-arm
|
|
||||||
device: rknn
|
|
||||||
suffix: -rknn
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Prepare
|
- name: Prepare
|
||||||
run: |
|
run: |
|
||||||
@@ -147,13 +137,13 @@ jobs:
|
|||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
uses: docker/setup-buildx-action@v3.10.0
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
@@ -180,7 +170,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
uses: docker/build-push-action@v6.15.0
|
||||||
with:
|
with:
|
||||||
context: ${{ env.context }}
|
context: ${{ env.context }}
|
||||||
file: ${{ env.file }}
|
file: ${{ env.file }}
|
||||||
@@ -205,7 +195,7 @@ jobs:
|
|||||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||||
|
|
||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ml-digests-${{ matrix.device }}-${{ env.PLATFORM_PAIR }}
|
name: ml-digests-${{ matrix.device }}-${{ env.PLATFORM_PAIR }}
|
||||||
path: ${{ runner.temp }}/digests/*
|
path: ${{ runner.temp }}/digests/*
|
||||||
@@ -225,19 +215,15 @@ jobs:
|
|||||||
- device: cpu
|
- device: cpu
|
||||||
- device: cuda
|
- device: cuda
|
||||||
suffix: -cuda
|
suffix: -cuda
|
||||||
- device: rocm
|
|
||||||
suffix: -rocm
|
|
||||||
- device: openvino
|
- device: openvino
|
||||||
suffix: -openvino
|
suffix: -openvino
|
||||||
- device: armnn
|
- device: armnn
|
||||||
suffix: -armnn
|
suffix: -armnn
|
||||||
- device: rknn
|
|
||||||
suffix: -rknn
|
|
||||||
needs:
|
needs:
|
||||||
- build_and_push_ml
|
- build_and_push_ml
|
||||||
steps:
|
steps:
|
||||||
- name: Download digests
|
- name: Download digests
|
||||||
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ runner.temp }}/digests
|
path: ${{ runner.temp }}/digests
|
||||||
pattern: ml-digests-${{ matrix.device }}-*
|
pattern: ml-digests-${{ matrix.device }}-*
|
||||||
@@ -245,26 +231,26 @@ jobs:
|
|||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
if: ${{ github.event_name == 'release' }}
|
if: ${{ github.event_name == 'release' }}
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GHCR
|
- name: Login to GHCR
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Generate docker image tags
|
- name: Generate docker image tags
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
|
uses: docker/metadata-action@v5
|
||||||
env:
|
env:
|
||||||
DOCKER_METADATA_PR_HEAD_SHA: 'true'
|
DOCKER_METADATA_PR_HEAD_SHA: "true"
|
||||||
with:
|
with:
|
||||||
flavor: |
|
flavor: |
|
||||||
# Disable latest tag
|
# Disable latest tag
|
||||||
@@ -315,13 +301,13 @@ jobs:
|
|||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
@@ -348,7 +334,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
uses: docker/build-push-action@v6.15.0
|
||||||
with:
|
with:
|
||||||
context: ${{ env.context }}
|
context: ${{ env.context }}
|
||||||
file: ${{ env.file }}
|
file: ${{ env.file }}
|
||||||
@@ -373,7 +359,7 @@ jobs:
|
|||||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||||
|
|
||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: server-digests-${{ env.PLATFORM_PAIR }}
|
name: server-digests-${{ env.PLATFORM_PAIR }}
|
||||||
path: ${{ runner.temp }}/digests/*
|
path: ${{ runner.temp }}/digests/*
|
||||||
@@ -391,7 +377,7 @@ jobs:
|
|||||||
- build_and_push_server
|
- build_and_push_server
|
||||||
steps:
|
steps:
|
||||||
- name: Download digests
|
- name: Download digests
|
||||||
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ runner.temp }}/digests
|
path: ${{ runner.temp }}/digests
|
||||||
pattern: server-digests-*
|
pattern: server-digests-*
|
||||||
@@ -399,26 +385,26 @@ jobs:
|
|||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
if: ${{ github.event_name == 'release' }}
|
if: ${{ github.event_name == 'release' }}
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GHCR
|
- name: Login to GHCR
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Generate docker image tags
|
- name: Generate docker image tags
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
|
uses: docker/metadata-action@v5
|
||||||
env:
|
env:
|
||||||
DOCKER_METADATA_PR_HEAD_SHA: 'true'
|
DOCKER_METADATA_PR_HEAD_SHA: "true"
|
||||||
with:
|
with:
|
||||||
flavor: |
|
flavor: |
|
||||||
# Disable latest tag
|
# Disable latest tag
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
|
||||||
@@ -17,9 +18,9 @@ jobs:
|
|||||||
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
- id: found_paths
|
- id: found_paths
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
|
uses: dorny/paths-filter@v3
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
docs:
|
docs:
|
||||||
@@ -41,10 +42,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './docs/.nvmrc'
|
node-version-file: './docs/.nvmrc'
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Upload build output
|
- name: Upload build output
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: docs-build-output
|
name: docs-build-output
|
||||||
path: docs/build/
|
path: docs/build/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: Docs deploy
|
name: Docs deploy
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ['Docs build']
|
workflows: ["Docs build"]
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
run: echo 'The triggering workflow did not succeed' && exit 1
|
run: echo 'The triggering workflow did not succeed' && exit 1
|
||||||
- name: Get artifact
|
- name: Get artifact
|
||||||
id: get-artifact
|
id: get-artifact
|
||||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
return { found: true, id: matchArtifact.id };
|
return { found: true, id: matchArtifact.id };
|
||||||
- name: Determine deploy parameters
|
- name: Determine deploy parameters
|
||||||
id: parameters
|
id: parameters
|
||||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const eventType = context.payload.workflow_run.event;
|
const eventType = context.payload.workflow_run.event;
|
||||||
@@ -98,11 +98,11 @@ jobs:
|
|||||||
if: ${{ fromJson(needs.checks.outputs.artifact).found && fromJson(needs.checks.outputs.parameters).shouldDeploy }}
|
if: ${{ fromJson(needs.checks.outputs.artifact).found && fromJson(needs.checks.outputs.parameters).shouldDeploy }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Load parameters
|
- name: Load parameters
|
||||||
id: parameters
|
id: parameters
|
||||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const json = `${{ needs.checks.outputs.parameters }}`;
|
const json = `${{ needs.checks.outputs.parameters }}`;
|
||||||
@@ -115,7 +115,7 @@ jobs:
|
|||||||
echo "Starting docs deployment for ${{ steps.parameters.outputs.event }} ${{ steps.parameters.outputs.name }}"
|
echo "Starting docs deployment for ${{ steps.parameters.outputs.event }} ${{ steps.parameters.outputs.name }}"
|
||||||
|
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
let artifact = ${{ needs.checks.outputs.artifact }};
|
let artifact = ${{ needs.checks.outputs.artifact }};
|
||||||
@@ -138,12 +138,12 @@ jobs:
|
|||||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
||||||
uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
|
uses: gruntwork-io/terragrunt-action@v2
|
||||||
with:
|
with:
|
||||||
tg_version: '0.58.12'
|
tg_version: "0.58.12"
|
||||||
tofu_version: '1.7.1'
|
tofu_version: "1.7.1"
|
||||||
tg_dir: 'deployment/modules/cloudflare/docs'
|
tg_dir: "deployment/modules/cloudflare/docs"
|
||||||
tg_command: 'apply'
|
tg_command: "apply"
|
||||||
|
|
||||||
- name: Deploy Docs Subdomain Output
|
- name: Deploy Docs Subdomain Output
|
||||||
id: docs-output
|
id: docs-output
|
||||||
@@ -153,12 +153,12 @@ jobs:
|
|||||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
||||||
uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
|
uses: gruntwork-io/terragrunt-action@v2
|
||||||
with:
|
with:
|
||||||
tg_version: '0.58.12'
|
tg_version: "0.58.12"
|
||||||
tofu_version: '1.7.1'
|
tofu_version: "1.7.1"
|
||||||
tg_dir: 'deployment/modules/cloudflare/docs'
|
tg_dir: "deployment/modules/cloudflare/docs"
|
||||||
tg_command: 'output -json'
|
tg_command: "output -json"
|
||||||
|
|
||||||
- name: Output Cleaning
|
- name: Output Cleaning
|
||||||
id: clean
|
id: clean
|
||||||
@@ -167,13 +167,13 @@ jobs:
|
|||||||
echo "output=$TG_OUT" >> $GITHUB_OUTPUT
|
echo "output=$TG_OUT" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Publish to Cloudflare Pages
|
- name: Publish to Cloudflare Pages
|
||||||
uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca # v1
|
uses: cloudflare/pages-action@v1
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN_PAGES_UPLOAD }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN_PAGES_UPLOAD }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
projectName: ${{ fromJson(steps.clean.outputs.output).pages_project_name.value }}
|
projectName: ${{ fromJson(steps.clean.outputs.output).pages_project_name.value }}
|
||||||
workingDirectory: 'docs'
|
workingDirectory: "docs"
|
||||||
directory: 'build'
|
directory: "build"
|
||||||
branch: ${{ steps.parameters.outputs.name }}
|
branch: ${{ steps.parameters.outputs.name }}
|
||||||
wranglerVersion: '3'
|
wranglerVersion: '3'
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ jobs:
|
|||||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
||||||
uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
|
uses: gruntwork-io/terragrunt-action@v2
|
||||||
with:
|
with:
|
||||||
tg_version: '0.58.12'
|
tg_version: '0.58.12'
|
||||||
tofu_version: '1.7.1'
|
tofu_version: '1.7.1'
|
||||||
@@ -192,7 +192,7 @@ jobs:
|
|||||||
tg_command: 'apply'
|
tg_command: 'apply'
|
||||||
|
|
||||||
- name: Comment
|
- name: Comment
|
||||||
uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b # v3
|
uses: actions-cool/maintain-one-comment@v3
|
||||||
if: ${{ steps.parameters.outputs.event == 'pr' }}
|
if: ${{ steps.parameters.outputs.event == 'pr' }}
|
||||||
with:
|
with:
|
||||||
number: ${{ fromJson(needs.checks.outputs.parameters).pr_number }}
|
number: ${{ fromJson(needs.checks.outputs.parameters).pr_number }}
|
||||||
|
|||||||
@@ -9,24 +9,24 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Destroy Docs Subdomain
|
- name: Destroy Docs Subdomain
|
||||||
env:
|
env:
|
||||||
TF_VAR_prefix_name: 'pr-${{ github.event.number }}'
|
TF_VAR_prefix_name: "pr-${{ github.event.number }}"
|
||||||
TF_VAR_prefix_event_type: 'pr'
|
TF_VAR_prefix_event_type: "pr"
|
||||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
||||||
uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
|
uses: gruntwork-io/terragrunt-action@v2
|
||||||
with:
|
with:
|
||||||
tg_version: '0.58.12'
|
tg_version: "0.58.12"
|
||||||
tofu_version: '1.7.1'
|
tofu_version: "1.7.1"
|
||||||
tg_dir: 'deployment/modules/cloudflare/docs'
|
tg_dir: "deployment/modules/cloudflare/docs"
|
||||||
tg_command: 'destroy -refresh=false'
|
tg_command: "destroy -refresh=false"
|
||||||
|
|
||||||
- name: Comment
|
- name: Comment
|
||||||
uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b # v3
|
uses: actions-cool/maintain-one-comment@v3
|
||||||
with:
|
with:
|
||||||
number: ${{ github.event.number }}
|
number: ${{ github.event.number }}
|
||||||
delete: true
|
delete: true
|
||||||
|
|||||||
@@ -13,19 +13,19 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Generate a token
|
- name: Generate a token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1
|
uses: actions/create-github-app-token@v1
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
||||||
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
||||||
|
|
||||||
- name: 'Checkout'
|
- name: 'Checkout'
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.ref }}
|
ref: ${{ github.event.pull_request.head.ref }}
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
@@ -33,13 +33,13 @@ jobs:
|
|||||||
run: make install-all && make format-all
|
run: make install-all && make format-all
|
||||||
|
|
||||||
- name: Commit and push
|
- name: Commit and push
|
||||||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9
|
uses: EndBug/add-and-commit@v9
|
||||||
with:
|
with:
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
message: 'chore: fix formatting'
|
message: 'chore: fix formatting'
|
||||||
|
|
||||||
- name: Remove label
|
- name: Remove label
|
||||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
uses: actions/github-script@v7
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
@@ -49,3 +49,4 @@ jobs:
|
|||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
name: 'fix:formatting'
|
name: 'fix:formatting'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Require PR to have a changelog label
|
- name: Require PR to have a changelog label
|
||||||
uses: mheap/github-action-required-labels@388fd6af37b34cdfe5a23b37060e763217e58b03 # v5
|
uses: mheap/github-action-required-labels@v5
|
||||||
with:
|
with:
|
||||||
mode: exactly
|
mode: exactly
|
||||||
count: 1
|
count: 1
|
||||||
use_regex: true
|
use_regex: true
|
||||||
labels: 'changelog:.*'
|
labels: "changelog:.*"
|
||||||
add_comment: true
|
add_comment: true
|
||||||
message: 'Label error. Requires {{errorString}} {{count}} of: {{ provided }}. Found: {{ applied }}. A maintainer will add the required label.'
|
message: "Label error. Requires {{errorString}} {{count}} of: {{ provided }}. Found: {{ applied }}. A maintainer will add the required label."
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: 'Pull Request Labeler'
|
name: "Pull Request Labeler"
|
||||||
on:
|
on:
|
||||||
- pull_request_target
|
- pull_request_target
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
labeler:
|
labeler:
|
||||||
@@ -9,4 +9,4 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5
|
- uses: actions/labeler@v5
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: PR Conventional Commit Validation
|
- name: PR Conventional Commit Validation
|
||||||
uses: ytanikin/PRConventionalCommits@1.3.0
|
uses: ytanikin/PRConventionalCommits@1.3.0
|
||||||
with:
|
with:
|
||||||
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]'
|
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]'
|
||||||
add_label: 'false'
|
add_label: 'false'
|
||||||
|
|||||||
@@ -31,25 +31,25 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Generate a token
|
- name: Generate a token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1
|
uses: actions/create-github-app-token@v1
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
||||||
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
|
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v5
|
uses: astral-sh/setup-uv@v5
|
||||||
|
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
run: misc/release/pump-version.sh -s "${{ inputs.serverBump }}" -m "${{ inputs.mobileBump }}"
|
run: misc/release/pump-version.sh -s "${{ inputs.serverBump }}" -m "${{ inputs.mobileBump }}"
|
||||||
|
|
||||||
- name: Commit and tag
|
- name: Commit and tag
|
||||||
id: push-tag
|
id: push-tag
|
||||||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9
|
uses: EndBug/add-and-commit@v9
|
||||||
with:
|
with:
|
||||||
default_author: github_actions
|
default_author: github_actions
|
||||||
message: 'chore: version ${{ env.IMMICH_VERSION }}'
|
message: 'chore: version ${{ env.IMMICH_VERSION }}'
|
||||||
@@ -70,23 +70,23 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Generate a token
|
- name: Generate a token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1
|
uses: actions/create-github-app-token@v1
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
||||||
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ steps.generate-token.outputs.token }}
|
||||||
|
|
||||||
- name: Download APK
|
- name: Download APK
|
||||||
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-apk-signed
|
name: release-apk-signed
|
||||||
|
|
||||||
- name: Create draft release
|
- name: Create draft release
|
||||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
tag_name: ${{ env.IMMICH_VERSION }}
|
tag_name: ${{ env.IMMICH_VERSION }}
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2
|
- uses: mshick/add-pr-comment@v2
|
||||||
with:
|
with:
|
||||||
message-id: 'preview-status'
|
message-id: "preview-status"
|
||||||
message: 'Deploying preview environment to https://pr-${{ github.event.pull_request.number }}.preview.internal.immich.cloud/'
|
message: "Deploying preview environment to https://pr-${{ github.event.pull_request.number }}.preview.internal.immich.cloud/"
|
||||||
|
|
||||||
remove-label:
|
remove-label:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
- uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
github.rest.issues.removeLabel({
|
github.rest.issues.removeLabel({
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
working-directory: ./open-api/typescript-sdk
|
working-directory: ./open-api/typescript-sdk
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@v4
|
||||||
# Setup .npmrc file to publish to npm
|
# Setup .npmrc file to publish to npm
|
||||||
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ jobs:
|
|||||||
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
- id: found_paths
|
- id: found_paths
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
|
uses: dorny/paths-filter@v3
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
mobile:
|
mobile:
|
||||||
@@ -38,10 +38,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
working-directory: ./mobile
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Find file changes
|
- name: Find file changes
|
||||||
uses: tj-actions/verify-changed-files@6ed7632824d235029086612d4330d659005af687 # v20
|
uses: tj-actions/verify-changed-files@v20
|
||||||
id: verify-changed-files
|
id: verify-changed-files
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
|
|||||||
+31
-59
@@ -21,12 +21,11 @@ jobs:
|
|||||||
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
should_run_e2e_web: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.web == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run_e2e_web: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.web == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
should_run_e2e_server_cli: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.server == 'true' || steps.found_paths.outputs.cli == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
should_run_e2e_server_cli: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.server == 'true' || steps.found_paths.outputs.cli == 'true' || steps.should_force.outputs.should_force == 'true' }}
|
||||||
should_run_.github: ${{ steps.found_paths.outputs['.github'] == 'true' || steps.should_force.outputs.should_force == 'true' }} # redundant to have should_force but if someone changes the trigger then this won't have to be changed
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
- id: found_paths
|
- id: found_paths
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
|
uses: dorny/paths-filter@v3
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
web:
|
web:
|
||||||
@@ -46,8 +45,6 @@ jobs:
|
|||||||
- 'machine-learning/**'
|
- 'machine-learning/**'
|
||||||
workflow:
|
workflow:
|
||||||
- '.github/workflows/test.yml'
|
- '.github/workflows/test.yml'
|
||||||
.github:
|
|
||||||
- '.github/**'
|
|
||||||
|
|
||||||
- name: Check if we should force jobs to run
|
- name: Check if we should force jobs to run
|
||||||
id: should_force
|
id: should_force
|
||||||
@@ -64,10 +61,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
@@ -101,10 +98,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
|
|
||||||
@@ -142,10 +139,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
|
|
||||||
@@ -176,10 +173,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './web/.nvmrc'
|
node-version-file: './web/.nvmrc'
|
||||||
|
|
||||||
@@ -221,10 +218,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
|
|
||||||
@@ -260,10 +257,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
@@ -285,12 +282,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
|
|
||||||
@@ -327,12 +324,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
|
|
||||||
@@ -363,9 +360,9 @@ jobs:
|
|||||||
if: ${{ needs.pre-job.outputs.should_run_mobile == 'true' }}
|
if: ${{ needs.pre-job.outputs.should_run_mobile == 'true' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
@@ -382,10 +379,10 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
working-directory: ./machine-learning
|
working-directory: ./machine-learning
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # v5
|
uses: astral-sh/setup-uv@v5
|
||||||
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5
|
- uses: actions/setup-python@v5
|
||||||
# TODO: add caching when supported (https://github.com/actions/setup-python/pull/818)
|
# TODO: add caching when supported (https://github.com/actions/setup-python/pull/818)
|
||||||
# with:
|
# with:
|
||||||
# python-version: 3.11
|
# python-version: 3.11
|
||||||
@@ -406,36 +403,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
uv run pytest app --cov=app --cov-report term-missing
|
uv run pytest app --cov=app --cov-report term-missing
|
||||||
|
|
||||||
github-files-formatting:
|
|
||||||
name: .github Files Formatting
|
|
||||||
needs: pre-job
|
|
||||||
if: ${{ needs.pre-job.outputs['should_run_.github'] == 'true' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: ./.github
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: './.github/.nvmrc'
|
|
||||||
|
|
||||||
- name: Run npm install
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run formatter
|
|
||||||
run: npm run format
|
|
||||||
if: ${{ !cancelled() }}
|
|
||||||
|
|
||||||
shellcheck:
|
shellcheck:
|
||||||
name: ShellCheck
|
name: ShellCheck
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@v4
|
||||||
- name: Run ShellCheck
|
- name: Run ShellCheck
|
||||||
uses: ludeeus/action-shellcheck@master
|
uses: ludeeus/action-shellcheck@master
|
||||||
with:
|
with:
|
||||||
@@ -449,10 +421,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
@@ -466,7 +438,7 @@ jobs:
|
|||||||
run: make open-api
|
run: make open-api
|
||||||
|
|
||||||
- name: Find file changes
|
- name: Find file changes
|
||||||
uses: tj-actions/verify-changed-files@6ed7632824d235029086612d4330d659005af687 # v20
|
uses: tj-actions/verify-changed-files@v20
|
||||||
id: verify-changed-files
|
id: verify-changed-files
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
@@ -504,10 +476,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
@@ -528,7 +500,7 @@ jobs:
|
|||||||
run: npm run typeorm:migrations:generate ./src/migrations/TestMigration
|
run: npm run typeorm:migrations:generate ./src/migrations/TestMigration
|
||||||
|
|
||||||
- name: Find file changes
|
- name: Find file changes
|
||||||
uses: tj-actions/verify-changed-files@6ed7632824d235029086612d4330d659005af687 # v20
|
uses: tj-actions/verify-changed-files@v20
|
||||||
id: verify-changed-files
|
id: verify-changed-files
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
@@ -547,7 +519,7 @@ jobs:
|
|||||||
DB_URL: postgres://postgres:postgres@localhost:5432/immich
|
DB_URL: postgres://postgres:postgres@localhost:5432/immich
|
||||||
|
|
||||||
- name: Find file changes
|
- name: Find file changes
|
||||||
uses: tj-actions/verify-changed-files@6ed7632824d235029086612d4330d659005af687 # v20
|
uses: tj-actions/verify-changed-files@v20
|
||||||
id: verify-changed-sql-files
|
id: verify-changed-sql-files
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
|
|||||||
@@ -11,22 +11,22 @@ jobs:
|
|||||||
should_run: ${{ steps.found_paths.outputs.i18n == 'true' && github.head_ref != 'chore/translations'}}
|
should_run: ${{ steps.found_paths.outputs.i18n == 'true' && github.head_ref != 'chore/translations'}}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@v4
|
||||||
- id: found_paths
|
- id: found_paths
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
|
uses: dorny/paths-filter@v3
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
i18n:
|
i18n:
|
||||||
- 'i18n/!(en)**\.json'
|
- 'i18n/!(en)**\.json'
|
||||||
- name: Debug
|
- name: Debug
|
||||||
run: |
|
run: |
|
||||||
echo "Should run: ${{ steps.found_paths.outputs.i18n == 'true' && github.head_ref != 'chore/translations'}}"
|
echo "Should run: ${{ steps.found_paths.outputs.i18n == 'true' && github.head_ref != 'chore/translations'}}"
|
||||||
echo "Found i18n paths: ${{ steps.found_paths.outputs.i18n }}"
|
echo "Found i18n paths: ${{ steps.found_paths.outputs.i18n }}"
|
||||||
echo "Head ref: ${{ github.head_ref }}"
|
echo "Head ref: ${{ github.head_ref }}"
|
||||||
|
|
||||||
enforce-lock:
|
enforce-lock:
|
||||||
name: Check Weblate Lock
|
name: Check Weblate Lock
|
||||||
needs: [pre-job]
|
needs: [ pre-job ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ needs.pre-job.outputs.should_run == 'true' }}
|
if: ${{ needs.pre-job.outputs.should_run == 'true' }}
|
||||||
steps:
|
steps:
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
- name: Find Pull Request
|
- name: Find Pull Request
|
||||||
uses: juliangruber/find-pull-request-action@48b6133aa6c826f267ebd33aa2d29470f9d9e7d0 # v1
|
uses: juliangruber/find-pull-request-action@v1
|
||||||
id: find-pr
|
id: find-pr
|
||||||
with:
|
with:
|
||||||
branch: chore/translations
|
branch: chore/translations
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
run: exit 1
|
run: exit 1
|
||||||
success-check-lock:
|
success-check-lock:
|
||||||
name: Weblate Lock Check Success
|
name: Weblate Lock Check Success
|
||||||
needs: [enforce-lock]
|
needs: [ enforce-lock ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ attach-server:
|
|||||||
renovate:
|
renovate:
|
||||||
LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset
|
LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset
|
||||||
|
|
||||||
MODULES = e2e server web cli sdk docs .github
|
MODULES = e2e server web cli sdk docs
|
||||||
|
|
||||||
audit-%:
|
audit-%:
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
||||||
@@ -77,14 +77,14 @@ test-medium:
|
|||||||
test-medium-dev:
|
test-medium-dev:
|
||||||
docker exec -it immich_server /bin/sh -c "npm run test:medium"
|
docker exec -it immich_server /bin/sh -c "npm run test:medium"
|
||||||
|
|
||||||
build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
|
build-all: $(foreach M,$(filter-out e2e,$(MODULES)),build-$M) ;
|
||||||
install-all: $(foreach M,$(MODULES),install-$M) ;
|
install-all: $(foreach M,$(MODULES),install-$M) ;
|
||||||
check-all: $(foreach M,$(filter-out sdk cli docs .github,$(MODULES)),check-$M) ;
|
check-all: $(foreach M,$(filter-out sdk cli docs,$(MODULES)),check-$M) ;
|
||||||
lint-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),lint-$M) ;
|
lint-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),lint-$M) ;
|
||||||
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
|
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
|
||||||
audit-all: $(foreach M,$(MODULES),audit-$M) ;
|
audit-all: $(foreach M,$(MODULES),audit-$M) ;
|
||||||
hygiene-all: lint-all format-all check-all sql audit-all;
|
hygiene-all: lint-all format-all check-all sql audit-all;
|
||||||
test-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),test-$M) ;
|
test-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),test-$M) ;
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
||||||
|
|||||||
Generated
+58
-69
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.54",
|
"version": "2.2.53",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.54",
|
"version": "2.2.53",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^4.0.3",
|
"chokidar": "^4.0.3",
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
||||||
"@typescript-eslint/parser": "^8.15.0",
|
"@typescript-eslint/parser": "^8.15.0",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
@@ -55,14 +55,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.130.0",
|
"version": "1.129.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.9",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -809,16 +809,6 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-helpers": {
|
|
||||||
"version": "0.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz",
|
|
||||||
"integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@eslint/core": {
|
"node_modules/@eslint/core": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
|
||||||
@@ -894,9 +884,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.22.0",
|
"version": "9.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
|
||||||
"integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==",
|
"integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1528,17 +1518,17 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz",
|
||||||
"integrity": "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==",
|
"integrity": "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.26.1",
|
"@typescript-eslint/scope-manager": "8.26.0",
|
||||||
"@typescript-eslint/type-utils": "8.26.1",
|
"@typescript-eslint/type-utils": "8.26.0",
|
||||||
"@typescript-eslint/utils": "8.26.1",
|
"@typescript-eslint/utils": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1",
|
"@typescript-eslint/visitor-keys": "8.26.0",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1558,16 +1548,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.0.tgz",
|
||||||
"integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==",
|
"integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.26.1",
|
"@typescript-eslint/scope-manager": "8.26.0",
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.26.1",
|
"@typescript-eslint/typescript-estree": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1",
|
"@typescript-eslint/visitor-keys": "8.26.0",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1583,14 +1573,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz",
|
||||||
"integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==",
|
"integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1"
|
"@typescript-eslint/visitor-keys": "8.26.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1601,14 +1591,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz",
|
||||||
"integrity": "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==",
|
"integrity": "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.26.1",
|
"@typescript-eslint/typescript-estree": "8.26.0",
|
||||||
"@typescript-eslint/utils": "8.26.1",
|
"@typescript-eslint/utils": "8.26.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.0.1"
|
"ts-api-utils": "^2.0.1"
|
||||||
},
|
},
|
||||||
@@ -1625,9 +1615,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.0.tgz",
|
||||||
"integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==",
|
"integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1639,14 +1629,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz",
|
||||||
"integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==",
|
"integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1",
|
"@typescript-eslint/visitor-keys": "8.26.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -1666,16 +1656,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.0.tgz",
|
||||||
"integrity": "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==",
|
"integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "8.26.1",
|
"@typescript-eslint/scope-manager": "8.26.0",
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.26.1"
|
"@typescript-eslint/typescript-estree": "8.26.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1690,13 +1680,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz",
|
||||||
"integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==",
|
"integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2379,19 +2369,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.22.0",
|
"version": "9.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
|
||||||
"integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==",
|
"integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.19.2",
|
"@eslint/config-array": "^0.19.2",
|
||||||
"@eslint/config-helpers": "^0.1.0",
|
|
||||||
"@eslint/core": "^0.12.0",
|
"@eslint/core": "^0.12.0",
|
||||||
"@eslint/eslintrc": "^3.3.0",
|
"@eslint/eslintrc": "^3.3.0",
|
||||||
"@eslint/js": "9.22.0",
|
"@eslint/js": "9.21.0",
|
||||||
"@eslint/plugin-kit": "^0.2.7",
|
"@eslint/plugin-kit": "^0.2.7",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@@ -2403,7 +2392,7 @@
|
|||||||
"cross-spawn": "^7.0.6",
|
"cross-spawn": "^7.0.6",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^8.3.0",
|
"eslint-scope": "^8.2.0",
|
||||||
"eslint-visitor-keys": "^4.2.0",
|
"eslint-visitor-keys": "^4.2.0",
|
||||||
"espree": "^10.3.0",
|
"espree": "^10.3.0",
|
||||||
"esquery": "^1.5.0",
|
"esquery": "^1.5.0",
|
||||||
@@ -2531,9 +2520,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
"version": "8.3.0",
|
"version": "8.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
|
||||||
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
"integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.54",
|
"version": "2.2.53",
|
||||||
"description": "Command Line Interface (CLI) for Immich",
|
"description": "Command Line Interface (CLI) for Immich",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./dist/index.js",
|
"exports": "./dist/index.js",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
||||||
"@typescript-eslint/parser": "^8.15.0",
|
"@typescript-eslint/parser": "^8.15.0",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
|
|||||||
@@ -95,12 +95,12 @@ services:
|
|||||||
image: immich-machine-learning-dev:latest
|
image: immich-machine-learning-dev:latest
|
||||||
# extends:
|
# extends:
|
||||||
# file: hwaccel.ml.yml
|
# file: hwaccel.ml.yml
|
||||||
# service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
|
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference
|
||||||
build:
|
build:
|
||||||
context: ../machine-learning
|
context: ../machine-learning
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
args:
|
||||||
- DEVICE=cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
|
- DEVICE=cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference
|
||||||
ports:
|
ports:
|
||||||
- 3003:3003
|
- 3003:3003
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ services:
|
|||||||
image: immich-machine-learning:latest
|
image: immich-machine-learning:latest
|
||||||
# extends:
|
# extends:
|
||||||
# file: hwaccel.ml.yml
|
# file: hwaccel.ml.yml
|
||||||
# service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
|
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference
|
||||||
build:
|
build:
|
||||||
context: ../machine-learning
|
context: ../machine-learning
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
args:
|
||||||
- DEVICE=cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
|
- DEVICE=cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference
|
||||||
ports:
|
ports:
|
||||||
- 3003:3003
|
- 3003:3003
|
||||||
volumes:
|
volumes:
|
||||||
@@ -77,12 +77,22 @@ services:
|
|||||||
- 5432:5432
|
- 5432:5432
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: >-
|
test: >-
|
||||||
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1;
|
||||||
|
Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align
|
||||||
|
--command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')";
|
||||||
|
echo "checksum failure count is $$Chksum";
|
||||||
|
[ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
command: >-
|
command: >-
|
||||||
postgres -c shared_preload_libraries=vectors.so -c 'search_path="$$user", public, vectors' -c logging_collector=on -c max_wal_size=2GB -c shared_buffers=512MB -c wal_compression=on
|
postgres
|
||||||
|
-c shared_preload_libraries=vectors.so
|
||||||
|
-c 'search_path="$$user", public, vectors'
|
||||||
|
-c logging_collector=on
|
||||||
|
-c max_wal_size=2GB
|
||||||
|
-c shared_buffers=512MB
|
||||||
|
-c wal_compression=on
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
||||||
@@ -90,7 +100,7 @@ services:
|
|||||||
container_name: immich_prometheus
|
container_name: immich_prometheus
|
||||||
ports:
|
ports:
|
||||||
- 9090:9090
|
- 9090:9090
|
||||||
image: prom/prometheus@sha256:502ad90314c7485892ce696cb14a99fceab9fc27af29f4b427f41bd39701a199
|
image: prom/prometheus@sha256:6927e0919a144aa7616fd0137d4816816d42f6b816de3af269ab065250859a62
|
||||||
volumes:
|
volumes:
|
||||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
- prometheus-data:/prometheus
|
- prometheus-data:/prometheus
|
||||||
@@ -99,7 +109,7 @@ services:
|
|||||||
# add data source for http://immich-prometheus:9090 to get started
|
# add data source for http://immich-prometheus:9090 to get started
|
||||||
immich-grafana:
|
immich-grafana:
|
||||||
container_name: immich_grafana
|
container_name: immich_grafana
|
||||||
command: [ './run.sh', '-disable-reporting' ]
|
command: ['./run.sh', '-disable-reporting']
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
image: grafana/grafana:11.5.2-ubuntu@sha256:8b5858c447e06fd7a89006b562ba7bba7c4d5813600c7982374c41852adefaeb
|
image: grafana/grafana:11.5.2-ubuntu@sha256:8b5858c447e06fd7a89006b562ba7bba7c4d5813600c7982374c41852adefaeb
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ services:
|
|||||||
|
|
||||||
immich-machine-learning:
|
immich-machine-learning:
|
||||||
container_name: immich_machine_learning
|
container_name: immich_machine_learning
|
||||||
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
|
# For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
|
||||||
# Example tag: ${IMMICH_VERSION:-release}-cuda
|
# Example tag: ${IMMICH_VERSION:-release}-cuda
|
||||||
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
|
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
|
||||||
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
|
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
|
||||||
# file: hwaccel.ml.yml
|
# file: hwaccel.ml.yml
|
||||||
# service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
|
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
|
||||||
volumes:
|
volumes:
|
||||||
- model-cache:/cache
|
- model-cache:/cache
|
||||||
env_file:
|
env_file:
|
||||||
@@ -67,12 +67,22 @@ services:
|
|||||||
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: >-
|
test: >-
|
||||||
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1;
|
||||||
|
Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align
|
||||||
|
--command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')";
|
||||||
|
echo "checksum failure count is $$Chksum";
|
||||||
|
[ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
command: >-
|
command: >-
|
||||||
postgres -c shared_preload_libraries=vectors.so -c 'search_path="$$user", public, vectors' -c logging_collector=on -c max_wal_size=2GB -c shared_buffers=512MB -c wal_compression=on
|
postgres
|
||||||
|
-c shared_preload_libraries=vectors.so
|
||||||
|
-c 'search_path="$$user", public, vectors'
|
||||||
|
-c logging_collector=on
|
||||||
|
-c max_wal_size=2GB
|
||||||
|
-c shared_buffers=512MB
|
||||||
|
-c wal_compression=on
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -13,13 +13,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /lib/firmware/mali_csffw.bin:/lib/firmware/mali_csffw.bin:ro # Mali firmware for your chipset (not always required depending on the driver)
|
- /lib/firmware/mali_csffw.bin:/lib/firmware/mali_csffw.bin:ro # Mali firmware for your chipset (not always required depending on the driver)
|
||||||
- /usr/lib/libmali.so:/usr/lib/libmali.so:ro # Mali driver for your chipset (always required)
|
- /usr/lib/libmali.so:/usr/lib/libmali.so:ro # Mali driver for your chipset (always required)
|
||||||
|
|
||||||
rknn:
|
|
||||||
security_opt:
|
|
||||||
- systempaths=unconfined
|
|
||||||
- apparmor=unconfined
|
|
||||||
devices:
|
|
||||||
- /dev/dri:/dev/dri
|
|
||||||
|
|
||||||
cpu: {}
|
cpu: {}
|
||||||
|
|
||||||
@@ -33,13 +26,6 @@ services:
|
|||||||
capabilities:
|
capabilities:
|
||||||
- gpu
|
- gpu
|
||||||
|
|
||||||
rocm:
|
|
||||||
group_add:
|
|
||||||
- video
|
|
||||||
devices:
|
|
||||||
- /dev/dri:/dev/dri
|
|
||||||
- /dev/kfd:/dev/kfd
|
|
||||||
|
|
||||||
openvino:
|
openvino:
|
||||||
device_cgroup_rules:
|
device_cgroup_rules:
|
||||||
- 'c 189:* rmw'
|
- 'c 189:* rmw'
|
||||||
|
|||||||
+1
-1
@@ -262,7 +262,7 @@ No, this is not supported. Only models listed in the [Hugging Face][huggingface]
|
|||||||
|
|
||||||
### I want to be able to search in other languages besides English. How can I do that?
|
### I want to be able to search in other languages besides English. How can I do that?
|
||||||
|
|
||||||
You can change to a multilingual CLIP model. See [here](/docs/features/searching#clip-models) for instructions.
|
You can change to a multilingual CLIP model. See [here](/docs/features/searching#clip-model) for instructions.
|
||||||
|
|
||||||
### Does Immich support Facial Recognition for videos?
|
### Does Immich support Facial Recognition for videos?
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ The `immich-server` docker image comes preinstalled with an administrative CLI (
|
|||||||
| `enable-oauth-login` | Enable OAuth login |
|
| `enable-oauth-login` | Enable OAuth login |
|
||||||
| `disable-oauth-login` | Disable OAuth login |
|
| `disable-oauth-login` | Disable OAuth login |
|
||||||
| `list-users` | List Immich users |
|
| `list-users` | List Immich users |
|
||||||
| `version` | Print Immich version |
|
|
||||||
|
|
||||||
## How to run a command
|
## How to run a command
|
||||||
|
|
||||||
@@ -81,10 +80,3 @@ immich-admin list-users
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
Print Immich Version
|
|
||||||
|
|
||||||
```
|
|
||||||
immich-admin version
|
|
||||||
v1.129.0
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ The `immich-server` container will need access to the gallery. Modify your docke
|
|||||||
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
|
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
|
||||||
+ - /home/user/old-pics:/mnt/media/old-pics:ro
|
+ - /home/user/old-pics:/mnt/media/old-pics:ro
|
||||||
+ - /mnt/media/videos:/mnt/media/videos:ro
|
+ - /mnt/media/videos:/mnt/media/videos:ro
|
||||||
+ - /mnt/media/videos2:/mnt/media/videos2 # WARNING: Immich will be able to delete the files in this folder, as it does not end with :ro
|
+ - /mnt/media/videos2:/mnt/media/videos2 # the files in this folder can be deleted, as it does not end with :ro
|
||||||
+ - "C:/Users/user_name/Desktop/my media:/mnt/media/my-media:ro" # import path in Windows system.
|
+ - "C:/Users/user_name/Desktop/my media:/mnt/media/my-media:ro" # import path in Windows system.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ You do not need to redo any machine learning jobs after enabling hardware accele
|
|||||||
|
|
||||||
- ARM NN (Mali)
|
- ARM NN (Mali)
|
||||||
- CUDA (NVIDIA GPUs with [compute capability](https://developer.nvidia.com/cuda-gpus) 5.2 or higher)
|
- CUDA (NVIDIA GPUs with [compute capability](https://developer.nvidia.com/cuda-gpus) 5.2 or higher)
|
||||||
- ROCm (AMD GPUs)
|
|
||||||
- OpenVINO (Intel GPUs such as Iris Xe and Arc)
|
- OpenVINO (Intel GPUs such as Iris Xe and Arc)
|
||||||
- RKNN (Rockchip)
|
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
@@ -21,7 +19,6 @@ You do not need to redo any machine learning jobs after enabling hardware accele
|
|||||||
- Only Linux and Windows (through WSL2) servers are supported.
|
- Only Linux and Windows (through WSL2) servers are supported.
|
||||||
- ARM NN is only supported on devices with Mali GPUs. Other Arm devices are not supported.
|
- ARM NN is only supported on devices with Mali GPUs. Other Arm devices are not supported.
|
||||||
- Some models may not be compatible with certain backends. CUDA is the most reliable.
|
- Some models may not be compatible with certain backends. CUDA is the most reliable.
|
||||||
- Search latency isn't improved by ARM NN due to model compatibility issues preventing its use. However, smart search jobs do make use of ARM NN.
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -36,7 +33,6 @@ You do not need to redo any machine learning jobs after enabling hardware accele
|
|||||||
- The `hwaccel.ml.yml` file assumes the path to it is `/usr/lib/libmali.so`, so update accordingly if it is elsewhere
|
- The `hwaccel.ml.yml` file assumes the path to it is `/usr/lib/libmali.so`, so update accordingly if it is elsewhere
|
||||||
- The `hwaccel.ml.yml` file assumes an additional file `/lib/firmware/mali_csffw.bin`, so update accordingly if your device's driver does not require this file
|
- The `hwaccel.ml.yml` file assumes an additional file `/lib/firmware/mali_csffw.bin`, so update accordingly if your device's driver does not require this file
|
||||||
- Optional: Configure your `.env` file, see [environment variables](/docs/install/environment-variables) for ARM NN specific settings
|
- Optional: Configure your `.env` file, see [environment variables](/docs/install/environment-variables) for ARM NN specific settings
|
||||||
- In particular, the `MACHINE_LEARNING_ANN_FP16_TURBO` can significantly improve performance at the cost of very slightly lower accuracy
|
|
||||||
|
|
||||||
#### CUDA
|
#### CUDA
|
||||||
|
|
||||||
@@ -45,38 +41,22 @@ You do not need to redo any machine learning jobs after enabling hardware accele
|
|||||||
- The installed driver must be >= 535 (it must support CUDA 12.2).
|
- The installed driver must be >= 535 (it must support CUDA 12.2).
|
||||||
- On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed.
|
- On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed.
|
||||||
|
|
||||||
#### ROCm
|
|
||||||
|
|
||||||
- The GPU must be supported by ROCm. If it isn't officially supported, you can attempt to use the `HSA_OVERRIDE_GFX_VERSION` environmental variable: `HSA_OVERRIDE_GFX_VERSION=<a supported version, e.g. 10.3.0>`. If this doesn't work, you might need to also set `HSA_USE_SVM=0`.
|
|
||||||
- The ROCm image is quite large and requires at least 35GiB of free disk space. However, pulling later updates to the service through Docker will generally only amount to a few hundred megabytes as the rest will be cached.
|
|
||||||
- This backend is new and may experience some issues. For example, GPU power consumption can be higher than usual after running inference, even if the machine learning service is idle. In this case, it will only go back to normal after being idle for 5 minutes (configurable with the [MACHINE_LEARNING_MODEL_TTL](/docs/install/environment-variables) setting).
|
|
||||||
|
|
||||||
#### OpenVINO
|
#### OpenVINO
|
||||||
|
|
||||||
- Integrated GPUs are more likely to experience issues than discrete GPUs, especially for older processors or servers with low RAM.
|
- Integrated GPUs are more likely to experience issues than discrete GPUs, especially for older processors or servers with low RAM.
|
||||||
- Ensure the server's kernel version is new enough to use the device for hardware accceleration.
|
- Ensure the server's kernel version is new enough to use the device for hardware accceleration.
|
||||||
- Expect higher RAM usage when using OpenVINO compared to CPU processing.
|
- Expect higher RAM usage when using OpenVINO compared to CPU processing.
|
||||||
|
|
||||||
#### RKNN
|
|
||||||
|
|
||||||
- You must have a supported Rockchip SoC: only RK3566, RK3568, RK3576 and RK3588 are supported at this moment.
|
|
||||||
- Make sure you have the appropriate linux kernel driver installed
|
|
||||||
- This is usually pre-installed on the device vendor's Linux images
|
|
||||||
- RKNPU driver V0.9.8 or later must be available in the host server
|
|
||||||
- You may confirm this by running `cat /sys/kernel/debug/rknpu/version` to check the version
|
|
||||||
- Optional: Configure your `.env` file, see [environment variables](/docs/install/environment-variables) for RKNN specific settings
|
|
||||||
- In particular, setting `MACHINE_LEARNING_RKNN_THREADS` to 2 or 3 can _dramatically_ improve performance for RK3576 and RK3588 compared to the default of 1, at the expense of multiplying the amount of RAM each model uses by that amount.
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. If you do not already have it, download the latest [`hwaccel.ml.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
|
1. If you do not already have it, download the latest [`hwaccel.ml.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
|
||||||
2. In the `docker-compose.yml` under `immich-machine-learning`, uncomment the `extends` section and change `cpu` to the appropriate backend.
|
2. In the `docker-compose.yml` under `immich-machine-learning`, uncomment the `extends` section and change `cpu` to the appropriate backend.
|
||||||
3. Still in `immich-machine-learning`, add one of -[armnn, cuda, rocm, openvino] to the `image` section's tag at the end of the line.
|
3. Still in `immich-machine-learning`, add one of -[armnn, cuda, openvino] to the `image` section's tag at the end of the line.
|
||||||
4. Redeploy the `immich-machine-learning` container with these updated settings.
|
4. Redeploy the `immich-machine-learning` container with these updated settings.
|
||||||
|
|
||||||
### Confirming Device Usage
|
### Confirming Device Usage
|
||||||
|
|
||||||
You can confirm the device is being recognized and used by checking its utilization. There are many tools to display this, such as `nvtop` for NVIDIA or Intel, `intel_gpu_top` for Intel, and `radeontop` for AMD.
|
You can confirm the device is being recognized and used by checking its utilization. There are many tools to display this, such as `nvtop` for NVIDIA or Intel and `intel_gpu_top` for Intel.
|
||||||
|
|
||||||
You can also check the logs of the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, or when you search with text in Immich, you should either see a log for `Available ORT providers` containing the relevant provider (e.g. `CUDAExecutionProvider` in the case of CUDA), or a `Loaded ANN model` log entry without errors in the case of ARM NN.
|
You can also check the logs of the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, or when you search with text in Immich, you should either see a log for `Available ORT providers` containing the relevant provider (e.g. `CUDAExecutionProvider` in the case of CUDA), or a `Loaded ANN model` log entry without errors in the case of ARM NN.
|
||||||
|
|
||||||
@@ -147,12 +127,3 @@ Note that you should increase job concurrencies to increase overall utilization
|
|||||||
- If you encounter an error when a model is running, try a different model to see if the issue is model-specific.
|
- If you encounter an error when a model is running, try a different model to see if the issue is model-specific.
|
||||||
- You may want to increase concurrency past the default for higher utilization. However, keep in mind that this will also increase VRAM consumption.
|
- You may want to increase concurrency past the default for higher utilization. However, keep in mind that this will also increase VRAM consumption.
|
||||||
- Larger models benefit more from hardware acceleration, if you have the VRAM for them.
|
- Larger models benefit more from hardware acceleration, if you have the VRAM for them.
|
||||||
- Compared to ARM NN, RKNPU has:
|
|
||||||
- Wider model support (including for search, which ARM NN does not accelerate)
|
|
||||||
- Less heat generation
|
|
||||||
- Very slightly lower accuracy (RKNPU always uses FP16, while ARM NN by default uses higher precision FP32 unless `MACHINE_LEARNING_ANN_FP16_TURBO` is enabled)
|
|
||||||
- Varying speed (tested on RK3588):
|
|
||||||
- If `MACHINE_LEARNING_RKNN_THREADS` is at the default of 1, RKNPU will have substantially lower throughput for ML jobs than ARM NN in most cases, but similar latency (such as when searching)
|
|
||||||
- If `MACHINE_LEARNING_RKNN_THREADS` is set to 3, it will be somewhat faster than ARM NN at FP32, but somewhat slower than ARM NN if `MACHINE_LEARNING_ANN_FP16_TURBO` is enabled
|
|
||||||
- When other tasks also use the GPU (like transcoding), RKNPU has a significant advantage over ARM NN as it uses the otherwise idle NPU instead of competing for GPU usage
|
|
||||||
- Lower RAM usage if `MACHINE_LEARNING_RKNN_THREADS` is at the default of 1, but significantly higher if greater than 1 (which is necessary for it to fully utilize the NPU and hence be comparable in speed to ARM NN)
|
|
||||||
|
|||||||
+8
-1133
File diff suppressed because it is too large
Load Diff
@@ -23,12 +23,12 @@ name: immich_remote_ml
|
|||||||
services:
|
services:
|
||||||
immich-machine-learning:
|
immich-machine-learning:
|
||||||
container_name: immich_machine_learning
|
container_name: immich_machine_learning
|
||||||
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino] to the image tag.
|
# For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
|
||||||
# Example tag: ${IMMICH_VERSION:-release}-cuda
|
# Example tag: ${IMMICH_VERSION:-release}-cuda
|
||||||
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
|
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
|
||||||
# extends:
|
# extends:
|
||||||
# file: hwaccel.ml.yml
|
# file: hwaccel.ml.yml
|
||||||
# service: # set to one of [armnn, cuda, rocm, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
|
# service: # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
|
||||||
volumes:
|
volumes:
|
||||||
- model-cache:/cache
|
- model-cache:/cache
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
@@ -170,8 +170,6 @@ Redis (Sentinel) URL example JSON before encoding:
|
|||||||
| `MACHINE_LEARNING_MAX_BATCH_SIZE__FACIAL_RECOGNITION` | Set the maximum number of faces that will be processed at once by the facial recognition model | None (`1` if using OpenVINO) | machine learning |
|
| `MACHINE_LEARNING_MAX_BATCH_SIZE__FACIAL_RECOGNITION` | Set the maximum number of faces that will be processed at once by the facial recognition model | None (`1` if using OpenVINO) | machine learning |
|
||||||
| `MACHINE_LEARNING_PING_TIMEOUT` | How long (ms) to wait for a PING response when checking if an ML server is available | `2000` | server |
|
| `MACHINE_LEARNING_PING_TIMEOUT` | How long (ms) to wait for a PING response when checking if an ML server is available | `2000` | server |
|
||||||
| `MACHINE_LEARNING_AVAILABILITY_BACKOFF_TIME` | How long to ignore ML servers that are offline before trying again | `30000` | server |
|
| `MACHINE_LEARNING_AVAILABILITY_BACKOFF_TIME` | How long to ignore ML servers that are offline before trying again | `30000` | server |
|
||||||
| `MACHINE_LEARNING_RKNN` | Enable RKNN hardware acceleration if supported | `True` | machine learning |
|
|
||||||
| `MACHINE_LEARNING_RKNN_THREADS` | How many threads of RKNN runtime should be spinned up while inferencing. | `1` | machine learning |
|
|
||||||
|
|
||||||
\*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
|
\*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
|
||||||
|
|
||||||
|
|||||||
Generated
+9
-9
@@ -5308,9 +5308,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/autoprefixer": {
|
"node_modules/autoprefixer": {
|
||||||
"version": "10.4.21",
|
"version": "10.4.20",
|
||||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
|
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
|
||||||
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
|
"integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -5327,11 +5327,11 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"browserslist": "^4.24.4",
|
"browserslist": "^4.23.3",
|
||||||
"caniuse-lite": "^1.0.30001702",
|
"caniuse-lite": "^1.0.30001646",
|
||||||
"fraction.js": "^4.3.7",
|
"fraction.js": "^4.3.7",
|
||||||
"normalize-range": "^0.1.2",
|
"normalize-range": "^0.1.2",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.0.1",
|
||||||
"postcss-value-parser": "^4.2.0"
|
"postcss-value-parser": "^4.2.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -5781,9 +5781,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001706",
|
"version": "1.0.30001695",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
|
||||||
"integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==",
|
"integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
|||||||
Vendored
-4
@@ -1,8 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"label": "v1.130.0",
|
|
||||||
"url": "https://v1.130.0.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "v1.129.0",
|
"label": "v1.129.0",
|
||||||
"url": "https://v1.129.0.archive.immich.app"
|
"url": "https://v1.129.0.archive.immich.app"
|
||||||
|
|||||||
Generated
+74
-85
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.130.0",
|
"version": "1.129.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.130.0",
|
"version": "1.129.0",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.9",
|
||||||
"@types/oidc-provider": "^8.5.1",
|
"@types/oidc-provider": "^8.5.1",
|
||||||
"@types/pg": "^8.11.0",
|
"@types/pg": "^8.11.0",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
},
|
},
|
||||||
"../cli": {
|
"../cli": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.54",
|
"version": "2.2.53",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
||||||
"@typescript-eslint/parser": "^8.15.0",
|
"@typescript-eslint/parser": "^8.15.0",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
@@ -95,14 +95,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.130.0",
|
"version": "1.129.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.9",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -828,16 +828,6 @@
|
|||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-helpers": {
|
|
||||||
"version": "0.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz",
|
|
||||||
"integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@eslint/core": {
|
"node_modules/@eslint/core": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
|
||||||
@@ -889,9 +879,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.22.0",
|
"version": "9.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
|
||||||
"integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==",
|
"integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1743,9 +1733,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/oidc-provider": {
|
"node_modules/@types/oidc-provider": {
|
||||||
"version": "8.8.1",
|
"version": "8.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/oidc-provider/-/oidc-provider-8.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/oidc-provider/-/oidc-provider-8.8.0.tgz",
|
||||||
"integrity": "sha512-Yi/OJ7s0CFJ1AWAQrY2EO/zkV9uppLtiGAzrA07lBDveUOvxtYh7GflnHFXcgufVaPxVAjdykizjTYTMNVhdJw==",
|
"integrity": "sha512-9Jtutw4dyAz0PN8EWlxqeNrGHsEZ9EH4QZjfkZIbhmKuiuHIrzoz/S1zHNXX8ogfhWtPp1swMyzXBSo6RTTj1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1892,17 +1882,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz",
|
||||||
"integrity": "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==",
|
"integrity": "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.26.1",
|
"@typescript-eslint/scope-manager": "8.26.0",
|
||||||
"@typescript-eslint/type-utils": "8.26.1",
|
"@typescript-eslint/type-utils": "8.26.0",
|
||||||
"@typescript-eslint/utils": "8.26.1",
|
"@typescript-eslint/utils": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1",
|
"@typescript-eslint/visitor-keys": "8.26.0",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1922,16 +1912,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.0.tgz",
|
||||||
"integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==",
|
"integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.26.1",
|
"@typescript-eslint/scope-manager": "8.26.0",
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.26.1",
|
"@typescript-eslint/typescript-estree": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1",
|
"@typescript-eslint/visitor-keys": "8.26.0",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1947,14 +1937,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz",
|
||||||
"integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==",
|
"integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1"
|
"@typescript-eslint/visitor-keys": "8.26.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1965,14 +1955,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz",
|
||||||
"integrity": "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==",
|
"integrity": "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.26.1",
|
"@typescript-eslint/typescript-estree": "8.26.0",
|
||||||
"@typescript-eslint/utils": "8.26.1",
|
"@typescript-eslint/utils": "8.26.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.0.1"
|
"ts-api-utils": "^2.0.1"
|
||||||
},
|
},
|
||||||
@@ -1989,9 +1979,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.0.tgz",
|
||||||
"integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==",
|
"integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2003,14 +1993,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz",
|
||||||
"integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==",
|
"integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.26.1",
|
"@typescript-eslint/visitor-keys": "8.26.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -2056,16 +2046,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.0.tgz",
|
||||||
"integrity": "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==",
|
"integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "8.26.1",
|
"@typescript-eslint/scope-manager": "8.26.0",
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.26.1"
|
"@typescript-eslint/typescript-estree": "8.26.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2080,13 +2070,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.26.1",
|
"version": "8.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz",
|
||||||
"integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==",
|
"integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.26.1",
|
"@typescript-eslint/types": "8.26.0",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3167,19 +3157,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.22.0",
|
"version": "9.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
|
||||||
"integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==",
|
"integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.19.2",
|
"@eslint/config-array": "^0.19.2",
|
||||||
"@eslint/config-helpers": "^0.1.0",
|
|
||||||
"@eslint/core": "^0.12.0",
|
"@eslint/core": "^0.12.0",
|
||||||
"@eslint/eslintrc": "^3.3.0",
|
"@eslint/eslintrc": "^3.3.0",
|
||||||
"@eslint/js": "9.22.0",
|
"@eslint/js": "9.21.0",
|
||||||
"@eslint/plugin-kit": "^0.2.7",
|
"@eslint/plugin-kit": "^0.2.7",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@@ -3191,7 +3180,7 @@
|
|||||||
"cross-spawn": "^7.0.6",
|
"cross-spawn": "^7.0.6",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^8.3.0",
|
"eslint-scope": "^8.2.0",
|
||||||
"eslint-visitor-keys": "^4.2.0",
|
"eslint-visitor-keys": "^4.2.0",
|
||||||
"espree": "^10.3.0",
|
"espree": "^10.3.0",
|
||||||
"esquery": "^1.5.0",
|
"esquery": "^1.5.0",
|
||||||
@@ -3319,9 +3308,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
"version": "8.3.0",
|
"version": "8.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
|
||||||
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
"integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -5222,15 +5211,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.14.0",
|
"version": "8.13.3",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.13.3.tgz",
|
||||||
"integrity": "sha512-nXbVpyoaXVmdqlKEzToFf37qzyeeh7mbiXsnoWvstSqohj88yaa/I/Rq/HEVn2QPSZEuLIJa/jSpRDyzjEx4FQ==",
|
"integrity": "sha512-P6tPt9jXbL9HVu/SSRERNYaYG++MjnscnegFh9pPHihfoBSujsrka0hyuymMzeJKFWrcG8wvCKy8rCe8e5nDUQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.7.0",
|
"pg-connection-string": "^2.7.0",
|
||||||
"pg-pool": "^3.8.0",
|
"pg-pool": "^3.7.1",
|
||||||
"pg-protocol": "^1.8.0",
|
"pg-protocol": "^1.7.1",
|
||||||
"pg-types": "^2.1.0",
|
"pg-types": "^2.1.0",
|
||||||
"pgpass": "1.x"
|
"pgpass": "1.x"
|
||||||
},
|
},
|
||||||
@@ -5282,9 +5271,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg-pool": {
|
"node_modules/pg-pool": {
|
||||||
"version": "3.8.0",
|
"version": "3.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz",
|
||||||
"integrity": "sha512-VBw3jiVm6ZOdLBTIcXLNdSotb6Iy3uOCwDGFAksZCXmi10nyRvnP2v3jl4d+IsLYRyXf6o9hIm/ZtUzlByNUdw==",
|
"integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -5292,9 +5281,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg-protocol": {
|
"node_modules/pg-protocol": {
|
||||||
"version": "1.8.0",
|
"version": "1.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz",
|
||||||
"integrity": "sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g==",
|
"integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.130.0",
|
"version": "1.129.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.9",
|
||||||
"@types/oidc-provider": "^8.5.1",
|
"@types/oidc-provider": "^8.5.1",
|
||||||
"@types/pg": "^8.11.0",
|
"@types/pg": "^8.11.0",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
|
|||||||
+3
-3
@@ -493,7 +493,7 @@ export const utils = {
|
|||||||
value: accessToken,
|
value: accessToken,
|
||||||
domain,
|
domain,
|
||||||
path: '/',
|
path: '/',
|
||||||
expires: 2_058_028_213,
|
expires: 1_742_402_728,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
sameSite: 'Lax',
|
sameSite: 'Lax',
|
||||||
@@ -503,7 +503,7 @@ export const utils = {
|
|||||||
value: 'password',
|
value: 'password',
|
||||||
domain,
|
domain,
|
||||||
path: '/',
|
path: '/',
|
||||||
expires: 2_058_028_213,
|
expires: 1_742_402_728,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
sameSite: 'Lax',
|
sameSite: 'Lax',
|
||||||
@@ -513,7 +513,7 @@ export const utils = {
|
|||||||
value: 'true',
|
value: 'true',
|
||||||
domain,
|
domain,
|
||||||
path: '/',
|
path: '/',
|
||||||
expires: 2_058_028_213,
|
expires: 1_742_402_728,
|
||||||
httpOnly: false,
|
httpOnly: false,
|
||||||
secure: false,
|
secure: false,
|
||||||
sameSite: 'Lax',
|
sameSite: 'Lax',
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ test.describe('Shared Links', () => {
|
|||||||
await page.goto(`/share/${sharedLink.key}`);
|
await page.goto(`/share/${sharedLink.key}`);
|
||||||
await page.getByRole('heading', { name: 'Test Album' }).waitFor();
|
await page.getByRole('heading', { name: 'Test Album' }).waitFor();
|
||||||
await page.locator(`[data-asset-id="${asset.id}"]`).hover();
|
await page.locator(`[data-asset-id="${asset.id}"]`).hover();
|
||||||
await page.waitForSelector('[data-group] svg');
|
await page.waitForSelector('#asset-group-by-date svg');
|
||||||
await page.getByRole('checkbox').click();
|
await page.getByRole('checkbox').click();
|
||||||
await page.getByRole('button', { name: 'Download' }).click();
|
await page.getByRole('button', { name: 'Download' }).click();
|
||||||
await page.getByText('DOWNLOADING', { exact: true }).waitFor();
|
await page.getByText('DOWNLOADING', { exact: true }).waitFor();
|
||||||
|
|||||||
@@ -1082,9 +1082,7 @@
|
|||||||
"remove_url": "Remove URL",
|
"remove_url": "Remove URL",
|
||||||
"remove_user": "Remove user",
|
"remove_user": "Remove user",
|
||||||
"removed_api_key": "Removed API Key: {name}",
|
"removed_api_key": "Removed API Key: {name}",
|
||||||
"remove_memory": "Remove memory",
|
|
||||||
"removed_memory": "Removed memory",
|
"removed_memory": "Removed memory",
|
||||||
"remove_photo_from_memory": "Remove photo from this memory",
|
|
||||||
"removed_photo_from_memory": "Removed photo from memory",
|
"removed_photo_from_memory": "Removed photo from memory",
|
||||||
"removed_from_archive": "Removed from archive",
|
"removed_from_archive": "Removed from archive",
|
||||||
"removed_from_favorites": "Removed from favorites",
|
"removed_from_favorites": "Removed from favorites",
|
||||||
|
|||||||
@@ -1,27 +1,5 @@
|
|||||||
*.zip
|
*.zip
|
||||||
*.onnx
|
*.onnx
|
||||||
*.rknn
|
|
||||||
*.npy
|
|
||||||
*_attr__value
|
|
||||||
*.weight
|
|
||||||
*.bias
|
|
||||||
onnx__*
|
|
||||||
*in_proj_bias
|
|
||||||
*.proj
|
|
||||||
*.latent
|
|
||||||
*.pos_embed
|
|
||||||
vocab.txt
|
|
||||||
export/immich_model_exporter/models/**/README.md
|
|
||||||
export/**/results/*.json
|
|
||||||
export/**/root
|
|
||||||
*.armnn
|
|
||||||
tokenizer.json
|
|
||||||
tokenizer_config.json
|
|
||||||
special_tokens_map.json
|
|
||||||
preprocess_cfg.json
|
|
||||||
config.json
|
|
||||||
merges.txt
|
|
||||||
vocab.json
|
|
||||||
upload/
|
upload/
|
||||||
venv/
|
venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
ARG DEVICE=cpu
|
ARG DEVICE=cpu
|
||||||
|
|
||||||
FROM python:3.11-bookworm@sha256:d270285656e8f061ae0004297df62ac4b26d5cef9408b9cc9a5bf08c2cd8d60c AS builder-cpu
|
FROM python:3.11-bookworm@sha256:68a8863d0625f42d47e0684f33ca02f19d6094ef859a8af237aaf645195ed477 AS builder-cpu
|
||||||
|
|
||||||
FROM builder-cpu AS builder-openvino
|
FROM builder-cpu AS builder-openvino
|
||||||
|
|
||||||
@@ -15,36 +15,6 @@ RUN mkdir /opt/armnn && \
|
|||||||
cd /opt/ann && \
|
cd /opt/ann && \
|
||||||
sh build.sh
|
sh build.sh
|
||||||
|
|
||||||
FROM builder-cpu AS builder-rknn
|
|
||||||
|
|
||||||
# Warning: 25GiB+ disk space required to pull this image
|
|
||||||
# TODO: find a way to reduce the image size
|
|
||||||
FROM rocm/dev-ubuntu-22.04:6.3.4-complete@sha256:1f7e92ca7e3a3785680473329ed1091fc99db3e90fcb3a1688f2933e870ed76b AS builder-rocm
|
|
||||||
|
|
||||||
WORKDIR /code
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends wget git python3.10-venv
|
|
||||||
RUN wget -nv https://github.com/Kitware/CMake/releases/download/v3.30.1/cmake-3.30.1-linux-x86_64.sh && \
|
|
||||||
chmod +x cmake-3.30.1-linux-x86_64.sh && \
|
|
||||||
mkdir -p /code/cmake-3.30.1-linux-x86_64 && \
|
|
||||||
./cmake-3.30.1-linux-x86_64.sh --skip-license --prefix=/code/cmake-3.30.1-linux-x86_64 && \
|
|
||||||
rm cmake-3.30.1-linux-x86_64.sh
|
|
||||||
|
|
||||||
ENV PATH=/code/cmake-3.30.1-linux-x86_64/bin:${PATH}
|
|
||||||
|
|
||||||
RUN git clone --single-branch --branch v1.20.1 --recursive "https://github.com/Microsoft/onnxruntime" onnxruntime
|
|
||||||
WORKDIR /code/onnxruntime
|
|
||||||
# Fix for multi-threading based on comments in https://github.com/microsoft/onnxruntime/pull/19567
|
|
||||||
# TODO: find a way to fix this without disabling algo caching
|
|
||||||
COPY ./patches/* /tmp/
|
|
||||||
RUN git apply /tmp/*.patch
|
|
||||||
|
|
||||||
RUN /bin/sh ./dockerfiles/scripts/install_common_deps.sh
|
|
||||||
# Note: the `parallel` setting uses a substantial amount of RAM
|
|
||||||
RUN ./build.sh --allow_running_as_root --config Release --build_wheel --update --build --parallel 17 --cmake_extra_defines\
|
|
||||||
ONNXRUNTIME_VERSION=1.20.1 --skip_tests --use_rocm --rocm_home=/opt/rocm
|
|
||||||
RUN mv /code/onnxruntime/build/Linux/Release/dist/*.whl /opt/
|
|
||||||
|
|
||||||
FROM builder-${DEVICE} AS builder
|
FROM builder-${DEVICE} AS builder
|
||||||
|
|
||||||
ARG DEVICE
|
ARG DEVICE
|
||||||
@@ -55,25 +25,22 @@ WORKDIR /usr/src/app
|
|||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends g++
|
RUN apt-get update && apt-get install -y --no-install-recommends g++
|
||||||
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest@sha256:cb641b1979723dc5ab87d61f079000009edc107d30ae7cbb6e7419fdac044e9f /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:latest@sha256:562193a4a9d398f8aedddcb223e583da394ee735de36b5815f8f1d22cb49be15 /uv /uvx /bin/
|
||||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
--mount=type=bind,source=uv.lock,target=uv.lock \
|
--mount=type=bind,source=uv.lock,target=uv.lock \
|
||||||
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
||||||
uv sync --frozen --extra ${DEVICE} --no-dev --no-editable --no-install-project --compile-bytecode --no-progress --active --link-mode copy
|
uv sync --frozen --extra ${DEVICE} --no-dev --no-editable --no-install-project --compile-bytecode --no-progress --active --link-mode copy
|
||||||
RUN if [ "$DEVICE" = "rocm" ]; then \
|
|
||||||
uv pip install /opt/onnxruntime_rocm-*.whl; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
FROM python:3.11-slim-bookworm@sha256:7029b00486ac40bed03e36775b864d3f3d39dcbdf19cd45e6a52d541e6c178f0 AS prod-cpu
|
FROM python:3.11-slim-bookworm@sha256:614c8691ab74150465ec9123378cd4dde7a6e57be9e558c3108df40664667a4c AS prod-cpu
|
||||||
|
|
||||||
FROM prod-cpu AS prod-openvino
|
FROM prod-cpu AS prod-openvino
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install --no-install-recommends -yqq ocl-icd-libopencl1 wget && \
|
apt-get install --no-install-recommends -yqq ocl-icd-libopencl1 wget && \
|
||||||
wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-core_1.0.17384.11_amd64.deb && \
|
wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-core_1.0.17384.11_amd64.deb && \
|
||||||
wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-opencl_1.0.17384.11_amd64.deb && \
|
wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-opencl_1.0.17384.11_amd64.deb && \
|
||||||
wget -nv https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/intel-opencl-icd_24.31.30508.7_amd64.deb && \
|
wget https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/intel-opencl-icd_24.31.30508.7_amd64.deb && \
|
||||||
wget -nv https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/libigdgmm12_22.4.1_amd64.deb && \
|
wget https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/libigdgmm12_22.4.1_amd64.deb && \
|
||||||
dpkg -i *.deb && \
|
dpkg -i *.deb && \
|
||||||
rm *.deb && \
|
rm *.deb && \
|
||||||
apt-get remove wget -yqq && \
|
apt-get remove wget -yqq && \
|
||||||
@@ -90,8 +57,6 @@ COPY --from=builder-cuda /usr/local/bin/python3 /usr/local/bin/python3
|
|||||||
COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11
|
COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11
|
||||||
COPY --from=builder-cuda /usr/local/lib/libpython3.11.so /usr/local/lib/libpython3.11.so
|
COPY --from=builder-cuda /usr/local/lib/libpython3.11.so /usr/local/lib/libpython3.11.so
|
||||||
|
|
||||||
FROM rocm/dev-ubuntu-22.04:6.3.4-complete@sha256:1f7e92ca7e3a3785680473329ed1091fc99db3e90fcb3a1688f2933e870ed76b AS prod-rocm
|
|
||||||
|
|
||||||
FROM prod-cpu AS prod-armnn
|
FROM prod-cpu AS prod-armnn
|
||||||
|
|
||||||
ENV LD_LIBRARY_PATH=/opt/armnn
|
ENV LD_LIBRARY_PATH=/opt/armnn
|
||||||
@@ -112,16 +77,11 @@ COPY --from=builder-armnn \
|
|||||||
/opt/ann/build.sh \
|
/opt/ann/build.sh \
|
||||||
/opt/armnn/
|
/opt/armnn/
|
||||||
|
|
||||||
FROM prod-cpu AS prod-rknn
|
|
||||||
|
|
||||||
ADD --checksum=sha256:73993ed4b440460825f21611731564503cc1d5a0c123746477da6cd574f34885 https://github.com/airockchip/rknn-toolkit2/raw/refs/tags/v2.3.0/rknpu2/runtime/Linux/librknn_api/aarch64/librknnrt.so /usr/lib/
|
|
||||||
|
|
||||||
FROM prod-${DEVICE} AS prod
|
FROM prod-${DEVICE} AS prod
|
||||||
|
|
||||||
ARG DEVICE
|
ARG DEVICE
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends tini $(if ! [ "$DEVICE" = "openvino" ] && ! [ "$DEVICE" = "rocm" ]; then echo "libmimalloc2.0"; fi) && \
|
apt-get install -y --no-install-recommends tini $(if ! [ "$DEVICE" = "openvino" ]; then echo "libmimalloc2.0"; fi) && \
|
||||||
apt-get autoremove -yqq && \
|
apt-get autoremove -yqq && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
@@ -163,4 +123,4 @@ ENV IMMICH_SOURCE_URL=https://github.com/immich-app/immich/commit/${BUILD_SOURCE
|
|||||||
ENTRYPOINT ["tini", "--"]
|
ENTRYPOINT ["tini", "--"]
|
||||||
CMD ["./start.sh"]
|
CMD ["./start.sh"]
|
||||||
|
|
||||||
HEALTHCHECK CMD python3 healthcheck.py
|
HEALTHCHECK CMD python3 healthcheck.py
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
This project uses [uv](https://docs.astral.sh/uv/getting-started/installation/), so be sure to install it first.
|
This project uses [uv](https://docs.astral.sh/uv/getting-started/installation/), so be sure to install it first.
|
||||||
Running `uv sync --extra cpu` will install everything you need in an isolated virtual environment.
|
Running `uv sync --extra cpu` will install everything you need in an isolated virtual environment.
|
||||||
CUDA, ROCM and OpenVINO are supported as acceleration APIs. To use them, you can replace `--extra cpu` with either of `--extra cuda`, `--extra rocm` or `--extra openvino`. In the case of CUDA, a [compute capability](https://developer.nvidia.com/cuda-gpus) of 5.2 or higher is required.
|
CUDA and OpenVINO are supported as acceleration APIs. To use them, you can replace `--group cpu` with either of `--group cuda` or `--group openvino`. In the case of CUDA, a [compute capability](https://developer.nvidia.com/cuda-gpus) of 5.2 or higher is required.
|
||||||
|
|
||||||
To add or remove dependencies, you can use the commands `uv add $PACKAGE_NAME` and `uv remove $PACKAGE_NAME`, respectively.
|
To add or remove dependencies, you can use the commands `uv add $PACKAGE_NAME` and `uv remove $PACKAGE_NAME`, respectively.
|
||||||
Be sure to commit the `uv.lock` and `pyproject.toml` files with `uv lock` to reflect any changes in dependencies.
|
Be sure to commit the `uv.lock` and `pyproject.toml` files with `uv lock` to reflect any changes in dependencies.
|
||||||
|
|||||||
@@ -64,8 +64,6 @@ class Settings(BaseSettings):
|
|||||||
ann: bool = True
|
ann: bool = True
|
||||||
ann_fp16_turbo: bool = False
|
ann_fp16_turbo: bool = False
|
||||||
ann_tuning_level: int = 2
|
ann_tuning_level: int = 2
|
||||||
rknn: bool = True
|
|
||||||
rknn_threads: int = 1
|
|
||||||
preload: PreloadModelData | None = None
|
preload: PreloadModelData | None = None
|
||||||
max_batch_size: MaxBatchSize | None = None
|
max_batch_size: MaxBatchSize | None = None
|
||||||
|
|
||||||
|
|||||||
@@ -136,12 +136,6 @@ def ann_session() -> Iterator[mock.Mock]:
|
|||||||
yield mocked
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
|
||||||
def rknn_session() -> Iterator[mock.Mock]:
|
|
||||||
with mock.patch("app.sessions.rknn.RknnPoolExecutor") as mocked:
|
|
||||||
yield mocked
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def rmtree() -> Iterator[mock.Mock]:
|
def rmtree() -> Iterator[mock.Mock]:
|
||||||
with mock.patch("app.models.base.rmtree", autospec=True) as mocked:
|
with mock.patch("app.models.base.rmtree", autospec=True) as mocked:
|
||||||
|
|||||||
@@ -226,9 +226,9 @@ async def load(model: InferenceModel) -> InferenceModel:
|
|||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
if model.model_format == ModelFormat.ONNX:
|
if model.model_format == ModelFormat.ONNX:
|
||||||
raise e
|
raise e
|
||||||
|
log.exception(e)
|
||||||
log.warning(
|
log.warning(
|
||||||
f"{model.model_format.upper()} is available, but model '{model.model_name}' does not support it.",
|
f"{model.model_format.upper()} is available, but model '{model.model_name}' does not support it."
|
||||||
exc_info=e,
|
|
||||||
)
|
)
|
||||||
model.model_format = ModelFormat.ONNX
|
model.model_format = ModelFormat.ONNX
|
||||||
model.load()
|
model.load()
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from typing import Any, ClassVar
|
|||||||
from huggingface_hub import snapshot_download
|
from huggingface_hub import snapshot_download
|
||||||
|
|
||||||
import ann.ann
|
import ann.ann
|
||||||
import app.sessions.rknn as rknn
|
|
||||||
from app.sessions.ort import OrtSession
|
from app.sessions.ort import OrtSession
|
||||||
|
|
||||||
from ..config import clean_name, log, settings
|
from ..config import clean_name, log, settings
|
||||||
@@ -67,17 +66,12 @@ class InferenceModel(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def _download(self) -> None:
|
def _download(self) -> None:
|
||||||
ignored_patterns: dict[ModelFormat, list[str]] = {
|
ignore_patterns = [] if self.model_format == ModelFormat.ARMNN else ["*.armnn"]
|
||||||
ModelFormat.ONNX: ["*.armnn", "*.rknn"],
|
|
||||||
ModelFormat.ARMNN: ["*.rknn"],
|
|
||||||
ModelFormat.RKNN: ["*.armnn"],
|
|
||||||
}
|
|
||||||
|
|
||||||
snapshot_download(
|
snapshot_download(
|
||||||
f"immich-app/{clean_name(self.model_name)}",
|
f"immich-app/{clean_name(self.model_name)}",
|
||||||
cache_dir=self.cache_dir,
|
cache_dir=self.cache_dir,
|
||||||
local_dir=self.cache_dir,
|
local_dir=self.cache_dir,
|
||||||
ignore_patterns=ignored_patterns.get(self.model_format, []),
|
ignore_patterns=ignore_patterns,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load(self) -> ModelSession:
|
def _load(self) -> ModelSession:
|
||||||
@@ -114,25 +108,17 @@ class InferenceModel(ABC):
|
|||||||
session: ModelSession = AnnSession(model_path)
|
session: ModelSession = AnnSession(model_path)
|
||||||
case ".onnx":
|
case ".onnx":
|
||||||
session = OrtSession(model_path)
|
session = OrtSession(model_path)
|
||||||
case ".rknn":
|
|
||||||
session = rknn.RknnSession(model_path)
|
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f"Unsupported model file type: {model_path.suffix}")
|
raise ValueError(f"Unsupported model file type: {model_path.suffix}")
|
||||||
return session
|
return session
|
||||||
|
|
||||||
def model_path_for_format(self, model_format: ModelFormat) -> Path:
|
|
||||||
model_path_prefix = rknn.model_prefix if model_format == ModelFormat.RKNN else None
|
|
||||||
if model_path_prefix:
|
|
||||||
return self.model_dir / model_path_prefix / f"model.{model_format}"
|
|
||||||
return self.model_dir / f"model.{model_format}"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model_dir(self) -> Path:
|
def model_dir(self) -> Path:
|
||||||
return self.cache_dir / self.model_type.value
|
return self.cache_dir / self.model_type.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model_path(self) -> Path:
|
def model_path(self) -> Path:
|
||||||
return self.model_path_for_format(self.model_format)
|
return self.model_dir / f"model.{self.model_format}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model_task(self) -> ModelTask:
|
def model_task(self) -> ModelTask:
|
||||||
@@ -169,9 +155,4 @@ class InferenceModel(ABC):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def _model_format_default(self) -> ModelFormat:
|
def _model_format_default(self) -> ModelFormat:
|
||||||
if rknn.is_available:
|
return ModelFormat.ARMNN if ann.ann.is_available and settings.ann else ModelFormat.ONNX
|
||||||
return ModelFormat.RKNN
|
|
||||||
elif ann.ann.is_available and settings.ann:
|
|
||||||
return ModelFormat.ARMNN
|
|
||||||
else:
|
|
||||||
return ModelFormat.ONNX
|
|
||||||
|
|||||||
@@ -44,18 +44,6 @@ _OPENCLIP_MODELS = {
|
|||||||
"nllb-clip-base-siglip__v1",
|
"nllb-clip-base-siglip__v1",
|
||||||
"nllb-clip-large-siglip__mrl",
|
"nllb-clip-large-siglip__mrl",
|
||||||
"nllb-clip-large-siglip__v1",
|
"nllb-clip-large-siglip__v1",
|
||||||
"ViT-B-16-SigLIP2__webli",
|
|
||||||
"ViT-B-32-SigLIP2-256__webli",
|
|
||||||
"ViT-L-16-SigLIP2-256__webli",
|
|
||||||
"ViT-L-16-SigLIP2-384__webli",
|
|
||||||
"ViT-L-16-SigLIP2-512__webli",
|
|
||||||
"ViT-SO400M-14-SigLIP2-378__webli",
|
|
||||||
"ViT-SO400M-14-SigLIP2__webli",
|
|
||||||
"ViT-SO400M-16-SigLIP2-256__webli",
|
|
||||||
"ViT-SO400M-16-SigLIP2-384__webli",
|
|
||||||
"ViT-SO400M-16-SigLIP2-512__webli",
|
|
||||||
"ViT-gopt-16-SigLIP2-256__webli",
|
|
||||||
"ViT-gopt-16-SigLIP2-384__webli",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -75,15 +63,7 @@ _INSIGHTFACE_MODELS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SUPPORTED_PROVIDERS = [
|
SUPPORTED_PROVIDERS = ["CUDAExecutionProvider", "OpenVINOExecutionProvider", "CPUExecutionProvider"]
|
||||||
"CUDAExecutionProvider",
|
|
||||||
"ROCMExecutionProvider",
|
|
||||||
"OpenVINOExecutionProvider",
|
|
||||||
"CPUExecutionProvider",
|
|
||||||
]
|
|
||||||
|
|
||||||
RKNN_SUPPORTED_SOCS = ["rk3566", "rk3568", "rk3576", "rk3588"]
|
|
||||||
RKNN_COREMASK_SUPPORTED_SOCS = ["rk3576", "rk3588"]
|
|
||||||
|
|
||||||
|
|
||||||
def get_model_source(model_name: str) -> ModelSource | None:
|
def get_model_source(model_name: str) -> ModelSource | None:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class FaceRecognizer(InferenceModel):
|
|||||||
self._add_batch_axis(self.model_path)
|
self._add_batch_axis(self.model_path)
|
||||||
session = self._make_session(self.model_path)
|
session = self._make_session(self.model_path)
|
||||||
self.model = ArcFaceONNX(
|
self.model = ArcFaceONNX(
|
||||||
self.model_path_for_format(ModelFormat.ONNX).as_posix(),
|
self.model_path.with_suffix(".onnx").as_posix(),
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
return session
|
return session
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class ModelType(StrEnum):
|
|||||||
class ModelFormat(StrEnum):
|
class ModelFormat(StrEnum):
|
||||||
ARMNN = "armnn"
|
ARMNN = "armnn"
|
||||||
ONNX = "onnx"
|
ONNX = "onnx"
|
||||||
RKNN = "rknn"
|
|
||||||
|
|
||||||
|
|
||||||
class ModelSource(StrEnum):
|
class ModelSource(StrEnum):
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class OrtSession:
|
|||||||
match provider:
|
match provider:
|
||||||
case "CPUExecutionProvider":
|
case "CPUExecutionProvider":
|
||||||
options = {"arena_extend_strategy": "kSameAsRequested"}
|
options = {"arena_extend_strategy": "kSameAsRequested"}
|
||||||
case "CUDAExecutionProvider" | "ROCMExecutionProvider":
|
case "CUDAExecutionProvider":
|
||||||
options = {"arena_extend_strategy": "kSameAsRequested", "device_id": settings.device_id}
|
options = {"arena_extend_strategy": "kSameAsRequested", "device_id": settings.device_id}
|
||||||
case "OpenVINOExecutionProvider":
|
case "OpenVINOExecutionProvider":
|
||||||
options = {
|
options = {
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any, NamedTuple
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from numpy.typing import NDArray
|
|
||||||
|
|
||||||
from app.config import log, settings
|
|
||||||
from app.schemas import SessionNode
|
|
||||||
|
|
||||||
from .rknnpool import RknnPoolExecutor, is_available, soc_name
|
|
||||||
|
|
||||||
is_available = is_available and settings.rknn
|
|
||||||
model_prefix = Path("rknpu") / soc_name if is_available and soc_name is not None else None
|
|
||||||
|
|
||||||
|
|
||||||
def run_inference(rknn_lite: Any, input: list[NDArray[np.float32]]) -> list[NDArray[np.float32]]:
|
|
||||||
outputs: list[NDArray[np.float32]] = rknn_lite.inference(inputs=input, data_format="nchw")
|
|
||||||
return outputs
|
|
||||||
|
|
||||||
|
|
||||||
input_output_mapping: dict[str, dict[str, Any]] = {
|
|
||||||
"detection": {
|
|
||||||
"input": {"norm_tensor:0": (1, 3, 640, 640)},
|
|
||||||
"output": {
|
|
||||||
"norm_tensor:1": (12800, 1),
|
|
||||||
"norm_tensor:2": (3200, 1),
|
|
||||||
"norm_tensor:3": (800, 1),
|
|
||||||
"norm_tensor:4": (12800, 4),
|
|
||||||
"norm_tensor:5": (3200, 4),
|
|
||||||
"norm_tensor:6": (800, 4),
|
|
||||||
"norm_tensor:7": (12800, 10),
|
|
||||||
"norm_tensor:8": (3200, 10),
|
|
||||||
"norm_tensor:9": (800, 10),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"recognition": {"input": {"norm_tensor:0": (1, 3, 112, 112)}, "output": {"norm_tensor:1": (1, 512)}},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class RknnSession:
|
|
||||||
def __init__(self, model_path: Path) -> None:
|
|
||||||
self.model_type = "detection" if "detection" in model_path.parts else "recognition"
|
|
||||||
self.tpe = settings.rknn_threads
|
|
||||||
|
|
||||||
log.info(f"Loading RKNN model from {model_path} with {self.tpe} threads.")
|
|
||||||
self.rknnpool = RknnPoolExecutor(model_path=model_path.as_posix(), tpes=self.tpe, func=run_inference)
|
|
||||||
log.info(f"Loaded RKNN model from {model_path} with {self.tpe} threads.")
|
|
||||||
|
|
||||||
def get_inputs(self) -> list[SessionNode]:
|
|
||||||
return [RknnNode(name=k, shape=v) for k, v in input_output_mapping[self.model_type]["input"].items()]
|
|
||||||
|
|
||||||
def get_outputs(self) -> list[SessionNode]:
|
|
||||||
return [RknnNode(name=k, shape=v) for k, v in input_output_mapping[self.model_type]["output"].items()]
|
|
||||||
|
|
||||||
def run(
|
|
||||||
self,
|
|
||||||
output_names: list[str] | None,
|
|
||||||
input_feed: dict[str, NDArray[np.float32]] | dict[str, NDArray[np.int32]],
|
|
||||||
run_options: Any = None,
|
|
||||||
) -> list[NDArray[np.float32]]:
|
|
||||||
input_data: list[NDArray[np.float32]] = [np.ascontiguousarray(v) for v in input_feed.values()]
|
|
||||||
self.rknnpool.put(input_data)
|
|
||||||
res = self.rknnpool.get()
|
|
||||||
if res is None:
|
|
||||||
raise RuntimeError("RKNN inference failed!")
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
class RknnNode(NamedTuple):
|
|
||||||
name: str | None
|
|
||||||
shape: tuple[int, ...]
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["RknnSession", "RknnNode", "is_available", "soc_name", "model_prefix"]
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
# This code is from leafqycc/rknn-multi-threaded
|
|
||||||
# Following Apache License 2.0
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from concurrent.futures import Future, ThreadPoolExecutor
|
|
||||||
from pathlib import Path
|
|
||||||
from queue import Queue
|
|
||||||
from typing import Callable
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from numpy.typing import NDArray
|
|
||||||
|
|
||||||
from app.config import log
|
|
||||||
from app.models.constants import RKNN_COREMASK_SUPPORTED_SOCS, RKNN_SUPPORTED_SOCS
|
|
||||||
|
|
||||||
|
|
||||||
def get_soc(device_tree_path: Path | str) -> str | None:
|
|
||||||
try:
|
|
||||||
with Path(device_tree_path).open() as f:
|
|
||||||
device_compatible_str = f.read()
|
|
||||||
for soc in RKNN_SUPPORTED_SOCS:
|
|
||||||
if soc in device_compatible_str:
|
|
||||||
return soc
|
|
||||||
log.warning("Device is not supported for RKNN")
|
|
||||||
except OSError as e:
|
|
||||||
log.warning(f"Could not read {device_tree_path}. Reason: %s", e)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
soc_name = None
|
|
||||||
is_available = False
|
|
||||||
try:
|
|
||||||
from rknnlite.api import RKNNLite
|
|
||||||
|
|
||||||
soc_name = get_soc("/proc/device-tree/compatible")
|
|
||||||
is_available = soc_name is not None
|
|
||||||
except ImportError:
|
|
||||||
log.debug("RKNN is not available")
|
|
||||||
|
|
||||||
|
|
||||||
def init_rknn(model_path: str) -> "RKNNLite":
|
|
||||||
if not is_available:
|
|
||||||
raise RuntimeError("rknn is not available!")
|
|
||||||
rknn_lite = RKNNLite()
|
|
||||||
rknn_lite.rknn_log.logger.setLevel(logging.ERROR)
|
|
||||||
ret = rknn_lite.load_rknn(model_path)
|
|
||||||
if ret != 0:
|
|
||||||
raise RuntimeError("Failed to load RKNN model")
|
|
||||||
|
|
||||||
if soc_name in RKNN_COREMASK_SUPPORTED_SOCS:
|
|
||||||
ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_AUTO)
|
|
||||||
else:
|
|
||||||
ret = rknn_lite.init_runtime() # Please do not set this parameter on other platforms.
|
|
||||||
|
|
||||||
if ret != 0:
|
|
||||||
raise RuntimeError("Failed to inititalize RKNN runtime environment")
|
|
||||||
|
|
||||||
return rknn_lite
|
|
||||||
|
|
||||||
|
|
||||||
class RknnPoolExecutor:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
model_path: str,
|
|
||||||
tpes: int,
|
|
||||||
func: Callable[["RKNNLite", list[NDArray[np.float32]]], list[NDArray[np.float32]]],
|
|
||||||
) -> None:
|
|
||||||
self.tpes = tpes
|
|
||||||
self.queue: Queue[Future[list[NDArray[np.float32]]]] = Queue()
|
|
||||||
self.rknn_pool = [init_rknn(model_path) for _ in range(tpes)]
|
|
||||||
self.pool = ThreadPoolExecutor(max_workers=tpes)
|
|
||||||
self.func = func
|
|
||||||
self.num = 0
|
|
||||||
|
|
||||||
def put(self, inputs: list[NDArray[np.float32]]) -> None:
|
|
||||||
self.queue.put(self.pool.submit(self.func, self.rknn_pool[self.num % self.tpes], inputs))
|
|
||||||
self.num += 1
|
|
||||||
|
|
||||||
def get(self) -> list[NDArray[np.float32]] | None:
|
|
||||||
if self.queue.empty():
|
|
||||||
return None
|
|
||||||
fut = self.queue.get()
|
|
||||||
return fut.result()
|
|
||||||
|
|
||||||
def release(self) -> None:
|
|
||||||
self.pool.shutdown()
|
|
||||||
for rknn_lite in self.rknn_pool:
|
|
||||||
rknn_lite.release()
|
|
||||||
|
|
||||||
def __del__(self) -> None:
|
|
||||||
self.release()
|
|
||||||
@@ -25,7 +25,6 @@ from app.models.facial_recognition.detection import FaceDetector
|
|||||||
from app.models.facial_recognition.recognition import FaceRecognizer
|
from app.models.facial_recognition.recognition import FaceRecognizer
|
||||||
from app.sessions.ann import AnnSession
|
from app.sessions.ann import AnnSession
|
||||||
from app.sessions.ort import OrtSession
|
from app.sessions.ort import OrtSession
|
||||||
from app.sessions.rknn import RknnSession, run_inference
|
|
||||||
|
|
||||||
from .config import Settings, settings
|
from .config import Settings, settings
|
||||||
from .models.base import InferenceModel
|
from .models.base import InferenceModel
|
||||||
@@ -70,14 +69,6 @@ class TestBase:
|
|||||||
|
|
||||||
assert encoder.model_format == ModelFormat.ARMNN
|
assert encoder.model_format == ModelFormat.ARMNN
|
||||||
|
|
||||||
def test_sets_default_model_format_to_rknn_if_available(self, mocker: MockerFixture) -> None:
|
|
||||||
mocker.patch.object(settings, "rknn", True)
|
|
||||||
mocker.patch("app.sessions.rknn.is_available", True)
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.model_format == ModelFormat.RKNN
|
|
||||||
|
|
||||||
def test_casts_cache_dir_string_to_path(self) -> None:
|
def test_casts_cache_dir_string_to_path(self) -> None:
|
||||||
cache_dir = "/test_cache"
|
cache_dir = "/test_cache"
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=cache_dir)
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=cache_dir)
|
||||||
@@ -134,7 +125,7 @@ class TestBase:
|
|||||||
"immich-app/ViT-B-32__openai",
|
"immich-app/ViT-B-32__openai",
|
||||||
cache_dir=encoder.cache_dir,
|
cache_dir=encoder.cache_dir,
|
||||||
local_dir=encoder.cache_dir,
|
local_dir=encoder.cache_dir,
|
||||||
ignore_patterns=["*.armnn", "*.rknn"],
|
ignore_patterns=["*.armnn"],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_download_downloads_armnn_if_preferred_format(self, snapshot_download: mock.Mock) -> None:
|
def test_download_downloads_armnn_if_preferred_format(self, snapshot_download: mock.Mock) -> None:
|
||||||
@@ -145,18 +136,7 @@ class TestBase:
|
|||||||
"immich-app/ViT-B-32__openai",
|
"immich-app/ViT-B-32__openai",
|
||||||
cache_dir=encoder.cache_dir,
|
cache_dir=encoder.cache_dir,
|
||||||
local_dir=encoder.cache_dir,
|
local_dir=encoder.cache_dir,
|
||||||
ignore_patterns=["*.rknn"],
|
ignore_patterns=[],
|
||||||
)
|
|
||||||
|
|
||||||
def test_download_downloads_rknn_if_preferred_format(self, snapshot_download: mock.Mock) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", model_format=ModelFormat.RKNN)
|
|
||||||
encoder.download()
|
|
||||||
|
|
||||||
snapshot_download.assert_called_once_with(
|
|
||||||
"immich-app/ViT-B-32__openai",
|
|
||||||
cache_dir=encoder.cache_dir,
|
|
||||||
local_dir=encoder.cache_dir,
|
|
||||||
ignore_patterns=["*.armnn"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_throws_exception_if_model_path_does_not_exist(
|
def test_throws_exception_if_model_path_does_not_exist(
|
||||||
@@ -180,7 +160,6 @@ class TestOrtSession:
|
|||||||
OV_EP = ["OpenVINOExecutionProvider", "CPUExecutionProvider"]
|
OV_EP = ["OpenVINOExecutionProvider", "CPUExecutionProvider"]
|
||||||
CUDA_EP_OUT_OF_ORDER = ["CPUExecutionProvider", "CUDAExecutionProvider"]
|
CUDA_EP_OUT_OF_ORDER = ["CPUExecutionProvider", "CUDAExecutionProvider"]
|
||||||
TRT_EP = ["TensorrtExecutionProvider", "CUDAExecutionProvider", "CPUExecutionProvider"]
|
TRT_EP = ["TensorrtExecutionProvider", "CUDAExecutionProvider", "CPUExecutionProvider"]
|
||||||
ROCM_EP = ["ROCMExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
|
|
||||||
@pytest.mark.providers(CPU_EP)
|
@pytest.mark.providers(CPU_EP)
|
||||||
def test_sets_cpu_provider(self, providers: list[str]) -> None:
|
def test_sets_cpu_provider(self, providers: list[str]) -> None:
|
||||||
@@ -220,12 +199,6 @@ class TestOrtSession:
|
|||||||
|
|
||||||
assert session.providers == self.CUDA_EP
|
assert session.providers == self.CUDA_EP
|
||||||
|
|
||||||
@pytest.mark.providers(ROCM_EP)
|
|
||||||
def test_uses_rocm(self, providers: list[str]) -> None:
|
|
||||||
session = OrtSession("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert session.providers == self.ROCM_EP
|
|
||||||
|
|
||||||
def test_sets_provider_kwarg(self) -> None:
|
def test_sets_provider_kwarg(self) -> None:
|
||||||
providers = ["CUDAExecutionProvider"]
|
providers = ["CUDAExecutionProvider"]
|
||||||
session = OrtSession("ViT-B-32__openai", providers=providers)
|
session = OrtSession("ViT-B-32__openai", providers=providers)
|
||||||
@@ -242,33 +215,19 @@ class TestOrtSession:
|
|||||||
{"arena_extend_strategy": "kSameAsRequested"},
|
{"arena_extend_strategy": "kSameAsRequested"},
|
||||||
]
|
]
|
||||||
|
|
||||||
def test_sets_provider_options_for_openvino(self) -> None:
|
def test_sets_device_id_for_openvino(self) -> None:
|
||||||
model_path = "/cache/ViT-B-32__openai/textual/model.onnx"
|
|
||||||
os.environ["MACHINE_LEARNING_DEVICE_ID"] = "1"
|
os.environ["MACHINE_LEARNING_DEVICE_ID"] = "1"
|
||||||
|
|
||||||
session = OrtSession(model_path, providers=["OpenVINOExecutionProvider"])
|
session = OrtSession("ViT-B-32__openai", providers=["OpenVINOExecutionProvider"])
|
||||||
|
|
||||||
assert session.provider_options == [
|
assert session.provider_options[0]["device_type"] == "GPU.1"
|
||||||
{
|
|
||||||
"device_type": "GPU.1",
|
|
||||||
"precision": "FP32",
|
|
||||||
"cache_dir": "/cache/ViT-B-32__openai/textual/openvino",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_sets_provider_options_for_cuda(self) -> None:
|
def test_sets_device_id_for_cuda(self) -> None:
|
||||||
os.environ["MACHINE_LEARNING_DEVICE_ID"] = "1"
|
os.environ["MACHINE_LEARNING_DEVICE_ID"] = "1"
|
||||||
|
|
||||||
session = OrtSession("ViT-B-32__openai", providers=["CUDAExecutionProvider"])
|
session = OrtSession("ViT-B-32__openai", providers=["CUDAExecutionProvider"])
|
||||||
|
|
||||||
assert session.provider_options == [{"arena_extend_strategy": "kSameAsRequested", "device_id": "1"}]
|
assert session.provider_options[0]["device_id"] == "1"
|
||||||
|
|
||||||
def test_sets_provider_options_for_rocm(self) -> None:
|
|
||||||
os.environ["MACHINE_LEARNING_DEVICE_ID"] = "1"
|
|
||||||
|
|
||||||
session = OrtSession("ViT-B-32__openai", providers=["ROCMExecutionProvider"])
|
|
||||||
|
|
||||||
assert session.provider_options == [{"arena_extend_strategy": "kSameAsRequested", "device_id": "1"}]
|
|
||||||
|
|
||||||
def test_sets_provider_options_kwarg(self) -> None:
|
def test_sets_provider_options_kwarg(self) -> None:
|
||||||
session = OrtSession(
|
session = OrtSession(
|
||||||
@@ -369,33 +328,6 @@ class TestAnnSession:
|
|||||||
np_spy.assert_has_calls([mock.call(input1), mock.call(input2)])
|
np_spy.assert_has_calls([mock.call(input1), mock.call(input2)])
|
||||||
|
|
||||||
|
|
||||||
class TestRknnSession:
|
|
||||||
def test_creates_rknn_session(self, rknn_session: mock.Mock, info: mock.Mock, mocker: MockerFixture) -> None:
|
|
||||||
model_path = mock.MagicMock(spec=Path)
|
|
||||||
tpe = 1
|
|
||||||
mocker.patch("app.sessions.rknn.soc_name", "rk3566")
|
|
||||||
mocker.patch("app.sessions.rknn.is_available", True)
|
|
||||||
RknnSession(model_path)
|
|
||||||
|
|
||||||
rknn_session.assert_called_once_with(model_path=model_path.as_posix(), tpes=tpe, func=run_inference)
|
|
||||||
|
|
||||||
info.assert_has_calls([mock.call(f"Loaded RKNN model from {model_path} with {tpe} threads.")])
|
|
||||||
|
|
||||||
def test_run_rknn(self, rknn_session: mock.Mock, mocker: MockerFixture) -> None:
|
|
||||||
rknn_session.return_value.load.return_value = 123
|
|
||||||
np_spy = mocker.spy(np, "ascontiguousarray")
|
|
||||||
mocker.patch("app.sessions.rknn.soc_name", "rk3566")
|
|
||||||
session = RknnSession(Path("ViT-B-32__openai"))
|
|
||||||
[input1, input2] = [np.random.rand(1, 3, 224, 224).astype(np.float32) for _ in range(2)]
|
|
||||||
input_feed = {"input.1": input1, "input.2": input2}
|
|
||||||
|
|
||||||
session.run(None, input_feed)
|
|
||||||
|
|
||||||
rknn_session.return_value.put.assert_called_once_with([input1, input2])
|
|
||||||
np_spy.call_count == 2
|
|
||||||
np_spy.assert_has_calls([mock.call(input1), mock.call(input2)])
|
|
||||||
|
|
||||||
|
|
||||||
class TestCLIP:
|
class TestCLIP:
|
||||||
embedding = np.random.rand(512).astype(np.float32)
|
embedding = np.random.rand(512).astype(np.float32)
|
||||||
cache_dir = Path("test_cache")
|
cache_dir = Path("test_cache")
|
||||||
@@ -897,7 +829,9 @@ class TestLoad:
|
|||||||
mock_model.clear_cache.assert_not_called()
|
mock_model.clear_cache.assert_not_called()
|
||||||
mock_model.load.assert_not_called()
|
mock_model.load.assert_not_called()
|
||||||
|
|
||||||
async def test_falls_back_to_onnx_if_other_format_does_not_exist(self, warning: mock.Mock) -> None:
|
async def test_falls_back_to_onnx_if_other_format_does_not_exist(
|
||||||
|
self, exception: mock.Mock, warning: mock.Mock
|
||||||
|
) -> None:
|
||||||
mock_model = mock.Mock(spec=InferenceModel)
|
mock_model = mock.Mock(spec=InferenceModel)
|
||||||
mock_model.model_name = "test_model_name"
|
mock_model.model_name = "test_model_name"
|
||||||
mock_model.model_type = ModelType.VISUAL
|
mock_model.model_type = ModelType.VISUAL
|
||||||
@@ -912,9 +846,8 @@ class TestLoad:
|
|||||||
|
|
||||||
mock_model.clear_cache.assert_not_called()
|
mock_model.clear_cache.assert_not_called()
|
||||||
assert mock_model.load.call_count == 2
|
assert mock_model.load.call_count == 2
|
||||||
warning.assert_called_once_with(
|
exception.assert_called_once_with(error)
|
||||||
"ARMNN is available, but model 'test_model_name' does not support it.", exc_info=error
|
warning.assert_called_once_with("ARMNN is available, but model 'test_model_name' does not support it.")
|
||||||
)
|
|
||||||
mock_model.model_format = ModelFormat.ONNX
|
mock_model.model_format = ModelFormat.ONNX
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
3.12
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
FROM mambaorg/micromamba:bookworm-slim@sha256:e3797091302382ea841498bc93a7b0a50f7c1448333d5e946d2d1608d0c5f43d AS builder
|
||||||
|
|
||||||
|
ENV TRANSFORMERS_CACHE=/cache \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
PATH="/opt/venv/bin:$PATH" \
|
||||||
|
PYTHONPATH=/usr/src
|
||||||
|
|
||||||
|
COPY --chown=$MAMBA_USER:$MAMBA_USER conda-lock.yml /tmp/conda-lock.yml
|
||||||
|
RUN micromamba install -y -n base -f /tmp/conda-lock.yml && \
|
||||||
|
micromamba remove -y -n base cxx-compiler && \
|
||||||
|
micromamba clean --all --yes
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
COPY --chown=$MAMBA_USER:$MAMBA_USER start.sh .
|
||||||
|
COPY --chown=$MAMBA_USER:$MAMBA_USER app .
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/_entrypoint.sh"]
|
||||||
|
CMD ["./start.sh"]
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
|||||||
|
name: base
|
||||||
|
channels:
|
||||||
|
- conda-forge
|
||||||
|
platforms:
|
||||||
|
- linux-64
|
||||||
|
- linux-aarch64
|
||||||
|
dependencies:
|
||||||
|
- black
|
||||||
|
- conda-lock
|
||||||
|
- mypy
|
||||||
|
- pytest
|
||||||
|
- pytest-cov
|
||||||
|
- pytest-mock
|
||||||
|
- ruff
|
||||||
|
category: dev
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: base
|
||||||
|
channels:
|
||||||
|
- conda-forge
|
||||||
|
- nvidia
|
||||||
|
- pytorch
|
||||||
|
platforms:
|
||||||
|
- linux-64
|
||||||
|
dependencies:
|
||||||
|
- cxx-compiler
|
||||||
|
- onnx==1.*
|
||||||
|
- onnxruntime==1.*
|
||||||
|
- open-clip-torch==2.*
|
||||||
|
- orjson==3.*
|
||||||
|
- pip
|
||||||
|
- python==3.11.*
|
||||||
|
- pytorch>=2.3
|
||||||
|
- rich==13.*
|
||||||
|
- safetensors==0.*
|
||||||
|
- setuptools==68.*
|
||||||
|
- torchvision
|
||||||
|
- transformers==4.*
|
||||||
|
- pip:
|
||||||
|
- multilingual-clip
|
||||||
|
- onnxsim
|
||||||
|
category: main
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
import json
|
|
||||||
import resource
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import typer
|
|
||||||
from tenacity import retry, stop_after_attempt, wait_fixed
|
|
||||||
from typing_extensions import Annotated
|
|
||||||
|
|
||||||
from .exporters.constants import DELETE_PATTERNS, SOURCE_TO_METADATA, ModelSource, ModelTask
|
|
||||||
from .exporters.onnx import export as onnx_export
|
|
||||||
from .exporters.rknn import export as rknn_export
|
|
||||||
|
|
||||||
app = typer.Typer(pretty_exceptions_show_locals=False)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_readme(model_name: str, model_source: ModelSource) -> str:
|
|
||||||
(name, link, type) = SOURCE_TO_METADATA[model_source]
|
|
||||||
match model_source:
|
|
||||||
case ModelSource.MCLIP:
|
|
||||||
tags = ["immich", "clip", "multilingual"]
|
|
||||||
case ModelSource.OPENCLIP:
|
|
||||||
tags = ["immich", "clip"]
|
|
||||||
lowered = model_name.lower()
|
|
||||||
if "xlm" in lowered or "nllb" in lowered:
|
|
||||||
tags.append("multilingual")
|
|
||||||
case ModelSource.INSIGHTFACE:
|
|
||||||
tags = ["immich", "facial-recognition"]
|
|
||||||
case _:
|
|
||||||
raise ValueError(f"Unsupported model source {model_source}")
|
|
||||||
|
|
||||||
return f"""---
|
|
||||||
tags:
|
|
||||||
{" - " + "\n - ".join(tags)}
|
|
||||||
---
|
|
||||||
# Model Description
|
|
||||||
|
|
||||||
This repo contains ONNX exports for the associated {type} model by {name}. See the [{name}]({link}) repo for more info.
|
|
||||||
|
|
||||||
This repo is specifically intended for use with [Immich](https://immich.app/), a self-hosted photo library.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def clean_name(model_name: str) -> str:
|
|
||||||
hf_model_name = model_name.split("/")[-1]
|
|
||||||
hf_model_name = hf_model_name.replace("xlm-roberta-large", "XLM-Roberta-Large")
|
|
||||||
hf_model_name = hf_model_name.replace("xlm-roberta-base", "XLM-Roberta-Base")
|
|
||||||
return hf_model_name
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
|
||||||
def export(model_name: str, model_source: ModelSource, output_dir: Path = Path("models"), cache: bool = True) -> None:
|
|
||||||
hf_model_name = clean_name(model_name)
|
|
||||||
output_dir = output_dir / hf_model_name
|
|
||||||
match model_source:
|
|
||||||
case ModelSource.MCLIP | ModelSource.OPENCLIP:
|
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
onnx_export(model_name, model_source, output_dir, cache=cache)
|
|
||||||
case ModelSource.INSIGHTFACE:
|
|
||||||
from huggingface_hub import snapshot_download
|
|
||||||
|
|
||||||
# TODO: start from insightface dump instead of downloading from HF
|
|
||||||
snapshot_download(f"immich-app/{hf_model_name}", local_dir=output_dir)
|
|
||||||
case _:
|
|
||||||
raise ValueError(f"Unsupported model source {model_source}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
rknn_export(output_dir, cache=cache)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Failed to export model {model_name} to rknn: {e}")
|
|
||||||
(output_dir / "rknpu").unlink(missing_ok=True)
|
|
||||||
|
|
||||||
readme_path = output_dir / "README.md"
|
|
||||||
if not (cache or readme_path.exists()):
|
|
||||||
with open(readme_path, "w") as f:
|
|
||||||
f.write(generate_readme(model_name, model_source))
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
|
||||||
def profile(model_dir: Path, model_task: ModelTask, output_path: Path) -> None:
|
|
||||||
from timeit import timeit
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import onnxruntime as ort
|
|
||||||
|
|
||||||
np.random.seed(0)
|
|
||||||
|
|
||||||
sess_options = ort.SessionOptions()
|
|
||||||
sess_options.enable_cpu_mem_arena = False
|
|
||||||
providers = ["CPUExecutionProvider"]
|
|
||||||
provider_options = [{"arena_extend_strategy": "kSameAsRequested"}]
|
|
||||||
match model_task:
|
|
||||||
case ModelTask.SEARCH:
|
|
||||||
textual = ort.InferenceSession(
|
|
||||||
model_dir / "textual" / "model.onnx",
|
|
||||||
sess_options=sess_options,
|
|
||||||
providers=providers,
|
|
||||||
provider_options=provider_options,
|
|
||||||
)
|
|
||||||
tokens = {node.name: np.random.rand(*node.shape).astype(np.int32) for node in textual.get_inputs()}
|
|
||||||
|
|
||||||
visual = ort.InferenceSession(
|
|
||||||
model_dir / "visual" / "model.onnx",
|
|
||||||
sess_options=sess_options,
|
|
||||||
providers=providers,
|
|
||||||
provider_options=provider_options,
|
|
||||||
)
|
|
||||||
image = {node.name: np.random.rand(*node.shape).astype(np.float32) for node in visual.get_inputs()}
|
|
||||||
|
|
||||||
def predict() -> None:
|
|
||||||
textual.run(None, tokens)
|
|
||||||
visual.run(None, image)
|
|
||||||
|
|
||||||
case ModelTask.FACIAL_RECOGNITION:
|
|
||||||
detection = ort.InferenceSession(
|
|
||||||
model_dir / "detection" / "model.onnx",
|
|
||||||
sess_options=sess_options,
|
|
||||||
providers=providers,
|
|
||||||
provider_options=provider_options,
|
|
||||||
)
|
|
||||||
image = {node.name: np.random.rand(1, 3, 640, 640).astype(np.float32) for node in detection.get_inputs()}
|
|
||||||
|
|
||||||
recognition = ort.InferenceSession(
|
|
||||||
model_dir / "recognition" / "model.onnx",
|
|
||||||
sess_options=sess_options,
|
|
||||||
providers=providers,
|
|
||||||
provider_options=provider_options,
|
|
||||||
)
|
|
||||||
face = {node.name: np.random.rand(1, 3, 112, 112).astype(np.float32) for node in recognition.get_inputs()}
|
|
||||||
|
|
||||||
def predict() -> None:
|
|
||||||
detection.run(None, image)
|
|
||||||
recognition.run(None, face)
|
|
||||||
|
|
||||||
case _:
|
|
||||||
raise ValueError(f"Unsupported model task {model_task}")
|
|
||||||
predict()
|
|
||||||
ms = timeit(predict, number=100)
|
|
||||||
rss = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
|
||||||
json.dump({"pretrained_model": model_dir.name, "peak_rss": rss, "exec_time_ms": ms}, output_path.open("w"))
|
|
||||||
print(f"Model {model_dir.name} took {ms:.2f}ms per iteration using {rss / 1024:.2f}MiB of memory")
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
|
||||||
def upload(
|
|
||||||
model_dir: Path,
|
|
||||||
hf_organization: str = "immich-app",
|
|
||||||
hf_auth_token: Annotated[str | None, typer.Option(envvar="HF_AUTH_TOKEN")] = None,
|
|
||||||
) -> None:
|
|
||||||
from huggingface_hub import create_repo, upload_folder
|
|
||||||
|
|
||||||
repo_id = f"{hf_organization}/{model_dir.name}"
|
|
||||||
|
|
||||||
@retry(stop=stop_after_attempt(5), wait=wait_fixed(5))
|
|
||||||
def upload_model() -> None:
|
|
||||||
create_repo(repo_id, exist_ok=True, token=hf_auth_token)
|
|
||||||
upload_folder(
|
|
||||||
repo_id=repo_id,
|
|
||||||
folder_path=model_dir,
|
|
||||||
# remote repo files to be deleted before uploading
|
|
||||||
# deletion is in the same commit as the upload, so it's atomic
|
|
||||||
delete_patterns=DELETE_PATTERNS,
|
|
||||||
token=hf_auth_token,
|
|
||||||
)
|
|
||||||
|
|
||||||
upload_model()
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from immich_model_exporter import app
|
|
||||||
|
|
||||||
app()
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
from enum import StrEnum
|
|
||||||
from typing import NamedTuple
|
|
||||||
|
|
||||||
|
|
||||||
class ModelSource(StrEnum):
|
|
||||||
INSIGHTFACE = "insightface"
|
|
||||||
MCLIP = "mclip"
|
|
||||||
OPENCLIP = "openclip"
|
|
||||||
|
|
||||||
|
|
||||||
class ModelTask(StrEnum):
|
|
||||||
FACIAL_RECOGNITION = "facial-recognition"
|
|
||||||
SEARCH = "clip"
|
|
||||||
|
|
||||||
|
|
||||||
class SourceMetadata(NamedTuple):
|
|
||||||
name: str
|
|
||||||
link: str
|
|
||||||
type: str
|
|
||||||
|
|
||||||
|
|
||||||
SOURCE_TO_METADATA = {
|
|
||||||
ModelSource.MCLIP: SourceMetadata("M-CLIP", "https://huggingface.co/M-CLIP", "CLIP"),
|
|
||||||
ModelSource.OPENCLIP: SourceMetadata("OpenCLIP", "https://github.com/mlfoundations/open_clip", "CLIP"),
|
|
||||||
ModelSource.INSIGHTFACE: SourceMetadata(
|
|
||||||
"InsightFace", "https://github.com/deepinsight/insightface/tree/master", "facial recognition"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SOURCE_TO_TASK = {
|
|
||||||
ModelSource.MCLIP: ModelTask.SEARCH,
|
|
||||||
ModelSource.OPENCLIP: ModelTask.SEARCH,
|
|
||||||
ModelSource.INSIGHTFACE: ModelTask.FACIAL_RECOGNITION,
|
|
||||||
}
|
|
||||||
|
|
||||||
RKNN_SOCS = ["rk3566", "rk3568", "rk3576", "rk3588"]
|
|
||||||
|
|
||||||
|
|
||||||
# glob to delete old UUID blobs when reuploading models
|
|
||||||
_uuid_char = "[a-fA-F0-9]"
|
|
||||||
_uuid_glob = _uuid_char * 8 + "-" + _uuid_char * 4 + "-" + _uuid_char * 4 + "-" + _uuid_char * 4 + "-" + _uuid_char * 12
|
|
||||||
DELETE_PATTERNS = [
|
|
||||||
"**/*onnx*",
|
|
||||||
"**/Constant*",
|
|
||||||
"**/*.weight",
|
|
||||||
"**/*.bias",
|
|
||||||
"**/*.proj",
|
|
||||||
"**/*in_proj_bias",
|
|
||||||
"**/*.npy",
|
|
||||||
"**/*.latent",
|
|
||||||
"**/*.pos_embed",
|
|
||||||
f"**/{_uuid_glob}",
|
|
||||||
]
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from ..constants import ModelSource
|
|
||||||
from .models import mclip, openclip
|
|
||||||
|
|
||||||
|
|
||||||
def export(
|
|
||||||
model_name: str, model_source: ModelSource, output_dir: Path, opset_version: int = 19, cache: bool = True
|
|
||||||
) -> None:
|
|
||||||
visual_dir = output_dir / "visual"
|
|
||||||
textual_dir = output_dir / "textual"
|
|
||||||
match model_source:
|
|
||||||
case ModelSource.MCLIP:
|
|
||||||
mclip.to_onnx(model_name, opset_version, visual_dir, textual_dir, cache=cache)
|
|
||||||
case ModelSource.OPENCLIP:
|
|
||||||
name, _, pretrained = model_name.partition("__")
|
|
||||||
config = openclip.OpenCLIPModelConfig(name, pretrained)
|
|
||||||
openclip.to_onnx(config, opset_version, visual_dir, textual_dir, cache=cache)
|
|
||||||
case _:
|
|
||||||
raise ValueError(f"Unsupported model source {model_source}")
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
import warnings
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from functools import cached_property
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from .util import get_model_path, save_config
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class OpenCLIPModelConfig:
|
|
||||||
name: str
|
|
||||||
pretrained: str
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def model_config(self) -> dict[str, Any]:
|
|
||||||
import open_clip
|
|
||||||
|
|
||||||
config: dict[str, Any] | None = open_clip.get_model_config(self.name)
|
|
||||||
if config is None:
|
|
||||||
raise ValueError(f"Unknown model {self.name}")
|
|
||||||
return config
|
|
||||||
|
|
||||||
@property
|
|
||||||
def image_size(self) -> int:
|
|
||||||
image_size: int = self.model_config["vision_cfg"]["image_size"]
|
|
||||||
return image_size
|
|
||||||
|
|
||||||
@property
|
|
||||||
def sequence_length(self) -> int:
|
|
||||||
context_length: int = self.model_config["text_cfg"].get("context_length", 77)
|
|
||||||
return context_length
|
|
||||||
|
|
||||||
|
|
||||||
def to_onnx(
|
|
||||||
model_cfg: OpenCLIPModelConfig,
|
|
||||||
opset_version: int,
|
|
||||||
output_dir_visual: Path | str | None = None,
|
|
||||||
output_dir_textual: Path | str | None = None,
|
|
||||||
cache: bool = True,
|
|
||||||
) -> tuple[Path | None, Path | None]:
|
|
||||||
visual_path = None
|
|
||||||
textual_path = None
|
|
||||||
if output_dir_visual is not None:
|
|
||||||
output_dir_visual = Path(output_dir_visual)
|
|
||||||
visual_path = get_model_path(output_dir_visual)
|
|
||||||
|
|
||||||
if output_dir_textual is not None:
|
|
||||||
output_dir_textual = Path(output_dir_textual)
|
|
||||||
textual_path = get_model_path(output_dir_textual)
|
|
||||||
|
|
||||||
if cache and ((textual_path is None or textual_path.exists()) and (visual_path is None or visual_path.exists())):
|
|
||||||
print(f"Models {textual_path} and {visual_path} already exist, skipping")
|
|
||||||
return visual_path, textual_path
|
|
||||||
|
|
||||||
import open_clip
|
|
||||||
import torch
|
|
||||||
from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
torch.backends.mha.set_fastpath_enabled(False)
|
|
||||||
|
|
||||||
model = open_clip.create_model(
|
|
||||||
model_cfg.name,
|
|
||||||
pretrained=model_cfg.pretrained,
|
|
||||||
jit=False,
|
|
||||||
require_pretrained=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
text_vision_cfg = open_clip.get_model_config(model_cfg.name)
|
|
||||||
|
|
||||||
model.eval()
|
|
||||||
for param in model.parameters():
|
|
||||||
param.requires_grad_(False)
|
|
||||||
|
|
||||||
if visual_path is not None and output_dir_visual is not None:
|
|
||||||
if not cache or not visual_path.exists():
|
|
||||||
save_config(
|
|
||||||
open_clip.get_model_preprocess_cfg(model),
|
|
||||||
output_dir_visual / "preprocess_cfg.json",
|
|
||||||
)
|
|
||||||
save_config(text_vision_cfg, output_dir_visual.parent / "config.json")
|
|
||||||
_export_image_encoder(model, model_cfg, visual_path, opset_version)
|
|
||||||
else:
|
|
||||||
print(f"Model {visual_path} already exists, skipping")
|
|
||||||
|
|
||||||
if textual_path is not None and output_dir_textual is not None:
|
|
||||||
if not cache or not textual_path.exists():
|
|
||||||
tokenizer_name = text_vision_cfg["text_cfg"].get("hf_tokenizer_name", "openai/clip-vit-base-patch32")
|
|
||||||
AutoTokenizer.from_pretrained(tokenizer_name).save_pretrained(output_dir_textual)
|
|
||||||
_export_text_encoder(model, model_cfg, textual_path, opset_version)
|
|
||||||
else:
|
|
||||||
print(f"Model {textual_path} already exists, skipping")
|
|
||||||
return visual_path, textual_path
|
|
||||||
|
|
||||||
|
|
||||||
def _export_image_encoder(
|
|
||||||
model: Any, model_cfg: OpenCLIPModelConfig, output_path: Path | str, opset_version: int
|
|
||||||
) -> None:
|
|
||||||
import torch
|
|
||||||
|
|
||||||
output_path = Path(output_path)
|
|
||||||
|
|
||||||
def encode_image(image: torch.Tensor) -> torch.Tensor:
|
|
||||||
output = model.encode_image(image, normalize=True)
|
|
||||||
assert isinstance(output, torch.Tensor)
|
|
||||||
return output
|
|
||||||
|
|
||||||
model.forward = encode_image
|
|
||||||
|
|
||||||
args = (torch.randn(1, 3, model_cfg.image_size, model_cfg.image_size),)
|
|
||||||
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
warnings.simplefilter("ignore", UserWarning)
|
|
||||||
torch.onnx.export(
|
|
||||||
model,
|
|
||||||
args,
|
|
||||||
output_path.as_posix(),
|
|
||||||
input_names=["image"],
|
|
||||||
output_names=["embedding"],
|
|
||||||
opset_version=opset_version,
|
|
||||||
# dynamic_axes={"image": {0: "batch_size"}},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _export_text_encoder(
|
|
||||||
model: Any, model_cfg: OpenCLIPModelConfig, output_path: Path | str, opset_version: int
|
|
||||||
) -> None:
|
|
||||||
import torch
|
|
||||||
|
|
||||||
output_path = Path(output_path)
|
|
||||||
|
|
||||||
def encode_text(text: torch.Tensor) -> torch.Tensor:
|
|
||||||
output = model.encode_text(text, normalize=True)
|
|
||||||
assert isinstance(output, torch.Tensor)
|
|
||||||
return output
|
|
||||||
|
|
||||||
model.forward = encode_text
|
|
||||||
|
|
||||||
args = (torch.ones(1, model_cfg.sequence_length, dtype=torch.int32),)
|
|
||||||
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
warnings.simplefilter("ignore", UserWarning)
|
|
||||||
torch.onnx.export(
|
|
||||||
model,
|
|
||||||
args,
|
|
||||||
output_path.as_posix(),
|
|
||||||
input_names=["text"],
|
|
||||||
output_names=["embedding"],
|
|
||||||
opset_version=opset_version,
|
|
||||||
# dynamic_axes={"text": {0: "batch_size"}},
|
|
||||||
)
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from .constants import RKNN_SOCS
|
|
||||||
|
|
||||||
|
|
||||||
def _export_platform(
|
|
||||||
model_dir: Path,
|
|
||||||
target_platform: str,
|
|
||||||
inputs: list[str] | None = None,
|
|
||||||
input_size_list: list[list[int]] | None = None,
|
|
||||||
fuse_matmul_softmax_matmul_to_sdpa: bool = True,
|
|
||||||
cache: bool = True,
|
|
||||||
) -> None:
|
|
||||||
from rknn.api import RKNN
|
|
||||||
|
|
||||||
input_path = model_dir / "model.onnx"
|
|
||||||
output_path = model_dir / "rknpu" / target_platform / "model.rknn"
|
|
||||||
if cache and output_path.exists():
|
|
||||||
print(f"Model {input_path} already exists at {output_path}, skipping")
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"Exporting model {input_path} to {output_path}")
|
|
||||||
|
|
||||||
rknn = RKNN(verbose=False)
|
|
||||||
|
|
||||||
rknn.config(
|
|
||||||
target_platform=target_platform,
|
|
||||||
disable_rules=["fuse_matmul_softmax_matmul_to_sdpa"] if not fuse_matmul_softmax_matmul_to_sdpa else [],
|
|
||||||
enable_flash_attention=False,
|
|
||||||
model_pruning=True,
|
|
||||||
)
|
|
||||||
ret = rknn.load_onnx(model=input_path.as_posix(), inputs=inputs, input_size_list=input_size_list)
|
|
||||||
|
|
||||||
if ret != 0:
|
|
||||||
raise RuntimeError("Load failed!")
|
|
||||||
|
|
||||||
ret = rknn.build(do_quantization=False)
|
|
||||||
|
|
||||||
if ret != 0:
|
|
||||||
raise RuntimeError("Build failed!")
|
|
||||||
|
|
||||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
ret = rknn.export_rknn(output_path.as_posix())
|
|
||||||
if ret != 0:
|
|
||||||
raise RuntimeError("Export rknn model failed!")
|
|
||||||
|
|
||||||
|
|
||||||
def _export_platforms(
|
|
||||||
model_dir: Path,
|
|
||||||
inputs: list[str] | None = None,
|
|
||||||
input_size_list: list[list[int]] | None = None,
|
|
||||||
cache: bool = True,
|
|
||||||
) -> None:
|
|
||||||
fuse_matmul_softmax_matmul_to_sdpa = True
|
|
||||||
for soc in RKNN_SOCS:
|
|
||||||
try:
|
|
||||||
_export_platform(
|
|
||||||
model_dir,
|
|
||||||
soc,
|
|
||||||
inputs=inputs,
|
|
||||||
input_size_list=input_size_list,
|
|
||||||
fuse_matmul_softmax_matmul_to_sdpa=fuse_matmul_softmax_matmul_to_sdpa,
|
|
||||||
cache=cache,
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Failed to export model for {soc}: {e}")
|
|
||||||
if "inputs or 'outputs' must be set" in str(e):
|
|
||||||
print("Retrying without fuse_matmul_softmax_matmul_to_sdpa")
|
|
||||||
fuse_matmul_softmax_matmul_to_sdpa = False
|
|
||||||
_export_platform(
|
|
||||||
model_dir,
|
|
||||||
soc,
|
|
||||||
inputs=inputs,
|
|
||||||
input_size_list=input_size_list,
|
|
||||||
fuse_matmul_softmax_matmul_to_sdpa=fuse_matmul_softmax_matmul_to_sdpa,
|
|
||||||
cache=cache,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def export(model_dir: Path, cache: bool = True) -> None:
|
|
||||||
textual = model_dir / "textual"
|
|
||||||
visual = model_dir / "visual"
|
|
||||||
detection = model_dir / "detection"
|
|
||||||
recognition = model_dir / "recognition"
|
|
||||||
|
|
||||||
if textual.is_dir():
|
|
||||||
_export_platforms(textual, cache=cache)
|
|
||||||
|
|
||||||
if visual.is_dir():
|
|
||||||
_export_platforms(visual, cache=cache)
|
|
||||||
|
|
||||||
if detection.is_dir():
|
|
||||||
_export_platforms(detection, inputs=["input.1"], input_size_list=[[1, 3, 640, 640]], cache=cache)
|
|
||||||
|
|
||||||
if recognition.is_dir():
|
|
||||||
_export_platforms(recognition, inputs=["input.1"], input_size_list=[[1, 3, 112, 112]], cache=cache)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import json
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
models_dir = Path("models")
|
|
||||||
model_to_embed_dim = {}
|
|
||||||
for model_dir in models_dir.iterdir():
|
|
||||||
if not model_dir.is_dir():
|
|
||||||
continue
|
|
||||||
|
|
||||||
config_path = model_dir / "config.json"
|
|
||||||
if not config_path.exists():
|
|
||||||
print(f"Skipping {model_dir.name} as it does not have a config.json")
|
|
||||||
continue
|
|
||||||
with open(config_path) as f:
|
|
||||||
config = json.load(f)
|
|
||||||
embed_dim = config.get("embed_dim")
|
|
||||||
if embed_dim is None:
|
|
||||||
print(f"Skipping {model_dir.name} as it does not have an embed_dim")
|
|
||||||
continue
|
|
||||||
print(f"{model_dir.name}: {embed_dim}")
|
|
||||||
model_to_embed_dim[model_dir.name] = {"dimSize": embed_dim}
|
|
||||||
print(json.dumps(model_to_embed_dim))
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
import polars as pl
|
|
||||||
|
|
||||||
|
|
||||||
def collapsed_table(language: str, df: pl.DataFrame) -> str:
|
|
||||||
with pl.Config(
|
|
||||||
tbl_formatting="ASCII_MARKDOWN",
|
|
||||||
tbl_hide_column_data_types=True,
|
|
||||||
tbl_hide_dataframe_shape=True,
|
|
||||||
fmt_str_lengths=100,
|
|
||||||
tbl_rows=1000,
|
|
||||||
tbl_width_chars=1000,
|
|
||||||
):
|
|
||||||
return f"<details>\n<summary>{language}</summary>\n{str(df)}\n</details>"
|
|
||||||
|
|
||||||
|
|
||||||
languages = {
|
|
||||||
"en": "English",
|
|
||||||
"ar": "Arabic",
|
|
||||||
"bn": "Bengali",
|
|
||||||
"zh": "Chinese (Simplified)",
|
|
||||||
"hr": "Croatian",
|
|
||||||
"quz": "Cusco Quechua",
|
|
||||||
"cs": "Czech",
|
|
||||||
"da": "Danish",
|
|
||||||
"nl": "Dutch",
|
|
||||||
"fil": "Filipino",
|
|
||||||
"fi": "Finnish",
|
|
||||||
"fr": "French",
|
|
||||||
"de": "German",
|
|
||||||
"el": "Greek",
|
|
||||||
"he": "Hebrew",
|
|
||||||
"hi": "Hindi",
|
|
||||||
"hu": "Hungarian",
|
|
||||||
"id": "Indonesian",
|
|
||||||
"it": "Italian",
|
|
||||||
"ja": "Japanese",
|
|
||||||
"ko": "Korean",
|
|
||||||
"mi": "Maori",
|
|
||||||
"no": "Norwegian",
|
|
||||||
"fa": "Persian",
|
|
||||||
"pl": "Polish",
|
|
||||||
"pt": "Portuguese",
|
|
||||||
"ro": "Romanian",
|
|
||||||
"ru": "Russian",
|
|
||||||
"es": "Spanish",
|
|
||||||
"sw": "Swahili",
|
|
||||||
"sv": "Swedish",
|
|
||||||
"te": "Telugu",
|
|
||||||
"th": "Thai",
|
|
||||||
"tr": "Turkish",
|
|
||||||
"uk": "Ukrainian",
|
|
||||||
"vi": "Vietnamese",
|
|
||||||
}
|
|
||||||
|
|
||||||
profile_df = pl.scan_ndjson("profiling/*.json").select("pretrained_model", "peak_rss", "exec_time_ms")
|
|
||||||
eval_df = pl.scan_ndjson("results/*.json").select("model", "pretrained", "language", "metrics")
|
|
||||||
|
|
||||||
eval_df = eval_df.with_columns(
|
|
||||||
model=pl.col("model")
|
|
||||||
.str.replace("xlm-roberta-base", "XLM-Roberta-Base")
|
|
||||||
.str.replace("xlm-roberta-large", "XLM-Roberta-Large")
|
|
||||||
)
|
|
||||||
eval_df = eval_df.with_columns(pretrained_model=pl.concat_str(pl.col("model"), pl.col("pretrained"), separator="__"))
|
|
||||||
eval_df = eval_df.drop("model", "pretrained")
|
|
||||||
eval_df = eval_df.join(profile_df, on="pretrained_model")
|
|
||||||
|
|
||||||
eval_df = eval_df.with_columns(
|
|
||||||
recall=(
|
|
||||||
pl.col("metrics").struct.field("image_retrieval_recall@1")
|
|
||||||
+ pl.col("metrics").struct.field("image_retrieval_recall@5")
|
|
||||||
+ pl.col("metrics").struct.field("image_retrieval_recall@10")
|
|
||||||
)
|
|
||||||
* (100 / 3)
|
|
||||||
)
|
|
||||||
|
|
||||||
pareto_front = eval_df.join_where(
|
|
||||||
eval_df.select("language", "peak_rss", "exec_time_ms", "recall").rename(
|
|
||||||
{
|
|
||||||
"language": "language_other",
|
|
||||||
"peak_rss": "peak_rss_other",
|
|
||||||
"exec_time_ms": "exec_time_ms_other",
|
|
||||||
"recall": "recall_other",
|
|
||||||
}
|
|
||||||
),
|
|
||||||
(pl.col("language") == pl.col("language_other"))
|
|
||||||
& (pl.col("peak_rss_other") <= pl.col("peak_rss"))
|
|
||||||
& (pl.col("exec_time_ms_other") <= pl.col("exec_time_ms"))
|
|
||||||
& (pl.col("recall_other") >= pl.col("recall"))
|
|
||||||
& (
|
|
||||||
(pl.col("peak_rss_other") < pl.col("peak_rss"))
|
|
||||||
| (pl.col("exec_time_ms_other") < pl.col("exec_time_ms"))
|
|
||||||
| (pl.col("recall_other") > pl.col("recall"))
|
|
||||||
),
|
|
||||||
)
|
|
||||||
eval_df = eval_df.join(pareto_front, on=["pretrained_model", "language"], how="left")
|
|
||||||
eval_df = eval_df.with_columns(is_pareto=pl.col("recall_other").is_null())
|
|
||||||
eval_df = (
|
|
||||||
eval_df.drop("peak_rss_other", "exec_time_ms_other", "recall_other", "language_other")
|
|
||||||
.unique(subset=["pretrained_model", "language"])
|
|
||||||
.collect()
|
|
||||||
)
|
|
||||||
eval_df.write_parquet("model_info.parquet")
|
|
||||||
|
|
||||||
eval_df = eval_df.drop("metrics")
|
|
||||||
eval_df = eval_df.filter(pl.col("recall") >= 20)
|
|
||||||
eval_df = eval_df.sort("recall", descending=True)
|
|
||||||
eval_df = eval_df.select(
|
|
||||||
pl.col("pretrained_model").alias("Model"),
|
|
||||||
(pl.col("peak_rss") / 1024).round().cast(pl.UInt32).alias("Memory (MiB)"),
|
|
||||||
pl.col("exec_time_ms").round(2).alias("Execution Time (ms)"),
|
|
||||||
pl.col("language").alias("Language"),
|
|
||||||
pl.col("recall").round(2).alias("Recall (%)"),
|
|
||||||
pl.when(pl.col("is_pareto")).then(pl.lit("✅")).otherwise(pl.lit("❌")).alias("Pareto Optimal"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
for language in languages:
|
|
||||||
lang_df = eval_df.filter(pl.col("Language") == language).drop("Language")
|
|
||||||
if lang_df.shape[0] == 0:
|
|
||||||
continue
|
|
||||||
print(collapsed_table(languages[language], lang_df))
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from exporters.constants import ModelSource
|
|
||||||
|
|
||||||
from immich_model_exporter import clean_name
|
|
||||||
from immich_model_exporter.exporters.constants import SOURCE_TO_TASK
|
|
||||||
|
|
||||||
mclip = [
|
|
||||||
"M-CLIP/LABSE-Vit-L-14",
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-B-16Plus",
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-B-32",
|
|
||||||
"M-CLIP/XLM-Roberta-Large-Vit-L-14",
|
|
||||||
]
|
|
||||||
|
|
||||||
openclip = [
|
|
||||||
"RN101__openai",
|
|
||||||
"RN101__yfcc15m",
|
|
||||||
"RN50__cc12m",
|
|
||||||
"RN50__openai",
|
|
||||||
"RN50__yfcc15m",
|
|
||||||
"RN50x16__openai",
|
|
||||||
"RN50x4__openai",
|
|
||||||
"RN50x64__openai",
|
|
||||||
"ViT-B-16-SigLIP-256__webli",
|
|
||||||
"ViT-B-16-SigLIP-384__webli",
|
|
||||||
"ViT-B-16-SigLIP-512__webli",
|
|
||||||
"ViT-B-16-SigLIP-i18n-256__webli",
|
|
||||||
"ViT-B-16-SigLIP2__webli",
|
|
||||||
"ViT-B-16-SigLIP__webli",
|
|
||||||
"ViT-B-16-plus-240__laion400m_e31",
|
|
||||||
"ViT-B-16-plus-240__laion400m_e32",
|
|
||||||
"ViT-B-16__laion400m_e31",
|
|
||||||
"ViT-B-16__laion400m_e32",
|
|
||||||
"ViT-B-16__openai",
|
|
||||||
"ViT-B-32-SigLIP2-256__webli",
|
|
||||||
"ViT-B-32__laion2b-s34b-b79k",
|
|
||||||
"ViT-B-32__laion2b_e16",
|
|
||||||
"ViT-B-32__laion400m_e31",
|
|
||||||
"ViT-B-32__laion400m_e32",
|
|
||||||
"ViT-B-32__openai",
|
|
||||||
"ViT-H-14-378-quickgelu__dfn5b",
|
|
||||||
"ViT-H-14-quickgelu__dfn5b",
|
|
||||||
"ViT-H-14__laion2b-s32b-b79k",
|
|
||||||
"ViT-L-14-336__openai",
|
|
||||||
"ViT-L-14-quickgelu__dfn2b",
|
|
||||||
"ViT-L-14__laion2b-s32b-b82k",
|
|
||||||
"ViT-L-14__laion400m_e31",
|
|
||||||
"ViT-L-14__laion400m_e32",
|
|
||||||
"ViT-L-14__openai",
|
|
||||||
"ViT-L-16-SigLIP-256__webli",
|
|
||||||
"ViT-L-16-SigLIP-384__webli",
|
|
||||||
"ViT-L-16-SigLIP2-256__webli",
|
|
||||||
"ViT-L-16-SigLIP2-384__webli",
|
|
||||||
"ViT-L-16-SigLIP2-512__webli",
|
|
||||||
"ViT-SO400M-14-SigLIP-384__webli",
|
|
||||||
"ViT-SO400M-14-SigLIP2-378__webli",
|
|
||||||
"ViT-SO400M-14-SigLIP2__webli",
|
|
||||||
"ViT-SO400M-16-SigLIP2-256__webli",
|
|
||||||
"ViT-SO400M-16-SigLIP2-384__webli",
|
|
||||||
"ViT-SO400M-16-SigLIP2-512__webli",
|
|
||||||
"ViT-gopt-16-SigLIP2-256__webli",
|
|
||||||
"ViT-gopt-16-SigLIP2-384__webli",
|
|
||||||
"nllb-clip-base-siglip__mrl",
|
|
||||||
"nllb-clip-base-siglip__v1",
|
|
||||||
"nllb-clip-large-siglip__mrl",
|
|
||||||
"nllb-clip-large-siglip__v1",
|
|
||||||
"xlm-roberta-base-ViT-B-32__laion5b_s13b_b90k",
|
|
||||||
"xlm-roberta-large-ViT-H-14__frozen_laion5b_s13b_b90k",
|
|
||||||
]
|
|
||||||
|
|
||||||
insightface = [
|
|
||||||
"antelopev2",
|
|
||||||
"buffalo_l",
|
|
||||||
"buffalo_m",
|
|
||||||
"buffalo_s",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def export_models(models: list[str], source: ModelSource) -> None:
|
|
||||||
profiling_dir = Path("profiling")
|
|
||||||
profiling_dir.mkdir(exist_ok=True)
|
|
||||||
for model in models:
|
|
||||||
try:
|
|
||||||
model_dir = f"models/{clean_name(model)}"
|
|
||||||
task = SOURCE_TO_TASK[source]
|
|
||||||
|
|
||||||
print(f"Processing model {model}")
|
|
||||||
subprocess.check_call(["python", "-m", "immich_model_exporter", "export", model, source])
|
|
||||||
subprocess.check_call(
|
|
||||||
[
|
|
||||||
"python",
|
|
||||||
"-m",
|
|
||||||
"immich_model_exporter",
|
|
||||||
"profile",
|
|
||||||
model_dir,
|
|
||||||
task,
|
|
||||||
"--output_path",
|
|
||||||
profiling_dir / f"{model}.json",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
subprocess.check_call(["python", "-m", "immich_model_exporter", "upload", model_dir])
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Failed to export model {model}: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
export_models(mclip, ModelSource.MCLIP)
|
|
||||||
export_models(openclip, ModelSource.OPENCLIP)
|
|
||||||
export_models(insightface, ModelSource.INSIGHTFACE)
|
|
||||||
|
|
||||||
Path("results").mkdir(exist_ok=True)
|
|
||||||
subprocess.check_call(
|
|
||||||
[
|
|
||||||
"python",
|
|
||||||
"clip_benchmark",
|
|
||||||
"eval",
|
|
||||||
"--pretrained_model",
|
|
||||||
*[name.replace("__", ",") for name in openclip],
|
|
||||||
"--task",
|
|
||||||
"zeroshot_retrieval",
|
|
||||||
"--dataset",
|
|
||||||
"crossmodal3600",
|
|
||||||
"--batch_size",
|
|
||||||
"64",
|
|
||||||
"--language",
|
|
||||||
"ar",
|
|
||||||
"bn",
|
|
||||||
"cs",
|
|
||||||
"da",
|
|
||||||
"de",
|
|
||||||
"el",
|
|
||||||
"en",
|
|
||||||
"es",
|
|
||||||
"fa",
|
|
||||||
"fi",
|
|
||||||
"fil",
|
|
||||||
"fr",
|
|
||||||
"he",
|
|
||||||
"hi",
|
|
||||||
"hr",
|
|
||||||
"hu",
|
|
||||||
"id",
|
|
||||||
"it",
|
|
||||||
"ja",
|
|
||||||
"ko",
|
|
||||||
"mi",
|
|
||||||
"nl",
|
|
||||||
"no",
|
|
||||||
"pl",
|
|
||||||
"pt",
|
|
||||||
"quz",
|
|
||||||
"ro",
|
|
||||||
"ru",
|
|
||||||
"sv",
|
|
||||||
"sw",
|
|
||||||
"te",
|
|
||||||
"th",
|
|
||||||
"tr",
|
|
||||||
"uk",
|
|
||||||
"vi",
|
|
||||||
"zh",
|
|
||||||
"--recall_k",
|
|
||||||
"1",
|
|
||||||
"5",
|
|
||||||
"10",
|
|
||||||
"--no_amp",
|
|
||||||
"--output",
|
|
||||||
"results/{dataset}_{language}_{model}_{pretrained}.json",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
+13
-21
@@ -1,6 +1,11 @@
|
|||||||
|
import os
|
||||||
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
|
||||||
|
import torch
|
||||||
|
from multilingual_clip.pt_multilingual_clip import MultilingualCLIP
|
||||||
|
from transformers import AutoTokenizer
|
||||||
|
|
||||||
from .openclip import OpenCLIPModelConfig
|
from .openclip import OpenCLIPModelConfig
|
||||||
from .openclip import to_onnx as openclip_to_onnx
|
from .openclip import to_onnx as openclip_to_onnx
|
||||||
@@ -16,38 +21,25 @@ _MCLIP_TO_OPENCLIP = {
|
|||||||
|
|
||||||
def to_onnx(
|
def to_onnx(
|
||||||
model_name: str,
|
model_name: str,
|
||||||
opset_version: int,
|
|
||||||
output_dir_visual: Path | str,
|
output_dir_visual: Path | str,
|
||||||
output_dir_textual: Path | str,
|
output_dir_textual: Path | str,
|
||||||
cache: bool = True,
|
|
||||||
) -> tuple[Path, Path]:
|
) -> tuple[Path, Path]:
|
||||||
textual_path = get_model_path(output_dir_textual)
|
textual_path = get_model_path(output_dir_textual)
|
||||||
if not cache or not textual_path.exists():
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
import torch
|
model = MultilingualCLIP.from_pretrained(model_name, cache_dir=os.environ.get("CACHE_DIR", tmpdir))
|
||||||
from multilingual_clip.pt_multilingual_clip import MultilingualCLIP
|
|
||||||
from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
torch.backends.mha.set_fastpath_enabled(False)
|
|
||||||
|
|
||||||
model = MultilingualCLIP.from_pretrained(model_name)
|
|
||||||
AutoTokenizer.from_pretrained(model_name).save_pretrained(output_dir_textual)
|
AutoTokenizer.from_pretrained(model_name).save_pretrained(output_dir_textual)
|
||||||
|
|
||||||
model.eval()
|
model.eval()
|
||||||
for param in model.parameters():
|
for param in model.parameters():
|
||||||
param.requires_grad_(False)
|
param.requires_grad_(False)
|
||||||
|
|
||||||
_export_text_encoder(model, textual_path, opset_version)
|
export_text_encoder(model, textual_path)
|
||||||
else:
|
visual_path, _ = openclip_to_onnx(_MCLIP_TO_OPENCLIP[model_name], output_dir_visual)
|
||||||
print(f"Model {textual_path} already exists, skipping")
|
assert visual_path is not None, "Visual model export failed"
|
||||||
visual_path, _ = openclip_to_onnx(_MCLIP_TO_OPENCLIP[model_name], opset_version, output_dir_visual, cache=cache)
|
|
||||||
assert visual_path is not None, "Visual model export failed"
|
|
||||||
return visual_path, textual_path
|
return visual_path, textual_path
|
||||||
|
|
||||||
|
|
||||||
def _export_text_encoder(model: Any, output_path: Path | str, opset_version: int) -> None:
|
def export_text_encoder(model: MultilingualCLIP, output_path: Path | str) -> None:
|
||||||
import torch
|
|
||||||
from multilingual_clip.pt_multilingual_clip import MultilingualCLIP
|
|
||||||
|
|
||||||
output_path = Path(output_path)
|
output_path = Path(output_path)
|
||||||
|
|
||||||
def forward(self: MultilingualCLIP, input_ids: torch.Tensor, attention_mask: torch.Tensor) -> torch.Tensor:
|
def forward(self: MultilingualCLIP, input_ids: torch.Tensor, attention_mask: torch.Tensor) -> torch.Tensor:
|
||||||
@@ -69,7 +61,7 @@ def _export_text_encoder(model: Any, output_path: Path | str, opset_version: int
|
|||||||
output_path.as_posix(),
|
output_path.as_posix(),
|
||||||
input_names=["input_ids", "attention_mask"],
|
input_names=["input_ids", "attention_mask"],
|
||||||
output_names=["embedding"],
|
output_names=["embedding"],
|
||||||
opset_version=opset_version,
|
opset_version=17,
|
||||||
# dynamic_axes={
|
# dynamic_axes={
|
||||||
# "input_ids": {0: "batch_size", 1: "sequence_length"},
|
# "input_ids": {0: "batch_size", 1: "sequence_length"},
|
||||||
# "attention_mask": {0: "batch_size", 1: "sequence_length"},
|
# "attention_mask": {0: "batch_size", 1: "sequence_length"},
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import warnings
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import open_clip
|
||||||
|
import torch
|
||||||
|
from transformers import AutoTokenizer
|
||||||
|
|
||||||
|
from .util import get_model_path, save_config
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class OpenCLIPModelConfig:
|
||||||
|
name: str
|
||||||
|
pretrained: str
|
||||||
|
image_size: int = field(init=False)
|
||||||
|
sequence_length: int = field(init=False)
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
open_clip_cfg = open_clip.get_model_config(self.name)
|
||||||
|
if open_clip_cfg is None:
|
||||||
|
raise ValueError(f"Unknown model {self.name}")
|
||||||
|
self.image_size = open_clip_cfg["vision_cfg"]["image_size"]
|
||||||
|
self.sequence_length = open_clip_cfg["text_cfg"].get("context_length", 77)
|
||||||
|
|
||||||
|
|
||||||
|
def to_onnx(
|
||||||
|
model_cfg: OpenCLIPModelConfig,
|
||||||
|
output_dir_visual: Path | str | None = None,
|
||||||
|
output_dir_textual: Path | str | None = None,
|
||||||
|
) -> tuple[Path | None, Path | None]:
|
||||||
|
visual_path = None
|
||||||
|
textual_path = None
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
model = open_clip.create_model(
|
||||||
|
model_cfg.name,
|
||||||
|
pretrained=model_cfg.pretrained,
|
||||||
|
jit=False,
|
||||||
|
cache_dir=os.environ.get("CACHE_DIR", tmpdir),
|
||||||
|
require_pretrained=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
text_vision_cfg = open_clip.get_model_config(model_cfg.name)
|
||||||
|
|
||||||
|
model.eval()
|
||||||
|
for param in model.parameters():
|
||||||
|
param.requires_grad_(False)
|
||||||
|
|
||||||
|
if output_dir_visual is not None:
|
||||||
|
output_dir_visual = Path(output_dir_visual)
|
||||||
|
visual_path = get_model_path(output_dir_visual)
|
||||||
|
|
||||||
|
save_config(open_clip.get_model_preprocess_cfg(model), output_dir_visual / "preprocess_cfg.json")
|
||||||
|
save_config(text_vision_cfg, output_dir_visual.parent / "config.json")
|
||||||
|
export_image_encoder(model, model_cfg, visual_path)
|
||||||
|
|
||||||
|
if output_dir_textual is not None:
|
||||||
|
output_dir_textual = Path(output_dir_textual)
|
||||||
|
textual_path = get_model_path(output_dir_textual)
|
||||||
|
|
||||||
|
tokenizer_name = text_vision_cfg["text_cfg"].get("hf_tokenizer_name", "openai/clip-vit-base-patch32")
|
||||||
|
AutoTokenizer.from_pretrained(tokenizer_name).save_pretrained(output_dir_textual)
|
||||||
|
export_text_encoder(model, model_cfg, textual_path)
|
||||||
|
return visual_path, textual_path
|
||||||
|
|
||||||
|
|
||||||
|
def export_image_encoder(model: open_clip.CLIP, model_cfg: OpenCLIPModelConfig, output_path: Path | str) -> None:
|
||||||
|
output_path = Path(output_path)
|
||||||
|
|
||||||
|
def encode_image(image: torch.Tensor) -> torch.Tensor:
|
||||||
|
output = model.encode_image(image, normalize=True)
|
||||||
|
assert isinstance(output, torch.Tensor)
|
||||||
|
return output
|
||||||
|
|
||||||
|
args = (torch.randn(1, 3, model_cfg.image_size, model_cfg.image_size),)
|
||||||
|
traced = torch.jit.trace(encode_image, args) # type: ignore[no-untyped-call]
|
||||||
|
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter("ignore", UserWarning)
|
||||||
|
torch.onnx.export(
|
||||||
|
traced,
|
||||||
|
args,
|
||||||
|
output_path.as_posix(),
|
||||||
|
input_names=["image"],
|
||||||
|
output_names=["embedding"],
|
||||||
|
opset_version=17,
|
||||||
|
# dynamic_axes={"image": {0: "batch_size"}},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def export_text_encoder(model: open_clip.CLIP, model_cfg: OpenCLIPModelConfig, output_path: Path | str) -> None:
|
||||||
|
output_path = Path(output_path)
|
||||||
|
|
||||||
|
def encode_text(text: torch.Tensor) -> torch.Tensor:
|
||||||
|
output = model.encode_text(text, normalize=True)
|
||||||
|
assert isinstance(output, torch.Tensor)
|
||||||
|
return output
|
||||||
|
|
||||||
|
args = (torch.ones(1, model_cfg.sequence_length, dtype=torch.int32),)
|
||||||
|
traced = torch.jit.trace(encode_text, args) # type: ignore[no-untyped-call]
|
||||||
|
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter("ignore", UserWarning)
|
||||||
|
torch.onnx.export(
|
||||||
|
traced,
|
||||||
|
args,
|
||||||
|
output_path.as_posix(),
|
||||||
|
input_names=["text"],
|
||||||
|
output_names=["embedding"],
|
||||||
|
opset_version=17,
|
||||||
|
# dynamic_axes={"text": {0: "batch_size"}},
|
||||||
|
)
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import onnx
|
||||||
|
import onnxruntime as ort
|
||||||
|
import onnxsim
|
||||||
|
|
||||||
|
|
||||||
|
def save_onnx(model: onnx.ModelProto, output_path: Path | str) -> None:
|
||||||
|
try:
|
||||||
|
onnx.save(model, output_path)
|
||||||
|
except ValueError as e:
|
||||||
|
if "The proto size is larger than the 2 GB limit." in str(e):
|
||||||
|
onnx.save(model, output_path, save_as_external_data=True, size_threshold=1_000_000)
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
def optimize_onnxsim(model_path: Path | str, output_path: Path | str) -> None:
|
||||||
|
model_path = Path(model_path)
|
||||||
|
output_path = Path(output_path)
|
||||||
|
model = onnx.load(model_path.as_posix())
|
||||||
|
model, check = onnxsim.simplify(model)
|
||||||
|
assert check, "Simplified ONNX model could not be validated"
|
||||||
|
for file in model_path.parent.iterdir():
|
||||||
|
if file.name.startswith("Constant") or "onnx" in file.name or file.suffix == ".weight":
|
||||||
|
file.unlink()
|
||||||
|
save_onnx(model, output_path)
|
||||||
|
|
||||||
|
|
||||||
|
def optimize_ort(
|
||||||
|
model_path: Path | str,
|
||||||
|
output_path: Path | str,
|
||||||
|
level: ort.GraphOptimizationLevel = ort.GraphOptimizationLevel.ORT_ENABLE_BASIC,
|
||||||
|
) -> None:
|
||||||
|
model_path = Path(model_path)
|
||||||
|
output_path = Path(output_path)
|
||||||
|
|
||||||
|
sess_options = ort.SessionOptions()
|
||||||
|
sess_options.graph_optimization_level = level
|
||||||
|
sess_options.optimized_model_filepath = output_path.as_posix()
|
||||||
|
|
||||||
|
ort.InferenceSession(model_path.as_posix(), providers=["CPUExecutionProvider"], sess_options=sess_options)
|
||||||
|
|
||||||
|
|
||||||
|
def optimize(model_path: Path | str) -> None:
|
||||||
|
model_path = Path(model_path)
|
||||||
|
|
||||||
|
optimize_ort(model_path, model_path)
|
||||||
|
optimize_onnxsim(model_path, model_path)
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "immich_model_exporter"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.10, <4.0"
|
|
||||||
dependencies = [
|
|
||||||
"huggingface-hub>=0.29.3",
|
|
||||||
"multilingual-clip>=1.0.10",
|
|
||||||
"onnx>=1.14.1",
|
|
||||||
"onnxruntime>=1.16.0",
|
|
||||||
"open-clip-torch>=2.31.0",
|
|
||||||
"typer>=0.15.2",
|
|
||||||
"rknn-toolkit2>=2.3.0",
|
|
||||||
"transformers>=4.49.0",
|
|
||||||
"tenacity>=9.0.0",
|
|
||||||
"clip-benchmark>=1.6.1",
|
|
||||||
"polars>=1.25.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependency-groups]
|
|
||||||
dev = ["black>=23.3.0", "mypy>=1.3.0", "ruff>=0.0.272"]
|
|
||||||
|
|
||||||
[tool.uv]
|
|
||||||
override-dependencies = [
|
|
||||||
"onnx>=1.16.0,<2",
|
|
||||||
"onnxruntime>=1.18.2,<2",
|
|
||||||
"torch>=2.4",
|
|
||||||
"torchvision>=0.21",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.hatch.build.targets.sdist]
|
|
||||||
include = ["immich_model_exporter"]
|
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
|
||||||
include = ["immich_model_exporter"]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
|
|
||||||
[tool.mypy]
|
|
||||||
python_version = "3.12"
|
|
||||||
follow_imports = "silent"
|
|
||||||
warn_redundant_casts = true
|
|
||||||
disallow_any_generics = true
|
|
||||||
check_untyped_defs = true
|
|
||||||
disallow_untyped_defs = true
|
|
||||||
ignore_missing_imports = true
|
|
||||||
|
|
||||||
[tool.ruff]
|
|
||||||
line-length = 120
|
|
||||||
target-version = "py312"
|
|
||||||
|
|
||||||
[tool.ruff.lint]
|
|
||||||
select = ["E", "F", "I"]
|
|
||||||
|
|
||||||
[tool.black]
|
|
||||||
line-length = 120
|
|
||||||
target-version = ['py312']
|
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import gc
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
import torch
|
||||||
|
from huggingface_hub import create_repo, upload_folder
|
||||||
|
from models import mclip, openclip
|
||||||
|
from models.optimize import optimize
|
||||||
|
from rich.progress import Progress
|
||||||
|
|
||||||
|
models = [
|
||||||
|
"M-CLIP/LABSE-Vit-L-14",
|
||||||
|
"M-CLIP/XLM-Roberta-Large-Vit-B-16Plus",
|
||||||
|
"M-CLIP/XLM-Roberta-Large-Vit-B-32",
|
||||||
|
"M-CLIP/XLM-Roberta-Large-Vit-L-14",
|
||||||
|
"RN101::openai",
|
||||||
|
"RN101::yfcc15m",
|
||||||
|
"RN50::cc12m",
|
||||||
|
"RN50::openai",
|
||||||
|
"RN50::yfcc15m",
|
||||||
|
"RN50x16::openai",
|
||||||
|
"RN50x4::openai",
|
||||||
|
"RN50x64::openai",
|
||||||
|
"ViT-B-16-SigLIP-256::webli",
|
||||||
|
"ViT-B-16-SigLIP-384::webli",
|
||||||
|
"ViT-B-16-SigLIP-512::webli",
|
||||||
|
"ViT-B-16-SigLIP-i18n-256::webli",
|
||||||
|
"ViT-B-16-SigLIP::webli",
|
||||||
|
"ViT-B-16-plus-240::laion400m_e31",
|
||||||
|
"ViT-B-16-plus-240::laion400m_e32",
|
||||||
|
"ViT-B-16::laion400m_e31",
|
||||||
|
"ViT-B-16::laion400m_e32",
|
||||||
|
"ViT-B-16::openai",
|
||||||
|
"ViT-B-32::laion2b-s34b-b79k",
|
||||||
|
"ViT-B-32::laion2b_e16",
|
||||||
|
"ViT-B-32::laion400m_e31",
|
||||||
|
"ViT-B-32::laion400m_e32",
|
||||||
|
"ViT-B-32::openai",
|
||||||
|
"ViT-H-14-378-quickgelu::dfn5b",
|
||||||
|
"ViT-H-14-quickgelu::dfn5b",
|
||||||
|
"ViT-H-14::laion2b-s32b-b79k",
|
||||||
|
"ViT-L-14-336::openai",
|
||||||
|
"ViT-L-14-quickgelu::dfn2b",
|
||||||
|
"ViT-L-14::laion2b-s32b-b82k",
|
||||||
|
"ViT-L-14::laion400m_e31",
|
||||||
|
"ViT-L-14::laion400m_e32",
|
||||||
|
"ViT-L-14::openai",
|
||||||
|
"ViT-L-16-SigLIP-256::webli",
|
||||||
|
"ViT-L-16-SigLIP-384::webli",
|
||||||
|
"ViT-SO400M-14-SigLIP-384::webli",
|
||||||
|
"ViT-g-14::laion2b-s12b-b42k",
|
||||||
|
"nllb-clip-base-siglip::mrl",
|
||||||
|
"nllb-clip-base-siglip::v1",
|
||||||
|
"nllb-clip-large-siglip::mrl",
|
||||||
|
"nllb-clip-large-siglip::v1",
|
||||||
|
"xlm-roberta-base-ViT-B-32::laion5b_s13b_b90k",
|
||||||
|
"xlm-roberta-large-ViT-H-14::frozen_laion5b_s13b_b90k",
|
||||||
|
]
|
||||||
|
|
||||||
|
# glob to delete old UUID blobs when reuploading models
|
||||||
|
uuid_char = "[a-fA-F0-9]"
|
||||||
|
uuid_glob = uuid_char * 8 + "-" + uuid_char * 4 + "-" + uuid_char * 4 + "-" + uuid_char * 4 + "-" + uuid_char * 12
|
||||||
|
|
||||||
|
# remote repo files to be deleted before uploading
|
||||||
|
# deletion is in the same commit as the upload, so it's atomic
|
||||||
|
delete_patterns = ["**/*onnx*", "**/Constant*", "**/*.weight", "**/*.bias", f"**/{uuid_glob}"]
|
||||||
|
|
||||||
|
with Progress() as progress:
|
||||||
|
task = progress.add_task("[green]Exporting models...", total=len(models))
|
||||||
|
token = os.environ.get("HF_AUTH_TOKEN")
|
||||||
|
torch.backends.mha.set_fastpath_enabled(False)
|
||||||
|
with TemporaryDirectory() as tmp:
|
||||||
|
tmpdir = Path(tmp)
|
||||||
|
for model in models:
|
||||||
|
model_name = model.split("/")[-1].replace("::", "__")
|
||||||
|
hf_model_name = model_name.replace("xlm-roberta-large", "XLM-Roberta-Large")
|
||||||
|
hf_model_name = model_name.replace("xlm-roberta-base", "XLM-Roberta-Base")
|
||||||
|
config_path = tmpdir / model_name / "config.json"
|
||||||
|
|
||||||
|
def export() -> None:
|
||||||
|
progress.update(task, description=f"[green]Exporting {hf_model_name}")
|
||||||
|
visual_dir = tmpdir / hf_model_name / "visual"
|
||||||
|
textual_dir = tmpdir / hf_model_name / "textual"
|
||||||
|
if model.startswith("M-CLIP"):
|
||||||
|
visual_path, textual_path = mclip.to_onnx(model, visual_dir, textual_dir)
|
||||||
|
else:
|
||||||
|
name, _, pretrained = model_name.partition("__")
|
||||||
|
config = openclip.OpenCLIPModelConfig(name, pretrained)
|
||||||
|
visual_path, textual_path = openclip.to_onnx(config, visual_dir, textual_dir)
|
||||||
|
progress.update(task, description=f"[green]Optimizing {hf_model_name} (visual)")
|
||||||
|
optimize(visual_path)
|
||||||
|
progress.update(task, description=f"[green]Optimizing {hf_model_name} (textual)")
|
||||||
|
optimize(textual_path)
|
||||||
|
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
def upload() -> None:
|
||||||
|
progress.update(task, description=f"[yellow]Uploading {hf_model_name}")
|
||||||
|
repo_id = f"immich-app/{hf_model_name}"
|
||||||
|
|
||||||
|
create_repo(repo_id, exist_ok=True)
|
||||||
|
upload_folder(
|
||||||
|
repo_id=repo_id,
|
||||||
|
folder_path=tmpdir / hf_model_name,
|
||||||
|
delete_patterns=delete_patterns,
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
|
||||||
|
export()
|
||||||
|
if token is not None:
|
||||||
|
upload()
|
||||||
|
progress.update(task, advance=1)
|
||||||
Generated
-1924
File diff suppressed because it is too large
Load Diff
@@ -1,179 +0,0 @@
|
|||||||
commit 16839b58d9b3c3162a67ce5d776b36d4d24e801f
|
|
||||||
Author: mertalev <101130780+mertalev@users.noreply.github.com>
|
|
||||||
Date: Wed Mar 5 11:25:38 2025 -0500
|
|
||||||
|
|
||||||
disable algo caching (attributed to @dmnieto in https://github.com/microsoft/onnxruntime/pull/19567)
|
|
||||||
|
|
||||||
diff --git a/onnxruntime/core/providers/rocm/nn/conv.cc b/onnxruntime/core/providers/rocm/nn/conv.cc
|
|
||||||
index d7f47d07a8..4060a2af52 100644
|
|
||||||
--- a/onnxruntime/core/providers/rocm/nn/conv.cc
|
|
||||||
+++ b/onnxruntime/core/providers/rocm/nn/conv.cc
|
|
||||||
@@ -127,7 +127,6 @@ Status Conv<T, NHWC>::UpdateState(OpKernelContext* context, bool bias_expected)
|
|
||||||
|
|
||||||
if (w_dims_changed) {
|
|
||||||
s_.last_w_dims = gsl::make_span(w_dims);
|
|
||||||
- s_.cached_benchmark_fwd_results.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ORT_RETURN_IF_ERROR(conv_attrs_.ValidateInputShape(X->Shape(), W->Shape(), channels_last, channels_last));
|
|
||||||
@@ -277,35 +276,6 @@ Status Conv<T, NHWC>::UpdateState(OpKernelContext* context, bool bias_expected)
|
|
||||||
HIP_CALL_THROW(hipMalloc(&s_.b_zero, malloc_size));
|
|
||||||
HIP_CALL_THROW(hipMemsetAsync(s_.b_zero, 0, malloc_size, Stream(context)));
|
|
||||||
}
|
|
||||||
-
|
|
||||||
- if (!s_.cached_benchmark_fwd_results.contains(x_dims_miopen)) {
|
|
||||||
- miopenConvAlgoPerf_t perf;
|
|
||||||
- int algo_count = 1;
|
|
||||||
- const ROCMExecutionProvider* rocm_ep = static_cast<const ROCMExecutionProvider*>(this->Info().GetExecutionProvider());
|
|
||||||
- static constexpr int num_algos = MIOPEN_CONVOLUTION_FWD_ALGO_COUNT;
|
|
||||||
- size_t max_ws_size = rocm_ep->GetMiopenConvUseMaxWorkspace() ? GetMaxWorkspaceSize(GetMiopenHandle(context), s_, kAllAlgos, num_algos, rocm_ep->GetDeviceId())
|
|
||||||
- : AlgoSearchWorkspaceSize;
|
|
||||||
- IAllocatorUniquePtr<void> algo_search_workspace = GetTransientScratchBuffer<void>(max_ws_size);
|
|
||||||
- MIOPEN_RETURN_IF_ERROR(miopenFindConvolutionForwardAlgorithm(
|
|
||||||
- GetMiopenHandle(context),
|
|
||||||
- s_.x_tensor,
|
|
||||||
- s_.x_data,
|
|
||||||
- s_.w_desc,
|
|
||||||
- s_.w_data,
|
|
||||||
- s_.conv_desc,
|
|
||||||
- s_.y_tensor,
|
|
||||||
- s_.y_data,
|
|
||||||
- 1, // requestedAlgoCount
|
|
||||||
- &algo_count, // returnedAlgoCount
|
|
||||||
- &perf,
|
|
||||||
- algo_search_workspace.get(),
|
|
||||||
- max_ws_size,
|
|
||||||
- false)); // Do not do exhaustive algo search.
|
|
||||||
- s_.cached_benchmark_fwd_results.insert(x_dims_miopen, {perf.fwd_algo, perf.memory});
|
|
||||||
- }
|
|
||||||
- const auto& perf = s_.cached_benchmark_fwd_results.at(x_dims_miopen);
|
|
||||||
- s_.fwd_algo = perf.fwd_algo;
|
|
||||||
- s_.workspace_bytes = perf.memory;
|
|
||||||
} else {
|
|
||||||
// set Y
|
|
||||||
s_.Y = context->Output(0, TensorShape(s_.y_dims));
|
|
||||||
@@ -319,6 +289,31 @@ Status Conv<T, NHWC>::UpdateState(OpKernelContext* context, bool bias_expected)
|
|
||||||
s_.y_data = reinterpret_cast<HipT*>(s_.Y->MutableData<T>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ miopenConvAlgoPerf_t perf;
|
|
||||||
+ int algo_count = 1;
|
|
||||||
+ const ROCMExecutionProvider* rocm_ep = static_cast<const ROCMExecutionProvider*>(this->Info().GetExecutionProvider());
|
|
||||||
+ static constexpr int num_algos = MIOPEN_CONVOLUTION_FWD_ALGO_COUNT;
|
|
||||||
+ size_t max_ws_size = rocm_ep->GetMiopenConvUseMaxWorkspace() ? GetMaxWorkspaceSize(GetMiopenHandle(context), s_, kAllAlgos, num_algos, rocm_ep->GetDeviceId())
|
|
||||||
+ : AlgoSearchWorkspaceSize;
|
|
||||||
+ IAllocatorUniquePtr<void> algo_search_workspace = GetTransientScratchBuffer<void>(max_ws_size);
|
|
||||||
+ MIOPEN_RETURN_IF_ERROR(miopenFindConvolutionForwardAlgorithm(
|
|
||||||
+ GetMiopenHandle(context),
|
|
||||||
+ s_.x_tensor,
|
|
||||||
+ s_.x_data,
|
|
||||||
+ s_.w_desc,
|
|
||||||
+ s_.w_data,
|
|
||||||
+ s_.conv_desc,
|
|
||||||
+ s_.y_tensor,
|
|
||||||
+ s_.y_data,
|
|
||||||
+ 1, // requestedAlgoCount
|
|
||||||
+ &algo_count, // returnedAlgoCount
|
|
||||||
+ &perf,
|
|
||||||
+ algo_search_workspace.get(),
|
|
||||||
+ max_ws_size,
|
|
||||||
+ false)); // Do not do exhaustive algo search.
|
|
||||||
+ s_.fwd_algo = perf.fwd_algo;
|
|
||||||
+ s_.workspace_bytes = perf.memory;
|
|
||||||
return Status::OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/onnxruntime/core/providers/rocm/nn/conv.h b/onnxruntime/core/providers/rocm/nn/conv.h
|
|
||||||
index bc9846203e..d54218f258 100644
|
|
||||||
--- a/onnxruntime/core/providers/rocm/nn/conv.h
|
|
||||||
+++ b/onnxruntime/core/providers/rocm/nn/conv.h
|
|
||||||
@@ -108,9 +108,6 @@ class lru_unordered_map {
|
|
||||||
list_type lru_list_;
|
|
||||||
};
|
|
||||||
|
|
||||||
-// cached miopen descriptors
|
|
||||||
-constexpr size_t MAX_CACHED_ALGO_PERF_RESULTS = 10000;
|
|
||||||
-
|
|
||||||
template <typename AlgoPerfType>
|
|
||||||
struct MiopenConvState {
|
|
||||||
// if x/w dims changed, update algo and miopenTensors
|
|
||||||
@@ -148,9 +145,6 @@ struct MiopenConvState {
|
|
||||||
decltype(AlgoPerfType().memory) memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
- lru_unordered_map<TensorShapeVector, PerfFwdResultParams, vector_hash> cached_benchmark_fwd_results{MAX_CACHED_ALGO_PERF_RESULTS};
|
|
||||||
- lru_unordered_map<TensorShapeVector, PerfBwdResultParams, vector_hash> cached_benchmark_bwd_results{MAX_CACHED_ALGO_PERF_RESULTS};
|
|
||||||
-
|
|
||||||
// Some properties needed to support asymmetric padded Conv nodes
|
|
||||||
bool post_slicing_required;
|
|
||||||
TensorShapeVector slice_starts;
|
|
||||||
diff --git a/onnxruntime/core/providers/rocm/nn/conv_transpose.cc b/onnxruntime/core/providers/rocm/nn/conv_transpose.cc
|
|
||||||
index 7447113fdf..a662e35b2e 100644
|
|
||||||
--- a/onnxruntime/core/providers/rocm/nn/conv_transpose.cc
|
|
||||||
+++ b/onnxruntime/core/providers/rocm/nn/conv_transpose.cc
|
|
||||||
@@ -76,7 +76,6 @@ Status ConvTranspose<T, NHWC>::DoConvTranspose(OpKernelContext* context, bool dy
|
|
||||||
|
|
||||||
if (w_dims_changed) {
|
|
||||||
s_.last_w_dims = gsl::make_span(w_dims);
|
|
||||||
- s_.cached_benchmark_bwd_results.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ConvTransposeAttributes::Prepare p;
|
|
||||||
@@ -126,35 +125,29 @@ Status ConvTranspose<T, NHWC>::DoConvTranspose(OpKernelContext* context, bool dy
|
|
||||||
}
|
|
||||||
|
|
||||||
y_data = reinterpret_cast<HipT*>(p.Y->MutableData<T>());
|
|
||||||
-
|
|
||||||
- if (!s_.cached_benchmark_bwd_results.contains(x_dims)) {
|
|
||||||
- IAllocatorUniquePtr<void> algo_search_workspace = GetScratchBuffer<void>(AlgoSearchWorkspaceSize, context->GetComputeStream());
|
|
||||||
-
|
|
||||||
- miopenConvAlgoPerf_t perf;
|
|
||||||
- int algo_count = 1;
|
|
||||||
- MIOPEN_RETURN_IF_ERROR(miopenFindConvolutionBackwardDataAlgorithm(
|
|
||||||
- GetMiopenHandle(context),
|
|
||||||
- s_.x_tensor,
|
|
||||||
- x_data,
|
|
||||||
- s_.w_desc,
|
|
||||||
- w_data,
|
|
||||||
- s_.conv_desc,
|
|
||||||
- s_.y_tensor,
|
|
||||||
- y_data,
|
|
||||||
- 1,
|
|
||||||
- &algo_count,
|
|
||||||
- &perf,
|
|
||||||
- algo_search_workspace.get(),
|
|
||||||
- AlgoSearchWorkspaceSize,
|
|
||||||
- false));
|
|
||||||
- s_.cached_benchmark_bwd_results.insert(x_dims, {perf.bwd_data_algo, perf.memory});
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- const auto& perf = s_.cached_benchmark_bwd_results.at(x_dims);
|
|
||||||
- s_.bwd_data_algo = perf.bwd_data_algo;
|
|
||||||
- s_.workspace_bytes = perf.memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ IAllocatorUniquePtr<void> algo_search_workspace = GetScratchBuffer<void>(AlgoSearchWorkspaceSize, context->GetComputeStream());
|
|
||||||
+ miopenConvAlgoPerf_t perf;
|
|
||||||
+ int algo_count = 1;
|
|
||||||
+ MIOPEN_RETURN_IF_ERROR(miopenFindConvolutionBackwardDataAlgorithm(
|
|
||||||
+ GetMiopenHandle(context),
|
|
||||||
+ s_.x_tensor,
|
|
||||||
+ x_data,
|
|
||||||
+ s_.w_desc,
|
|
||||||
+ w_data,
|
|
||||||
+ s_.conv_desc,
|
|
||||||
+ s_.y_tensor,
|
|
||||||
+ y_data,
|
|
||||||
+ 1,
|
|
||||||
+ &algo_count,
|
|
||||||
+ &perf,
|
|
||||||
+ algo_search_workspace.get(),
|
|
||||||
+ AlgoSearchWorkspaceSize,
|
|
||||||
+ false));
|
|
||||||
+ s_.bwd_data_algo = perf.bwd_data_algo;
|
|
||||||
+ s_.workspace_bytes = perf.memory;
|
|
||||||
+
|
|
||||||
// The following block will be executed in case there has been no change in the shapes of the
|
|
||||||
// input and the filter compared to the previous run
|
|
||||||
if (!y_data) {
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
|
|
||||||
index d90a2a355..bb1a7de12 100644
|
|
||||||
--- a/cmake/CMakeLists.txt
|
|
||||||
+++ b/cmake/CMakeLists.txt
|
|
||||||
@@ -295,7 +295,7 @@ if (onnxruntime_USE_ROCM)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT CMAKE_HIP_ARCHITECTURES)
|
|
||||||
- set(CMAKE_HIP_ARCHITECTURES "gfx908;gfx90a;gfx1030;gfx1100;gfx1101;gfx940;gfx941;gfx942;gfx1200;gfx1201")
|
|
||||||
+ set(CMAKE_HIP_ARCHITECTURES "gfx900;gfx908;gfx90a;gfx1030;gfx1100;gfx1101;gfx1102;gfx940;gfx941;gfx942;gfx1200;gfx1201")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
file(GLOB rocm_cmake_components ${onnxruntime_ROCM_HOME}/lib/cmake/*)
|
|
||||||
@@ -51,8 +51,6 @@ cpu = ["onnxruntime>=1.15.0,<2"]
|
|||||||
cuda = ["onnxruntime-gpu>=1.17.0,<2"]
|
cuda = ["onnxruntime-gpu>=1.17.0,<2"]
|
||||||
openvino = ["onnxruntime-openvino>=1.17.1,<1.19.0"]
|
openvino = ["onnxruntime-openvino>=1.17.1,<1.19.0"]
|
||||||
armnn = ["onnxruntime>=1.15.0,<2"]
|
armnn = ["onnxruntime>=1.15.0,<2"]
|
||||||
rknn = ["onnxruntime>=1.15.0,<2", "rknn-toolkit-lite2>=2.3.0,<3"]
|
|
||||||
rocm = []
|
|
||||||
|
|
||||||
[tool.uv]
|
[tool.uv]
|
||||||
compile-bytecode = true
|
compile-bytecode = true
|
||||||
|
|||||||
@@ -2,19 +2,16 @@
|
|||||||
|
|
||||||
echo "Initializing Immich ML $IMMICH_SOURCE_REF"
|
echo "Initializing Immich ML $IMMICH_SOURCE_REF"
|
||||||
|
|
||||||
|
lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.2"
|
||||||
|
# mimalloc seems to increase memory usage dramatically with openvino, need to investigate
|
||||||
if ! [ "$DEVICE" = "openvino" ]; then
|
if ! [ "$DEVICE" = "openvino" ]; then
|
||||||
|
export LD_PRELOAD="$lib_path"
|
||||||
|
export LD_BIND_NOW=1
|
||||||
: "${MACHINE_LEARNING_WORKER_TIMEOUT:=120}"
|
: "${MACHINE_LEARNING_WORKER_TIMEOUT:=120}"
|
||||||
else
|
else
|
||||||
: "${MACHINE_LEARNING_WORKER_TIMEOUT:=300}"
|
: "${MACHINE_LEARNING_WORKER_TIMEOUT:=300}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# mimalloc seems to increase memory usage dramatically with openvino, need to investigate
|
|
||||||
if ! [ "$DEVICE" = "openvino" ] && ! [ "$DEVICE" = "rocm" ]; then
|
|
||||||
lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.2"
|
|
||||||
export LD_PRELOAD="$lib_path"
|
|
||||||
export LD_BIND_NOW=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
: "${IMMICH_HOST:=[::]}"
|
: "${IMMICH_HOST:=[::]}"
|
||||||
: "${IMMICH_PORT:=3003}"
|
: "${IMMICH_PORT:=3003}"
|
||||||
: "${MACHINE_LEARNING_WORKERS:=1}"
|
: "${MACHINE_LEARNING_WORKERS:=1}"
|
||||||
|
|||||||
Generated
+45
-122
@@ -876,7 +876,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "huggingface-hub"
|
name = "huggingface-hub"
|
||||||
version = "0.29.3"
|
version = "0.29.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "filelock" },
|
{ name = "filelock" },
|
||||||
@@ -887,9 +887,9 @@ dependencies = [
|
|||||||
{ name = "tqdm" },
|
{ name = "tqdm" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/e5/f9/851f34b02970e8143d41d4001b2d49e54ef113f273902103823b8bc95ada/huggingface_hub-0.29.3.tar.gz", hash = "sha256:64519a25716e0ba382ba2d3fb3ca082e7c7eb4a2fc634d200e8380006e0760e5", size = 390123 }
|
sdist = { url = "https://files.pythonhosted.org/packages/58/b2/f8b3c9842a794e8203448725aefa02d7c9e0da42d5f22f4ed806057cc36e/huggingface_hub-0.29.2.tar.gz", hash = "sha256:590b29c0dcbd0ee4b7b023714dc1ad8563fe4a68a91463438b74e980d28afaf3", size = 389816 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/40/0c/37d380846a2e5c9a3c6a73d26ffbcfdcad5fc3eacf42fdf7cff56f2af634/huggingface_hub-0.29.3-py3-none-any.whl", hash = "sha256:0b25710932ac649c08cdbefa6c6ccb8e88eef82927cacdb048efb726429453aa", size = 468997 },
|
{ url = "https://files.pythonhosted.org/packages/13/5f/088ff08dc41808fcd99d9972b9bcfa7e3a35e30e8b0a3155b57938f1611c/huggingface_hub-0.29.2-py3-none-any.whl", hash = "sha256:c56f20fca09ef19da84dcde2b76379ecdaddf390b083f59f166715584953307d", size = 468087 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1050,7 +1050,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "locust"
|
name = "locust"
|
||||||
version = "2.33.2"
|
version = "2.33.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "configargparse" },
|
{ name = "configargparse" },
|
||||||
@@ -1069,9 +1069,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "werkzeug" },
|
{ name = "werkzeug" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/9e/09ee87dc12b240248731080bfd460c7d384aadb3171f6d03a4e7314cd0e1/locust-2.33.2.tar.gz", hash = "sha256:e626ed0156f36cec94c3c6b030fc91046469e7e2f5c2e91a99aab0f28b84977e", size = 2237716 }
|
sdist = { url = "https://files.pythonhosted.org/packages/f8/d4/873b1415c8a667982c5f229c6b74abed9fe0ead29ad87d862e5116ea2679/locust-2.33.0.tar.gz", hash = "sha256:ba291b7ab2349cc2db540adb8888bc93feb89ea4e4e10d80b935e5065091e8e9", size = 2237622 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/9c/c7/bb55ac53173d3e92b1b2577d0f36439500406ca5be476a27b7bc01ae8a75/locust-2.33.2-py3-none-any.whl", hash = "sha256:a2f3b53dcd5ed22cecee874cd989912749663d82ec9b030637d3e43044e5878e", size = 2254591 },
|
{ url = "https://files.pythonhosted.org/packages/1d/e5/57b58d9a545fbb2981de59ca25534d5ab4abb6742e6400bb49576ecab5ec/locust-2.33.0-py3-none-any.whl", hash = "sha256:77fcc5cc35cceee5e12d99f5bb23bc441d145bdef6967c2e93d6e4d93451553e", size = 2254520 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1109,10 +1109,6 @@ cuda = [
|
|||||||
openvino = [
|
openvino = [
|
||||||
{ name = "onnxruntime-openvino" },
|
{ name = "onnxruntime-openvino" },
|
||||||
]
|
]
|
||||||
rknn = [
|
|
||||||
{ name = "onnxruntime" },
|
|
||||||
{ name = "rknn-toolkit-lite2" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
@@ -1166,7 +1162,6 @@ requires-dist = [
|
|||||||
{ name = "insightface", specifier = ">=0.7.3,<1.0" },
|
{ name = "insightface", specifier = ">=0.7.3,<1.0" },
|
||||||
{ name = "onnxruntime", marker = "extra == 'armnn'", specifier = ">=1.15.0,<2" },
|
{ name = "onnxruntime", marker = "extra == 'armnn'", specifier = ">=1.15.0,<2" },
|
||||||
{ name = "onnxruntime", marker = "extra == 'cpu'", specifier = ">=1.15.0,<2" },
|
{ name = "onnxruntime", marker = "extra == 'cpu'", specifier = ">=1.15.0,<2" },
|
||||||
{ name = "onnxruntime", marker = "extra == 'rknn'", specifier = ">=1.15.0,<2" },
|
|
||||||
{ name = "onnxruntime-gpu", marker = "extra == 'cuda'", specifier = ">=1.17.0,<2", index = "https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/" },
|
{ name = "onnxruntime-gpu", marker = "extra == 'cuda'", specifier = ">=1.17.0,<2", index = "https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/" },
|
||||||
{ name = "onnxruntime-openvino", marker = "extra == 'openvino'", specifier = ">=1.17.1,<1.19.0" },
|
{ name = "onnxruntime-openvino", marker = "extra == 'openvino'", specifier = ">=1.17.1,<1.19.0" },
|
||||||
{ name = "opencv-python-headless", specifier = ">=4.7.0.72,<5.0" },
|
{ name = "opencv-python-headless", specifier = ">=4.7.0.72,<5.0" },
|
||||||
@@ -1176,11 +1171,10 @@ requires-dist = [
|
|||||||
{ name = "pydantic-settings", specifier = ">=2.5.2,<3" },
|
{ name = "pydantic-settings", specifier = ">=2.5.2,<3" },
|
||||||
{ name = "python-multipart", specifier = ">=0.0.6,<1.0" },
|
{ name = "python-multipart", specifier = ">=0.0.6,<1.0" },
|
||||||
{ name = "rich", specifier = ">=13.4.2" },
|
{ name = "rich", specifier = ">=13.4.2" },
|
||||||
{ name = "rknn-toolkit-lite2", marker = "extra == 'rknn'", specifier = ">=2.3.0,<3" },
|
|
||||||
{ name = "tokenizers", specifier = ">=0.15.0,<1.0" },
|
{ name = "tokenizers", specifier = ">=0.15.0,<1.0" },
|
||||||
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.22.0,<1.0" },
|
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.22.0,<1.0" },
|
||||||
]
|
]
|
||||||
provides-extras = ["cpu", "cuda", "openvino", "armnn", "rknn", "rocm"]
|
provides-extras = ["cpu", "cuda", "openvino", "armnn"]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
@@ -2137,100 +2131,29 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rknn-toolkit-lite2"
|
|
||||||
version = "2.3.0"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "numpy" },
|
|
||||||
{ name = "psutil" },
|
|
||||||
{ name = "ruamel-yaml" },
|
|
||||||
]
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ed/77/6af374a4a8cd2aee762a1fb8a3050dcf3f129134bbdc4bb6bed755c4325b/rknn_toolkit_lite2-2.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b6733689bd09a262bcb6ba4744e690dd4b37ebeac4ed427cf45242c4b4ce9a4", size = 559372 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9b/0c/76ff1eb09d09ce4394a6959d2343a321d28dd9e604348ffdafceafdc344c/rknn_toolkit_lite2-2.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3e4fefe355dc34a155680e4bcb9e4abb37ebc271f045ec9e0a4a3a018bc5beb", size = 569149 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/6e/8679562028051b02312212defc6e8c07248953f10dd7ad506e941b575bf3/rknn_toolkit_lite2-2.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37394371d1561f470c553f39869d7c35ff93405dffe3d0d72babf297a2b0aee9", size = 527457 },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ruamel-yaml"
|
|
||||||
version = "0.18.10"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "ruamel-yaml-clib", marker = "python_full_version < '3.13' and platform_python_implementation == 'CPython'" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/ea/46/f44d8be06b85bc7c4d8c95d658be2b68f27711f279bf9dd0612a5e4794f5/ruamel.yaml-0.18.10.tar.gz", hash = "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58", size = 143447 }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c2/36/dfc1ebc0081e6d39924a2cc53654497f967a084a436bb64402dfce4254d9/ruamel.yaml-0.18.10-py3-none-any.whl", hash = "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1", size = 117729 },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ruamel-yaml-clib"
|
|
||||||
version = "0.2.12"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/20/84/80203abff8ea4993a87d823a5f632e4d92831ef75d404c9fc78d0176d2b5/ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f", size = 225315 }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/70/57/40a958e863e299f0c74ef32a3bde9f2d1ea8d69669368c0c502a0997f57f/ruamel.yaml.clib-0.2.12-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5", size = 131301 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/98/a8/29a3eb437b12b95f50a6bcc3d7d7214301c6c529d8fdc227247fa84162b5/ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969", size = 633728 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/35/6d/ae05a87a3ad540259c3ad88d71275cbd1c0f2d30ae04c65dcbfb6dcd4b9f/ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df", size = 722230 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/b7/20c6f3c0b656fe609675d69bc135c03aac9e3865912444be6339207b6648/ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76", size = 686712 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/11/d12dbf683471f888d354dac59593873c2b45feb193c5e3e0f2ebf85e68b9/ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6", size = 663936 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/14/4c268f5077db5c83f743ee1daeb236269fa8577133a5cfa49f8b382baf13/ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd", size = 696580 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/fc/8cd12f189c6405a4c1cf37bd633aa740a9538c8e40497c231072d0fef5cf/ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a", size = 663393 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/80/29/c0a017b704aaf3cbf704989785cd9c5d5b8ccec2dae6ac0c53833c84e677/ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da", size = 100326 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3a/65/fa39d74db4e2d0cd252355732d966a460a41cd01c6353b820a0952432839/ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28", size = 118079 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fb/8f/683c6ad562f558cbc4f7c029abcd9599148c51c54b5ef0f24f2638da9fbb/ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6", size = 132224 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3c/d2/b79b7d695e2f21da020bd44c782490578f300dd44f0a4c57a92575758a76/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e", size = 641480 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/6e/264c50ce2a31473a9fdbf4fa66ca9b2b17c7455b31ef585462343818bd6c/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e", size = 739068 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/29/88c2567bc893c84d88b4c48027367c3562ae69121d568e8a3f3a8d363f4d/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52", size = 703012 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/46/879763c619b5470820f0cd6ca97d134771e502776bc2b844d2adb6e37753/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642", size = 704352 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/02/80/ece7e6034256a4186bbe50dee28cd032d816974941a6abf6a9d65e4228a7/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2", size = 737344 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f0/ca/e4106ac7e80efbabdf4bf91d3d32fc424e41418458251712f5672eada9ce/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3", size = 714498 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/67/58/b1f60a1d591b771298ffa0428237afb092c7f29ae23bad93420b1eb10703/ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4", size = 100205 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b4/4f/b52f634c9548a9291a70dfce26ca7ebce388235c93588a1068028ea23fcc/ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb", size = 118185 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/48/41/e7a405afbdc26af961678474a55373e1b323605a4f5e2ddd4a80ea80f628/ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632", size = 133433 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/b0/b850385604334c2ce90e3ee1013bd911aedf058a934905863a6ea95e9eb4/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d", size = 647362 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/44/d0/3f68a86e006448fb6c005aee66565b9eb89014a70c491d70c08de597f8e4/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c", size = 754118 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/52/a9/d39f3c5ada0a3bb2870d7db41901125dbe2434fa4f12ca8c5b83a42d7c53/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd", size = 706497 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/fa/097e38135dadd9ac25aecf2a54be17ddf6e4c23e43d538492a90ab3d71c6/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31", size = 698042 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/d5/a659ca6f503b9379b930f13bc6b130c9f176469b73b9834296822a83a132/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680", size = 745831 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/db/5d/36619b61ffa2429eeaefaab4f3374666adf36ad8ac6330d855848d7d36fd/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d", size = 715692 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/82/85cb92f15a4231c89b95dfe08b09eb6adca929ef7df7e17ab59902b6f589/ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5", size = 98777 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/8f/c3654f6f1ddb75daf3922c3d8fc6005b1ab56671ad56ffb874d908bfa668/ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4", size = 115523 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/00/4864119668d71a5fa45678f380b5923ff410701565821925c69780356ffa/ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a", size = 132011 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/5e/212f473a93ae78c669ffa0cb051e3fee1139cb2d385d2ae1653d64281507/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475", size = 642488 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/8f/ecfbe2123ade605c49ef769788f79c38ddb1c8fa81e01f4dbf5cf1a44b16/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef", size = 745066 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e2/a9/28f60726d29dfc01b8decdb385de4ced2ced9faeb37a847bd5cf26836815/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6", size = 701785 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/84/7e/8e7ec45920daa7f76046578e4f677a3215fe8f18ee30a9cb7627a19d9b4c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf", size = 693017 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c5/b3/d650eaade4ca225f02a648321e1ab835b9d361c60d51150bac49063b83fa/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1", size = 741270 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/87/b8/01c29b924dcbbed75cc45b30c30d565d763b9c4d540545a0eeecffb8f09c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01", size = 709059 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/8c/ed73f047a73638257aa9377ad356bea4d96125b305c34a28766f4445cc0f/ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6", size = 98583 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/85/e8e751d8791564dd333d5d9a4eab0a7a115f7e349595417fd50ecae3395c/ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3", size = 115190 },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.11.0"
|
version = "0.9.9"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/77/2b/7ca27e854d92df5e681e6527dc0f9254c9dc06c8408317893cf96c851cdd/ruff-0.11.0.tar.gz", hash = "sha256:e55c620690a4a7ee6f1cccb256ec2157dc597d109400ae75bbf944fc9d6462e2", size = 3799407 }
|
sdist = { url = "https://files.pythonhosted.org/packages/6f/c3/418441a8170e8d53d05c0b9dad69760dbc7b8a12c10dbe6db1e1205d2377/ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933", size = 3717448 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/48/40/3d0340a9e5edc77d37852c0cd98c5985a5a8081fc3befaeb2ae90aaafd2b/ruff-0.11.0-py3-none-linux_armv6l.whl", hash = "sha256:dc67e32bc3b29557513eb7eeabb23efdb25753684b913bebb8a0c62495095acb", size = 10098158 },
|
{ url = "https://files.pythonhosted.org/packages/bc/c3/2c4afa9ba467555d074b146d9aed0633a56ccdb900839fb008295d037b89/ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367", size = 10027252 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/a9/d8f5abb3b87b973b007649ac7bf63665a05b2ae2b2af39217b09f52abbbf/ruff-0.11.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38c23fd9bdec4eb437b4c1e3595905a0a8edfccd63a790f818b28c78fe345639", size = 10879071 },
|
{ url = "https://files.pythonhosted.org/packages/33/d1/439e58487cf9eac26378332e25e7d5ade4b800ce1eec7dc2cfc9b0d7ca96/ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7", size = 10840721 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ab/62/aaa198614c6211677913ec480415c5e6509586d7b796356cec73a2f8a3e6/ruff-0.11.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7c8661b0be91a38bd56db593e9331beaf9064a79028adee2d5f392674bbc5e88", size = 10247944 },
|
{ url = "https://files.pythonhosted.org/packages/50/44/fead822c38281ba0122f1b76b460488a175a9bd48b130650a6fb6dbcbcf9/ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d", size = 10161439 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/52/59e0a9f2cf1ce5e6cbe336b6dd0144725c8ea3b97cac60688f4e7880bf13/ruff-0.11.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6c0e8d3d2db7e9f6efd884f44b8dc542d5b6b590fc4bb334fdbc624d93a29a2", size = 10421725 },
|
{ url = "https://files.pythonhosted.org/packages/11/ae/d404a2ab8e61ddf6342e09cc6b7f7846cce6b243e45c2007dbe0ca928a5d/ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a", size = 10336264 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/c3/dcd71acc6dff72ce66d13f4be5bca1dbed4db678dff2f0f6f307b04e5c02/ruff-0.11.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c3156d3f4b42e57247275a0a7e15a851c165a4fc89c5e8fa30ea6da4f7407b8", size = 9954435 },
|
{ url = "https://files.pythonhosted.org/packages/6a/4e/7c268aa7d84cd709fb6f046b8972313142cffb40dfff1d2515c5e6288d54/ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe", size = 9908774 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/9a/342d336c7c52dbd136dee97d4c7797e66c3f92df804f8f3b30da59b92e9c/ruff-0.11.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:490b1e147c1260545f6d041c4092483e3f6d8eba81dc2875eaebcf9140b53905", size = 11492664 },
|
{ url = "https://files.pythonhosted.org/packages/cc/26/c618a878367ef1b76270fd027ca93692657d3f6122b84ba48911ef5f2edc/ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c", size = 11428127 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/84/35/6e7defd2d7ca95cc385ac1bd9f7f2e4a61b9cc35d60a263aebc8e590c462/ruff-0.11.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1bc09a7419e09662983b1312f6fa5dab829d6ab5d11f18c3760be7ca521c9329", size = 12207856 },
|
{ url = "https://files.pythonhosted.org/packages/d7/9a/c5588a93d9bfed29f565baf193fe802fa676a0c837938137ea6cf0576d8c/ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be", size = 12133187 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/22/78/da669c8731bacf40001c880ada6d31bcfb81f89cc996230c3b80d319993e/ruff-0.11.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcfa478daf61ac8002214eb2ca5f3e9365048506a9d52b11bea3ecea822bb844", size = 11645156 },
|
{ url = "https://files.pythonhosted.org/packages/3e/ff/e7980a7704a60905ed7e156a8d73f604c846d9bd87deda9cabfa6cba073a/ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590", size = 11602937 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ee/47/e27d17d83530a208f4a9ab2e94f758574a04c51e492aa58f91a3ed7cbbcb/ruff-0.11.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6fbb2aed66fe742a6a3a0075ed467a459b7cedc5ae01008340075909d819df1e", size = 13884167 },
|
{ url = "https://files.pythonhosted.org/packages/24/78/3690444ad9e3cab5c11abe56554c35f005b51d1d118b429765249095269f/ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb", size = 13771698 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/5e/42ffbb0a5d4b07bbc642b7d58357b4e19a0f4774275ca6ca7d1f7b5452cd/ruff-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c0c1ff014351c0b0cdfdb1e35fa83b780f1e065667167bb9502d47ca41e6db", size = 11348311 },
|
{ url = "https://files.pythonhosted.org/packages/6e/bf/e477c2faf86abe3988e0b5fd22a7f3520e820b2ee335131aca2e16120038/ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0", size = 11249026 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c8/51/dc3ce0c5ce1a586727a3444a32f98b83ba99599bb1ebca29d9302886e87f/ruff-0.11.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e4fd5ff5de5f83e0458a138e8a869c7c5e907541aec32b707f57cf9a5e124445", size = 10305039 },
|
{ url = "https://files.pythonhosted.org/packages/f7/82/cdaffd59e5a8cb5b14c408c73d7a555a577cf6645faaf83e52fe99521715/ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17", size = 10220432 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/60/e0/475f0c2f26280f46f2d6d1df1ba96b3399e0234cf368cc4c88e6ad10dcd9/ruff-0.11.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:96bc89a5c5fd21a04939773f9e0e276308be0935de06845110f43fd5c2e4ead7", size = 9937939 },
|
{ url = "https://files.pythonhosted.org/packages/fe/a4/2507d0026225efa5d4412b6e294dfe54725a78652a5c7e29e6bd0fc492f3/ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1", size = 9874602 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e2/d3/3e61b7fd3e9cdd1e5b8c7ac188bec12975c824e51c5cd3d64caf81b0331e/ruff-0.11.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a9352b9d767889ec5df1483f94870564e8102d4d7e99da52ebf564b882cdc2c7", size = 10923259 },
|
{ url = "https://files.pythonhosted.org/packages/d5/be/f3aab1813846b476c4bcffe052d232244979c3cd99d751c17afb530ca8e4/ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57", size = 10851212 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/32/cd74149ebb40b62ddd14bd2d1842149aeb7f74191fb0f49bd45c76909ff2/ruff-0.11.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:049a191969a10897fe052ef9cc7491b3ef6de79acd7790af7d7897b7a9bfbcb6", size = 11406212 },
|
{ url = "https://files.pythonhosted.org/packages/8b/45/8e5fd559bea0d2f57c4e12bf197a2fade2fac465aa518284f157dfbca92b/ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e", size = 11327490 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/00/ef/033022a6b104be32e899b00de704d7c6d1723a54d4c9e09d147368f14b62/ruff-0.11.0-py3-none-win32.whl", hash = "sha256:3191e9116b6b5bbe187447656f0c8526f0d36b6fd89ad78ccaad6bdc2fad7df2", size = 10310905 },
|
{ url = "https://files.pythonhosted.org/packages/42/55/e6c90f13880aeef327746052907e7e930681f26a164fe130ddac28b08269/ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1", size = 10227912 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ed/8a/163f2e78c37757d035bd56cd60c8d96312904ca4a6deeab8442d7b3cbf89/ruff-0.11.0-py3-none-win_amd64.whl", hash = "sha256:c58bfa00e740ca0a6c43d41fb004cd22d165302f360aaa56f7126d544db31a21", size = 11411730 },
|
{ url = "https://files.pythonhosted.org/packages/35/b2/da925693cb82a1208aa34966c0f36cb222baca94e729dd22a587bc22d0f3/ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1", size = 11355632 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4e/f7/096f6efabe69b49d7ca61052fc70289c05d8d35735c137ef5ba5ef423662/ruff-0.11.0-py3-none-win_arm64.whl", hash = "sha256:868364fc23f5aa122b00c6f794211e85f7e78f5dffdf7c590ab90b8c4e69b657", size = 10538956 },
|
{ url = "https://files.pythonhosted.org/packages/31/d8/de873d1c1b020d668d8ec9855d390764cb90cf8f6486c0983da52be8b7b7/ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf", size = 10435860 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2398,27 +2321,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokenizers"
|
name = "tokenizers"
|
||||||
version = "0.21.1"
|
version = "0.21.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "huggingface-hub" },
|
{ name = "huggingface-hub" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/92/76/5ac0c97f1117b91b7eb7323dcd61af80d72f790b4df71249a7850c195f30/tokenizers-0.21.1.tar.gz", hash = "sha256:a1bb04dc5b448985f86ecd4b05407f5a8d97cb2c0532199b2a302a604a0165ab", size = 343256 }
|
sdist = { url = "https://files.pythonhosted.org/packages/20/41/c2be10975ca37f6ec40d7abd7e98a5213bb04f284b869c1a24e6504fd94d/tokenizers-0.21.0.tar.gz", hash = "sha256:ee0894bf311b75b0c03079f33859ae4b2334d675d4e93f5a4132e1eae2834fe4", size = 343021 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a5/1f/328aee25f9115bf04262e8b4e5a2050b7b7cf44b59c74e982db7270c7f30/tokenizers-0.21.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e78e413e9e668ad790a29456e677d9d3aa50a9ad311a40905d6861ba7692cf41", size = 2780767 },
|
{ url = "https://files.pythonhosted.org/packages/b0/5c/8b09607b37e996dc47e70d6a7b6f4bdd4e4d5ab22fe49d7374565c7fefaf/tokenizers-0.21.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3c4c93eae637e7d2aaae3d376f06085164e1660f89304c0ab2b1d08a406636b2", size = 2647461 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ae/1a/4526797f3719b0287853f12c5ad563a9be09d446c44ac784cdd7c50f76ab/tokenizers-0.21.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:cd51cd0a91ecc801633829fcd1fda9cf8682ed3477c6243b9a095539de4aecf3", size = 2650555 },
|
{ url = "https://files.pythonhosted.org/packages/22/7a/88e58bb297c22633ed1c9d16029316e5b5ac5ee44012164c2edede599a5e/tokenizers-0.21.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:f53ea537c925422a2e0e92a24cce96f6bc5046bbef24a1652a5edc8ba975f62e", size = 2563639 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4d/7a/a209b29f971a9fdc1da86f917fe4524564924db50d13f0724feed37b2a4d/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28da6b72d4fb14ee200a1bd386ff74ade8992d7f725f2bde2c495a9a98cf4d9f", size = 2937541 },
|
{ url = "https://files.pythonhosted.org/packages/f7/14/83429177c19364df27d22bc096d4c2e431e0ba43e56c525434f1f9b0fd00/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b177fb54c4702ef611de0c069d9169f0004233890e0c4c5bd5508ae05abf193", size = 2903304 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3c/1e/b788b50ffc6191e0b1fc2b0d49df8cff16fe415302e5ceb89f619d12c5bc/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34d8cfde551c9916cb92014e040806122295a6800914bab5865deb85623931cf", size = 2819058 },
|
{ url = "https://files.pythonhosted.org/packages/7e/db/3433eab42347e0dc5452d8fcc8da03f638c9accffefe5a7c78146666964a/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6b43779a269f4629bebb114e19c3fca0223296ae9fea8bb9a7a6c6fb0657ff8e", size = 2804378 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/aa/3626dfa09a0ecc5b57a8c58eeaeb7dd7ca9a37ad9dd681edab5acd55764c/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaa852d23e125b73d283c98f007e06d4595732104b65402f46e8ef24b588d9f8", size = 3133278 },
|
{ url = "https://files.pythonhosted.org/packages/57/8b/7da5e6f89736c2ade02816b4733983fca1c226b0c42980b1ae9dc8fcf5cc/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aeb255802be90acfd363626753fda0064a8df06031012fe7d52fd9a905eb00e", size = 3095488 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/4d/8fbc203838b3d26269f944a89459d94c858f5b3f9a9b6ee9728cdcf69161/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a21a15d5c8e603331b8a59548bbe113564136dc0f5ad8306dd5033459a226da0", size = 3144253 },
|
{ url = "https://files.pythonhosted.org/packages/4d/f6/5ed6711093dc2c04a4e03f6461798b12669bc5a17c8be7cce1240e0b5ce8/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8b09dbeb7a8d73ee204a70f94fc06ea0f17dcf0844f16102b9f414f0b7463ba", size = 3121410 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d8/1b/2bd062adeb7c7511b847b32e356024980c0ffcf35f28947792c2d8ad2288/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2fdbd4c067c60a0ac7eca14b6bd18a5bebace54eb757c706b47ea93204f7a37c", size = 3398225 },
|
{ url = "https://files.pythonhosted.org/packages/81/42/07600892d48950c5e80505b81411044a2d969368cdc0d929b1c847bf6697/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:400832c0904f77ce87c40f1a8a27493071282f785724ae62144324f171377273", size = 3388821 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8a/63/38be071b0c8e06840bc6046991636bcb30c27f6bb1e670f4f4bc87cf49cc/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd9a0061e403546f7377df940e866c3e678d7d4e9643d0461ea442b4f89e61a", size = 3038874 },
|
{ url = "https://files.pythonhosted.org/packages/22/06/69d7ce374747edaf1695a4f61b83570d91cc8bbfc51ccfecf76f56ab4aac/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84ca973b3a96894d1707e189c14a774b701596d579ffc7e69debfc036a61a04", size = 3008868 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/83/afa94193c09246417c23a3c75a8a0a96bf44ab5630a3015538d0c316dd4b/tokenizers-0.21.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:db9484aeb2e200c43b915a1a0150ea885e35f357a5a8fabf7373af333dcc8dbf", size = 9014448 },
|
{ url = "https://files.pythonhosted.org/packages/c8/69/54a0aee4d576045b49a0eb8bffdc495634309c823bf886042e6f46b80058/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:eb7202d231b273c34ec67767378cd04c767e967fda12d4a9e36208a34e2f137e", size = 8975831 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ae/b3/0e1a37d4f84c0f014d43701c11eb8072704f6efe8d8fc2dcdb79c47d76de/tokenizers-0.21.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ed248ab5279e601a30a4d67bdb897ecbe955a50f1e7bb62bd99f07dd11c2f5b6", size = 8937877 },
|
{ url = "https://files.pythonhosted.org/packages/f7/f3/b776061e4f3ebf2905ba1a25d90380aafd10c02d406437a8ba22d1724d76/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:089d56db6782a73a27fd8abf3ba21779f5b85d4a9f35e3b493c7bbcbbf0d539b", size = 8920746 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ac/33/ff08f50e6d615eb180a4a328c65907feb6ded0b8f990ec923969759dc379/tokenizers-0.21.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:9ac78b12e541d4ce67b4dfd970e44c060a2147b9b2a21f509566d556a509c67d", size = 9186645 },
|
{ url = "https://files.pythonhosted.org/packages/d8/ee/ce83d5ec8b6844ad4c3ecfe3333d58ecc1adc61f0878b323a15355bcab24/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:c87ca3dc48b9b1222d984b6b7490355a6fdb411a2d810f6f05977258400ddb74", size = 9161814 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/aa/8ae85f69a9f6012c6f8011c6f4aa1c96154c816e9eea2e1b758601157833/tokenizers-0.21.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e5a69c1a4496b81a5ee5d2c1f3f7fbdf95e90a0196101b0ee89ed9956b8a168f", size = 9384380 },
|
{ url = "https://files.pythonhosted.org/packages/18/07/3e88e65c0ed28fa93aa0c4d264988428eef3df2764c3126dc83e243cb36f/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4145505a973116f91bc3ac45988a92e618a6f83eb458f49ea0790df94ee243ff", size = 9357138 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/5b/a5d98c89f747455e8b7a9504910c865d5e51da55e825a7ae641fb5ff0a58/tokenizers-0.21.1-cp39-abi3-win32.whl", hash = "sha256:1039a3a5734944e09de1d48761ade94e00d0fa760c0e0551151d4dd851ba63e3", size = 2239506 },
|
{ url = "https://files.pythonhosted.org/packages/15/b0/dc4572ca61555fc482ebc933f26cb407c6aceb3dc19c301c68184f8cad03/tokenizers-0.21.0-cp39-abi3-win32.whl", hash = "sha256:eb1702c2f27d25d9dd5b389cc1f2f51813e99f8ca30d9e25348db6585a97e24a", size = 2202266 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e6/b6/072a8e053ae600dcc2ac0da81a23548e3b523301a442a6ca900e92ac35be/tokenizers-0.21.1-cp39-abi3-win_amd64.whl", hash = "sha256:0f0dcbcc9f6e13e675a66d7a5f2f225a736745ce484c1a4e07476a89ccdad382", size = 2435481 },
|
{ url = "https://files.pythonhosted.org/packages/44/69/d21eb253fa91622da25585d362a874fa4710be600f0ea9446d8d0217cec1/tokenizers-0.21.0-cp39-abi3-win_amd64.whl", hash = "sha256:87841da5a25a3a5f70c102de371db120f41873b854ba65e52bccd57df5a3780c", size = 2389192 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2465,14 +2388,14 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "types-setuptools"
|
name = "types-setuptools"
|
||||||
version = "76.0.0.20250313"
|
version = "75.8.2.20250305"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "setuptools" },
|
{ name = "setuptools" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b8/0f/2d1d000c2be3919bcdea15e5da48456bf1e55c18d02c5509ea59dade1408/types_setuptools-76.0.0.20250313.tar.gz", hash = "sha256:b2be66f550f95f3cad2a7d46177b273c7e9c80df7d257fa57addbbcfc8126a9e", size = 43627 }
|
sdist = { url = "https://files.pythonhosted.org/packages/4f/18/a996861f5225e7d533a8d8b6aa61bcc9183429a6b8bc93b850aa2e22974d/types_setuptools-75.8.2.20250305.tar.gz", hash = "sha256:a987269b49488f21961a1d99aa8d281b611625883def6392a93855b31544e405", size = 42609 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/89/ea9669a0a76b160ffb312d0b02b15bad053c1bc81d2a54e42e3a402ca754/types_setuptools-76.0.0.20250313-py3-none-any.whl", hash = "sha256:bf454b2a49b8cfd7ebcf5844d4dd5fe4c8666782df1e3663c5866fd51a47460e", size = 65845 },
|
{ url = "https://files.pythonhosted.org/packages/d9/5b/bb33f99239a6d54ed1d8220a088d96d2ccacac7abb317df0d68d2500f3be/types_setuptools-75.8.2.20250305-py3-none-any.whl", hash = "sha256:ba80953fd1f5f49e552285c024f75b5223096a38a5138a54d18ddd3fa8f6a2d4", size = 63727 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"flutter": "3.29.2"
|
"flutter": "3.29.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<!-- Flutter needs it to communicate with the running application
|
<!-- Flutter needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
</manifest>
|
||||||
<application android:label="Immich-Debug" tools:replace="android:label">
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ platform :android do
|
|||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 188,
|
"android.injected.version.code" => 187,
|
||||||
"android.injected.version.name" => "1.130.0",
|
"android.injected.version.name" => "1.129.0",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "تحرير التاريخ والوقت",
|
"control_bottom_app_bar_edit_time": "تحرير التاريخ والوقت",
|
||||||
"control_bottom_app_bar_favorite": "مفضل",
|
"control_bottom_app_bar_favorite": "مفضل",
|
||||||
"control_bottom_app_bar_share": "يشارك",
|
"control_bottom_app_bar_share": "يشارك",
|
||||||
"control_bottom_app_bar_share_link": "Share Link",
|
|
||||||
"control_bottom_app_bar_share_to": "مشاركة إلى",
|
"control_bottom_app_bar_share_to": "مشاركة إلى",
|
||||||
"control_bottom_app_bar_stack": "تجميع",
|
"control_bottom_app_bar_stack": "تجميع",
|
||||||
"control_bottom_app_bar_trash_from_immich": "حذفه ونقله في سله المهملات",
|
"control_bottom_app_bar_trash_from_immich": "حذفه ونقله في سله المهملات",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "وحدة زمنية",
|
"edit_date_time_dialog_timezone": "وحدة زمنية",
|
||||||
"edit_image_title": "Edit",
|
"edit_image_title": "Edit",
|
||||||
"edit_location_dialog_title": "موقع",
|
"edit_location_dialog_title": "موقع",
|
||||||
"empty_folder": "This folder is empty",
|
|
||||||
"end_date": "End date",
|
"end_date": "End date",
|
||||||
"enqueued": "Enqueued",
|
"enqueued": "Enqueued",
|
||||||
"enter_wifi_name": "Enter WiFi name",
|
"enter_wifi_name": "Enter WiFi name",
|
||||||
@@ -265,10 +263,6 @@
|
|||||||
"exif_bottom_sheet_location_add": "إضافة موقع",
|
"exif_bottom_sheet_location_add": "إضافة موقع",
|
||||||
"exif_bottom_sheet_people": "الناس",
|
"exif_bottom_sheet_people": "الناس",
|
||||||
"exif_bottom_sheet_person_add_person": "اضف اسما",
|
"exif_bottom_sheet_person_add_person": "اضف اسما",
|
||||||
"exif_bottom_sheet_person_age": "Age {}",
|
|
||||||
"exif_bottom_sheet_person_age_months": "Age {} months",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "Age 1 year, {} months",
|
|
||||||
"exif_bottom_sheet_person_age_years": "Age {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "أعمال جارية",
|
"experimental_settings_new_asset_list_subtitle": "أعمال جارية",
|
||||||
"experimental_settings_new_asset_list_title": "تمكين شبكة الصور التجريبية",
|
"experimental_settings_new_asset_list_title": "تمكين شبكة الصور التجريبية",
|
||||||
"experimental_settings_subtitle": "استخدام على مسؤوليتك الخاصة!",
|
"experimental_settings_subtitle": "استخدام على مسؤوليتك الخاصة!",
|
||||||
@@ -276,16 +270,11 @@
|
|||||||
"external_network": "External network",
|
"external_network": "External network",
|
||||||
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"failed_to_load_assets": "Failed to load assets",
|
|
||||||
"failed_to_load_folder": "Failed to load folder",
|
|
||||||
"favorites": "Favorites",
|
"favorites": "Favorites",
|
||||||
"favorites_page_no_favorites": "لم يتم العثور على الأصول المفضلة",
|
"favorites_page_no_favorites": "لم يتم العثور على الأصول المفضلة",
|
||||||
"favorites_page_title": "المفضلة",
|
"favorites_page_title": "المفضلة",
|
||||||
"filename_search": "File name or extension",
|
"filename_search": "File name or extension",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"folder": "Folder",
|
|
||||||
"folder_not_found": "Folder not found",
|
|
||||||
"folders": "Folders",
|
|
||||||
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
||||||
"grant_permission": "Grant permission",
|
"grant_permission": "Grant permission",
|
||||||
"haptic_feedback_switch": "تمكين ردود الفعل اللمسية",
|
"haptic_feedback_switch": "تمكين ردود الفعل اللمسية",
|
||||||
|
|||||||
+307
-318
@@ -8,26 +8,26 @@
|
|||||||
"action_common_update": "Actualitzar",
|
"action_common_update": "Actualitzar",
|
||||||
"add_a_name": "Afegeix un nom",
|
"add_a_name": "Afegeix un nom",
|
||||||
"add_endpoint": "afegir endpoint",
|
"add_endpoint": "afegir endpoint",
|
||||||
"add_to_album_bottom_sheet_added": "Afegit a {album}",
|
"add_to_album_bottom_sheet_added": "Added to {album}",
|
||||||
"add_to_album_bottom_sheet_already_exists": "Ja està a {album}",
|
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
|
||||||
"advanced_settings_log_level_title": "Nivell de registre: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Alguns dispositius són molt lents en carregar miniatures dels elements del dispositiu. Activeu aquest paràmetre per carregar imatges remotes en el seu lloc.",
|
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
||||||
"advanced_settings_prefer_remote_title": "Prefereix imatges remotes",
|
"advanced_settings_prefer_remote_title": "Prefereix imatges remotes",
|
||||||
"advanced_settings_proxy_headers_subtitle": "Definiu les capçaleres de proxy que Immich per enviar amb cada sol·licitud de xarxa",
|
"advanced_settings_proxy_headers_subtitle": "Definiu les capçaleres de proxy que Immich per enviar amb cada sol·licitud de xarxa",
|
||||||
"advanced_settings_proxy_headers_title": "Capçaleres de proxy",
|
"advanced_settings_proxy_headers_title": "Capçaleres de proxy",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Omet la verificació del certificat SSL del servidor. Requerit per a certificats autosignats.",
|
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Permet certificats SSL autosignats",
|
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
||||||
"advanced_settings_tile_subtitle": "Configuració avançada de l'usuari",
|
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
||||||
"advanced_settings_tile_title": "Avançat",
|
"advanced_settings_tile_title": "Avançat",
|
||||||
"advanced_settings_troubleshooting_subtitle": "Habilita funcions addicionals per a la resolució de problemes",
|
"advanced_settings_troubleshooting_subtitle": "Enable additional features for troubleshooting",
|
||||||
"advanced_settings_troubleshooting_title": "Resolució de problemes",
|
"advanced_settings_troubleshooting_title": "Resolució de problemes",
|
||||||
"album_info_card_backup_album_excluded": "Exclosos",
|
"album_info_card_backup_album_excluded": "Exclosos",
|
||||||
"album_info_card_backup_album_included": "Inclosos",
|
"album_info_card_backup_album_included": "Inclosos",
|
||||||
"albums": "Àlbums",
|
"albums": "Àlbums",
|
||||||
"album_thumbnail_card_item": "1 element",
|
"album_thumbnail_card_item": "1 item",
|
||||||
"album_thumbnail_card_items": "{} elements",
|
"album_thumbnail_card_items": "{} items",
|
||||||
"album_thumbnail_card_shared": " · Compartit",
|
"album_thumbnail_card_shared": " · Shared",
|
||||||
"album_thumbnail_owned": "Propi",
|
"album_thumbnail_owned": "Owned",
|
||||||
"album_thumbnail_shared_by": "Compartit per {}",
|
"album_thumbnail_shared_by": "Compartit per {}",
|
||||||
"album_viewer_appbar_delete_confirm": "Confirmes que vols suprimir aquest àlbum del teu compte?",
|
"album_viewer_appbar_delete_confirm": "Confirmes que vols suprimir aquest àlbum del teu compte?",
|
||||||
"album_viewer_appbar_share_delete": "Esborra l'àlbum",
|
"album_viewer_appbar_share_delete": "Esborra l'àlbum",
|
||||||
@@ -37,28 +37,28 @@
|
|||||||
"album_viewer_appbar_share_err_title": "Error al modificar el títol de l'àlbum",
|
"album_viewer_appbar_share_err_title": "Error al modificar el títol de l'àlbum",
|
||||||
"album_viewer_appbar_share_leave": "Surt de l'àlbum",
|
"album_viewer_appbar_share_leave": "Surt de l'àlbum",
|
||||||
"album_viewer_appbar_share_remove": "Treu de l'àlbum",
|
"album_viewer_appbar_share_remove": "Treu de l'àlbum",
|
||||||
"album_viewer_appbar_share_to": "Comparteix amb",
|
"album_viewer_appbar_share_to": "Share To",
|
||||||
"album_viewer_page_share_add_users": "Afegeix usuaris",
|
"album_viewer_page_share_add_users": "Afegeix usuaris",
|
||||||
"all": "Tot",
|
"all": "Tot",
|
||||||
"all_people_page_title": "Persones",
|
"all_people_page_title": "Persones",
|
||||||
"all_videos_page_title": "Vídeos",
|
"all_videos_page_title": "Vídeos",
|
||||||
"app_bar_signout_dialog_content": "Estàs segur que vols tancar la sessió?",
|
"app_bar_signout_dialog_content": "Are you sure you want to sign out?",
|
||||||
"app_bar_signout_dialog_ok": "Sí",
|
"app_bar_signout_dialog_ok": "Yes",
|
||||||
"app_bar_signout_dialog_title": "Tanca la sessió",
|
"app_bar_signout_dialog_title": "Sign out",
|
||||||
"archived": "Arxivat",
|
"archived": "Arxivat",
|
||||||
"archive_page_no_archived_assets": "No s'ha trobat res arxivat",
|
"archive_page_no_archived_assets": "No s'ha trobat res arxivat",
|
||||||
"archive_page_title": "Arxiu({})",
|
"archive_page_title": "Arxiu({})",
|
||||||
"asset_action_delete_err_read_only": "No es poden esborrar el fitxer(s) de només lectura, ometent",
|
"asset_action_delete_err_read_only": "No es poden esborrar el fitxer(s) de només lectura, ometent",
|
||||||
"asset_action_share_err_offline": "No s'ha pogut obtenir el fitxer(s) sense connexió, ometent",
|
"asset_action_share_err_offline": "No s'ha pogut obtenir el fitxer(s) sense connexió, ometent",
|
||||||
"asset_list_group_by_sub_title": "Agrupar per",
|
"asset_list_group_by_sub_title": "Agrupar per",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "Disseny dinàmic",
|
"asset_list_layout_settings_dynamic_layout_title": "Dynamic layout",
|
||||||
"asset_list_layout_settings_group_automatically": "Automàtic",
|
"asset_list_layout_settings_group_automatically": "Automàtic",
|
||||||
"asset_list_layout_settings_group_by": "Agrupa elements per",
|
"asset_list_layout_settings_group_by": "Group assets by",
|
||||||
"asset_list_layout_settings_group_by_month": "Mes",
|
"asset_list_layout_settings_group_by_month": "Month",
|
||||||
"asset_list_layout_settings_group_by_month_day": "Mes + dia",
|
"asset_list_layout_settings_group_by_month_day": "Month + day",
|
||||||
"asset_list_layout_sub_title": "Disseny",
|
"asset_list_layout_sub_title": "Disseny",
|
||||||
"asset_list_settings_subtitle": "Configuració del disseny de la graella de fotos",
|
"asset_list_settings_subtitle": "Photo grid layout settings",
|
||||||
"asset_list_settings_title": "Graella de fotos",
|
"asset_list_settings_title": "Photo Grid",
|
||||||
"asset_restored_successfully": "Element recuperat correctament",
|
"asset_restored_successfully": "Element recuperat correctament",
|
||||||
"assets_deleted_permanently": "{} element(s) esborrats permanentment",
|
"assets_deleted_permanently": "{} element(s) esborrats permanentment",
|
||||||
"assets_deleted_permanently_from_server": "{} element(s) esborrats permanentment del servidor d'Immich",
|
"assets_deleted_permanently_from_server": "{} element(s) esborrats permanentment del servidor d'Immich",
|
||||||
@@ -73,97 +73,97 @@
|
|||||||
"background_location_permission": "Permís d'ubicació en segon pla",
|
"background_location_permission": "Permís d'ubicació en segon pla",
|
||||||
"background_location_permission_content": "Per canviar de xarxa quan s'executa en segon pla, Immich ha de *sempre* tenir accés a la ubicació precisa perquè l'aplicació pugui llegir el nom de la xarxa Wi-Fi",
|
"background_location_permission_content": "Per canviar de xarxa quan s'executa en segon pla, Immich ha de *sempre* tenir accés a la ubicació precisa perquè l'aplicació pugui llegir el nom de la xarxa Wi-Fi",
|
||||||
"backup_album_selection_page_albums_device": "Àlbums al dispositiu ({})",
|
"backup_album_selection_page_albums_device": "Àlbums al dispositiu ({})",
|
||||||
"backup_album_selection_page_albums_tap": "Un toc per incloure, doble toc per excloure",
|
"backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude",
|
||||||
"backup_album_selection_page_assets_scatter": "Els elements poden dispersar-se en diversos àlbums. Per tant, els àlbums es poden incloure o excloure durant el procés de còpia de seguretat.",
|
"backup_album_selection_page_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.",
|
||||||
"backup_album_selection_page_select_albums": "Selecciona àlbums",
|
"backup_album_selection_page_select_albums": "Selecciona àlbums",
|
||||||
"backup_album_selection_page_selection_info": "Informació de la selecció",
|
"backup_album_selection_page_selection_info": "Informació de la selecció",
|
||||||
"backup_album_selection_page_total_assets": "Total d'elements únics",
|
"backup_album_selection_page_total_assets": "Total d'elements únics",
|
||||||
"backup_all": "Tots",
|
"backup_all": "All",
|
||||||
"backup_background_service_backup_failed_message": "No s'ha pogut copiar els elements. Tornant a intentar…",
|
"backup_background_service_backup_failed_message": "Failed to backup assets. Retrying…",
|
||||||
"backup_background_service_connection_failed_message": "No s'ha pogut connectar al servidor. Tornant a intentar…",
|
"backup_background_service_connection_failed_message": "Failed to connect to the server. Retrying…",
|
||||||
"backup_background_service_current_upload_notification": "Pujant {}",
|
"backup_background_service_current_upload_notification": "Pujant {}",
|
||||||
"backup_background_service_default_notification": "Cercant nous elements...",
|
"backup_background_service_default_notification": "Cercant nous elements...",
|
||||||
"backup_background_service_error_title": "Error copiant",
|
"backup_background_service_error_title": "Error copiant",
|
||||||
"backup_background_service_in_progress_notification": "Copiant els teus elements",
|
"backup_background_service_in_progress_notification": "Copiant els teus elements",
|
||||||
"backup_background_service_upload_failure_notification": "Error al pujar {}",
|
"backup_background_service_upload_failure_notification": "Error al pujar {}",
|
||||||
"backup_controller_page_albums": "Copia els àlbums",
|
"backup_controller_page_albums": "Copia els àlbums",
|
||||||
"backup_controller_page_background_app_refresh_disabled_content": "Activa l'actualització en segon pla de l'aplicació a Configuració > General > Actualització en segon pla per utilitzar la copia de seguretat en segon pla.",
|
"backup_controller_page_background_app_refresh_disabled_content": "Enable background app refresh in Settings > General > Background App Refresh in order to use background backup.",
|
||||||
"backup_controller_page_background_app_refresh_disabled_title": "Actualització en segon pla desactivada",
|
"backup_controller_page_background_app_refresh_disabled_title": "Background app refresh disabled",
|
||||||
"backup_controller_page_background_app_refresh_enable_button_text": "Vés a configuració",
|
"backup_controller_page_background_app_refresh_enable_button_text": "Vés a configuració",
|
||||||
"backup_controller_page_background_battery_info_link": "Mostra'm com",
|
"backup_controller_page_background_battery_info_link": "Mostra'm com",
|
||||||
"backup_controller_page_background_battery_info_message": "Per obtenir la millor experiència de copia de seguretat en segon pla, desactiveu qualsevol optimització de bateria que restringeixi l'activitat en segon pla per a Immich.\n\nAtès que això és específic del dispositiu, busqueu la informació necessària per al fabricant del vostre dispositiu",
|
"backup_controller_page_background_battery_info_message": "For the best background backup experience, please disable any battery optimizations restricting background activity for Immich.\n\nSince this is device-specific, please lookup the required information for your device manufacturer.",
|
||||||
"backup_controller_page_background_battery_info_ok": "D'acord",
|
"backup_controller_page_background_battery_info_ok": "D'acord",
|
||||||
"backup_controller_page_background_battery_info_title": "Optimitzacions de bateria",
|
"backup_controller_page_background_battery_info_title": "Optimitzacions de bateria",
|
||||||
"backup_controller_page_background_charging": "Només mentre es carrega",
|
"backup_controller_page_background_charging": "Només mentre es carrega",
|
||||||
"backup_controller_page_background_configure_error": "No s'ha pogut configurar el servei en segon pla",
|
"backup_controller_page_background_configure_error": "Failed to configure the background service",
|
||||||
"backup_controller_page_background_delay": "Retard en la copia de seguretat de nous elements: {}",
|
"backup_controller_page_background_delay": "Delay new assets backup: {}",
|
||||||
"backup_controller_page_background_description": "Activeu el servei en segon pla per copiar automàticament tots els nous elements sense haver d'obrir l'aplicació.",
|
"backup_controller_page_background_description": "Turn on the background service to automatically backup any new assets without needing to open the app",
|
||||||
"backup_controller_page_background_is_off": "La còpia automàtica en segon pla està desactivada",
|
"backup_controller_page_background_is_off": "Automatic background backup is off",
|
||||||
"backup_controller_page_background_is_on": "La còpia automàtica en segon pla està activada",
|
"backup_controller_page_background_is_on": "Automatic background backup is on",
|
||||||
"backup_controller_page_background_turn_off": "Desactiva el servei en segon pla",
|
"backup_controller_page_background_turn_off": "Turn off background service",
|
||||||
"backup_controller_page_background_turn_on": "Activa el servei en segon pla",
|
"backup_controller_page_background_turn_on": "Turn on background service",
|
||||||
"backup_controller_page_background_wifi": "Només amb WiFi",
|
"backup_controller_page_background_wifi": "Only on WiFi",
|
||||||
"backup_controller_page_backup": "Còpia",
|
"backup_controller_page_backup": "Còpia",
|
||||||
"backup_controller_page_backup_selected": "Seleccionat: ",
|
"backup_controller_page_backup_selected": "Selected: ",
|
||||||
"backup_controller_page_backup_sub": "Fotografies i vídeos copiats",
|
"backup_controller_page_backup_sub": "Fotografies i vídeos copiats",
|
||||||
"backup_controller_page_cancel": "Cancel·la",
|
"backup_controller_page_cancel": "Cancel·la",
|
||||||
"backup_controller_page_created": "Creat el: {}",
|
"backup_controller_page_created": "Created on: {}",
|
||||||
"backup_controller_page_desc_backup": "Activeu la còpia de seguretat per pujar automàticament els nous elements al servidor en obrir l'aplicació.",
|
"backup_controller_page_desc_backup": "Turn on foreground backup to automatically upload new assets to the server when opening the app.",
|
||||||
"backup_controller_page_excluded": "Exclosos:",
|
"backup_controller_page_excluded": "Exclosos:",
|
||||||
"backup_controller_page_failed": "Fallats ({})",
|
"backup_controller_page_failed": "Failed ({})",
|
||||||
"backup_controller_page_filename": "Nom de l'arxiu: {} [{}]",
|
"backup_controller_page_filename": "File name: {} [{}]",
|
||||||
"backup_controller_page_id": "ID: {}",
|
"backup_controller_page_id": "ID: {}",
|
||||||
"backup_controller_page_info": "Informació de la còpia",
|
"backup_controller_page_info": "Informació de la còpia",
|
||||||
"backup_controller_page_none_selected": "Cap seleccionat",
|
"backup_controller_page_none_selected": "None selected",
|
||||||
"backup_controller_page_remainder": "Restant",
|
"backup_controller_page_remainder": "Restant",
|
||||||
"backup_controller_page_remainder_sub": "Fotografies i vídeos restants per copiar de la selecció",
|
"backup_controller_page_remainder_sub": "Fotografies i vídeos restants per copiar de la selecció",
|
||||||
"backup_controller_page_select": "Selecciona",
|
"backup_controller_page_select": "Selecciona",
|
||||||
"backup_controller_page_server_storage": "Emmagatzematge del servidor",
|
"backup_controller_page_server_storage": "Server Storage",
|
||||||
"backup_controller_page_start_backup": "Inicia la còpia",
|
"backup_controller_page_start_backup": "Inicia la còpia",
|
||||||
"backup_controller_page_status_off": "La copia de seguretat està desactivada",
|
"backup_controller_page_status_off": "Automatic foreground backup is off",
|
||||||
"backup_controller_page_status_on": "La copia de seguretat està activada",
|
"backup_controller_page_status_on": "Automatic foreground backup is on",
|
||||||
"backup_controller_page_storage_format": "{} de {} utilitzats",
|
"backup_controller_page_storage_format": "{} of {} used",
|
||||||
"backup_controller_page_to_backup": "Àlbums a copiar",
|
"backup_controller_page_to_backup": "Àlbums a copiar",
|
||||||
"backup_controller_page_total": "Total",
|
"backup_controller_page_total": "Total",
|
||||||
"backup_controller_page_total_sub": "Totes les fotografies i vídeos dels àlbums seleccionats",
|
"backup_controller_page_total_sub": "Totes les fotografies i vídeos dels àlbums seleccionats",
|
||||||
"backup_controller_page_turn_off": "Desactiva la còpia de seguretat",
|
"backup_controller_page_turn_off": "Turn off foreground backup",
|
||||||
"backup_controller_page_turn_on": "Activa la còpia de seguretat",
|
"backup_controller_page_turn_on": "Turn on foreground backup",
|
||||||
"backup_controller_page_uploading_file_info": "S'està pujant la informació del fitxer",
|
"backup_controller_page_uploading_file_info": "Uploading file info",
|
||||||
"backup_err_only_album": "No es pot eliminar l'únic àlbum",
|
"backup_err_only_album": "Cannot remove the only album",
|
||||||
"backup_info_card_assets": "elements",
|
"backup_info_card_assets": "elements",
|
||||||
"backup_manual_cancelled": "Cancel·lat",
|
"backup_manual_cancelled": "Cancelled",
|
||||||
"backup_manual_failed": "Fallat",
|
"backup_manual_failed": "Failed",
|
||||||
"backup_manual_in_progress": "La pujada ja està en curs. Torneu-ho a provar més tard",
|
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
|
||||||
"backup_manual_success": "Èxit",
|
"backup_manual_success": "Success",
|
||||||
"backup_manual_title": "Estat de pujada",
|
"backup_manual_title": "Upload status",
|
||||||
"backup_options_page_title": "Opcions de còpia de seguretat",
|
"backup_options_page_title": "Opcions de còpia de seguretat",
|
||||||
"backup_setting_subtitle": "Gestiona la configuració de càrrega en segon pla i en primer pla",
|
"backup_setting_subtitle": "Gestiona la configuració de càrrega en segon pla i en primer pla",
|
||||||
"cache_settings_album_thumbnails": "Miniatures de la pàgina de la biblioteca ({} elements)",
|
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
|
||||||
"cache_settings_clear_cache_button": "Neteja la memòria cau",
|
"cache_settings_clear_cache_button": "Clear cache",
|
||||||
"cache_settings_clear_cache_button_title": "Neteja la memòria cau de l'aplicació. Això impactarà significativament el rendiment fins que la memòria cau es torni a reconstruir.",
|
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "NETEJA",
|
"cache_settings_duplicated_assets_clear_button": "CLEAR",
|
||||||
"cache_settings_duplicated_assets_subtitle": "Fotos i vídeos que estan a la llista negra de l'aplicació.",
|
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
|
||||||
"cache_settings_duplicated_assets_title": "Elements duplicats ({})",
|
"cache_settings_duplicated_assets_title": "Duplicated Assets ({})",
|
||||||
"cache_settings_image_cache_size": "Mida de la memòria cau de imatges ({} elements)",
|
"cache_settings_image_cache_size": "Image cache size ({} assets)",
|
||||||
"cache_settings_statistics_album": "Miniatures de la biblioteca",
|
"cache_settings_statistics_album": "Library thumbnails",
|
||||||
"cache_settings_statistics_assets": "{} elements ({})",
|
"cache_settings_statistics_assets": "{} elements ({})",
|
||||||
"cache_settings_statistics_full": "Imatges completes",
|
"cache_settings_statistics_full": "Imatges completes",
|
||||||
"cache_settings_statistics_shared": "Miniatures d'àlbums compartits",
|
"cache_settings_statistics_shared": "Shared album thumbnails",
|
||||||
"cache_settings_statistics_thumbnail": "Miniatures",
|
"cache_settings_statistics_thumbnail": "Miniatures",
|
||||||
"cache_settings_statistics_title": "Ús de memòria cau",
|
"cache_settings_statistics_title": "Ús de memòria cau",
|
||||||
"cache_settings_subtitle": "Controla el comportament de la memòria cau de l'aplicació mòbil Immich",
|
"cache_settings_subtitle": "Control the caching behaviour of the Immich mobile application",
|
||||||
"cache_settings_thumbnail_size": "Mida de la memòria cau de les miniatures ({} elements)",
|
"cache_settings_thumbnail_size": "Thumbnail cache size ({} assets)",
|
||||||
"cache_settings_tile_subtitle": "Controla el comportament de l'emmagatzematge local",
|
"cache_settings_tile_subtitle": "Control the local storage behaviour",
|
||||||
"cache_settings_tile_title": "Emmagatzematge local",
|
"cache_settings_tile_title": "Local Storage",
|
||||||
"cache_settings_title": "Configuració de la memòria cau",
|
"cache_settings_title": "Configuració de la memòria cau",
|
||||||
"cancel": "Cancel·la",
|
"cancel": "Cancel·la",
|
||||||
"canceled": "Cancel·lat",
|
"canceled": "Cancel·lat",
|
||||||
"change_display_order": "Canvia l'ordre de visualització",
|
"change_display_order": "Canvia l'ordre de visualització",
|
||||||
"change_password_form_confirm_password": "Confirma la contrasenya",
|
"change_password_form_confirm_password": "Confirma la contrasenya",
|
||||||
"change_password_form_description": "Hola {name},\n\nAquesta és la primera vegada que inicies sessió al sistema o bé s'ha sol·licitat canviar la teva contrasenya. Si us plau, introdueix la nova contrasenya a continuació.",
|
"change_password_form_description": "Hi {name},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||||
"change_password_form_new_password": "Nova contrasenya",
|
"change_password_form_new_password": "New Password",
|
||||||
"change_password_form_password_mismatch": "Les contrasenyes no coincideixen",
|
"change_password_form_password_mismatch": "Passwords do not match",
|
||||||
"change_password_form_reenter_new_password": "Torna a introduir la nova contrasenya",
|
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||||
"check_corrupt_asset_backup": "Comprovar les còpies de seguretat corruptes",
|
"check_corrupt_asset_backup": "Comprovar les còpies de seguretat corruptes",
|
||||||
"check_corrupt_asset_backup_button": "Realitzar comprovació",
|
"check_corrupt_asset_backup_button": "Realitzar comprovació",
|
||||||
"check_corrupt_asset_backup_description": "Executeu aquesta comprovació només mitjançant Wi-Fi i un cop s'hagi fet una còpia de seguretat de tots els actius. El procediment pot trigar uns minuts.",
|
"check_corrupt_asset_backup_description": "Executeu aquesta comprovació només mitjançant Wi-Fi i un cop s'hagi fet una còpia de seguretat de tots els actius. El procediment pot trigar uns minuts.",
|
||||||
@@ -176,14 +176,14 @@
|
|||||||
"client_cert_remove_msg": "S'ha eliminat el certificat del client",
|
"client_cert_remove_msg": "S'ha eliminat el certificat del client",
|
||||||
"client_cert_subtitle": "Només admet el format PKCS12 (.p12, .pfx). La importació/eliminació de certificats només està disponible abans d'iniciar sessió",
|
"client_cert_subtitle": "Només admet el format PKCS12 (.p12, .pfx). La importació/eliminació de certificats només està disponible abans d'iniciar sessió",
|
||||||
"client_cert_title": "Certificat de client SSL",
|
"client_cert_title": "Certificat de client SSL",
|
||||||
"common_add_to_album": "Afegir a l'àlbum",
|
"common_add_to_album": "Add to album",
|
||||||
"common_change_password": "Canvia la contrasenya",
|
"common_change_password": "Change Password",
|
||||||
"common_create_new_album": "Crea un àlbum nou",
|
"common_create_new_album": "Crea un àlbum nou",
|
||||||
"common_server_error": "Si us plau, comproveu la vostra connexió de xarxa, assegureu-vos que el servidor és accessible i que les versions de l'aplicació i del servidor són compatibles.",
|
"common_server_error": "Please check your network connection, make sure the server is reachable and app/server versions are compatible.",
|
||||||
"common_shared": "Compartit",
|
"common_shared": "Compartit",
|
||||||
"completed": "Completat",
|
"completed": "Completat",
|
||||||
"contextual_search": "Sortida del sol a la platja",
|
"contextual_search": "Sortida del sol a la platja",
|
||||||
"control_bottom_app_bar_add_to_album": "Afegir a l'àlbum",
|
"control_bottom_app_bar_add_to_album": "Add to album",
|
||||||
"control_bottom_app_bar_album_info": "{} elements",
|
"control_bottom_app_bar_album_info": "{} elements",
|
||||||
"control_bottom_app_bar_album_info_shared": "{} elements - Compartits",
|
"control_bottom_app_bar_album_info_shared": "{} elements - Compartits",
|
||||||
"control_bottom_app_bar_archive": "Arxiu",
|
"control_bottom_app_bar_archive": "Arxiu",
|
||||||
@@ -193,32 +193,31 @@
|
|||||||
"control_bottom_app_bar_delete_from_local": "Suprimeix del dispositiu",
|
"control_bottom_app_bar_delete_from_local": "Suprimeix del dispositiu",
|
||||||
"control_bottom_app_bar_download": "Descarrega",
|
"control_bottom_app_bar_download": "Descarrega",
|
||||||
"control_bottom_app_bar_edit": "Edita",
|
"control_bottom_app_bar_edit": "Edita",
|
||||||
"control_bottom_app_bar_edit_location": "Edita la ubicació",
|
"control_bottom_app_bar_edit_location": "Edit Location",
|
||||||
"control_bottom_app_bar_edit_time": "Edita data i hora",
|
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
||||||
"control_bottom_app_bar_favorite": "Preferit",
|
"control_bottom_app_bar_favorite": "Preferit",
|
||||||
"control_bottom_app_bar_share": "Comparteix",
|
"control_bottom_app_bar_share": "Share",
|
||||||
"control_bottom_app_bar_share_link": "Comparteix l'enllaç",
|
"control_bottom_app_bar_share_to": "Share To",
|
||||||
"control_bottom_app_bar_share_to": "Comparteix a",
|
"control_bottom_app_bar_stack": "Stack",
|
||||||
"control_bottom_app_bar_stack": "Apilar",
|
|
||||||
"control_bottom_app_bar_trash_from_immich": "Mou a paperera",
|
"control_bottom_app_bar_trash_from_immich": "Mou a paperera",
|
||||||
"control_bottom_app_bar_unarchive": "Desarxiva",
|
"control_bottom_app_bar_unarchive": "Desarxiva",
|
||||||
"control_bottom_app_bar_unfavorite": "No preferit",
|
"control_bottom_app_bar_unfavorite": "Unfavorite",
|
||||||
"control_bottom_app_bar_upload": "Puja",
|
"control_bottom_app_bar_upload": "Upload",
|
||||||
"create_album": "Crear àlbum",
|
"create_album": "Crear àlbum",
|
||||||
"create_album_page_untitled": "Sense títol",
|
"create_album_page_untitled": "Untitled",
|
||||||
"create_new": "CREAR NOU",
|
"create_new": "CREAR NOU",
|
||||||
"create_shared_album_page_create": "Crea",
|
"create_shared_album_page_create": "Create",
|
||||||
"create_shared_album_page_share": "Comparteix",
|
"create_shared_album_page_share": "Comparteix",
|
||||||
"create_shared_album_page_share_add_assets": "AFEGEIX ELEMENTS",
|
"create_shared_album_page_share_add_assets": "AFEGEIX ELEMENTS",
|
||||||
"create_shared_album_page_share_select_photos": "Escull fotografies",
|
"create_shared_album_page_share_select_photos": "Escull fotografies",
|
||||||
"crop": "Retalla",
|
"crop": "Retalla",
|
||||||
"curated_location_page_title": "Localitzacions",
|
"curated_location_page_title": "Localitzacions",
|
||||||
"curated_object_page_title": "Coses",
|
"curated_object_page_title": "Coses",
|
||||||
"current_server_address": "Adreça actual del servidor",
|
"current_server_address": "Current server address",
|
||||||
"daily_title_text_date": "E, dd MMM",
|
"daily_title_text_date": "E, MMM dd",
|
||||||
"daily_title_text_date_year": "E, dd MMM, yyyy",
|
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||||
"date_format": "E, d LLL, y • hh:mm",
|
"date_format": "E, LLL d, y • h:mm a",
|
||||||
"delete_dialog_alert": "Aquests elements seran eliminats de manera permanent d'Immich i del vostre dispositiu.",
|
"delete_dialog_alert": "These items will be permanently deleted from Immich and from your device",
|
||||||
"delete_dialog_alert_local": "Aquests elements s'eliminaran permanentment del vostre dispositiu, però encara estaran disponibles al servidor Immich",
|
"delete_dialog_alert_local": "Aquests elements s'eliminaran permanentment del vostre dispositiu, però encara estaran disponibles al servidor Immich",
|
||||||
"delete_dialog_alert_local_non_backed_up": "Alguns dels elements no tenen còpia de seguretat a Immich i s'eliminaran permanentment del dispositiu",
|
"delete_dialog_alert_local_non_backed_up": "Alguns dels elements no tenen còpia de seguretat a Immich i s'eliminaran permanentment del dispositiu",
|
||||||
"delete_dialog_alert_remote": "Aquests elements s'eliminaran permanentment del servidor Immich",
|
"delete_dialog_alert_remote": "Aquests elements s'eliminaran permanentment del servidor Immich",
|
||||||
@@ -228,11 +227,11 @@
|
|||||||
"delete_dialog_title": "Esborra permanentment",
|
"delete_dialog_title": "Esborra permanentment",
|
||||||
"delete_local_dialog_ok_backed_up_only": "Esborrar només les que tinguin còpia de seguretat",
|
"delete_local_dialog_ok_backed_up_only": "Esborrar només les que tinguin còpia de seguretat",
|
||||||
"delete_local_dialog_ok_force": "Suprimeix de totes maneres",
|
"delete_local_dialog_ok_force": "Suprimeix de totes maneres",
|
||||||
"delete_shared_link_dialog_content": "Esteu segurs que voleu eliminar aquest enllaç compartit?",
|
"delete_shared_link_dialog_content": "Are you sure you want to delete this shared link?",
|
||||||
"delete_shared_link_dialog_title": "Suprimeix l'enllaç compartit",
|
"delete_shared_link_dialog_title": "Delete Shared Link",
|
||||||
"description_input_hint_text": "Afegeix descripció...",
|
"description_input_hint_text": "Afegeix descripció...",
|
||||||
"description_input_submit_error": "S'ha produït un error en actualitzar la descripció, comproveu el registre per a més detalls",
|
"description_input_submit_error": "Error updating description, check the log for more details",
|
||||||
"description_search": "Jornada de senderisme al Pedraforca",
|
"description_search": "Jornada de senderisme a Sapa",
|
||||||
"download_canceled": "Descàrrega cancel·lada",
|
"download_canceled": "Descàrrega cancel·lada",
|
||||||
"download_complete": "Descàrrega completada",
|
"download_complete": "Descàrrega completada",
|
||||||
"download_enqueue": "Descàrrega en cua",
|
"download_enqueue": "Descàrrega en cua",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "Zona horària",
|
"edit_date_time_dialog_timezone": "Zona horària",
|
||||||
"edit_image_title": "Editar",
|
"edit_image_title": "Editar",
|
||||||
"edit_location_dialog_title": "Ubicació",
|
"edit_location_dialog_title": "Ubicació",
|
||||||
"empty_folder": "Aquesta carpeta és buida",
|
|
||||||
"end_date": "Data final",
|
"end_date": "Data final",
|
||||||
"enqueued": "En cua",
|
"enqueued": "En cua",
|
||||||
"enter_wifi_name": "Introdueix el nom de WiFi",
|
"enter_wifi_name": "Introdueix el nom de WiFi",
|
||||||
@@ -262,32 +260,23 @@
|
|||||||
"exif_bottom_sheet_description": "Afegeix descripció",
|
"exif_bottom_sheet_description": "Afegeix descripció",
|
||||||
"exif_bottom_sheet_details": "DETALLS",
|
"exif_bottom_sheet_details": "DETALLS",
|
||||||
"exif_bottom_sheet_location": "UBICACIÓ",
|
"exif_bottom_sheet_location": "UBICACIÓ",
|
||||||
"exif_bottom_sheet_location_add": "Afegeix una ubicació",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
"exif_bottom_sheet_people": "PERSONES",
|
"exif_bottom_sheet_people": "PERSONES",
|
||||||
"exif_bottom_sheet_person_add_person": "Afegir nom",
|
"exif_bottom_sheet_person_add_person": "Afegir nom",
|
||||||
"exif_bottom_sheet_person_age": "Edat {}",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"exif_bottom_sheet_person_age_months": "Edat {} mesos",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"exif_bottom_sheet_person_age_year_months": "Edat 1 any, {} mesos",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
"exif_bottom_sheet_person_age_years": "Edat {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "Treball en curs",
|
|
||||||
"experimental_settings_new_asset_list_title": "Habilita la graella de fotos experimental",
|
|
||||||
"experimental_settings_subtitle": "Utilitzeu-ho sota la vostra responsabilitat!",
|
|
||||||
"experimental_settings_title": "Experimental",
|
"experimental_settings_title": "Experimental",
|
||||||
"external_network": "Xarxa externa",
|
"external_network": "Xarxa externa",
|
||||||
"external_network_sheet_info": "Quan no estigui a la xarxa WiFi preferida, l'aplicació es connectarà al servidor mitjançant el primer dels URL següents a què pot arribar, començant de dalt a baix.",
|
"external_network_sheet_info": "Quan no estigui a la xarxa WiFi preferida, l'aplicació es connectarà al servidor mitjançant el primer dels URL següents a què pot arribar, començant de dalt a baix.",
|
||||||
"failed": "Fallat",
|
"failed": "Fallat",
|
||||||
"failed_to_load_assets": "No s'han pogut carregar els elements",
|
"favorites": "Favorits",
|
||||||
"failed_to_load_folder": "No s'ha pogut carregar la carpeta",
|
|
||||||
"favorites": "Preferits",
|
|
||||||
"favorites_page_no_favorites": "No s'han trobat preferits",
|
"favorites_page_no_favorites": "No s'han trobat preferits",
|
||||||
"favorites_page_title": "Preferits",
|
"favorites_page_title": "Favorites",
|
||||||
"filename_search": "Nom o extensió del fitxer",
|
"filename_search": "Nom o extensió del fitxer",
|
||||||
"filter": "Filtrar",
|
"filter": "Filtrar",
|
||||||
"folder": "Carpeta",
|
|
||||||
"folder_not_found": "Carpeta no trobada",
|
|
||||||
"folders": "Carpetes",
|
|
||||||
"get_wifiname_error": "No s'ha pogut obtenir el nom de la Wi-Fi. Assegureu-vos que heu concedit els permisos necessaris i que esteu connectat a una xarxa Wi-Fi",
|
"get_wifiname_error": "No s'ha pogut obtenir el nom de la Wi-Fi. Assegureu-vos que heu concedit els permisos necessaris i que esteu connectat a una xarxa Wi-Fi",
|
||||||
"grant_permission": "Concedir permís",
|
"grant_permission": "Grant permission",
|
||||||
"haptic_feedback_switch": "Activa la resposta hàptica",
|
"haptic_feedback_switch": "Activa la resposta hàptica",
|
||||||
"haptic_feedback_title": "Resposta Hàptica",
|
"haptic_feedback_title": "Resposta Hàptica",
|
||||||
"header_settings_add_header_tip": "Afegeix Capçalera",
|
"header_settings_add_header_tip": "Afegeix Capçalera",
|
||||||
@@ -296,43 +285,43 @@
|
|||||||
"header_settings_header_value_input": "Valor de la capçalera",
|
"header_settings_header_value_input": "Valor de la capçalera",
|
||||||
"header_settings_page_title": "Capçaleres de proxy",
|
"header_settings_page_title": "Capçaleres de proxy",
|
||||||
"headers_settings_tile_subtitle": "Definiu les capçaleres de proxy que l'aplicació hauria d'enviar amb cada sol·licitud de xarxa",
|
"headers_settings_tile_subtitle": "Definiu les capçaleres de proxy que l'aplicació hauria d'enviar amb cada sol·licitud de xarxa",
|
||||||
"headers_settings_tile_title": "Capçaleres proxy personalitzades",
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "S'han afegit {added} elements a l'àlbum {album}. {failed} elements ja existeixen a l'àlbum.",
|
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
||||||
"home_page_add_to_album_err_local": "Encara no es poden afegir elements locals als àlbums, ometent",
|
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
||||||
"home_page_add_to_album_success": "S'han afegit {added} elements a l'àlbum {album}.",
|
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
||||||
"home_page_album_err_partner": "Encara no es poden afegir elements dels companys als àlbums, ometent",
|
"home_page_album_err_partner": "Can not add partner assets to an album yet, skipping",
|
||||||
"home_page_archive_err_local": "Encara no es poden arxivar elements locals, ometent",
|
"home_page_archive_err_local": "Can not archive local assets yet, skipping",
|
||||||
"home_page_archive_err_partner": "No es poden arxivar els elements de companys, ometent",
|
"home_page_archive_err_partner": "Can not archive partner assets, skipping",
|
||||||
"home_page_building_timeline": "Construint la línia de temps",
|
"home_page_building_timeline": "Building the timeline",
|
||||||
"home_page_delete_err_partner": "No es poden suprimir els elements de companys, ometent",
|
"home_page_delete_err_partner": "Can not delete partner assets, skipping",
|
||||||
"home_page_delete_remote_err_local": "Elements locals a la selecció d'eliminació remota, ometent",
|
"home_page_delete_remote_err_local": "Elements locals a la selecció d'eliminació remota, ometent",
|
||||||
"home_page_favorite_err_local": "Encara no es pot afegir a preferits elements locals, ometent",
|
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
||||||
"home_page_favorite_err_partner": "Encara no es pot afegir a preferits elements de companys, ometent",
|
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
||||||
"home_page_first_time_notice": "Si és la primera vegada que utilitzes l'app, si us plau, assegura't d'escollir un àlbum de còpia de seguretat perquè la línia de temps pugui carregar fotos i vídeos als àlbums.",
|
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
||||||
"home_page_share_err_local": "No es poden compartir els elements locals a través d'un enllaç, ometent",
|
"home_page_share_err_local": "Can not share local assets via link, skipping",
|
||||||
"home_page_upload_err_limit": "Només es poden pujar un màxim de 30 elements alhora, ometent",
|
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
|
||||||
"ignore_icloud_photos": "Ignora fotos d'iCloud",
|
"ignore_icloud_photos": "Ignora fotos d'iCloud",
|
||||||
"ignore_icloud_photos_description": "Les fotos emmagatzemades a iCloud no es penjaran al servidor Immich",
|
"ignore_icloud_photos_description": "Les fotos emmagatzemades a iCloud no es penjaran al servidor Immich",
|
||||||
"image_saved_successfully": "Imatge desada",
|
"image_saved_successfully": "Imatge desada",
|
||||||
"image_viewer_page_state_provider_download_error": "Error de baixada",
|
"image_viewer_page_state_provider_download_error": "Download Error",
|
||||||
"image_viewer_page_state_provider_download_started": "Baixada començada",
|
"image_viewer_page_state_provider_download_started": "Descàrrega començada",
|
||||||
"image_viewer_page_state_provider_download_success": "Baixada amb èxit",
|
"image_viewer_page_state_provider_download_success": "Download Success",
|
||||||
"image_viewer_page_state_provider_share_error": "Error en compartir",
|
"image_viewer_page_state_provider_share_error": "Share Error",
|
||||||
"invalid_date": "Data invàlida",
|
"invalid_date": "Data invàlida",
|
||||||
"invalid_date_format": "Format de data invàlid",
|
"invalid_date_format": "Format de data invàlid",
|
||||||
"library": "Llibreria",
|
"library": "Llibreria",
|
||||||
"library_page_albums": "Àlbums",
|
"library_page_albums": "Àlbums",
|
||||||
"library_page_archive": "Arxiu",
|
"library_page_archive": "Arxiu",
|
||||||
"library_page_device_albums": "Àlbums al Dispositiu",
|
"library_page_device_albums": "Àlbums al Dispositiu",
|
||||||
"library_page_favorites": "Preferits",
|
"library_page_favorites": "Favorites",
|
||||||
"library_page_new_album": "Nou àlbum",
|
"library_page_new_album": "New album",
|
||||||
"library_page_sharing": "Compartint",
|
"library_page_sharing": "Sharing",
|
||||||
"library_page_sort_asset_count": "Nombre d'elements",
|
"library_page_sort_asset_count": "Number of assets",
|
||||||
"library_page_sort_created": "Creat més recentment",
|
"library_page_sort_created": "Created date",
|
||||||
"library_page_sort_last_modified": "Darrera modificació",
|
"library_page_sort_last_modified": "Last modified",
|
||||||
"library_page_sort_most_oldest_photo": "Foto més antiga",
|
"library_page_sort_most_oldest_photo": "Oldest photo",
|
||||||
"library_page_sort_most_recent_photo": "Foto més recent",
|
"library_page_sort_most_recent_photo": "Most recent photo",
|
||||||
"library_page_sort_title": "Títol de l'àlbum",
|
"library_page_sort_title": "Album title",
|
||||||
"local_network": "Xarxa local",
|
"local_network": "Xarxa local",
|
||||||
"local_network_sheet_info": "L'aplicació es connectarà al servidor mitjançant aquest URL quan utilitzeu la xarxa Wi-Fi especificada",
|
"local_network_sheet_info": "L'aplicació es connectarà al servidor mitjançant aquest URL quan utilitzeu la xarxa Wi-Fi especificada",
|
||||||
"location_permission": "Permís d'ubicació",
|
"location_permission": "Permís d'ubicació",
|
||||||
@@ -340,61 +329,61 @@
|
|||||||
"location_picker_choose_on_map": "Escollir en el mapa",
|
"location_picker_choose_on_map": "Escollir en el mapa",
|
||||||
"location_picker_latitude": "Latitud",
|
"location_picker_latitude": "Latitud",
|
||||||
"location_picker_latitude_error": "Introdueix una latitud vàlida",
|
"location_picker_latitude_error": "Introdueix una latitud vàlida",
|
||||||
"location_picker_latitude_hint": "Introdueix aquí la latitud",
|
"location_picker_latitude_hint": "Enter your latitude here",
|
||||||
"location_picker_longitude": "Longitud",
|
"location_picker_longitude": "Longitud",
|
||||||
"location_picker_longitude_error": "Introdueix una longitud vàlida",
|
"location_picker_longitude_error": "Introdueix una longitud vàlida",
|
||||||
"location_picker_longitude_hint": "Introdueix aquí la longitud",
|
"location_picker_longitude_hint": "Introdueix aquí la longitud",
|
||||||
"login_disabled": "S'ha desactivat l'inici de sessió",
|
"login_disabled": "Login has been disabled",
|
||||||
"login_form_api_exception": "Excepció de l'API. Comproveu l'URL del servidor i torneu-ho a provar.",
|
"login_form_api_exception": "API exception. Please check the server URL and try again.",
|
||||||
"login_form_back_button_text": "Enrere",
|
"login_form_back_button_text": "Back",
|
||||||
"login_form_button_text": "Entra",
|
"login_form_button_text": "Entra",
|
||||||
"login_form_email_hint": "elteu@correu.cat",
|
"login_form_email_hint": "elteu@correu.cat",
|
||||||
"login_form_endpoint_hint": "http://ip-del-servidor:port",
|
"login_form_endpoint_hint": "http://ip-del-servidor:port",
|
||||||
"login_form_endpoint_url": "URL del servidor",
|
"login_form_endpoint_url": "URL del servidor",
|
||||||
"login_form_err_http": "Especifica http:// o https://",
|
"login_form_err_http": "Especifica http:// o https://",
|
||||||
"login_form_err_invalid_email": "Adreça de correu electrònic no vàlida",
|
"login_form_err_invalid_email": "Adreça de correu electrònic no vàlida",
|
||||||
"login_form_err_invalid_url": "URL no vàlid",
|
"login_form_err_invalid_url": "Invalid URL",
|
||||||
"login_form_err_leading_whitespace": "Espai en blanc al principi",
|
"login_form_err_leading_whitespace": "Espai en blanc al principi",
|
||||||
"login_form_err_trailing_whitespace": "Espai en blanc al final",
|
"login_form_err_trailing_whitespace": "Espai en blanc al final",
|
||||||
"login_form_failed_get_oauth_server_config": "Error en iniciar sessió amb OAuth, comprova l'URL del servidor",
|
"login_form_failed_get_oauth_server_config": "Error logging using OAuth, check server URL",
|
||||||
"login_form_failed_get_oauth_server_disable": "La funcionalitat OAuth no està disponible en aquest servidor",
|
"login_form_failed_get_oauth_server_disable": "OAuth feature is not available on this server",
|
||||||
"login_form_failed_login": "Error en iniciar sessió, comprova l'URL del servidor, el correu electrònic i la contrasenya.",
|
"login_form_failed_login": "Error logging you in, check server URL, email and password",
|
||||||
"login_form_handshake_exception": "S'ha produït una excepció de handshake amb el servidor. Activa el suport per certificats autofirmats a la configuració si estàs fent servir un certificat autofirmat.",
|
"login_form_handshake_exception": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.",
|
||||||
"login_form_label_email": "Correu electrònic",
|
"login_form_label_email": "Correu electrònic",
|
||||||
"login_form_label_password": "Contrasenya",
|
"login_form_label_password": "Contrasenya",
|
||||||
"login_form_next_button": "Següent",
|
"login_form_next_button": "Següent",
|
||||||
"login_form_password_hint": "contrasenya",
|
"login_form_password_hint": "contrasenya",
|
||||||
"login_form_save_login": "Mantingues identificat",
|
"login_form_save_login": "Mantingues identificat",
|
||||||
"login_form_server_empty": "Introdueix l'URL del servidor.",
|
"login_form_server_empty": "Enter a server URL.",
|
||||||
"login_form_server_error": "No s'ha pogut connectar al servidor.",
|
"login_form_server_error": "Could not connect to server.",
|
||||||
"login_password_changed_error": "S'ha produït un error en actualitzar la contrasenya",
|
"login_password_changed_error": "There was an error updating your password",
|
||||||
"login_password_changed_success": "La contrasenya s'ha canviat correctament",
|
"login_password_changed_success": "Password updated successfully",
|
||||||
"map_assets_in_bound": "{} foto",
|
"map_assets_in_bound": "{} foto",
|
||||||
"map_assets_in_bounds": "{} fotos",
|
"map_assets_in_bounds": "{} fotos",
|
||||||
"map_cannot_get_user_location": "No es pot obtenir la ubicació de l'usuari",
|
"map_cannot_get_user_location": "Cannot get user's location",
|
||||||
"map_location_dialog_cancel": "Cancel·la",
|
"map_location_dialog_cancel": "Cancel",
|
||||||
"map_location_dialog_yes": "Sí",
|
"map_location_dialog_yes": "Yes",
|
||||||
"map_location_picker_page_use_location": "Utilitzar aquesta ubicació",
|
"map_location_picker_page_use_location": "Utilitzar aquesta ubicació",
|
||||||
"map_location_service_disabled_content": "El servei de localització s'ha d'activar per mostrar els elements de la teva ubicació actual. Vols activar-lo ara?",
|
"map_location_service_disabled_content": "Location service needs to be enabled to display assets from your current location. Do you want to enable it now?",
|
||||||
"map_location_service_disabled_title": "Servei de localització desactivat",
|
"map_location_service_disabled_title": "Location Service disabled",
|
||||||
"map_no_assets_in_bounds": "No hi ha fotos en aquesta zona",
|
"map_no_assets_in_bounds": "No photos in this area",
|
||||||
"map_no_location_permission_content": "Es necessita el permís de localització per mostrar els elements de la teva ubicació actual. Vols permetre-ho ara?",
|
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
|
||||||
"map_no_location_permission_title": "Permís de localització denegat",
|
"map_no_location_permission_title": "Location Permission denied",
|
||||||
"map_settings_dark_mode": "Mode fosc",
|
"map_settings_dark_mode": "Dark mode",
|
||||||
"map_settings_date_range_option_all": "Tot",
|
"map_settings_date_range_option_all": "All",
|
||||||
"map_settings_date_range_option_day": "Últimes 24 hores",
|
"map_settings_date_range_option_day": "Últimes 24 hores",
|
||||||
"map_settings_date_range_option_days": "Darrers {} dies",
|
"map_settings_date_range_option_days": "Darrers {} dies",
|
||||||
"map_settings_date_range_option_year": "Any passat",
|
"map_settings_date_range_option_year": "Any passat",
|
||||||
"map_settings_date_range_option_years": "Darrers {} anys",
|
"map_settings_date_range_option_years": "Darrers {} anys",
|
||||||
"map_settings_dialog_cancel": "Cancel·la",
|
"map_settings_dialog_cancel": "Cancel",
|
||||||
"map_settings_dialog_save": "Desa",
|
"map_settings_dialog_save": "Save",
|
||||||
"map_settings_dialog_title": "Configuració del mapa",
|
"map_settings_dialog_title": "Map Settings",
|
||||||
"map_settings_include_show_archived": "Incloure arxivats",
|
"map_settings_include_show_archived": "Include Archived",
|
||||||
"map_settings_include_show_partners": "Incloure companys",
|
"map_settings_include_show_partners": "Incloure companys",
|
||||||
"map_settings_only_relative_range": "Rang de dates",
|
"map_settings_only_relative_range": "Date range",
|
||||||
"map_settings_only_show_favorites": "Mostra només preferits",
|
"map_settings_only_show_favorites": "Show Favorite Only",
|
||||||
"map_settings_theme_settings": "Tema del Mapa",
|
"map_settings_theme_settings": "Tema del Mapa",
|
||||||
"map_zoom_to_see_photos": "Allunya per veure fotos",
|
"map_zoom_to_see_photos": "Zoom out to see photos",
|
||||||
"memories_all_caught_up": "Posat al dia",
|
"memories_all_caught_up": "Posat al dia",
|
||||||
"memories_check_back_tomorrow": "Torna demà per veure més records",
|
"memories_check_back_tomorrow": "Torna demà per veure més records",
|
||||||
"memories_start_over": "Torna a començar",
|
"memories_start_over": "Torna a començar",
|
||||||
@@ -402,7 +391,7 @@
|
|||||||
"memories_year_ago": "Fa un any",
|
"memories_year_ago": "Fa un any",
|
||||||
"memories_years_ago": "Fa {} anys",
|
"memories_years_ago": "Fa {} anys",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Fotos en moviment",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "No es pot canviar la data del fitxer(s) de només lectura, ometent",
|
"multiselect_grid_edit_date_time_err_read_only": "No es pot canviar la data del fitxer(s) de només lectura, ometent",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "No es pot canviar la localització de fitxers de només lectura. Saltant.",
|
"multiselect_grid_edit_gps_err_read_only": "No es pot canviar la localització de fitxers de només lectura. Saltant.",
|
||||||
"my_albums": "Els meus àlbums",
|
"my_albums": "Els meus àlbums",
|
||||||
@@ -411,58 +400,58 @@
|
|||||||
"no_assets_to_show": "No hi ha elements per mostrar",
|
"no_assets_to_show": "No hi ha elements per mostrar",
|
||||||
"no_name": "Sense nom",
|
"no_name": "Sense nom",
|
||||||
"notification_permission_dialog_cancel": "Cancel·la",
|
"notification_permission_dialog_cancel": "Cancel·la",
|
||||||
"notification_permission_dialog_content": "Per activar les notificacions, aneu a Configuració i seleccioneu permet.",
|
"notification_permission_dialog_content": "To enable notifications, go to Settings and select allow.",
|
||||||
"notification_permission_dialog_settings": "Configuració",
|
"notification_permission_dialog_settings": "Configuració",
|
||||||
"notification_permission_list_tile_content": "Atorga permís per a activar les notificacions.",
|
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
|
||||||
"notification_permission_list_tile_enable_button": "Activa les notificacions",
|
"notification_permission_list_tile_enable_button": "Activa les notificacions",
|
||||||
"notification_permission_list_tile_title": "Permís de notificacions",
|
"notification_permission_list_tile_title": "Notification Permission",
|
||||||
"not_selected": "No seleccionat",
|
"not_selected": "No seleccionat",
|
||||||
"on_this_device": "En aquest dispositiu",
|
"on_this_device": "En aquest dispositiu",
|
||||||
"partner_list_user_photos": "fotos de {user}",
|
"partner_list_user_photos": "fotos de {user}",
|
||||||
"partner_list_view_all": "Veure tot",
|
"partner_list_view_all": "Veure tot",
|
||||||
"partner_page_add_partner": "Afegeix company",
|
"partner_page_add_partner": "Afegeix company",
|
||||||
"partner_page_empty_message": "Les teves fotos encara no estan compartides amb cap company.",
|
"partner_page_empty_message": "Your photos are not yet shared with any partner.",
|
||||||
"partner_page_no_more_users": "No hi ha més usuaris a afegir",
|
"partner_page_no_more_users": "No more users to add",
|
||||||
"partner_page_partner_add_failed": "No s'ha pogut afegir el company",
|
"partner_page_partner_add_failed": "Failed to add partner",
|
||||||
"partner_page_select_partner": "Escull company",
|
"partner_page_select_partner": "Escull company",
|
||||||
"partner_page_shared_to_title": "Compartit amb",
|
"partner_page_shared_to_title": "Compartit amb",
|
||||||
"partner_page_stop_sharing_content": "{} ja no podrà accedir a les teves fotos.",
|
"partner_page_stop_sharing_content": "{} will no longer be able to access your photos.",
|
||||||
"partner_page_stop_sharing_title": "Vols deixar de compartir les teves fotos?",
|
"partner_page_stop_sharing_title": "Stop sharing your photos?",
|
||||||
"partner_page_title": "Company",
|
"partner_page_title": "Company",
|
||||||
"partners": "Companys",
|
"partners": "Companys",
|
||||||
"paused": "Pausat",
|
"paused": "Pausat",
|
||||||
"people": "Persones",
|
"people": "Persones",
|
||||||
"permission_onboarding_back": "Torna",
|
"permission_onboarding_back": "Back",
|
||||||
"permission_onboarding_continue_anyway": "Continua de totes maneres",
|
"permission_onboarding_continue_anyway": "Continue anyway",
|
||||||
"permission_onboarding_get_started": "Comença",
|
"permission_onboarding_get_started": "Get started",
|
||||||
"permission_onboarding_go_to_settings": "Ves a la configuració",
|
"permission_onboarding_go_to_settings": "Go to settings",
|
||||||
"permission_onboarding_grant_permission": "Dona permisos",
|
"permission_onboarding_grant_permission": "Dona permisos",
|
||||||
"permission_onboarding_log_out": "Tanca la sessió",
|
"permission_onboarding_log_out": "Log out",
|
||||||
"permission_onboarding_permission_denied": "S'ha denegat el permís. Per utilitzar Immich, concediu permisos de fotos i vídeos a Configuració.",
|
"permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
|
||||||
"permission_onboarding_permission_granted": "Permís concedit! Tot a punt.",
|
"permission_onboarding_permission_granted": "Permission granted! You are all set.",
|
||||||
"permission_onboarding_permission_limited": "Permís limitat. Per a permetre que Immich faci còpies de seguretat i gestioni tota la col·lecció de la galeria, concediu permisos de fotos i vídeos a Configuració.",
|
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
|
||||||
"permission_onboarding_request": "Immich requereix permís per veure les vostres fotos i vídeos.",
|
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
|
||||||
"places": "Llocs",
|
"places": "Llocs",
|
||||||
"preferences_settings_subtitle": "Gestiona les preferències de l'aplicació",
|
"preferences_settings_subtitle": "Gestiona les preferències de l'aplicació",
|
||||||
"preferences_settings_title": "Preferències",
|
"preferences_settings_title": "Preferències",
|
||||||
"profile_drawer_app_logs": "Registres",
|
"profile_drawer_app_logs": "Logs",
|
||||||
"profile_drawer_client_out_of_date_major": "L'aplicació mòbil està desactualitzada. Si us plau, actualitzeu a l'última versió major.",
|
"profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.",
|
||||||
"profile_drawer_client_out_of_date_minor": "L'aplicació mòbil està desactualitzada. Si us plau, actualitzeu a l'última versió menor.",
|
"profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.",
|
||||||
"profile_drawer_client_server_up_to_date": "El Client i el Servidor estan actualitzats",
|
"profile_drawer_client_server_up_to_date": "Client and Server are up-to-date",
|
||||||
"profile_drawer_documentation": "Documentació",
|
"profile_drawer_documentation": "Documentation",
|
||||||
"profile_drawer_github": "GitHub",
|
"profile_drawer_github": "GitHub",
|
||||||
"profile_drawer_server_out_of_date_major": "L'aplicació mòbil està desactualitzada. Si us plau, actualitzeu a l'última versió major.",
|
"profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.",
|
||||||
"profile_drawer_server_out_of_date_minor": "L'aplicació mòbil està desactualitzada. Si us plau, actualitzeu a l'última versió menor.",
|
"profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.",
|
||||||
"profile_drawer_settings": "Configuració",
|
"profile_drawer_settings": "Settings",
|
||||||
"profile_drawer_sign_out": "Tanca la sessió",
|
"profile_drawer_sign_out": "Tanca la sessió",
|
||||||
"profile_drawer_trash": "Paperera",
|
"profile_drawer_trash": "Trash",
|
||||||
"recently_added": "Afegit recentment",
|
"recently_added": "Afegit recentment",
|
||||||
"recently_added_page_title": "Afegit recentment",
|
"recently_added_page_title": "Recently Added",
|
||||||
"save": "Desa",
|
"save": "Desa",
|
||||||
"save_to_gallery": "Desa a galeria",
|
"save_to_gallery": "Desa a galeria",
|
||||||
"scaffold_body_error_occurred": "S'ha produït un error",
|
"scaffold_body_error_occurred": "S'ha produït un error",
|
||||||
"search_albums": "Cerca àlbums",
|
"search_albums": "Cerca àlbums",
|
||||||
"search_bar_hint": "Cerca les teves fotos",
|
"search_bar_hint": "Search your photos",
|
||||||
"search_filter_apply": "Aplicar filtre",
|
"search_filter_apply": "Aplicar filtre",
|
||||||
"search_filter_camera": "Càmera",
|
"search_filter_camera": "Càmera",
|
||||||
"search_filter_camera_make": "Marca",
|
"search_filter_camera_make": "Marca",
|
||||||
@@ -474,7 +463,7 @@
|
|||||||
"search_filter_date_title": "Selecciona un rang de dates",
|
"search_filter_date_title": "Selecciona un rang de dates",
|
||||||
"search_filter_description": "Cerca per descripció",
|
"search_filter_description": "Cerca per descripció",
|
||||||
"search_filter_display_option_archive": "Arxivat",
|
"search_filter_display_option_archive": "Arxivat",
|
||||||
"search_filter_display_option_favorite": "Preferit",
|
"search_filter_display_option_favorite": "Favorit",
|
||||||
"search_filter_display_option_not_in_album": "No en àlbum",
|
"search_filter_display_option_not_in_album": "No en àlbum",
|
||||||
"search_filter_display_options": "Opcions de Visualització",
|
"search_filter_display_options": "Opcions de Visualització",
|
||||||
"search_filter_display_options_title": "Opcions de visualització",
|
"search_filter_display_options_title": "Opcions de visualització",
|
||||||
@@ -497,60 +486,60 @@
|
|||||||
"search_page_categories": "Categories",
|
"search_page_categories": "Categories",
|
||||||
"search_page_favorites": "Preferides",
|
"search_page_favorites": "Preferides",
|
||||||
"search_page_motion_photos": "Fotografies animades",
|
"search_page_motion_photos": "Fotografies animades",
|
||||||
"search_page_no_objects": "No hi ha informació d'objectes disponibles",
|
"search_page_no_objects": "No Objects Info Available",
|
||||||
"search_page_no_places": "No hi ha informació de llocs disponibles",
|
"search_page_no_places": "No Places Info Available",
|
||||||
"search_page_people": "Persones",
|
"search_page_people": "Persones",
|
||||||
"search_page_person_add_name_dialog_cancel": "Cancel·la",
|
"search_page_person_add_name_dialog_cancel": "Cancel",
|
||||||
"search_page_person_add_name_dialog_hint": "Nom",
|
"search_page_person_add_name_dialog_hint": "Name",
|
||||||
"search_page_person_add_name_dialog_save": "Desa",
|
"search_page_person_add_name_dialog_save": "Save",
|
||||||
"search_page_person_add_name_dialog_title": "Afegeix un nom",
|
"search_page_person_add_name_dialog_title": "Add a name",
|
||||||
"search_page_person_add_name_subtitle": "Troba'ls ràpid buscant per nom",
|
"search_page_person_add_name_subtitle": "Find them fast by name with search",
|
||||||
"search_page_person_add_name_title": "Afegeix un nom",
|
"search_page_person_add_name_title": "Add a name",
|
||||||
"search_page_person_edit_name": "Edita el nom",
|
"search_page_person_edit_name": "Edit name",
|
||||||
"search_page_places": "Llocs",
|
"search_page_places": "Llocs",
|
||||||
"search_page_recently_added": "Afegit recentment",
|
"search_page_recently_added": "Afegit recentment",
|
||||||
"search_page_screenshots": "Captures de pantalla",
|
"search_page_screenshots": "Captures de pantalla",
|
||||||
"search_page_search_photos_videos": "Cerca les teves fotos i vídeos",
|
"search_page_search_photos_videos": "Cerca les teves fotos i vídeos",
|
||||||
"search_page_selfies": "Autofotos",
|
"search_page_selfies": "Autofotos",
|
||||||
"search_page_things": "Coses",
|
"search_page_things": "Coses",
|
||||||
"search_page_videos": "Vídeos",
|
"search_page_videos": "Videos",
|
||||||
"search_page_view_all_button": "Veure tot",
|
"search_page_view_all_button": "Veure tot",
|
||||||
"search_page_your_activity": "La teva activitat",
|
"search_page_your_activity": "Your activity",
|
||||||
"search_page_your_map": "El teu mapa",
|
"search_page_your_map": "Your Map",
|
||||||
"search_result_page_new_search_hint": "Cerca nova",
|
"search_result_page_new_search_hint": "Cerca nova",
|
||||||
"search_suggestion_list_smart_search_hint_1": "La cerca intel·ligent està habilitada per defecte, per a cercar metadades utilitzeu la sintaxi ",
|
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:el-teu-terme-de-cerca",
|
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||||
"select_additional_user_for_sharing_page_suggestions": "Suggeriments",
|
"select_additional_user_for_sharing_page_suggestions": "Suggeriments",
|
||||||
"select_user_for_sharing_page_err_album": "Error al crear l'àlbum",
|
"select_user_for_sharing_page_err_album": "Error al crear l'àlbum",
|
||||||
"select_user_for_sharing_page_share_suggestions": "Suggeriments",
|
"select_user_for_sharing_page_share_suggestions": "Suggestions",
|
||||||
"server_endpoint": "Endpoint de Servidor",
|
"server_endpoint": "Endpoint de Servidor",
|
||||||
"server_info_box_app_version": "Versió de l'aplicació",
|
"server_info_box_app_version": "Versió de l'aplicació",
|
||||||
"server_info_box_latest_release": "Última versió",
|
"server_info_box_latest_release": "Latest Version",
|
||||||
"server_info_box_server_url": "URL del servidor",
|
"server_info_box_server_url": "Server URL",
|
||||||
"server_info_box_server_version": "Versió del servidor",
|
"server_info_box_server_version": "Versió del servidor",
|
||||||
"setting_image_viewer_help": "El visor de detalls carrega primer la miniatura petita, després carrega la vista prèvia de mida mitjana (si està habilitada), finalment carrega l'original (si està habilitada).",
|
"setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).",
|
||||||
"setting_image_viewer_original_subtitle": "Activa per carregar la imatge en resolució original (molt gran!). Desactiva per reduir el consum de dades (tant de xarxa com de memòria cau).",
|
"setting_image_viewer_original_subtitle": "Enable to load the original full-resolution image (large!). Disable to reduce data usage (both network and on device cache).",
|
||||||
"setting_image_viewer_original_title": "Carrega la imatge original",
|
"setting_image_viewer_original_title": "Load original image",
|
||||||
"setting_image_viewer_preview_subtitle": "Activa per carregar una imatge de resolució mitjana. Desactiva per carregar directament la imatge original, o bé utilitzar només la miniatura.",
|
"setting_image_viewer_preview_subtitle": "Enable to load a medium-resolution image. Disable to either directly load the original or only use the thumbnail.",
|
||||||
"setting_image_viewer_preview_title": "Carrega la imatge de vista prèvia",
|
"setting_image_viewer_preview_title": "Load preview image",
|
||||||
"setting_image_viewer_title": "Imatges",
|
"setting_image_viewer_title": "Imatges",
|
||||||
"setting_languages_apply": "Aplicar",
|
"setting_languages_apply": "Aplicar",
|
||||||
"setting_languages_subtitle": "Canvia el llenguatge de l'aplicació",
|
"setting_languages_subtitle": "Canvia el llenguatge de l'aplicació",
|
||||||
"setting_languages_title": "Idiomes",
|
"setting_languages_title": "Idiomes",
|
||||||
"setting_notifications_notify_failures_grace_period": "Notifica les fallades de la còpia de seguretat en segon pla: {}",
|
"setting_notifications_notify_failures_grace_period": "Notify background backup failures: {}",
|
||||||
"setting_notifications_notify_hours": "{} hores",
|
"setting_notifications_notify_hours": "{} hours",
|
||||||
"setting_notifications_notify_immediately": "immediatament",
|
"setting_notifications_notify_immediately": "immediately",
|
||||||
"setting_notifications_notify_minutes": "{} minuts",
|
"setting_notifications_notify_minutes": "{} minutes",
|
||||||
"setting_notifications_notify_never": "mai",
|
"setting_notifications_notify_never": "never",
|
||||||
"setting_notifications_notify_seconds": "{} segons",
|
"setting_notifications_notify_seconds": "{} seconds",
|
||||||
"setting_notifications_single_progress_subtitle": "Informació detallada del progrés de la pujada de cada fitxer",
|
"setting_notifications_single_progress_subtitle": "Detailed upload progress information per asset",
|
||||||
"setting_notifications_single_progress_title": "Mostra el progrés detallat de la còpia de seguretat en segon pla",
|
"setting_notifications_single_progress_title": "Show background backup detail progress",
|
||||||
"setting_notifications_subtitle": "Ajusta les preferències de notificació",
|
"setting_notifications_subtitle": "Adjust your notification preferences",
|
||||||
"setting_notifications_title": "Notificacions",
|
"setting_notifications_title": "Notifications",
|
||||||
"setting_notifications_total_progress_subtitle": "Progrés general de la pujada (elements completats/total)",
|
"setting_notifications_total_progress_subtitle": "Overall upload progress (done/total assets)",
|
||||||
"setting_notifications_total_progress_title": "Mostra el progrés total de la còpia de seguretat en segon pla",
|
"setting_notifications_total_progress_title": "Show background backup total progress",
|
||||||
"setting_pages_app_bar_settings": "Configuració",
|
"setting_pages_app_bar_settings": "Settings",
|
||||||
"settings_require_restart": "Si us plau, reinicieu Immich per a aplicar aquest canvi",
|
"settings_require_restart": "Please restart Immich to apply this setting",
|
||||||
"setting_video_viewer_looping_subtitle": "Habilita per reproduir automàticament un vídeo al visualitzador de detalls.",
|
"setting_video_viewer_looping_subtitle": "Habilita per reproduir automàticament un vídeo al visualitzador de detalls.",
|
||||||
"setting_video_viewer_looping_title": "Bucle",
|
"setting_video_viewer_looping_title": "Bucle",
|
||||||
"setting_video_viewer_original_video_subtitle": "Quan reproduïu un vídeo des del servidor, reproduïu l'original encara que hi hagi una transcodificació disponible. Pot conduir a l'amortització. Els vídeos disponibles localment es reprodueixen en qualitat original independentment d'aquesta configuració.",
|
"setting_video_viewer_original_video_subtitle": "Quan reproduïu un vídeo des del servidor, reproduïu l'original encara que hi hagi una transcodificació disponible. Pot conduir a l'amortització. Els vídeos disponibles localment es reprodueixen en qualitat original independentment d'aquesta configuració.",
|
||||||
@@ -561,33 +550,33 @@
|
|||||||
"share_add_title": "Afegeix un títol",
|
"share_add_title": "Afegeix un títol",
|
||||||
"share_assets_selected": "{} seleccionats",
|
"share_assets_selected": "{} seleccionats",
|
||||||
"share_create_album": "Crea un àlbum",
|
"share_create_album": "Crea un àlbum",
|
||||||
"shared_album_activities_input_disable": "Els comentaris estan desactivats",
|
"shared_album_activities_input_disable": "Comment is disabled",
|
||||||
"shared_album_activities_input_hint": "Digues alguna cosa",
|
"shared_album_activities_input_hint": "Say something",
|
||||||
"shared_album_activity_remove_content": "Voleu eliminar aquesta activitat?",
|
"shared_album_activity_remove_content": "Do you want to delete this activity?",
|
||||||
"shared_album_activity_remove_title": "Elimina l'activitat",
|
"shared_album_activity_remove_title": "Delete Activity",
|
||||||
"shared_album_activity_setting_subtitle": "Permet que altres responguin",
|
"shared_album_activity_setting_subtitle": "Let others respond",
|
||||||
"shared_album_activity_setting_title": "Comentaris i m'agrada",
|
"shared_album_activity_setting_title": "Comments & likes",
|
||||||
"shared_album_section_people_action_error": "S'ha produït un error en retirar-se/eliminar l'àlbum",
|
"shared_album_section_people_action_error": "Error leaving/removing from album",
|
||||||
"shared_album_section_people_action_leave": "Elimina l'usuari de l'àlbum",
|
"shared_album_section_people_action_leave": "Remove user from album",
|
||||||
"shared_album_section_people_action_remove_user": "Elimina l'usuari de l'àlbum",
|
"shared_album_section_people_action_remove_user": "Remove user from album",
|
||||||
"shared_album_section_people_owner_label": "Amo",
|
"shared_album_section_people_owner_label": "Owner",
|
||||||
"shared_album_section_people_title": "PERSONES",
|
"shared_album_section_people_title": "PEOPLE",
|
||||||
"share_dialog_preparing": "S'està preparant...",
|
"share_dialog_preparing": "Preparing...",
|
||||||
"shared_intent_upload_button_progress_text": "{} / {} Pujat",
|
"shared_intent_upload_button_progress_text": "{} / {} Pujat",
|
||||||
"shared_link_app_bar_title": "Enllaços compartits",
|
"shared_link_app_bar_title": "Shared Links",
|
||||||
"shared_link_clipboard_copied_massage": "S'ha copiat al porta-retalls",
|
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
||||||
"shared_link_clipboard_text": "Enllaç: {}\nContrasenya: {}",
|
"shared_link_clipboard_text": "Link: {}\nPassword: {}",
|
||||||
"shared_link_create_app_bar_title": "Crea un enllaç per compartir",
|
"shared_link_create_app_bar_title": "Create link to share",
|
||||||
"shared_link_create_error": "S'ha produït un error en crear l'enllaç compartit",
|
"shared_link_create_error": "Error while creating shared link",
|
||||||
"shared_link_create_info": "Permet que qualsevol persona amb l'enllaç vegi les fotografies seleccionades",
|
"shared_link_create_info": "Let anyone with the link see the selected photo(s)",
|
||||||
"shared_link_create_submit_button": "Crea enllaç",
|
"shared_link_create_submit_button": "Create link",
|
||||||
"shared_link_edit_allow_download": "Permet que usuaris públics descarreguin",
|
"shared_link_edit_allow_download": "Allow public user to download",
|
||||||
"shared_link_edit_allow_upload": "Permet que usuaris públics publiquin",
|
"shared_link_edit_allow_upload": "Allow public user to upload",
|
||||||
"shared_link_edit_app_bar_title": "Edita l'enllaç",
|
"shared_link_edit_app_bar_title": "Edit link",
|
||||||
"shared_link_edit_change_expiry": "Canvia la data de caducitat",
|
"shared_link_edit_change_expiry": "Change expiration time",
|
||||||
"shared_link_edit_description": "Descripció",
|
"shared_link_edit_description": "Description",
|
||||||
"shared_link_edit_description_hint": "Introduïu la descripció de compartició",
|
"shared_link_edit_description_hint": "Enter the share description",
|
||||||
"shared_link_edit_expire_after": "Caduca després de",
|
"shared_link_edit_expire_after": "Expire after",
|
||||||
"shared_link_edit_expire_after_option_day": "1 dia",
|
"shared_link_edit_expire_after_option_day": "1 dia",
|
||||||
"shared_link_edit_expire_after_option_days": "{} dies",
|
"shared_link_edit_expire_after_option_days": "{} dies",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 hora",
|
"shared_link_edit_expire_after_option_hour": "1 hora",
|
||||||
@@ -595,98 +584,98 @@
|
|||||||
"shared_link_edit_expire_after_option_minute": "1 minut",
|
"shared_link_edit_expire_after_option_minute": "1 minut",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} minuts",
|
"shared_link_edit_expire_after_option_minutes": "{} minuts",
|
||||||
"shared_link_edit_expire_after_option_months": "{} mesos",
|
"shared_link_edit_expire_after_option_months": "{} mesos",
|
||||||
"shared_link_edit_expire_after_option_never": "Mai",
|
"shared_link_edit_expire_after_option_never": "Never",
|
||||||
"shared_link_edit_expire_after_option_year": "any {}",
|
"shared_link_edit_expire_after_option_year": "any {}",
|
||||||
"shared_link_edit_password": "Contrasenya",
|
"shared_link_edit_password": "Password",
|
||||||
"shared_link_edit_password_hint": "Introduïu la contrasenya de compartició",
|
"shared_link_edit_password_hint": "Enter the share password",
|
||||||
"shared_link_edit_show_meta": "Mostra metadades",
|
"shared_link_edit_show_meta": "Show metadata",
|
||||||
"shared_link_edit_submit_button": "Actualitza l'enllaç",
|
"shared_link_edit_submit_button": "Update link",
|
||||||
"shared_link_empty": "No tens cap enllaç compartit",
|
"shared_link_empty": "You don't have any shared links",
|
||||||
"shared_link_error_server_url_fetch": "No s'ha pogut obtenir l'URL del servidor",
|
"shared_link_error_server_url_fetch": "Cannot fetch the server url",
|
||||||
"shared_link_expired": "Caducat",
|
"shared_link_expired": "Expired",
|
||||||
"shared_link_expires_day": "Caduca d'aquí a {} dia",
|
"shared_link_expires_day": "Caduca d'aquí a {} dia",
|
||||||
"shared_link_expires_days": "Caduca d'aquí a {} dies",
|
"shared_link_expires_days": "Caduca d'aquí a {} dies",
|
||||||
"shared_link_expires_hour": "Caduca d'aquí a {} hora",
|
"shared_link_expires_hour": "Caduca d'aquí a {} hora",
|
||||||
"shared_link_expires_hours": "Caduca d'aquí a {} hores",
|
"shared_link_expires_hours": "Caduca d'aquí a {} hores",
|
||||||
"shared_link_expires_minute": "Caduca d'aquí a {} minut",
|
"shared_link_expires_minute": "Caduca d'aquí a {} minut",
|
||||||
"shared_link_expires_minutes": "Caduca d'aquí a {} minuts",
|
"shared_link_expires_minutes": "Expires in {} minutes",
|
||||||
"shared_link_expires_never": "Caduca ∞",
|
"shared_link_expires_never": "Expires ∞",
|
||||||
"shared_link_expires_second": "Caduca d'aquí a {} segon",
|
"shared_link_expires_second": "Caduca d'aquí a {} segon",
|
||||||
"shared_link_expires_seconds": "Caduca d'aquí a {} segons",
|
"shared_link_expires_seconds": "Expires in {} seconds",
|
||||||
"shared_link_individual_shared": "Individual compartit",
|
"shared_link_individual_shared": "Individual compartit",
|
||||||
"shared_link_info_chip_download": "Baixa",
|
"shared_link_info_chip_download": "Download",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
"shared_link_info_chip_upload": "Puja",
|
"shared_link_info_chip_upload": "Puja",
|
||||||
"shared_link_manage_links": "Gestiona els enllaços compartits",
|
"shared_link_manage_links": "Manage Shared links",
|
||||||
"shared_link_public_album": "Àlbum públic",
|
"shared_link_public_album": "Àlbum públic",
|
||||||
"shared_links": "Enllaços compartits",
|
"shared_links": "Enllaços compartits",
|
||||||
"share_done": "Fet",
|
"share_done": "Done",
|
||||||
"shared_with_me": "Compartit amb mi",
|
"shared_with_me": "Compartit amb mi",
|
||||||
"share_invite": "Convida a l'àlbum",
|
"share_invite": "Convida a l'àlbum",
|
||||||
"sharing_page_album": "Àlbums compartits",
|
"sharing_page_album": "Shared albums",
|
||||||
"sharing_page_description": "Crea àlbums compartits per compartir fotos i vídeos amb persones de la teva xarxa.",
|
"sharing_page_description": "Create shared albums to share photos and videos with people in your network.",
|
||||||
"sharing_page_empty_list": "LLISTA BUIDA",
|
"sharing_page_empty_list": "EMPTY LIST",
|
||||||
"sharing_silver_appbar_create_shared_album": "Crea àlbum compartit",
|
"sharing_silver_appbar_create_shared_album": "Crea àlbum compartit",
|
||||||
"sharing_silver_appbar_shared_links": "Enllaços compartits",
|
"sharing_silver_appbar_shared_links": "Shared links",
|
||||||
"sharing_silver_appbar_share_partner": "Comparteix amb un company",
|
"sharing_silver_appbar_share_partner": "Comparteix amb un company",
|
||||||
"start_date": "Data inicial",
|
"start_date": "Data inicial",
|
||||||
"sync": "Sincronitzar",
|
"sync": "Sincronitzar",
|
||||||
"sync_albums": "Sincronitzar àlbums",
|
"sync_albums": "Sincronitzar àlbums",
|
||||||
"sync_albums_manual_subtitle": "Sincronitza tots els vídeos i fotos penjats amb els àlbums de còpia de seguretat seleccionats",
|
"sync_albums_manual_subtitle": "Sincronitza tots els vídeos i fotos penjats amb els àlbums de còpia de seguretat seleccionats",
|
||||||
"sync_upload_album_setting_subtitle": "Creeu i pugeu les seves fotos i vídeos als àlbums seleccionats a Immich",
|
"sync_upload_album_setting_subtitle": "Creeu i pugeu les seves fotos i vídeos als àlbums seleccionats a Immich",
|
||||||
"tab_controller_nav_library": "Llibreria",
|
"tab_controller_nav_library": "Library",
|
||||||
"tab_controller_nav_photos": "Fotografies",
|
"tab_controller_nav_photos": "Fotografies",
|
||||||
"tab_controller_nav_search": "Cerca",
|
"tab_controller_nav_search": "Cerca",
|
||||||
"tab_controller_nav_sharing": "Compartint",
|
"tab_controller_nav_sharing": "Compartint",
|
||||||
"theme_setting_asset_list_storage_indicator_title": "Mostra l'indicador d'emmagatzematge als títols dels elements",
|
"theme_setting_asset_list_storage_indicator_title": "Show storage indicator on asset tiles",
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "Nombre d'elements per fila ({})",
|
"theme_setting_asset_list_tiles_per_row_title": "Number of assets per row ({})",
|
||||||
"theme_setting_colorful_interface_subtitle": "Apliqueu color primari a les superfícies de fons.",
|
"theme_setting_colorful_interface_subtitle": "Apliqueu color primari a les superfícies de fons.",
|
||||||
"theme_setting_colorful_interface_title": "Interfície colorida",
|
"theme_setting_colorful_interface_title": "Interfície colorida",
|
||||||
"theme_setting_dark_mode_switch": "Tema fosc",
|
"theme_setting_dark_mode_switch": "Dark mode",
|
||||||
"theme_setting_image_viewer_quality_subtitle": "Ajusta la qualitat del visor de detalls d'imatges",
|
"theme_setting_image_viewer_quality_subtitle": "Adjust the quality of the detail image viewer",
|
||||||
"theme_setting_image_viewer_quality_title": "Qualitat del visor d'imatges",
|
"theme_setting_image_viewer_quality_title": "Image viewer quality",
|
||||||
"theme_setting_primary_color_subtitle": "Trieu un color per a les accions i els accents principals.",
|
"theme_setting_primary_color_subtitle": "Trieu un color per a les accions i els accents principals.",
|
||||||
"theme_setting_primary_color_title": "Color primari",
|
"theme_setting_primary_color_title": "Color primari",
|
||||||
"theme_setting_system_primary_color_title": "Utilitza color de sistema",
|
"theme_setting_system_primary_color_title": "Utilitza color de sistema",
|
||||||
"theme_setting_system_theme_switch": "Automàtic (Segueix la configuració del sistema)",
|
"theme_setting_system_theme_switch": "Automatic (Follow system setting)",
|
||||||
"theme_setting_theme_subtitle": "Trieu la configuració del tema de l'aplicació",
|
"theme_setting_theme_subtitle": "Choose the app's theme setting",
|
||||||
"theme_setting_theme_title": "Tema",
|
"theme_setting_theme_title": "Theme",
|
||||||
"theme_setting_three_stage_loading_subtitle": "La càrrega en tres etapes podria augmentar el rendiment de càrrega, però causa un consum de xarxa significativament més alt",
|
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
|
||||||
"theme_setting_three_stage_loading_title": "Activa la càrrega en tres etapes",
|
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
|
||||||
"translated_text_options": "Opcions",
|
"translated_text_options": "Options",
|
||||||
"trash": "Paperera",
|
"trash": "Paperera",
|
||||||
"trash_emptied": "Paperera buidada",
|
"trash_emptied": "Paperera buidada",
|
||||||
"trash_page_delete": "Elimina",
|
"trash_page_delete": "Delete",
|
||||||
"trash_page_delete_all": "Eliminar-ho tot",
|
"trash_page_delete_all": "Delete All",
|
||||||
"trash_page_empty_trash_btn": "Buida la paperera",
|
"trash_page_empty_trash_btn": "Empty trash",
|
||||||
"trash_page_empty_trash_dialog_content": "Segur que voleu eliminar els elements? Aquests elements seran eliminats permanentment de Immich",
|
"trash_page_empty_trash_dialog_content": "Do you want to empty your trashed assets? These items will be permanently removed from Immich",
|
||||||
"trash_page_empty_trash_dialog_ok": "Sí",
|
"trash_page_empty_trash_dialog_ok": "Ok",
|
||||||
"trash_page_info": "Els elements que s'enviïn a la paperera s'eliminaran permanentment després de {} dies",
|
"trash_page_info": "Trashed items will be permanently deleted after {} days",
|
||||||
"trash_page_no_assets": "No hi ha elements a la paperera",
|
"trash_page_no_assets": "No trashed assets",
|
||||||
"trash_page_restore": "Restaura",
|
"trash_page_restore": "Restore",
|
||||||
"trash_page_restore_all": "Restaura-ho tot",
|
"trash_page_restore_all": "Restore All",
|
||||||
"trash_page_select_assets_btn": "Selecciona elements",
|
"trash_page_select_assets_btn": "Select assets",
|
||||||
"trash_page_select_btn": "Selecciona",
|
"trash_page_select_btn": "Select",
|
||||||
"trash_page_title": "Paperera ({})",
|
"trash_page_title": "Trash ({})",
|
||||||
"upload": "Puja",
|
"upload": "Puja",
|
||||||
"upload_dialog_cancel": "Cancel·la",
|
"upload_dialog_cancel": "Cancel",
|
||||||
"upload_dialog_info": "Vols fer còpia de seguretat dels elements seleccionats al servidor?",
|
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
|
||||||
"upload_dialog_ok": "Puja",
|
"upload_dialog_ok": "Upload",
|
||||||
"upload_dialog_title": "Puja elements",
|
"upload_dialog_title": "Upload Asset",
|
||||||
"uploading": "Pujant",
|
"uploading": "Pujant",
|
||||||
"upload_to_immich": "Puja a Immich ({})",
|
"upload_to_immich": "Puja a Immich ({})",
|
||||||
"use_current_connection": "utilitzar la connexió actual",
|
"use_current_connection": "utilitzar la connexió actual",
|
||||||
"validate_endpoint_error": "Per favor introdueix un URL vàlid",
|
"validate_endpoint_error": "Per favor introdueix un URL vàlid",
|
||||||
"version_announcement_overlay_ack": "D'acord",
|
"version_announcement_overlay_ack": "Acknowledge",
|
||||||
"version_announcement_overlay_release_notes": "notes de llançament",
|
"version_announcement_overlay_release_notes": "release notes",
|
||||||
"version_announcement_overlay_text_1": "Hola amic, hi ha una nova versió d'",
|
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
|
||||||
"version_announcement_overlay_text_2": "si us plau, pren-te una estona per visitar les ",
|
"version_announcement_overlay_text_2": "please take your time to visit the ",
|
||||||
"version_announcement_overlay_text_3": " i assegura't que la teva configuració de docker-compose i .env estiguin actualitzades per evitar qualsevol error de configuració, especialment si utilitzes WatchTower o qualsevol mecanisme que gestioni l'actualització automàtica de l'aplicació del servidor.",
|
"version_announcement_overlay_text_3": " and ensure your docker-compose and .env setup is up-to-date to prevent any misconfigurations, especially if you use WatchTower or any mechanism that handles updating your server application automatically.",
|
||||||
"version_announcement_overlay_title": "Nova versió del servidor disponible \uD83C\uDF89",
|
"version_announcement_overlay_title": "New Server Version Available \uD83C\uDF89",
|
||||||
"videos": "Vídeos",
|
"videos": "Vídeos",
|
||||||
"viewer_remove_from_stack": "Elimina de la pila",
|
"viewer_remove_from_stack": "Remove from Stack",
|
||||||
"viewer_stack_use_as_main_asset": "Fes servir com a element principal",
|
"viewer_stack_use_as_main_asset": "Use as Main Asset",
|
||||||
"viewer_unstack": "Desapila",
|
"viewer_unstack": "Un-Stack",
|
||||||
"wifi_name": "Nom WiFi",
|
"wifi_name": "Nom WiFi",
|
||||||
"your_wifi_name": "El teu nom WiFi"
|
"your_wifi_name": "El teu nom WiFi"
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "Upravit datum a čas",
|
"control_bottom_app_bar_edit_time": "Upravit datum a čas",
|
||||||
"control_bottom_app_bar_favorite": "Oblíbené",
|
"control_bottom_app_bar_favorite": "Oblíbené",
|
||||||
"control_bottom_app_bar_share": "Sdílet",
|
"control_bottom_app_bar_share": "Sdílet",
|
||||||
"control_bottom_app_bar_share_link": "Sdílet odkaz",
|
|
||||||
"control_bottom_app_bar_share_to": "Sdílet v",
|
"control_bottom_app_bar_share_to": "Sdílet v",
|
||||||
"control_bottom_app_bar_stack": "Zásobník",
|
"control_bottom_app_bar_stack": "Zásobník",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Přesunout do koše",
|
"control_bottom_app_bar_trash_from_immich": "Přesunout do koše",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "Časové pásmo",
|
"edit_date_time_dialog_timezone": "Časové pásmo",
|
||||||
"edit_image_title": "Upravit",
|
"edit_image_title": "Upravit",
|
||||||
"edit_location_dialog_title": "Poloha",
|
"edit_location_dialog_title": "Poloha",
|
||||||
"empty_folder": "Tato složka je prázdná",
|
|
||||||
"end_date": "Konečné datum",
|
"end_date": "Konečné datum",
|
||||||
"enqueued": "Ve frontě",
|
"enqueued": "Ve frontě",
|
||||||
"enter_wifi_name": "Zadejte název WiFi",
|
"enter_wifi_name": "Zadejte název WiFi",
|
||||||
@@ -265,10 +263,6 @@
|
|||||||
"exif_bottom_sheet_location_add": "Přidat polohu",
|
"exif_bottom_sheet_location_add": "Přidat polohu",
|
||||||
"exif_bottom_sheet_people": "LIDÉ",
|
"exif_bottom_sheet_people": "LIDÉ",
|
||||||
"exif_bottom_sheet_person_add_person": "Přidat jméno",
|
"exif_bottom_sheet_person_add_person": "Přidat jméno",
|
||||||
"exif_bottom_sheet_person_age": "{} let",
|
|
||||||
"exif_bottom_sheet_person_age_months": "{} měsíců",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "1 rok a {} měsíců",
|
|
||||||
"exif_bottom_sheet_person_age_years": "{} let",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "Zpracovávám",
|
"experimental_settings_new_asset_list_subtitle": "Zpracovávám",
|
||||||
"experimental_settings_new_asset_list_title": "Povolení experimentální mřížky fotografií",
|
"experimental_settings_new_asset_list_title": "Povolení experimentální mřížky fotografií",
|
||||||
"experimental_settings_subtitle": "Používejte na vlastní riziko!",
|
"experimental_settings_subtitle": "Používejte na vlastní riziko!",
|
||||||
@@ -276,16 +270,11 @@
|
|||||||
"external_network": "Externí síť",
|
"external_network": "Externí síť",
|
||||||
"external_network_sheet_info": "Pokud nejste v preferované síti WiFi, aplikace se připojí k serveru prostřednictvím první z níže uvedených adres URL, které může dosáhnout, počínaje shora dolů",
|
"external_network_sheet_info": "Pokud nejste v preferované síti WiFi, aplikace se připojí k serveru prostřednictvím první z níže uvedených adres URL, které může dosáhnout, počínaje shora dolů",
|
||||||
"failed": "Selhalo",
|
"failed": "Selhalo",
|
||||||
"failed_to_load_assets": "Nepodařilo se načíst položky",
|
|
||||||
"failed_to_load_folder": "Nepodařilo se načíst složku",
|
|
||||||
"favorites": "Oblíbené",
|
"favorites": "Oblíbené",
|
||||||
"favorites_page_no_favorites": "Nebyla nalezena žádná oblíbená média",
|
"favorites_page_no_favorites": "Nebyla nalezena žádná oblíbená média",
|
||||||
"favorites_page_title": "Oblíbené",
|
"favorites_page_title": "Oblíbené",
|
||||||
"filename_search": "Název nebo přípona souboru",
|
"filename_search": "Název nebo přípona souboru",
|
||||||
"filter": "Filtr",
|
"filter": "Filtr",
|
||||||
"folder": "Složka",
|
|
||||||
"folder_not_found": "Složka nebyla nalezena",
|
|
||||||
"folders": "Složky",
|
|
||||||
"get_wifiname_error": "Nepodařilo se získat název Wi-Fi. Zkontrolujte, zda jste udělili potřebná oprávnění a zda jste připojeni k Wi-Fi síti",
|
"get_wifiname_error": "Nepodařilo se získat název Wi-Fi. Zkontrolujte, zda jste udělili potřebná oprávnění a zda jste připojeni k Wi-Fi síti",
|
||||||
"grant_permission": "Udělit oprávnění",
|
"grant_permission": "Udělit oprávnění",
|
||||||
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
|
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "Rediger tid og dato",
|
"control_bottom_app_bar_edit_time": "Rediger tid og dato",
|
||||||
"control_bottom_app_bar_favorite": "Favorit",
|
"control_bottom_app_bar_favorite": "Favorit",
|
||||||
"control_bottom_app_bar_share": "Del",
|
"control_bottom_app_bar_share": "Del",
|
||||||
"control_bottom_app_bar_share_link": "Share Link",
|
|
||||||
"control_bottom_app_bar_share_to": "Del til",
|
"control_bottom_app_bar_share_to": "Del til",
|
||||||
"control_bottom_app_bar_stack": "Stak",
|
"control_bottom_app_bar_stack": "Stak",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Flyt til papirkurv",
|
"control_bottom_app_bar_trash_from_immich": "Flyt til papirkurv",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "Tidszone",
|
"edit_date_time_dialog_timezone": "Tidszone",
|
||||||
"edit_image_title": "Rediger",
|
"edit_image_title": "Rediger",
|
||||||
"edit_location_dialog_title": "Placering",
|
"edit_location_dialog_title": "Placering",
|
||||||
"empty_folder": "This folder is empty",
|
|
||||||
"end_date": "End date",
|
"end_date": "End date",
|
||||||
"enqueued": "Enqueued",
|
"enqueued": "Enqueued",
|
||||||
"enter_wifi_name": "Indtast WiFi-navn",
|
"enter_wifi_name": "Indtast WiFi-navn",
|
||||||
@@ -265,10 +263,6 @@
|
|||||||
"exif_bottom_sheet_location_add": "Tilføj en placering",
|
"exif_bottom_sheet_location_add": "Tilføj en placering",
|
||||||
"exif_bottom_sheet_people": "PERSONER",
|
"exif_bottom_sheet_people": "PERSONER",
|
||||||
"exif_bottom_sheet_person_add_person": "Tilføj navn",
|
"exif_bottom_sheet_person_add_person": "Tilføj navn",
|
||||||
"exif_bottom_sheet_person_age": "Age {}",
|
|
||||||
"exif_bottom_sheet_person_age_months": "Age {} months",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "Age 1 year, {} months",
|
|
||||||
"exif_bottom_sheet_person_age_years": "Age {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "Under udarbejdelse",
|
"experimental_settings_new_asset_list_subtitle": "Under udarbejdelse",
|
||||||
"experimental_settings_new_asset_list_title": "Aktiver eksperimentelt fotogitter",
|
"experimental_settings_new_asset_list_title": "Aktiver eksperimentelt fotogitter",
|
||||||
"experimental_settings_subtitle": "Brug på eget ansvar!",
|
"experimental_settings_subtitle": "Brug på eget ansvar!",
|
||||||
@@ -276,16 +270,11 @@
|
|||||||
"external_network": "Eksternt netværk",
|
"external_network": "Eksternt netværk",
|
||||||
"external_network_sheet_info": "Nå der er ikke er forbundet til det foretrukne WiFi-netværk, vil appen forbinde til den første URL, den kan forbinde til, på listen nedenfor. Startende med i toppen",
|
"external_network_sheet_info": "Nå der er ikke er forbundet til det foretrukne WiFi-netværk, vil appen forbinde til den første URL, den kan forbinde til, på listen nedenfor. Startende med i toppen",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"failed_to_load_assets": "Failed to load assets",
|
|
||||||
"failed_to_load_folder": "Failed to load folder",
|
|
||||||
"favorites": "Favoritter",
|
"favorites": "Favoritter",
|
||||||
"favorites_page_no_favorites": "Ingen favoritter blev fundet",
|
"favorites_page_no_favorites": "Ingen favoritter blev fundet",
|
||||||
"favorites_page_title": "Favoritter",
|
"favorites_page_title": "Favoritter",
|
||||||
"filename_search": "File name or extension",
|
"filename_search": "File name or extension",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"folder": "Folder",
|
|
||||||
"folder_not_found": "Folder not found",
|
|
||||||
"folders": "Folders",
|
|
||||||
"get_wifiname_error": "Kunne ikke hente Wi-Fi-navn. Sørg for, at du har givet de nødvendige tilladelser og er forbundet til et Wi-Fi-netværk",
|
"get_wifiname_error": "Kunne ikke hente Wi-Fi-navn. Sørg for, at du har givet de nødvendige tilladelser og er forbundet til et Wi-Fi-netværk",
|
||||||
"grant_permission": "Giv tilladelse",
|
"grant_permission": "Giv tilladelse",
|
||||||
"haptic_feedback_switch": "Slå haptisk feedback til",
|
"haptic_feedback_switch": "Slå haptisk feedback til",
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "Datum und Uhrzeit bearbeiten",
|
"control_bottom_app_bar_edit_time": "Datum und Uhrzeit bearbeiten",
|
||||||
"control_bottom_app_bar_favorite": "Favorit",
|
"control_bottom_app_bar_favorite": "Favorit",
|
||||||
"control_bottom_app_bar_share": "Teilen",
|
"control_bottom_app_bar_share": "Teilen",
|
||||||
"control_bottom_app_bar_share_link": "Share Link",
|
|
||||||
"control_bottom_app_bar_share_to": "Teilen mit",
|
"control_bottom_app_bar_share_to": "Teilen mit",
|
||||||
"control_bottom_app_bar_stack": "Stapeln",
|
"control_bottom_app_bar_stack": "Stapeln",
|
||||||
"control_bottom_app_bar_trash_from_immich": "in den Papierkorb schieben",
|
"control_bottom_app_bar_trash_from_immich": "in den Papierkorb schieben",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "Zeitzone",
|
"edit_date_time_dialog_timezone": "Zeitzone",
|
||||||
"edit_image_title": "Bearbeiten",
|
"edit_image_title": "Bearbeiten",
|
||||||
"edit_location_dialog_title": "Ort bearbeiten",
|
"edit_location_dialog_title": "Ort bearbeiten",
|
||||||
"empty_folder": "Dieser Ordner ist leer",
|
|
||||||
"end_date": "Enddatum",
|
"end_date": "Enddatum",
|
||||||
"enqueued": "Eingereiht",
|
"enqueued": "Eingereiht",
|
||||||
"enter_wifi_name": "WLAN-Name eingeben",
|
"enter_wifi_name": "WLAN-Name eingeben",
|
||||||
@@ -265,10 +263,6 @@
|
|||||||
"exif_bottom_sheet_location_add": "Aufnahmeort hinzufügen",
|
"exif_bottom_sheet_location_add": "Aufnahmeort hinzufügen",
|
||||||
"exif_bottom_sheet_people": "PERSONEN",
|
"exif_bottom_sheet_people": "PERSONEN",
|
||||||
"exif_bottom_sheet_person_add_person": "Namen hinzufügen",
|
"exif_bottom_sheet_person_add_person": "Namen hinzufügen",
|
||||||
"exif_bottom_sheet_person_age": "Alter {}",
|
|
||||||
"exif_bottom_sheet_person_age_months": "Age {} months",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "Age 1 year, {} months",
|
|
||||||
"exif_bottom_sheet_person_age_years": "Age {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "In Arbeit",
|
"experimental_settings_new_asset_list_subtitle": "In Arbeit",
|
||||||
"experimental_settings_new_asset_list_title": "Experimentelles Fotogitter aktivieren",
|
"experimental_settings_new_asset_list_title": "Experimentelles Fotogitter aktivieren",
|
||||||
"experimental_settings_subtitle": "Benutzung auf eigene Gefahr!",
|
"experimental_settings_subtitle": "Benutzung auf eigene Gefahr!",
|
||||||
@@ -276,16 +270,11 @@
|
|||||||
"external_network": "Externes Netzwerk",
|
"external_network": "Externes Netzwerk",
|
||||||
"external_network_sheet_info": "Wenn sich die App nicht im bevorzugten WLAN-Netzwerk befindet, verbindet sie sich mit dem Server über die erste der folgenden URLs, die sie erreichen kann (von oben nach unten)",
|
"external_network_sheet_info": "Wenn sich die App nicht im bevorzugten WLAN-Netzwerk befindet, verbindet sie sich mit dem Server über die erste der folgenden URLs, die sie erreichen kann (von oben nach unten)",
|
||||||
"failed": "Fehlgeschlagen",
|
"failed": "Fehlgeschlagen",
|
||||||
"failed_to_load_assets": "Fehler beim Laden von Daten",
|
|
||||||
"failed_to_load_folder": "Fehler beim Laden des Ordners",
|
|
||||||
"favorites": "Favoriten",
|
"favorites": "Favoriten",
|
||||||
"favorites_page_no_favorites": "Keine favorisierten Inhalte gefunden",
|
"favorites_page_no_favorites": "Keine favorisierten Inhalte gefunden",
|
||||||
"favorites_page_title": "Favoriten",
|
"favorites_page_title": "Favoriten",
|
||||||
"filename_search": "Dateiname oder Dateityp",
|
"filename_search": "Dateiname oder Dateityp",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"folder": "Ordner",
|
|
||||||
"folder_not_found": "Ordner nicht gefunden",
|
|
||||||
"folders": "Ordner",
|
|
||||||
"get_wifiname_error": "WLAN-Name konnte nicht ermittelt werden. Vergewissere dich, dass die erforderlichen Berechtigungen erteilt wurden und du mit einem WLAN-Netzwerk verbunden bist.\n",
|
"get_wifiname_error": "WLAN-Name konnte nicht ermittelt werden. Vergewissere dich, dass die erforderlichen Berechtigungen erteilt wurden und du mit einem WLAN-Netzwerk verbunden bist.\n",
|
||||||
"grant_permission": "Erlaubnis gewähren",
|
"grant_permission": "Erlaubnis gewähren",
|
||||||
"haptic_feedback_switch": "Haptisches Feedback aktivieren",
|
"haptic_feedback_switch": "Haptisches Feedback aktivieren",
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "Επεξεργασία Ημερομηνίας & Ώρας",
|
"control_bottom_app_bar_edit_time": "Επεξεργασία Ημερομηνίας & Ώρας",
|
||||||
"control_bottom_app_bar_favorite": "Προσθήκη στα αγαπημένα",
|
"control_bottom_app_bar_favorite": "Προσθήκη στα αγαπημένα",
|
||||||
"control_bottom_app_bar_share": "Κοινοποίηση",
|
"control_bottom_app_bar_share": "Κοινοποίηση",
|
||||||
"control_bottom_app_bar_share_link": "Share Link",
|
|
||||||
"control_bottom_app_bar_share_to": "Κοινοποίηση Σε",
|
"control_bottom_app_bar_share_to": "Κοινοποίηση Σε",
|
||||||
"control_bottom_app_bar_stack": "Στοίβα",
|
"control_bottom_app_bar_stack": "Στοίβα",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Μετακίνηση στα Απορρίμματα",
|
"control_bottom_app_bar_trash_from_immich": "Μετακίνηση στα Απορρίμματα",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "Ζώνη ώρας",
|
"edit_date_time_dialog_timezone": "Ζώνη ώρας",
|
||||||
"edit_image_title": "Επεξεργασία",
|
"edit_image_title": "Επεξεργασία",
|
||||||
"edit_location_dialog_title": "Τοποθεσία",
|
"edit_location_dialog_title": "Τοποθεσία",
|
||||||
"empty_folder": "This folder is empty",
|
|
||||||
"end_date": "End date",
|
"end_date": "End date",
|
||||||
"enqueued": "Enqueued",
|
"enqueued": "Enqueued",
|
||||||
"enter_wifi_name": "Enter WiFi name",
|
"enter_wifi_name": "Enter WiFi name",
|
||||||
@@ -265,10 +263,6 @@
|
|||||||
"exif_bottom_sheet_location_add": "Προσθήκη τοποθεσίας",
|
"exif_bottom_sheet_location_add": "Προσθήκη τοποθεσίας",
|
||||||
"exif_bottom_sheet_people": "ΑΝΘΡΩΠΟΙ",
|
"exif_bottom_sheet_people": "ΑΝΘΡΩΠΟΙ",
|
||||||
"exif_bottom_sheet_person_add_person": "Προσθήκη ονόματος",
|
"exif_bottom_sheet_person_add_person": "Προσθήκη ονόματος",
|
||||||
"exif_bottom_sheet_person_age": "Age {}",
|
|
||||||
"exif_bottom_sheet_person_age_months": "Age {} months",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "Age 1 year, {} months",
|
|
||||||
"exif_bottom_sheet_person_age_years": "Age {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "Σε εξέλιξη",
|
"experimental_settings_new_asset_list_subtitle": "Σε εξέλιξη",
|
||||||
"experimental_settings_new_asset_list_title": "Ενεργοποίηση πειραματικού πλέγματος φωτογραφιών",
|
"experimental_settings_new_asset_list_title": "Ενεργοποίηση πειραματικού πλέγματος φωτογραφιών",
|
||||||
"experimental_settings_subtitle": "Χρησιμοποιείτε με δική σας ευθύνη!",
|
"experimental_settings_subtitle": "Χρησιμοποιείτε με δική σας ευθύνη!",
|
||||||
@@ -276,16 +270,11 @@
|
|||||||
"external_network": "External network",
|
"external_network": "External network",
|
||||||
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"failed_to_load_assets": "Failed to load assets",
|
|
||||||
"failed_to_load_folder": "Failed to load folder",
|
|
||||||
"favorites": "Αγαπημένα",
|
"favorites": "Αγαπημένα",
|
||||||
"favorites_page_no_favorites": "Δεν βρέθηκαν αγαπημένα στοιχεία",
|
"favorites_page_no_favorites": "Δεν βρέθηκαν αγαπημένα στοιχεία",
|
||||||
"favorites_page_title": "Αγαπημένα",
|
"favorites_page_title": "Αγαπημένα",
|
||||||
"filename_search": "Όνομα αρχείου ή επέκταση",
|
"filename_search": "Όνομα αρχείου ή επέκταση",
|
||||||
"filter": "Φίλτρο",
|
"filter": "Φίλτρο",
|
||||||
"folder": "Folder",
|
|
||||||
"folder_not_found": "Folder not found",
|
|
||||||
"folders": "Folders",
|
|
||||||
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
||||||
"grant_permission": "Grant permission",
|
"grant_permission": "Grant permission",
|
||||||
"haptic_feedback_switch": "Ενεργοποίηση απτικής ανάδρασης",
|
"haptic_feedback_switch": "Ενεργοποίηση απτικής ανάδρασης",
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
||||||
"control_bottom_app_bar_favorite": "Favorite",
|
"control_bottom_app_bar_favorite": "Favorite",
|
||||||
"control_bottom_app_bar_share": "Share",
|
"control_bottom_app_bar_share": "Share",
|
||||||
"control_bottom_app_bar_share_link": "Share Link",
|
|
||||||
"control_bottom_app_bar_share_to": "Share To",
|
"control_bottom_app_bar_share_to": "Share To",
|
||||||
"control_bottom_app_bar_stack": "Stack",
|
"control_bottom_app_bar_stack": "Stack",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
||||||
@@ -266,9 +265,6 @@
|
|||||||
"exif_bottom_sheet_people": "PEOPLE",
|
"exif_bottom_sheet_people": "PEOPLE",
|
||||||
"exif_bottom_sheet_person_add_person": "Add name",
|
"exif_bottom_sheet_person_add_person": "Add name",
|
||||||
"exif_bottom_sheet_person_age": "Age {}",
|
"exif_bottom_sheet_person_age": "Age {}",
|
||||||
"exif_bottom_sheet_person_age_months": "Age {} months",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "Age 1 year, {} months",
|
|
||||||
"exif_bottom_sheet_person_age_years": "Age {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
"experimental_settings_new_asset_list_subtitle": "Work in progress",
|
||||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||||
"experimental_settings_subtitle": "Use at your own risk!",
|
"experimental_settings_subtitle": "Use at your own risk!",
|
||||||
@@ -276,16 +272,16 @@
|
|||||||
"external_network": "External network",
|
"external_network": "External network",
|
||||||
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"failed_to_load_assets": "Failed to load assets",
|
|
||||||
"failed_to_load_folder": "Failed to load folder",
|
|
||||||
"favorites": "Favorites",
|
"favorites": "Favorites",
|
||||||
"favorites_page_no_favorites": "No favorite assets found",
|
"favorites_page_no_favorites": "No favorite assets found",
|
||||||
"favorites_page_title": "Favorites",
|
"favorites_page_title": "Favorites",
|
||||||
"filename_search": "File name or extension",
|
"filename_search": "File name or extension",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"folder": "Folder",
|
|
||||||
"folder_not_found": "Folder not found",
|
|
||||||
"folders": "Folders",
|
"folders": "Folders",
|
||||||
|
"folder": "Folder",
|
||||||
|
"failed_to_load_folder": "Failed to load folder",
|
||||||
|
"failed_to_load_assets": "Failed to load assets",
|
||||||
|
"folder_not_found": "Folder not found",
|
||||||
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
||||||
"grant_permission": "Grant permission",
|
"grant_permission": "Grant permission",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
@@ -689,4 +685,4 @@
|
|||||||
"viewer_unstack": "Un-Stack",
|
"viewer_unstack": "Un-Stack",
|
||||||
"wifi_name": "WiFi Name",
|
"wifi_name": "WiFi Name",
|
||||||
"your_wifi_name": "Your WiFi name"
|
"your_wifi_name": "Your WiFi name"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "Editar fecha y hora",
|
"control_bottom_app_bar_edit_time": "Editar fecha y hora",
|
||||||
"control_bottom_app_bar_favorite": "Favorito",
|
"control_bottom_app_bar_favorite": "Favorito",
|
||||||
"control_bottom_app_bar_share": "Compartir",
|
"control_bottom_app_bar_share": "Compartir",
|
||||||
"control_bottom_app_bar_share_link": "Share Link",
|
|
||||||
"control_bottom_app_bar_share_to": "Enviar",
|
"control_bottom_app_bar_share_to": "Enviar",
|
||||||
"control_bottom_app_bar_stack": "Apilar",
|
"control_bottom_app_bar_stack": "Apilar",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Mover a la papelera",
|
"control_bottom_app_bar_trash_from_immich": "Mover a la papelera",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "Zona horaria",
|
"edit_date_time_dialog_timezone": "Zona horaria",
|
||||||
"edit_image_title": "Editar",
|
"edit_image_title": "Editar",
|
||||||
"edit_location_dialog_title": "Ubicación",
|
"edit_location_dialog_title": "Ubicación",
|
||||||
"empty_folder": "This folder is empty",
|
|
||||||
"end_date": "End date",
|
"end_date": "End date",
|
||||||
"enqueued": "Enqueued",
|
"enqueued": "Enqueued",
|
||||||
"enter_wifi_name": "Enter WiFi name",
|
"enter_wifi_name": "Enter WiFi name",
|
||||||
@@ -265,10 +263,6 @@
|
|||||||
"exif_bottom_sheet_location_add": "Añadir ubicación",
|
"exif_bottom_sheet_location_add": "Añadir ubicación",
|
||||||
"exif_bottom_sheet_people": "PERSONAS",
|
"exif_bottom_sheet_people": "PERSONAS",
|
||||||
"exif_bottom_sheet_person_add_person": "Añadir nombre",
|
"exif_bottom_sheet_person_add_person": "Añadir nombre",
|
||||||
"exif_bottom_sheet_person_age": "Age {}",
|
|
||||||
"exif_bottom_sheet_person_age_months": "Age {} months",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "Age 1 year, {} months",
|
|
||||||
"exif_bottom_sheet_person_age_years": "Age {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
||||||
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
||||||
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
||||||
@@ -276,16 +270,11 @@
|
|||||||
"external_network": "External network",
|
"external_network": "External network",
|
||||||
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"failed_to_load_assets": "Failed to load assets",
|
|
||||||
"failed_to_load_folder": "Failed to load folder",
|
|
||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
"favorites_page_no_favorites": "No se encontraron elementos marcados como favoritos",
|
"favorites_page_no_favorites": "No se encontraron elementos marcados como favoritos",
|
||||||
"favorites_page_title": "Favoritos",
|
"favorites_page_title": "Favoritos",
|
||||||
"filename_search": "Nombre o extensión",
|
"filename_search": "Nombre o extensión",
|
||||||
"filter": "Filtrar",
|
"filter": "Filtrar",
|
||||||
"folder": "Folder",
|
|
||||||
"folder_not_found": "Folder not found",
|
|
||||||
"folders": "Folders",
|
|
||||||
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
||||||
"grant_permission": "Grant permission",
|
"grant_permission": "Grant permission",
|
||||||
"haptic_feedback_switch": "Activar respuesta háptica",
|
"haptic_feedback_switch": "Activar respuesta háptica",
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
"control_bottom_app_bar_edit_time": "Edit Date & Time",
|
||||||
"control_bottom_app_bar_favorite": "Favorito",
|
"control_bottom_app_bar_favorite": "Favorito",
|
||||||
"control_bottom_app_bar_share": "Compartir",
|
"control_bottom_app_bar_share": "Compartir",
|
||||||
"control_bottom_app_bar_share_link": "Share Link",
|
|
||||||
"control_bottom_app_bar_share_to": "Enviar",
|
"control_bottom_app_bar_share_to": "Enviar",
|
||||||
"control_bottom_app_bar_stack": "Apilar",
|
"control_bottom_app_bar_stack": "Apilar",
|
||||||
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
"control_bottom_app_bar_trash_from_immich": "Move to Trash",
|
||||||
@@ -253,7 +252,6 @@
|
|||||||
"edit_date_time_dialog_timezone": "Timezone",
|
"edit_date_time_dialog_timezone": "Timezone",
|
||||||
"edit_image_title": "Edit",
|
"edit_image_title": "Edit",
|
||||||
"edit_location_dialog_title": "Location",
|
"edit_location_dialog_title": "Location",
|
||||||
"empty_folder": "This folder is empty",
|
|
||||||
"end_date": "End date",
|
"end_date": "End date",
|
||||||
"enqueued": "Enqueued",
|
"enqueued": "Enqueued",
|
||||||
"enter_wifi_name": "Enter WiFi name",
|
"enter_wifi_name": "Enter WiFi name",
|
||||||
@@ -265,10 +263,6 @@
|
|||||||
"exif_bottom_sheet_location_add": "Add a location",
|
"exif_bottom_sheet_location_add": "Add a location",
|
||||||
"exif_bottom_sheet_people": "PERSONAS",
|
"exif_bottom_sheet_people": "PERSONAS",
|
||||||
"exif_bottom_sheet_person_add_person": "Add name",
|
"exif_bottom_sheet_person_add_person": "Add name",
|
||||||
"exif_bottom_sheet_person_age": "Age {}",
|
|
||||||
"exif_bottom_sheet_person_age_months": "Age {} months",
|
|
||||||
"exif_bottom_sheet_person_age_year_months": "Age 1 year, {} months",
|
|
||||||
"exif_bottom_sheet_person_age_years": "Age {}",
|
|
||||||
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
"experimental_settings_new_asset_list_subtitle": "Trabajo en progreso",
|
||||||
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
"experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental",
|
||||||
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
"experimental_settings_subtitle": "Úsalo bajo tu responsabilidad",
|
||||||
@@ -276,16 +270,11 @@
|
|||||||
"external_network": "External network",
|
"external_network": "External network",
|
||||||
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"failed_to_load_assets": "Failed to load assets",
|
|
||||||
"failed_to_load_folder": "Failed to load folder",
|
|
||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
"favorites_page_no_favorites": "No se encontraron recursos marcados como favoritos",
|
"favorites_page_no_favorites": "No se encontraron recursos marcados como favoritos",
|
||||||
"favorites_page_title": "Favoritos",
|
"favorites_page_title": "Favoritos",
|
||||||
"filename_search": "File name or extension",
|
"filename_search": "File name or extension",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"folder": "Folder",
|
|
||||||
"folder_not_found": "Folder not found",
|
|
||||||
"folders": "Folders",
|
|
||||||
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
"get_wifiname_error": "Could not get Wi-Fi name. Make sure you have granted the necessary permissions and are connected to a Wi-Fi network",
|
||||||
"grant_permission": "Grant permission",
|
"grant_permission": "Grant permission",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user