Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
e7f7fd1
squash
ildyria Apr 6, 2026
e8d5a72
fix
ildyria Apr 6, 2026
859bf81
fix ty
ildyria Apr 6, 2026
c454fd7
progress but still not ready
ildyria Apr 6, 2026
073de50
WIP still broken
ildyria Apr 8, 2026
20dc32f
more work
ildyria Apr 9, 2026
21872eb
Merge branch 'master' into assisted-vision
ildyria Apr 10, 2026
fe5983c
Merge branch 'master' into assisted-vision
ildyria Apr 10, 2026
f8d0353
disable AI vision for now
ildyria Apr 10, 2026
8f440eb
fixes
ildyria Apr 11, 2026
7229e5c
Merge branch 'pr/ildyria/4280' into assisted-vision
ildyria Apr 11, 2026
9b11422
WIP
ildyria Apr 11, 2026
f2595e6
more work
ildyria Apr 11, 2026
a80de73
more things
ildyria Apr 11, 2026
f077258
Merge branch 'master' into assisted-vision
ildyria Apr 11, 2026
e5f9037
feat(feature-30): implement policy gates, request authorizers, and ri…
Copilot Apr 11, 2026
231f575
docs: tick T-030-93 through T-030-103 as completed in tasks.md
Copilot Apr 11, 2026
86b29ab
Merge branch 'master' into assisted-vision
ildyria Apr 11, 2026
0e34152
Merge branch 'master' into assisted-vision
ildyria Apr 12, 2026
cdffae9
fixes
ildyria Apr 12, 2026
5f9e727
Fix language
ildyria Apr 12, 2026
092f616
Fix ty
ildyria Apr 12, 2026
4ccc43b
more fixes
ildyria Apr 12, 2026
74ff1de
more fixes
ildyria Apr 12, 2026
00cc766
Merge branch 'master' into assisted-vision
ildyria Apr 24, 2026
d0d056e
fix open questions
ildyria Apr 24, 2026
2bf7023
feat: migrate face recognition from InsightFace to DeepFace (MIT lice…
Copilot Apr 25, 2026
34b3daa
fixes
ildyria Apr 25, 2026
800fc6e
fixes
ildyria Apr 25, 2026
90acda6
force python 3.13
ildyria Apr 25, 2026
5538bd2
fix
ildyria Apr 25, 2026
1efba6b
fixes
ildyria Apr 26, 2026
4ef17a5
Add configuration data
ildyria May 1, 2026
dac77c8
feat(ai-vision): add min_face_size_pixels filter before laplacian che…
Copilot May 4, 2026
1ec0559
Merge branch 'master' into assisted-vision
ildyria May 5, 2026
8003352
fix formatting
ildyria May 5, 2026
43d61ba
Merge branch 'master' into assisted-vision
ildyria May 19, 2026
44e5280
Merge branch 'master' into assisted-vision
ildyria May 22, 2026
343e5d4
fixes
ildyria May 22, 2026
2354f9d
bump uv lock
ildyria May 22, 2026
8f20e82
Merge branch 'master' into assisted-vision
ildyria May 29, 2026
fc26268
Merge branch 'master' into assisted-vision
ildyria Jun 11, 2026
8e1009c
Merge branch 'master' into assisted-vision
ildyria Jun 12, 2026
f242f5d
Improvements
ildyria Jun 12, 2026
90e0ac8
progress
ildyria Jun 13, 2026
b2e6c67
Move it elsewhere
ildyria Jun 14, 2026
4fada48
also remove pipeline
ildyria Jun 14, 2026
9d2fb06
Merge branch 'master' into assisted-vision
ildyria Jun 15, 2026
260b19d
more fixes
ildyria Jun 16, 2026
39cd690
Merge branch 'master' into assisted-vision
ildyria Jun 16, 2026
0b4c24d
fixes
ildyria Jun 16, 2026
aec4a2f
Merge branch 'master' into assisted-vision
ildyria Jun 16, 2026
b682608
Merge branch 'master' into assisted-vision
ildyria Jun 16, 2026
1f8693b
fix
ildyria Jun 16, 2026
b46b6dd
fix table test
ildyria Jun 17, 2026
e406ca6
fix lang tests
ildyria Jun 17, 2026
080e5e8
fix test
ildyria Jun 17, 2026
6ae3ba6
Group AI Vision tests
ildyria Jun 17, 2026
6eab532
fix test
ildyria Jun 17, 2026
b7ec85e
simplify
ildyria Jun 17, 2026
662373b
fix
ildyria Jun 17, 2026
4a94c95
Merge branch 'master' into assisted-vision
ildyria Jun 17, 2026
fb8cb58
Refactoring
ildyria Jun 17, 2026
02d76f3
Merge branch 'master' into assisted-vision
ildyria Jun 17, 2026
9ffcb7f
refactoring
ildyria Jun 17, 2026
eaf5f09
more tests
ildyria Jun 18, 2026
035d50e
fix tests
ildyria Jun 19, 2026
7e256bc
fix formatting
ildyria Jun 19, 2026
8d0844a
fix
ildyria Jun 19, 2026
2dcad07
fix
ildyria Jun 19, 2026
cb7051a
fixes
ildyria Jun 19, 2026
37587fa
fix tests
ildyria Jun 19, 2026
483e800
more tests
ildyria Jun 19, 2026
3096953
progress
ildyria Jun 20, 2026
e77125b
Do not require SE
ildyria Jun 21, 2026
a675db7
Add more tests
ildyria Jun 21, 2026
64bfd92
Formatting
ildyria Jun 21, 2026
e23f5a3
Improve docker-compose
ildyria Jun 21, 2026
e4b06af
Merge branch 'master' into assisted-vision
ildyria Jun 21, 2026
0be4fbb
fix tests
ildyria Jun 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ vite/*
secrets/*
# Local testing @ildyria
public/uploads-bck/*
public/uploads/*
*.sql

# Node
node_modules/
Expand All @@ -56,8 +58,12 @@ npm-debug.log
# Mapping for database and config used by docker compose
lychee/*

# Python
ai-vision-service/*

# Laravel
/storage/logs/*
/storage/tmp/*
/storage/framework/cache/*
/storage/framework/sessions/*
/storage/framework/views/*
Expand Down
3 changes: 0 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ updates:
dependency-type: "production"
development-dependencies:
dependency-type: "development"
ignore:
- dependency-name: "typescript"
versions: [ ">=6.0.0" ]

- package-ecosystem: composer
directory: /
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@ jobs:
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: 'Dependency Review'
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
# with:
# # No fix available yet
# # Note that the model is directly baked into the inage
# # So the risk is limited.
# allow-ghsas: GHSA-hqmj-h5c6-369m
3 changes: 3 additions & 0 deletions .github/workflows/php_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
- Webshop
- ImageProcessing
- Precomputing
- AssistedVision
exclude:
# Some skips to reduce the number of runs
- php-version: 8.4
Expand All @@ -45,6 +46,8 @@ jobs:
test-suite: ImageProcessing
- php-version: 8.4
test-suite: Precomputing
- php-version: 8.4
test-suite: AssistedVision
# Service containers to run with `container-job`
services:
# Label used to access the service container
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ clover.xml
.NO_AUTO_COMPOSER_MIGRATE
storage/bootstrap/cache/*
storage/image-jobs/*
**/__pycache__/**
.coverage

# used by Vite
public/hot
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ test_ImageProcessing:
test_precomputing:
vendor/bin/phpunit --testsuite Precomputing --stop-on-failure --stop-on-error --no-coverage --log-junit report_precomputing.xml

test_assisted_vision:
vendor/bin/phpunit --testsuite AssistedVision --stop-on-failure --stop-on-error --no-coverage --log-junit report_assisted_vision.xml

test_v2:
vendor/bin/phpunit --testsuite Feature_v2 --stop-on-failure --stop-on-error --no-coverage --log-junit report_v2.xml

Expand Down
2 changes: 1 addition & 1 deletion app/Actions/Albums/Flow.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private function getQuery(Album|null $base, bool $with_relations): AlbumBuilder
'min_privilege_cover', 'min_privilege_cover.size_variants',
'statistics',
'photos',
'photos.statistics', 'photos.size_variants', 'photos.palette', 'photos.tags', 'photos.rating']);
'photos.statistics', 'photos.size_variants', 'photos.palette', 'photos.tags', 'photos.rating', 'photos.faces', 'photos.faces.person', ]);
}

// Only join what we need for ordering.
Expand Down
4 changes: 4 additions & 0 deletions app/Actions/Diagnostics/Errors.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
namespace App\Actions\Diagnostics;

use App\Actions\Diagnostics\Pipes\Checks\AdminUserExistsCheck;
use App\Actions\Diagnostics\Pipes\Checks\AiVisionServiceCheck;
use App\Actions\Diagnostics\Pipes\Checks\AiVisionServiceConfigCheck;
use App\Actions\Diagnostics\Pipes\Checks\AppUrlMatchCheck;
use App\Actions\Diagnostics\Pipes\Checks\AuthDisabledCheck;
use App\Actions\Diagnostics\Pipes\Checks\BasicPermissionCheck;
Expand Down Expand Up @@ -76,6 +78,8 @@ class Errors
SupporterCheck::class,
ImagickPdfCheck::class,
WatermarkerEnabledCheck::class,
AiVisionServiceCheck::class,
AiVisionServiceConfigCheck::class,
StatisticsIntegrityCheck::class,
WebshopCheck::class,
SecurityAdvisoriesCheck::class,
Expand Down
116 changes: 116 additions & 0 deletions app/Actions/Diagnostics/Pipes/Checks/AiVisionServiceCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

/**
* SPDX-License-Identifier: MIT
* Copyright (c) 2017-2018 Tobias Reich
* Copyright (c) 2018-2026 LycheeOrg.
*/

namespace App\Actions\Diagnostics\Pipes\Checks;

use App\Contracts\DiagnosticPipe;
use App\DTO\DiagnosticData;
use App\Repositories\ConfigManager;
use App\Services\Image\FacialRecognitionService;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Schema;

/**
* Check if the AI Vision service is properly configured and reachable.
*/
class AiVisionServiceCheck implements DiagnosticPipe
{
public function __construct(
protected readonly ConfigManager $config_manager,
protected readonly FacialRecognitionService $facial_recognition_service,
) {
}

/**
* {@inheritDoc}
*/
public function handle(array &$data, \Closure $next): array
{
if (!Schema::hasTable('configs')) {
return $next($data);
}

// Skip check if AI Vision is disabled
if (!$this->config_manager->getValueAsBool('ai_vision_enabled')) {
return $next($data);
}

if (!$this->facial_recognition_service->isConfigured()) {
$data[] = DiagnosticData::error(
'AI Vision: Service URL is not configured. Set AI_VISION_FACE_URL in your .env file.',
self::class,
[]
);

return $next($data);
}

$this->checkServiceHealth($data);

return $next($data);
}

/**
* Check if the AI Vision service health endpoint is reachable and returns proper data.
*
* @param DiagnosticData[] &$data
*
* @return void
*/
private function checkServiceHealth(array &$data): void
{
$service_url = config('features.ai-vision-service.face-url', '');

try {
$response = $this->facial_recognition_service->checkHealthRaw(5);

if (!$response->successful()) {
$data[] = DiagnosticData::error(
'AI Vision: Service health check failed with status ' . $response->status() . '. The service may be offline or unreachable.',
self::class,
['Check that the AI Vision service is running at: ' . $service_url]
);

return;
}

$health_data = $response->json();
if (!is_array($health_data) || !isset($health_data['status'])) {
$data[] = DiagnosticData::error(
'AI Vision: Service health endpoint returned invalid response format. Expected JSON with "status" field.',
self::class,
['Response: ' . $response->body()]
);

return;
}

if ($health_data['status'] !== 'ok' && $health_data['status'] !== 'healthy') {
$data[] = DiagnosticData::warn(
'AI Vision: Service reported unhealthy status: ' . $health_data['status'],
self::class,
[]
);
}
} catch (ConnectionException $e) {
$data[] = DiagnosticData::error(
'AI Vision: Could not connect to service at ' . rtrim($service_url, '/') . '/health',
self::class,
['Check that the AI Vision service is running and the URL is correct.', $e->getMessage()]
);
} catch (\Exception $e) {
// @codeCoverageIgnoreStart
$data[] = DiagnosticData::error(
'AI Vision: Service health check failed with error: ' . $e->getMessage(),
self::class,
[]
);
// @codeCoverageIgnoreEnd
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

/**
* SPDX-License-Identifier: MIT
* Copyright (c) 2017-2018 Tobias Reich
* Copyright (c) 2018-2026 LycheeOrg.
*/

namespace App\Actions\Diagnostics\Pipes\Checks;

use App\Contracts\DiagnosticPipe;
use App\DTO\DiagnosticData;
use App\Repositories\ConfigManager;
use App\Services\Image\FacialRecognitionService;
use Illuminate\Support\Facades\Schema;

/**
* In debug mode, expose the AI Vision runtime configuration in diagnostics.
*/
class AiVisionServiceConfigCheck implements DiagnosticPipe
{
public function __construct(
protected readonly ConfigManager $config_manager,
protected readonly FacialRecognitionService $facial_recognition_service,
) {
}

/**
* {@inheritDoc}
*/
public function handle(array &$data, \Closure $next): array
{
if (config('app.debug') !== true) {
return $next($data);
}

if (!Schema::hasTable('configs')) {
return $next($data);
}

if ($this->config_manager->getValueAsBool('ai_vision_enabled') !== true) {
return $next($data);
}

if (!$this->facial_recognition_service->isConfigured()) {
return $next($data);
}

$configuration = $this->facial_recognition_service->getConfiguration();
if ($configuration === null) {
$data[] = DiagnosticData::warn(
'AI Vision: Could not fetch runtime configuration from the service while APP_DEBUG is enabled.',
self::class,
[]
);

return $next($data);
}

$details = [];
foreach ($configuration as $key => $value) {
$details[] = $key . ': ' . $value;
}

$data[] = DiagnosticData::info(
'AI Vision: Runtime configuration from service (debug mode).',
self::class,
$details
);

return $next($data);
}
}
1 change: 1 addition & 0 deletions app/Actions/Photo/Create.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ private function handleStandalone(InitDTO $init_dto): Photo
Shared\GeodecodeLocation::class,
Shared\ExtractColourPalette::class,
Shared\NotifyAlbums::class,
Standalone\AutoScanFacesOnUpload::class,
];

return $this->executePipeOnDTO($pipes, $dto)->getPhoto();
Expand Down
54 changes: 54 additions & 0 deletions app/Actions/Photo/Pipes/Standalone/AutoScanFacesOnUpload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/**
* SPDX-License-Identifier: MIT
* Copyright (c) 2017-2018 Tobias Reich
* Copyright (c) 2018-2026 LycheeOrg.
*/

namespace App\Actions\Photo\Pipes\Standalone;

use App\Contracts\PhotoCreate\StandalonePipe;
use App\DTO\PhotoCreate\StandaloneDTO;
use App\Jobs\DispatchFaceScanJob;
use App\Repositories\ConfigManager;
use Illuminate\Support\Facades\Log;

/**
* Automatically trigger face scanning when a photo is uploaded,
* if the AI Vision face scanning feature is enabled.
*/
class AutoScanFacesOnUpload implements StandalonePipe
{
public function __construct(
protected readonly ConfigManager $config_manager,
) {
}

public function handle(StandaloneDTO $state, \Closure $next): StandaloneDTO
{
// Process through the rest of the pipeline first
$state = $next($state);

if ($state->photo->isPhoto() === false) {
// If this is not a photo (e.g., a video), we skip face scanning
return $state;
}

// Check if AI vision is enabled
if ($this->config_manager->getValueAsString('ai_vision_enabled') !== '1') {
return $state;
}

// Check if face scanning is enabled
if ($this->config_manager->getValueAsString('ai_vision_face_enabled') !== '1') {
return $state;
}

// Dispatch face scanning job for the uploaded photo
Log::info("AutoScanFacesOnUpload: dispatching face scan for photo {$state->photo->id}.");
DispatchFaceScanJob::dispatch($state->photo->id);

return $state;
}
}
Loading
Loading