Compare commits

...

22 Commits

Author SHA1 Message Date
Alex The Bot
08f66c2ae5 Version v1.91.3 2023-12-17 16:57:16 +00:00
Mert
4f38a283b4 fix(server): stricter dim size check for pgvecto.rs migration (#5767)
* stricter dim size check

* remove unused import

* added null check
2023-12-17 10:55:35 -06:00
Jon Howell
00771899da fix(docs): remove inline dev inquiries (#5733)
* fix(docs): correct link; remove inline dev inquiries

* unfix relative path
2023-12-17 10:46:29 -05:00
Mert
09402eb6d0 fix(ml): disable core dumps (#5770)
* update dockerfile

* remove sysctl line
2023-12-16 20:30:29 -06:00
Jon Howell
d9b5adf0f7 fix(docs): remove spurious hyphen in docker compose cmd (#5771)
The command example is correct, but the text just before it still references the old docker-compose command.
2023-12-16 19:49:14 -05:00
Alex The Bot
a15c799ba3 Version v1.91.2 2023-12-16 23:19:58 +00:00
Daniel Dietzler
bda9fd9dfe fix(web): settings switch state when disabled, simplify classes (#5762) 2023-12-16 17:17:38 -06:00
Daniel Dietzler
19754d4b21 fix clip concurrency not being persisted after queue renaming (#5769) 2023-12-16 22:32:15 +00:00
Alex
62347edf43 chore(web): improve map pin (#5761)
* chore(web): improve map pin

* zoom level
2023-12-16 20:21:13 +00:00
Daniel Dietzler
67f020380f disable version check settings when config file is set (#5756) 2023-12-16 20:39:17 +01:00
Alex The Bot
0aae9696f6 Version v1.91.1 2023-12-16 17:26:51 +00:00
martin
2f95cb89c1 fix(web): use env for web folder path (#5753)
* fix: use env for web folder path

* feat: use constant

* fix: use join

* update docs

* fix: icon
2023-12-16 11:15:30 -06:00
Mert
cb1201e690 chore(web): update job dashboard (#5745)
* rename clip encoding to smart search

* update job subtitles

* update api

* update smart search job title and subtitle

* fix `getJobName`

* change smart search icon

* formatting

* wording

* update reference to clip

* formatting

* update reference to Encode CLIP
2023-12-16 10:50:46 -06:00
Daniel Dietzler
a2deba4734 fix(web): never ungroup map markers. ever. (#5730) 2023-12-16 10:49:58 -06:00
Alex
ae2608e31d fix(web): cannot save exclusion pattern (#5738)
* fix(web): Ccannot save exclusive pattern

* remove console log
2023-12-16 10:48:49 -06:00
Mert
d8756f3897 fix(web): searching places (#5746) 2023-12-16 10:48:27 -06:00
Mohamed BOUSSAID
7839be3b49 Adding the new models to the whitelist (#5736) 2023-12-15 22:45:14 +00:00
Jason Rasmussen
94e11d52dc docs: fix redirects for cloudflare (#5734) 2023-12-15 15:20:50 -06:00
Jon Howell
05a1283500 fix(docs): Add title for External Library guide (#5732) 2023-12-15 14:38:14 -05:00
Alex
f8519d60c7 chore: post release tasks 2023-12-15 13:25:37 -06:00
Jon Howell
899c71f297 docs: add a walk-through guide for External Libraries (#5594)
* Add a walk-through guide for External Libraries

* Apply prettier to markdown

* Add screenshots for GUI elements

* fix format
2023-12-15 12:46:43 -06:00
martin
2aa5f55cbf docs: update milestone page (#5663) 2023-12-15 09:50:13 -06:00
81 changed files with 330 additions and 210 deletions

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -355,12 +355,6 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'backgroundTask': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'clipEncoding': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -403,6 +397,12 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'sidecar': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'smartSearch': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -2017,7 +2017,7 @@ export const JobName = {
VideoConversion: 'videoConversion',
ObjectTagging: 'objectTagging',
RecognizeFaces: 'recognizeFaces',
ClipEncoding: 'clipEncoding',
SmartSearch: 'smartSearch',
BackgroundTask: 'backgroundTask',
StorageTemplateMigration: 'storageTemplateMigration',
Migration: 'migration',
@@ -3785,12 +3785,6 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'backgroundTask': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'clipEncoding': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
@@ -3833,6 +3827,12 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'sidecar': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'smartSearch': JobSettingsDto;
/**
*
* @type {JobSettingsDto}

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -26,7 +26,7 @@ Immich optionally uses machine learning for several features. However, it can be
### How can I lower Immich's CPU usage?
The initial backup is the most intensive due to the number of jobs running. The most CPU-intensive ones are transcoding and machine learning jobs (Tag Images, Encode CLIP, Recognize Faces), and to a lesser extent thumbnail generation. Here are some ways to lower their CPU usage:
The initial backup is the most intensive due to the number of jobs running. The most CPU-intensive ones are transcoding and machine learning jobs (Tag Images, Smart Search, Recognize Faces), and to a lesser extent thumbnail generation. Here are some ways to lower their CPU usage:
- Lower the job concurrency for these jobs to 1.
- Under Settings > Transcoding Settings > Threads, set the number of threads to a low number like 1 or 2.

View File

@@ -0,0 +1,100 @@
# External Library
This guide walks you through adding an [External Library](../features/libraries#external-libraries).
This guide assumes you are running Immich in Docker and that the files you wish to access are stored
in a directory on the same machine.
# Mount the directory into the containers.
Edit `docker-compose.yml` to add two new mount points under `volumes:`
```
immich-server:
volumes:
- ${EXTERNAL_PATH}:/usr/src/app/external
```
Be sure to add exactly the same line to both `immich-server:` and `immich-microservices:`.
Edit `.env` to define `EXTERNAL_PATH`, substituting in the correct path for your computer:
```
EXTERNAL_PATH=<your-path-here>
```
On my computer, for example, I use this path:
```
EXTERNAL_PATH=/home/tenino/photos
```
Restart Immich.
```
docker compose down
docker compose up -d
```
# Set the External Path
In the Immich web UI:
- click the **Administration** link in the upper right corner.
<img src={require('./img/administration-link.png').default} width="50%" title="Administration link" />
- Select the **Users** tab
<img src={require('./img/users-tab.png').default} width="50%" title="Users tab" />
- Select the **pencil** next to your user ID
<img src={require('./img/pencil.png').default} width="50%" title="Pencil" />
- Fill in the **External Path** field with `/usr/src/app/external`
<img src={require('./img/external-path.png').default} width="50%" title="External Path field" />
Notice this matches the path _inside the container_ where we mounted your photos.
The purpose of the external path field is for administrators who have multiple users
on their Immich instance. It lets you prevent other authorized users from
navigating to your external library.
# Import the library
In the Immich web UI:
- Click your user avatar in the upper-right corner (circle with your initials)
<img src={require('./img/user-avatar.png').default} width="50%" title="User avatar" />
- Click **Account Settings**
<img src={require('./img/account-settings.png').default} width="50%" title="Account Settings button" />
- Click to expand **Libraries**
<img src={require('./img/libraries-dropdown.png').default} width="50%" title="Libraries dropdown" />
- Click the **Create External Library** button
<img src={require('./img/create-external-library-button.png').default} width="50%" title="Create External Library button" />
- Click the three-dots menu and select **Edit Import Paths**
<img src={require('./img/edit-import-paths.png').default} width="50%" title="Edit Import Paths menu option" />
- Click \*_Add path_
<img src={require('./img/add-path-button.png').default} width="50%" title="Add Path button" />
- Enter **.** as the path and click Add
<img src={require('./img/add-path-field.png').default} width="50%" title="Add Path field" />
- Save the new path
<img src={require('./img/path-save.png').default} width="50%" title="Path Save button" />
- Click the three-dots menu and select **Scan New Library Files**
<img src={require('./img/scan-new-library-files.png').default} width="50%" title="Scan New Library Files menu option" />
# Confirm stuff is happening
- Click **Administration**
<img src={require('./img/administration-link.png').default} width="50%" title="Administration link" />
- Select the **Jobs** tab
<img src={require('./img/jobs-tab.png').default} width="50%" title="Jobs tab" />
- You should see non-zero Active jobs for
Library, Generate Thumbnails, and Extract Metadata.
<img src={require('./img/job-status.png').default} width="50%" title="Job Status display" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -55,7 +55,7 @@ Optionally, you can use the [`hwaccel.yml`][hw-file] file to enable hardware acc
### Step 3 - Start the containers
From the directory you created in Step 1, (which should now contain your customized `docker-compose.yml` and `.env` files) run `docker-compose up -d`.
From the directory you created in Step 1, (which should now contain your customized `docker-compose.yml` and `.env` files) run `docker compose up -d`.
```bash title="Start the containers using docker compose command"
docker compose up -d

View File

@@ -30,14 +30,15 @@ These environment variables are used by the `docker-compose.yml` file and do **N
## General
| Variable | Description | Default | Services |
| :-------------------------- | :------------------------------------------- | :----------: | :------------------------------------------- |
| `TZ` | Timezone | | microservices |
| `NODE_ENV` | Environment (production, development) | `production` | server, microservices, machine learning, web |
| `LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices |
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload` | server, microservices |
| `PUBLIC_LOGIN_PAGE_MESSAGE` | Public Login Page Message | | web |
| `IMMICH_CONFIG_FILE` | Path to config file | | server |
| Variable | Description | Default | Services |
| :-------------------------- | :------------------------------------------- | :-----------------: | :------------------------------------------- |
| `TZ` | Timezone | | microservices |
| `NODE_ENV` | Environment (production, development) | `production` | server, microservices, machine learning, web |
| `LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices |
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload` | server, microservices |
| `PUBLIC_LOGIN_PAGE_MESSAGE` | Public Login Page Message | | web |
| `IMMICH_CONFIG_FILE` | Path to config file | | server |
| `IMMICH_WEB_ROOT` | Path of root index.html | `/usr/src/app/www'` | server |
:::tip

View File

@@ -26,12 +26,14 @@ import {
mdiMagnify,
mdiMap,
mdiMaterialDesign,
mdiMatrix,
mdiMerge,
mdiMonitor,
mdiMotionPlayOutline,
mdiPalette,
mdiPanVertical,
mdiPartyPopper,
mdiPencil,
mdiRaw,
mdiRotate360,
mdiSecurity,
@@ -52,6 +54,24 @@ import React from 'react';
import Timeline, { DateType, Item } from '../components/timeline';
const items: Item[] = [
{
icon: mdiMatrix,
description: 'Moved the search from typesense to pgvecto.rs',
title: 'Search improvement with pgvecto.rs',
release: 'v1.91.0',
tag: 'v1.91.0',
date: new Date(2023, 11, 15),
dateType: DateType.RELEASE,
},
{
icon: mdiPencil,
description: "Edit a photo or video's date, time, hours, timezone, and GPS information",
title: 'Edit metadata',
release: 'v1.90.0',
tag: 'v1.90.0',
date: new Date(2023, 11, 7),
dateType: DateType.RELEASE,
},
{
icon: mdiVectorCombine,
description:

View File

@@ -23,4 +23,3 @@
/docs/features/storage-template /docs/administration/storage-template 301
/docs/features/user-management /docs/administration/user-management 301
/docs/developer/contributing /docs/developer/pr-checklist 301

View File

@@ -1,29 +0,0 @@
{
"redirects": [
{ "source": "/docs", "destination": "/docs/overview/introduction" },
{ "source": "/docs/mobile-app-beta-program", "destination": "/docs/features/mobile-app" },
{ "source": "/docs/contribution-guidelines", "destination": "/docs/overview/support-the-project#contributing" },
{ "source": "/docs/install", "destination": "/docs/install/docker-compose" },
{ "source": "/docs/installation/one-step-installation", "destination": "/docs/install/script" },
{ "source": "/docs/installation/portainer-installation", "destination": "/docs/install/portainer" },
{ "source": "/docs/installation/recommended-installation", "destination": "/docs/install/docker-compose" },
{ "source": "/docs/installation/unraid", "destination": "/docs/install/unraid" },
{ "source": "/docs/installation/requirements", "destination": "/docs/install/requirements" },
{ "source": "/docs/overview/logo-meaning", "destination": "/docs/overview/logo" },
{ "source": "/docs/overview/technology-stack", "destination": "/docs/developer/architecture" },
{ "source": "/docs/usage/automatic-backup", "destination": "/docs/features/automatic-backup" },
{ "source": "/docs/usage/bulk-upload", "destination": "/docs/features/command-line-interface" },
{ "source": "/docs/features/bulk-upload", "destination": "/docs/features/command-line-interface" },
{ "source": "/docs/usage/oauth", "destination": "/docs/administration/oauth" },
{ "source": "/docs/usage/post-installation", "destination": "/docs/install/post-install" },
{ "source": "/docs/usage/update", "destination": "/docs/install/docker-compose#step-4---upgrading" },
{ "source": "/docs/usage/server-commands", "destination": "/docs/administration/server-commands" },
{ "source": "/docs/features/jobs", "destination": "/docs/administration/jobs" },
{ "source": "/docs/features/oauth", "destination": "/docs/administration/oauth" },
{ "source": "/docs/features/password-login", "destination": "/docs/administration/password-login" },
{ "source": "/docs/features/server-commands", "destination": "/docs/administration/server-commands" },
{ "source": "/docs/features/storage-template", "destination": "/docs/administration/storage-template" },
{ "source": "/docs/features/user-management", "destination": "/docs/administration/user-management" },
{ "source": "/docs/developer/contributing", "destination": "/docs/developer/pr-checklist" }
]
}

View File

@@ -25,6 +25,11 @@ ENV NODE_ENV=production \
PATH="/opt/venv/bin:$PATH" \
PYTHONPATH=/usr/src
# prevent core dumps
RUN echo "hard core 0" >> /etc/security/limits.conf && \
echo "fs.suid_dumpable 0" >> /etc/sysctl.conf && \
echo 'ulimit -S -c 0 > /dev/null 2>&1' >> /etc/profile
COPY --from=builder /opt/venv /opt/venv
COPY start.sh log_conf.json ./
COPY app .

View File

@@ -26,6 +26,9 @@ _OPENCLIP_MODELS = {
"ViT-L-14-336__openai",
"ViT-H-14__laion2b-s32b-b79k",
"ViT-g-14__laion2b-s12b-b42k",
"ViT-L-14-quickgelu__dfn2b",
"ViT-H-14-quickgelu__dfn5b",
"ViT-H-14-378-quickgelu__dfn5b",
}
@@ -34,6 +37,9 @@ _MCLIP_MODELS = {
"XLM-Roberta-Large-Vit-B-32",
"XLM-Roberta-Large-Vit-B-16Plus",
"XLM-Roberta-Large-Vit-L-14",
"XLM-Roberta-Large-ViT-H-14__frozen_laion5b_s13b_b90k",
"nllb-clip-base-siglip__v1",
"nllb-clip-large-siglip__v1",
}

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "machine-learning"
version = "1.91.0"
version = "1.91.3"
description = ""
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
readme = "README.md"

View File

@@ -36,7 +36,7 @@ platform :android do
build_type: 'Release',
properties: {
"android.injected.version.code" => 115,
"android.injected.version.name" => "1.91.0",
"android.injected.version.name" => "1.91.3",
}
)
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')

View File

@@ -5,17 +5,17 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000235">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000217">
</testcase>
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="27.74518">
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="66.694734">
</testcase>
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="25.612783">
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="27.6926">
</testcase>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 KiB

View File

@@ -169,4 +169,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
COCOAPODS: 1.11.3
COCOAPODS: 1.12.1

View File

@@ -379,7 +379,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 130;
CURRENT_PROJECT_VERSION = 131;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -515,7 +515,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 130;
CURRENT_PROJECT_VERSION = 131;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -543,7 +543,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 130;
CURRENT_PROJECT_VERSION = 131;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;

View File

@@ -54,11 +54,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.90.0</string>
<string>1.91.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>130</string>
<string>131</string>
<key>FLTEnableImpeller</key>
<true />
<key>ITSAppUsesNonExemptEncryption</key>

View File

@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta"
lane :beta do
increment_version_number(
version_number: "1.91.0"
version_number: "1.91.3"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,

View File

@@ -5,32 +5,32 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000234">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000273">
</testcase>
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.207521">
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.162117">
</testcase>
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="18.516191">
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="3.645923">
</testcase>
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.23018">
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.158953">
</testcase>
<testcase classname="fastlane.lanes" name="4: build_app" time="104.984834">
<testcase classname="fastlane.lanes" name="4: build_app" time="114.023733">
</testcase>
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="61.879749">
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="97.572612">
</testcase>

View File

@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 1.91.0
- API version: 1.91.3
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements

View File

@@ -9,7 +9,6 @@ import 'package:openapi/api.dart';
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**backgroundTask** | [**JobStatusDto**](JobStatusDto.md) | |
**clipEncoding** | [**JobStatusDto**](JobStatusDto.md) | |
**library_** | [**JobStatusDto**](JobStatusDto.md) | |
**metadataExtraction** | [**JobStatusDto**](JobStatusDto.md) | |
**migration** | [**JobStatusDto**](JobStatusDto.md) | |
@@ -17,6 +16,7 @@ Name | Type | Description | Notes
**recognizeFaces** | [**JobStatusDto**](JobStatusDto.md) | |
**search** | [**JobStatusDto**](JobStatusDto.md) | |
**sidecar** | [**JobStatusDto**](JobStatusDto.md) | |
**smartSearch** | [**JobStatusDto**](JobStatusDto.md) | |
**storageTemplateMigration** | [**JobStatusDto**](JobStatusDto.md) | |
**thumbnailGeneration** | [**JobStatusDto**](JobStatusDto.md) | |
**videoConversion** | [**JobStatusDto**](JobStatusDto.md) | |

View File

@@ -9,7 +9,6 @@ import 'package:openapi/api.dart';
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**backgroundTask** | [**JobSettingsDto**](JobSettingsDto.md) | |
**clipEncoding** | [**JobSettingsDto**](JobSettingsDto.md) | |
**library_** | [**JobSettingsDto**](JobSettingsDto.md) | |
**metadataExtraction** | [**JobSettingsDto**](JobSettingsDto.md) | |
**migration** | [**JobSettingsDto**](JobSettingsDto.md) | |
@@ -17,6 +16,7 @@ Name | Type | Description | Notes
**recognizeFaces** | [**JobSettingsDto**](JobSettingsDto.md) | |
**search** | [**JobSettingsDto**](JobSettingsDto.md) | |
**sidecar** | [**JobSettingsDto**](JobSettingsDto.md) | |
**smartSearch** | [**JobSettingsDto**](JobSettingsDto.md) | |
**storageTemplateMigration** | [**JobSettingsDto**](JobSettingsDto.md) | |
**thumbnailGeneration** | [**JobSettingsDto**](JobSettingsDto.md) | |
**videoConversion** | [**JobSettingsDto**](JobSettingsDto.md) | |

View File

@@ -14,7 +14,6 @@ class AllJobStatusResponseDto {
/// Returns a new [AllJobStatusResponseDto] instance.
AllJobStatusResponseDto({
required this.backgroundTask,
required this.clipEncoding,
required this.library_,
required this.metadataExtraction,
required this.migration,
@@ -22,6 +21,7 @@ class AllJobStatusResponseDto {
required this.recognizeFaces,
required this.search,
required this.sidecar,
required this.smartSearch,
required this.storageTemplateMigration,
required this.thumbnailGeneration,
required this.videoConversion,
@@ -29,8 +29,6 @@ class AllJobStatusResponseDto {
JobStatusDto backgroundTask;
JobStatusDto clipEncoding;
JobStatusDto library_;
JobStatusDto metadataExtraction;
@@ -45,6 +43,8 @@ class AllJobStatusResponseDto {
JobStatusDto sidecar;
JobStatusDto smartSearch;
JobStatusDto storageTemplateMigration;
JobStatusDto thumbnailGeneration;
@@ -54,7 +54,6 @@ class AllJobStatusResponseDto {
@override
bool operator ==(Object other) => identical(this, other) || other is AllJobStatusResponseDto &&
other.backgroundTask == backgroundTask &&
other.clipEncoding == clipEncoding &&
other.library_ == library_ &&
other.metadataExtraction == metadataExtraction &&
other.migration == migration &&
@@ -62,6 +61,7 @@ class AllJobStatusResponseDto {
other.recognizeFaces == recognizeFaces &&
other.search == search &&
other.sidecar == sidecar &&
other.smartSearch == smartSearch &&
other.storageTemplateMigration == storageTemplateMigration &&
other.thumbnailGeneration == thumbnailGeneration &&
other.videoConversion == videoConversion;
@@ -70,7 +70,6 @@ class AllJobStatusResponseDto {
int get hashCode =>
// ignore: unnecessary_parenthesis
(backgroundTask.hashCode) +
(clipEncoding.hashCode) +
(library_.hashCode) +
(metadataExtraction.hashCode) +
(migration.hashCode) +
@@ -78,17 +77,17 @@ class AllJobStatusResponseDto {
(recognizeFaces.hashCode) +
(search.hashCode) +
(sidecar.hashCode) +
(smartSearch.hashCode) +
(storageTemplateMigration.hashCode) +
(thumbnailGeneration.hashCode) +
(videoConversion.hashCode);
@override
String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, clipEncoding=$clipEncoding, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'backgroundTask'] = this.backgroundTask;
json[r'clipEncoding'] = this.clipEncoding;
json[r'library'] = this.library_;
json[r'metadataExtraction'] = this.metadataExtraction;
json[r'migration'] = this.migration;
@@ -96,6 +95,7 @@ class AllJobStatusResponseDto {
json[r'recognizeFaces'] = this.recognizeFaces;
json[r'search'] = this.search;
json[r'sidecar'] = this.sidecar;
json[r'smartSearch'] = this.smartSearch;
json[r'storageTemplateMigration'] = this.storageTemplateMigration;
json[r'thumbnailGeneration'] = this.thumbnailGeneration;
json[r'videoConversion'] = this.videoConversion;
@@ -111,7 +111,6 @@ class AllJobStatusResponseDto {
return AllJobStatusResponseDto(
backgroundTask: JobStatusDto.fromJson(json[r'backgroundTask'])!,
clipEncoding: JobStatusDto.fromJson(json[r'clipEncoding'])!,
library_: JobStatusDto.fromJson(json[r'library'])!,
metadataExtraction: JobStatusDto.fromJson(json[r'metadataExtraction'])!,
migration: JobStatusDto.fromJson(json[r'migration'])!,
@@ -119,6 +118,7 @@ class AllJobStatusResponseDto {
recognizeFaces: JobStatusDto.fromJson(json[r'recognizeFaces'])!,
search: JobStatusDto.fromJson(json[r'search'])!,
sidecar: JobStatusDto.fromJson(json[r'sidecar'])!,
smartSearch: JobStatusDto.fromJson(json[r'smartSearch'])!,
storageTemplateMigration: JobStatusDto.fromJson(json[r'storageTemplateMigration'])!,
thumbnailGeneration: JobStatusDto.fromJson(json[r'thumbnailGeneration'])!,
videoConversion: JobStatusDto.fromJson(json[r'videoConversion'])!,
@@ -170,7 +170,6 @@ class AllJobStatusResponseDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'backgroundTask',
'clipEncoding',
'library',
'metadataExtraction',
'migration',
@@ -178,6 +177,7 @@ class AllJobStatusResponseDto {
'recognizeFaces',
'search',
'sidecar',
'smartSearch',
'storageTemplateMigration',
'thumbnailGeneration',
'videoConversion',

View File

@@ -28,7 +28,7 @@ class JobName {
static const videoConversion = JobName._(r'videoConversion');
static const objectTagging = JobName._(r'objectTagging');
static const recognizeFaces = JobName._(r'recognizeFaces');
static const clipEncoding = JobName._(r'clipEncoding');
static const smartSearch = JobName._(r'smartSearch');
static const backgroundTask = JobName._(r'backgroundTask');
static const storageTemplateMigration = JobName._(r'storageTemplateMigration');
static const migration = JobName._(r'migration');
@@ -43,7 +43,7 @@ class JobName {
videoConversion,
objectTagging,
recognizeFaces,
clipEncoding,
smartSearch,
backgroundTask,
storageTemplateMigration,
migration,
@@ -93,7 +93,7 @@ class JobNameTypeTransformer {
case r'videoConversion': return JobName.videoConversion;
case r'objectTagging': return JobName.objectTagging;
case r'recognizeFaces': return JobName.recognizeFaces;
case r'clipEncoding': return JobName.clipEncoding;
case r'smartSearch': return JobName.smartSearch;
case r'backgroundTask': return JobName.backgroundTask;
case r'storageTemplateMigration': return JobName.storageTemplateMigration;
case r'migration': return JobName.migration;

View File

@@ -14,7 +14,6 @@ class SystemConfigJobDto {
/// Returns a new [SystemConfigJobDto] instance.
SystemConfigJobDto({
required this.backgroundTask,
required this.clipEncoding,
required this.library_,
required this.metadataExtraction,
required this.migration,
@@ -22,6 +21,7 @@ class SystemConfigJobDto {
required this.recognizeFaces,
required this.search,
required this.sidecar,
required this.smartSearch,
required this.storageTemplateMigration,
required this.thumbnailGeneration,
required this.videoConversion,
@@ -29,8 +29,6 @@ class SystemConfigJobDto {
JobSettingsDto backgroundTask;
JobSettingsDto clipEncoding;
JobSettingsDto library_;
JobSettingsDto metadataExtraction;
@@ -45,6 +43,8 @@ class SystemConfigJobDto {
JobSettingsDto sidecar;
JobSettingsDto smartSearch;
JobSettingsDto storageTemplateMigration;
JobSettingsDto thumbnailGeneration;
@@ -54,7 +54,6 @@ class SystemConfigJobDto {
@override
bool operator ==(Object other) => identical(this, other) || other is SystemConfigJobDto &&
other.backgroundTask == backgroundTask &&
other.clipEncoding == clipEncoding &&
other.library_ == library_ &&
other.metadataExtraction == metadataExtraction &&
other.migration == migration &&
@@ -62,6 +61,7 @@ class SystemConfigJobDto {
other.recognizeFaces == recognizeFaces &&
other.search == search &&
other.sidecar == sidecar &&
other.smartSearch == smartSearch &&
other.storageTemplateMigration == storageTemplateMigration &&
other.thumbnailGeneration == thumbnailGeneration &&
other.videoConversion == videoConversion;
@@ -70,7 +70,6 @@ class SystemConfigJobDto {
int get hashCode =>
// ignore: unnecessary_parenthesis
(backgroundTask.hashCode) +
(clipEncoding.hashCode) +
(library_.hashCode) +
(metadataExtraction.hashCode) +
(migration.hashCode) +
@@ -78,17 +77,17 @@ class SystemConfigJobDto {
(recognizeFaces.hashCode) +
(search.hashCode) +
(sidecar.hashCode) +
(smartSearch.hashCode) +
(storageTemplateMigration.hashCode) +
(thumbnailGeneration.hashCode) +
(videoConversion.hashCode);
@override
String toString() => 'SystemConfigJobDto[backgroundTask=$backgroundTask, clipEncoding=$clipEncoding, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
String toString() => 'SystemConfigJobDto[backgroundTask=$backgroundTask, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'backgroundTask'] = this.backgroundTask;
json[r'clipEncoding'] = this.clipEncoding;
json[r'library'] = this.library_;
json[r'metadataExtraction'] = this.metadataExtraction;
json[r'migration'] = this.migration;
@@ -96,6 +95,7 @@ class SystemConfigJobDto {
json[r'recognizeFaces'] = this.recognizeFaces;
json[r'search'] = this.search;
json[r'sidecar'] = this.sidecar;
json[r'smartSearch'] = this.smartSearch;
json[r'storageTemplateMigration'] = this.storageTemplateMigration;
json[r'thumbnailGeneration'] = this.thumbnailGeneration;
json[r'videoConversion'] = this.videoConversion;
@@ -111,7 +111,6 @@ class SystemConfigJobDto {
return SystemConfigJobDto(
backgroundTask: JobSettingsDto.fromJson(json[r'backgroundTask'])!,
clipEncoding: JobSettingsDto.fromJson(json[r'clipEncoding'])!,
library_: JobSettingsDto.fromJson(json[r'library'])!,
metadataExtraction: JobSettingsDto.fromJson(json[r'metadataExtraction'])!,
migration: JobSettingsDto.fromJson(json[r'migration'])!,
@@ -119,6 +118,7 @@ class SystemConfigJobDto {
recognizeFaces: JobSettingsDto.fromJson(json[r'recognizeFaces'])!,
search: JobSettingsDto.fromJson(json[r'search'])!,
sidecar: JobSettingsDto.fromJson(json[r'sidecar'])!,
smartSearch: JobSettingsDto.fromJson(json[r'smartSearch'])!,
storageTemplateMigration: JobSettingsDto.fromJson(json[r'storageTemplateMigration'])!,
thumbnailGeneration: JobSettingsDto.fromJson(json[r'thumbnailGeneration'])!,
videoConversion: JobSettingsDto.fromJson(json[r'videoConversion'])!,
@@ -170,7 +170,6 @@ class SystemConfigJobDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'backgroundTask',
'clipEncoding',
'library',
'metadataExtraction',
'migration',
@@ -178,6 +177,7 @@ class SystemConfigJobDto {
'recognizeFaces',
'search',
'sidecar',
'smartSearch',
'storageTemplateMigration',
'thumbnailGeneration',
'videoConversion',

View File

@@ -21,11 +21,6 @@ void main() {
// TODO
});
// JobStatusDto clipEncoding
test('to test the property `clipEncoding`', () async {
// TODO
});
// JobStatusDto library_
test('to test the property `library_`', () async {
// TODO
@@ -61,6 +56,11 @@ void main() {
// TODO
});
// JobStatusDto smartSearch
test('to test the property `smartSearch`', () async {
// TODO
});
// JobStatusDto storageTemplateMigration
test('to test the property `storageTemplateMigration`', () async {
// TODO

View File

@@ -21,11 +21,6 @@ void main() {
// TODO
});
// JobSettingsDto clipEncoding
test('to test the property `clipEncoding`', () async {
// TODO
});
// JobSettingsDto library_
test('to test the property `library_`', () async {
// TODO
@@ -61,6 +56,11 @@ void main() {
// TODO
});
// JobSettingsDto smartSearch
test('to test the property `smartSearch`', () async {
// TODO
});
// JobSettingsDto storageTemplateMigration
test('to test the property `storageTemplateMigration`', () async {
// TODO

View File

@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: "none"
version: 1.91.0+115
version: 1.91.3+115
isar_version: &isar_version 3.1.0+1
environment:

View File

@@ -6188,7 +6188,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
"version": "1.91.0",
"version": "1.91.3",
"contact": {}
},
"tags": [],
@@ -6470,9 +6470,6 @@
"backgroundTask": {
"$ref": "#/components/schemas/JobStatusDto"
},
"clipEncoding": {
"$ref": "#/components/schemas/JobStatusDto"
},
"library": {
"$ref": "#/components/schemas/JobStatusDto"
},
@@ -6494,6 +6491,9 @@
"sidecar": {
"$ref": "#/components/schemas/JobStatusDto"
},
"smartSearch": {
"$ref": "#/components/schemas/JobStatusDto"
},
"storageTemplateMigration": {
"$ref": "#/components/schemas/JobStatusDto"
},
@@ -6509,7 +6509,7 @@
"metadataExtraction",
"videoConversion",
"objectTagging",
"clipEncoding",
"smartSearch",
"storageTemplateMigration",
"migration",
"backgroundTask",
@@ -7821,7 +7821,7 @@
"videoConversion",
"objectTagging",
"recognizeFaces",
"clipEncoding",
"smartSearch",
"backgroundTask",
"storageTemplateMigration",
"migration",
@@ -9182,9 +9182,6 @@
"backgroundTask": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"clipEncoding": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"library": {
"$ref": "#/components/schemas/JobSettingsDto"
},
@@ -9206,6 +9203,9 @@
"sidecar": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"smartSearch": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"storageTemplateMigration": {
"$ref": "#/components/schemas/JobSettingsDto"
},
@@ -9221,7 +9221,7 @@
"metadataExtraction",
"videoConversion",
"objectTagging",
"clipEncoding",
"smartSearch",
"storageTemplateMigration",
"migration",
"backgroundTask",

View File

@@ -1,12 +1,12 @@
{
"name": "immich",
"version": "1.91.0",
"version": "1.91.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "immich",
"version": "1.91.0",
"version": "1.91.3",
"license": "UNLICENSED",
"dependencies": {
"@babel/runtime": "^7.22.11",

View File

@@ -1,6 +1,6 @@
{
"name": "immich",
"version": "1.91.0",
"version": "1.91.3",
"description": "",
"author": "",
"private": true,

View File

@@ -1,6 +1,6 @@
import { AssetType } from '@app/infra/entities';
import { Duration } from 'luxon';
import { extname } from 'node:path';
import { extname, join } from 'node:path';
import pkg from 'src/../../package.json';
export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 });
@@ -58,6 +58,8 @@ export const serverVersion = ServerVersion.fromString(pkg.version);
export const APP_MEDIA_LOCATION = process.env.IMMICH_MEDIA_LOCATION || './upload';
export const WEB_ROOT_PATH = join(process.env.IMMICH_WEB_ROOT || '/usr/src/app/www', 'index.html');
const image: Record<string, string[]> = {
'.3fr': ['image/3fr', 'image/x-hasselblad-3fr'],
'.ari': ['image/ari', 'image/x-arriflex-ari'],

View File

@@ -4,7 +4,7 @@ export enum QueueName {
VIDEO_CONVERSION = 'videoConversion',
OBJECT_TAGGING = 'objectTagging',
RECOGNIZE_FACES = 'recognizeFaces',
CLIP_ENCODING = 'clipEncoding',
SMART_SEARCH = 'smartSearch',
BACKGROUND_TASK = 'backgroundTask',
STORAGE_TEMPLATE_MIGRATION = 'storageTemplateMigration',
MIGRATION = 'migration',
@@ -135,8 +135,8 @@ export const JOBS_TO_QUEUE: Record<JobName, QueueName> = {
[JobName.RECOGNIZE_FACES]: QueueName.RECOGNIZE_FACES,
// clip
[JobName.QUEUE_ENCODE_CLIP]: QueueName.CLIP_ENCODING,
[JobName.ENCODE_CLIP]: QueueName.CLIP_ENCODING,
[JobName.QUEUE_ENCODE_CLIP]: QueueName.SMART_SEARCH,
[JobName.ENCODE_CLIP]: QueueName.SMART_SEARCH,
// XMP sidecars
[JobName.QUEUE_SIDECAR]: QueueName.SIDECAR,

View File

@@ -63,7 +63,7 @@ export class AllJobStatusResponseDto implements Record<QueueName, JobStatusDto>
[QueueName.OBJECT_TAGGING]!: JobStatusDto;
@ApiProperty({ type: JobStatusDto })
[QueueName.CLIP_ENCODING]!: JobStatusDto;
[QueueName.SMART_SEARCH]!: JobStatusDto;
@ApiProperty({ type: JobStatusDto })
[QueueName.STORAGE_TEMPLATE_MIGRATION]!: JobStatusDto;

View File

@@ -97,7 +97,7 @@ describe(JobService.name, () => {
await expect(sut.getAllJobsStatus()).resolves.toEqual({
[QueueName.BACKGROUND_TASK]: expectedJobStatus,
[QueueName.CLIP_ENCODING]: expectedJobStatus,
[QueueName.SMART_SEARCH]: expectedJobStatus,
[QueueName.METADATA_EXTRACTION]: expectedJobStatus,
[QueueName.OBJECT_TAGGING]: expectedJobStatus,
[QueueName.SEARCH]: expectedJobStatus,
@@ -171,7 +171,7 @@ describe(JobService.name, () => {
it('should handle a start clip encoding command', async () => {
jobMock.getQueueStatus.mockResolvedValue({ isActive: false, isPaused: false });
await sut.handleCommand(QueueName.CLIP_ENCODING, { command: JobCommand.START, force: false });
await sut.handleCommand(QueueName.SMART_SEARCH, { command: JobCommand.START, force: false });
expect(jobMock.queue).toHaveBeenCalledWith({ name: JobName.QUEUE_ENCODE_CLIP, data: { force: false } });
});
@@ -232,7 +232,7 @@ describe(JobService.name, () => {
SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({
job: {
[QueueName.BACKGROUND_TASK]: { concurrency: 10 },
[QueueName.CLIP_ENCODING]: { concurrency: 10 },
[QueueName.SMART_SEARCH]: { concurrency: 10 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 10 },
[QueueName.OBJECT_TAGGING]: { concurrency: 10 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 10 },
@@ -247,7 +247,7 @@ describe(JobService.name, () => {
} as SystemConfig);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.BACKGROUND_TASK, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.CLIP_ENCODING, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.SMART_SEARCH, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.METADATA_EXTRACTION, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.OBJECT_TAGGING, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.RECOGNIZE_FACES, 10);
@@ -367,7 +367,7 @@ describe(JobService.name, () => {
const featureTests: Array<{ queue: QueueName; feature: FeatureFlag; configKey: SystemConfigKey }> = [
{
queue: QueueName.CLIP_ENCODING,
queue: QueueName.SMART_SEARCH,
feature: FeatureFlag.CLIP_ENCODE,
configKey: SystemConfigKey.MACHINE_LEARNING_CLIP_ENABLED,
},

View File

@@ -98,7 +98,7 @@ export class JobService {
await this.configCore.requireFeature(FeatureFlag.TAG_IMAGE);
return this.jobRepository.queue({ name: JobName.QUEUE_OBJECT_TAGGING, data: { force } });
case QueueName.CLIP_ENCODING:
case QueueName.SMART_SEARCH:
await this.configCore.requireFeature(FeatureFlag.CLIP_ENCODE);
return this.jobRepository.queue({ name: JobName.QUEUE_ENCODE_CLIP, data: { force } });

View File

@@ -81,7 +81,7 @@ export const CLIP_MODEL_INFO: Record<string, ModelInfo> = {
'ViT-H-14-quickgelu__dfn5b': {
dimSize: 1024,
},
'ViT-H-14-378-quickgelu__dfn5b ': {
'ViT-H-14-378-quickgelu__dfn5b': {
dimSize: 1024,
},
'ViT-g-14__laion2b-s12b-b42k': {

View File

@@ -29,13 +29,13 @@ export class SmartInfoService {
}
async init() {
await this.jobRepository.pause(QueueName.CLIP_ENCODING);
await this.jobRepository.pause(QueueName.SMART_SEARCH);
let { isActive } = await this.jobRepository.getQueueStatus(QueueName.CLIP_ENCODING);
let { isActive } = await this.jobRepository.getQueueStatus(QueueName.SMART_SEARCH);
while (isActive) {
this.logger.verbose('Waiting for CLIP encoding queue to stop...');
await setTimeout(1000).then(async () => {
({ isActive } = await this.jobRepository.getQueueStatus(QueueName.CLIP_ENCODING));
({ isActive } = await this.jobRepository.getQueueStatus(QueueName.SMART_SEARCH));
});
}
@@ -43,7 +43,7 @@ export class SmartInfoService {
await this.repository.init(machineLearning.clip.modelName);
await this.jobRepository.resume(QueueName.CLIP_ENCODING);
await this.jobRepository.resume(QueueName.SMART_SEARCH);
}
async handleQueueObjectTagging({ force }: IBaseJob) {

View File

@@ -39,7 +39,7 @@ export class SystemConfigJobDto implements Record<QueueName, JobSettingsDto> {
@ValidateNested()
@IsObject()
@Type(() => JobSettingsDto)
[QueueName.CLIP_ENCODING]!: JobSettingsDto;
[QueueName.SMART_SEARCH]!: JobSettingsDto;
@ApiProperty({ type: JobSettingsDto })
@ValidateNested()

View File

@@ -47,7 +47,7 @@ export const defaults = Object.freeze<SystemConfig>({
},
job: {
[QueueName.BACKGROUND_TASK]: { concurrency: 5 },
[QueueName.CLIP_ENCODING]: { concurrency: 2 },
[QueueName.SMART_SEARCH]: { concurrency: 2 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 5 },
[QueueName.OBJECT_TAGGING]: { concurrency: 2 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 2 },

View File

@@ -27,7 +27,7 @@ const updates: SystemConfigEntity[] = [
const updatedConfig = Object.freeze<SystemConfig>({
job: {
[QueueName.BACKGROUND_TASK]: { concurrency: 5 },
[QueueName.CLIP_ENCODING]: { concurrency: 2 },
[QueueName.SMART_SEARCH]: { concurrency: 2 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 5 },
[QueueName.OBJECT_TAGGING]: { concurrency: 2 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 2 },

View File

@@ -7,6 +7,7 @@ import {
SharedLinkService,
StorageService,
SystemConfigService,
WEB_ROOT_PATH,
} from '@app/domain';
import { ImmichLogger } from '@app/infra/logger';
import { Injectable } from '@nestjs/common';
@@ -67,7 +68,7 @@ export class AppService {
ssr(excludePaths: string[]) {
let index = '';
try {
index = readFileSync('/usr/src/app/www/index.html').toString();
index = readFileSync(WEB_ROOT_PATH).toString();
} catch (error: Error | any) {
this.logger.warn('Unable to open `www/index.html, skipping SSR.');
}

View File

@@ -37,7 +37,7 @@ export enum SystemConfigKey {
JOB_VIDEO_CONVERSION_CONCURRENCY = 'job.videoConversion.concurrency',
JOB_OBJECT_TAGGING_CONCURRENCY = 'job.objectTagging.concurrency',
JOB_RECOGNIZE_FACES_CONCURRENCY = 'job.recognizeFaces.concurrency',
JOB_CLIP_ENCODING_CONCURRENCY = 'job.clipEncoding.concurrency',
JOB_CLIP_ENCODING_CONCURRENCY = 'job.smartSearch.concurrency',
JOB_BACKGROUND_TASK_CONCURRENCY = 'job.backgroundTask.concurrency',
JOB_STORAGE_TEMPLATE_MIGRATION_CONCURRENCY = 'job.storageTemplateMigration.concurrency',
JOB_SEARCH_CONCURRENCY = 'job.search.concurrency',

View File

@@ -1,3 +1,4 @@
import { getCLIPModelInfo } from '@app/domain/smart-info/smart-info.constant';
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UsePgVectors1700713871511 implements MigrationInterface {
@@ -8,13 +9,11 @@ export class UsePgVectors1700713871511 implements MigrationInterface {
SELECT CARDINALITY(embedding::real[]) as dimsize
FROM asset_faces
LIMIT 1`);
const clipDimQuery = await queryRunner.query(`
SELECT CARDINALITY("clipEmbedding"::real[]) as dimsize
FROM smart_info
LIMIT 1`);
const faceDimSize = faceDimQuery?.[0]?.['dimsize'] ?? 512;
const clipDimSize = clipDimQuery?.[0]?.['dimsize'] ?? 512;
const clipModelNameQuery = await queryRunner.query(`SELECT value FROM system_config WHERE key = 'machineLearning.clip.modelName'`);
const clipModelName: string = clipModelNameQuery?.[0]?.['value'] ?? 'ViT-B-32__openai';
const clipDimSize = getCLIPModelInfo(clipModelName.replace(/"/g, '')).dimSize;
await queryRunner.query('CREATE EXTENSION IF NOT EXISTS vectors');
@@ -32,7 +31,9 @@ export class UsePgVectors1700713871511 implements MigrationInterface {
INSERT INTO smart_search("assetId", embedding)
SELECT si."assetId", si."clipEmbedding"
FROM smart_info si
WHERE "clipEmbedding" IS NOT NULL`);
WHERE "clipEmbedding" IS NOT NULL
AND CARDINALITY("clipEmbedding"::real[]) = ${clipDimSize}
AND array_position(si."clipEmbedding", NULL) IS NULL`);
await queryRunner.query(`ALTER TABLE smart_info DROP COLUMN IF EXISTS "clipEmbedding"`);
}

View File

@@ -136,7 +136,7 @@ class ImmichApi {
[JobName.MetadataExtraction]: 'Extract Metadata',
[JobName.Sidecar]: 'Sidecar Metadata',
[JobName.ObjectTagging]: 'Tag Objects',
[JobName.ClipEncoding]: 'Encode Clip',
[JobName.SmartSearch]: 'Smart Search',
[JobName.RecognizeFaces]: 'Recognize Faces',
[JobName.VideoConversion]: 'Transcode Videos',
[JobName.StorageTemplateMigration]: 'Storage Template Migration',

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -355,12 +355,6 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'backgroundTask': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'clipEncoding': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -403,6 +397,12 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'sidecar': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'smartSearch': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -2017,7 +2017,7 @@ export const JobName = {
VideoConversion: 'videoConversion',
ObjectTagging: 'objectTagging',
RecognizeFaces: 'recognizeFaces',
ClipEncoding: 'clipEncoding',
SmartSearch: 'smartSearch',
BackgroundTask: 'backgroundTask',
StorageTemplateMigration: 'storageTemplateMigration',
Migration: 'migration',
@@ -3785,12 +3785,6 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'backgroundTask': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'clipEncoding': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
@@ -3833,6 +3827,12 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'sidecar': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'smartSearch': JobSettingsDto;
/**
*
* @type {JobSettingsDto}

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48.png" />

View File

@@ -0,0 +1 @@
<svg fill="#2443c2" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="101px" height="101px" viewBox="0 0 425.963 425.963" xml:space="preserve" stroke="#2443c2"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M213.285,0h-0.608C139.114,0,79.268,59.826,79.268,133.361c0,48.202,21.952,111.817,65.246,189.081 c32.098,57.281,64.646,101.152,64.972,101.588c0.906,1.217,2.334,1.934,3.847,1.934c0.043,0,0.087,0,0.13-0.002 c1.561-0.043,3.002-0.842,3.868-2.143c0.321-0.486,32.637-49.287,64.517-108.976c43.03-80.563,64.848-141.624,64.848-181.482 C346.693,59.825,286.846,0,213.285,0z M274.865,136.62c0,34.124-27.761,61.884-61.885,61.884 c-34.123,0-61.884-27.761-61.884-61.884s27.761-61.884,61.884-61.884C247.104,74.736,274.865,102.497,274.865,136.62z"></path> </g> </g></svg>

After

Width:  |  Height:  |  Size: 944 B

View File

@@ -12,10 +12,10 @@
mdiFileJpgBox,
mdiFileXmlBox,
mdiFolderMove,
mdiImageSearch,
mdiLibraryShelves,
mdiTable,
mdiTagMultiple,
mdiVectorCircle,
mdiVideo,
} from '@mdi/js';
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
@@ -56,12 +56,12 @@
[JobName.ThumbnailGeneration]: {
icon: mdiFileJpgBox,
title: api.getJobName(JobName.ThumbnailGeneration),
subtitle: 'Regenerate JPEG and WebP thumbnails',
subtitle: 'Generate large, small and blurred thumbnails for each asset, as well as thumbnails for each person',
},
[JobName.MetadataExtraction]: {
icon: mdiTable,
title: api.getJobName(JobName.MetadataExtraction),
subtitle: 'Extract metadata information i.e. GPS, resolution...etc',
subtitle: 'Extract metadata information from each asset, such as GPS and resolution',
},
[JobName.Library]: {
icon: mdiLibraryShelves,
@@ -81,26 +81,27 @@
[JobName.ObjectTagging]: {
icon: mdiTagMultiple,
title: api.getJobName(JobName.ObjectTagging),
subtitle: 'Run machine learning to tag objects\nNote that some assets may not have any objects detected',
subtitle:
'Run machine learning on assets to tag objects\nNote that some assets may not have any objects detected',
disabled: !$featureFlags.tagImage,
},
[JobName.ClipEncoding]: {
icon: mdiVectorCircle,
title: api.getJobName(JobName.ClipEncoding),
subtitle: 'Run machine learning to generate clip embeddings',
[JobName.SmartSearch]: {
icon: mdiImageSearch,
title: api.getJobName(JobName.SmartSearch),
subtitle: 'Run machine learning on assets to support smart search',
disabled: !$featureFlags.clipEncode,
},
[JobName.RecognizeFaces]: {
icon: mdiFaceRecognition,
title: api.getJobName(JobName.RecognizeFaces),
subtitle: 'Run machine learning to recognize faces',
subtitle: 'Run machine learning on assets to recognize faces',
handleCommand: handleFaceCommand,
disabled: !$featureFlags.facialRecognition,
},
[JobName.VideoConversion]: {
icon: mdiVideo,
title: api.getJobName(JobName.VideoConversion),
subtitle: 'Transcode videos not in the desired format',
subtitle: 'Transcode videos for wider compatibility with browsers and devices',
},
[JobName.StorageTemplateMigration]: {
icon: mdiFolderMove,

View File

@@ -23,7 +23,7 @@
JobName.Library,
JobName.Sidecar,
JobName.ObjectTagging,
JobName.ClipEncoding,
JobName.SmartSearch,
JobName.RecognizeFaces,
JobName.VideoConversion,
JobName.StorageTemplateMigration,

View File

@@ -12,6 +12,7 @@
import type { ResetOptions } from '$lib/utils/dipatch';
export let newVersionCheckConfig: SystemConfigNewVersionCheckDto; // this is the config that is being edited
export let disabled = false;
let savedConfig: SystemConfigNewVersionCheckDto;
let defaultConfig: SystemConfigNewVersionCheckDto;
@@ -86,11 +87,13 @@
title="ENABLED"
subtitle="Enable period requests to GitHub to check for new releases"
bind:checked={newVersionCheckConfig.enabled}
{disabled}
/>
<SettingButtonsRow
on:reset={({ detail }) => handleReset(detail)}
on:save={saveSetting}
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
{disabled}
/>
</div>
</div>

View File

@@ -42,16 +42,15 @@
/>
{#if disabled}
<span class="slider-disable cursor-not-allowed" />
<span class="slider slider-disabled cursor-not-allowed" />
{:else}
<span class="slider cursor-pointer" />
<span class="slider slider-enabled cursor-pointer" />
{/if}
</label>
</div>
<style>
.slider,
.slider-disable {
.slider {
position: absolute;
top: 0;
left: 0;
@@ -67,8 +66,7 @@
cursor: not-allowed;
}
.slider:before,
.slider-disable:before {
.slider:before {
position: absolute;
content: '';
height: 20px;
@@ -82,18 +80,18 @@
border-radius: 50%;
}
input:checked + .slider-disable {
background-color: gray;
}
input:checked + .slider {
background-color: #adcbfa;
}
input:checked + .slider:before {
-webkit-transform: translateX(18px);
-ms-transform: translateX(18px);
transform: translateX(18px);
background-color: #4250af;
}
input:checked + .slider-disabled {
background-color: gray;
}
input:checked + .slider-enabled {
background-color: #adcbfa;
}
</style>

View File

@@ -569,7 +569,13 @@
{#if latlng && $featureFlags.loaded && $featureFlags.map}
<div class="h-[360px]">
<Map mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]} center={latlng} zoom={14} simplified>
<Map
mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]}
center={latlng}
zoom={15}
simplified
useLocationPin
>
<svelte:fragment slot="popup" let:marker>
{@const { lat, lon } = marker}
<div class="flex flex-col items-center gap-1">

View File

@@ -20,7 +20,7 @@
import type { GeoJSONSource, LngLatLike, StyleSpecification } from 'maplibre-gl';
import type { Feature, Geometry, GeoJsonProperties, Point } from 'geojson';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiCog } from '@mdi/js';
import { mdiCog, mdiMapMarker } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
export let mapMarkers: MapMarkerResponseDto[];
@@ -29,6 +29,7 @@
export let center: LngLatLike | undefined = undefined;
export let simplified = false;
export let clickable = false;
export let useLocationPin = false;
let map: maplibregl.Map;
let marker: maplibregl.Marker | null = null;
@@ -141,7 +142,7 @@
}),
}}
id="geojson"
cluster={{ radius: 500 }}
cluster={{ radius: 500, maxZoom: 42 }}
>
<MarkerLayer
applyToClusters
@@ -165,11 +166,16 @@
$$slots.popup || handleAssetClick(event.detail.feature.properties.id, map);
}}
>
<img
src={api.getAssetThumbnailUrl(feature.properties?.id)}
class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-contain bg-immich-primary"
alt={`Image with id ${feature.properties?.id}`}
/>
{#if useLocationPin}
<Icon path={mdiMapMarker} size="60px" class="dark:text-immich-dark-primary text-immich-primary" />
{:else}
<img
src={api.getAssetThumbnailUrl(feature.properties?.id)}
class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-cover bg-immich-primary"
alt={`Image with id ${feature.properties?.id}`}
/>
{/if}
{#if $$slots.popup}
<Popup openOn="click" closeOnClickOutside>
<slot name="popup" marker={asMarker(feature)} />

View File

@@ -119,7 +119,6 @@
try {
const libraryId = libraries[updateLibraryIndex].id;
await api.libraryApi.updateLibrary({ id: libraryId, updateLibraryDto: { ...event } });
} catch (error) {
handleError(error, 'Unable to update library');
@@ -394,7 +393,7 @@
<div transition:slide={{ duration: 250 }} class="mb-4 ml-4 mr-4">
<LibraryScanSettingsForm
{library}
on:submit={({ detail }) => handleUpdate(detail)}
on:submit={({ detail }) => handleUpdate(detail.library)}
on:cancel={() => (editScanSettings = null)}
/>
</div>

View File

@@ -73,7 +73,7 @@
</div>
<div class="flex flex-row flex-wrap gap-4">
{#each places as item (item.data.id)}
<a class="relative" href="{AppRoute.SEARCH}?{Field.CITY}={item.value}" draggable="false">
<a class="relative" href="{AppRoute.SEARCH}?q={item.value}" draggable="false">
<div
class="flex w-[calc((100vw-(72px+5rem))/2)] max-w-[156px] justify-center overflow-hidden rounded-xl brightness-75 filter"
>
@@ -97,7 +97,7 @@
</div>
<div class="flex flex-row flex-wrap gap-4">
{#each things as item}
<a class="relative" href="{AppRoute.SEARCH}?{Field.OBJECTS}={item.value}" draggable="false">
<a class="relative" href="{AppRoute.SEARCH}?q={item.value}" draggable="false">
<div
class="flex w-[calc((100vw-(72px+5rem))/2)] max-w-[156px] justify-center overflow-hidden rounded-xl brightness-75 filter"
>

View File

@@ -116,7 +116,7 @@
</SettingAccordion>
<SettingAccordion title="Version Check" subtitle="Enable/disable the new version notification">
<NewVersionCheckSettings newVersionCheckConfig={configs.newVersionCheck} />
<NewVersionCheckSettings disabled={$featureFlags.configFile} newVersionCheckConfig={configs.newVersionCheck} />
</SettingAccordion>
<SettingAccordion

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB