Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/cluster-faces-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,10 @@ jobs:

- name: Set config
run: |
./occ config:app:set --value ${{ matrix.pure-js-mode }} recognize tensorflow.purejs
./occ config:app:set --lazy --value ${{ matrix.pure-js-mode }} recognize tensorflow.purejs
./occ config:app:set --value true recognize faces.enabled
# Don't force API key usage to allow tests to run
./occ config:app:set --value false recognize require_api_key
# only use one core. GH actions has 2
./occ config:app:set --value 1 recognize tensorflow.cores

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/files-scan-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ jobs:
- name: Set imagenet.enabled and concurrency.enabled
run: |
./occ config:app:set --value true recognize imagenet.enabled
./occ config:app:set --value true recognize concurrency.enabled
./occ config:app:set --lazy --value true recognize concurrency.enabled

- name: Run scan
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/full-run-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ jobs:

- name: Set pure-js mode
run: |
./occ config:app:set --value ${{ matrix.pure-js-mode }} recognize tensorflow.purejs
./occ config:app:set --lazy --value ${{ matrix.pure-js-mode }} recognize tensorflow.purejs

- name: Set imagenet.enabled
run: |
Expand Down
6 changes: 3 additions & 3 deletions lib/Classifiers/Audio/MusicnnClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function __construct(Logger $logger, IAppConfig $config, TagManager $tagM

#[Override]
public function classify(array $queueFiles): void {
if ($this->config->getAppValueString('tensorflow.purejs', 'false') === 'true') {
if ($this->config->getAppValueString('tensorflow.purejs', 'false', lazy: true) === 'true') {
$timeout = self::AUDIO_PUREJS_TIMEOUT;
} else {
$timeout = self::AUDIO_TIMEOUT;
Expand All @@ -43,8 +43,8 @@ public function classify(array $queueFiles): void {
*/
foreach ($classifierProcess as $queueFile => $results) {
$this->tagManager->assignTags($queueFile->getFileId(), $results);
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true');
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time());
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true', lazy: true);
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time(), lazy: true);
}
}
}
10 changes: 5 additions & 5 deletions lib/Classifiers/Classifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,15 @@ public function classifyFiles(string $model, array $queueFiles, int $timeout): \
$this->logger->debug('Classifying '.var_export($paths, true));

$command = [
$this->config->getAppValueString('node_binary'),
$this->config->getAppValueString('node_binary', lazy: true),
dirname(__DIR__, 2) . '/src/classifier_'.$model.'.js',
'-'
];

if (trim($this->config->getAppValueString('nice_binary', '')) !== '') {
if (trim($this->config->getAppValueString('nice_binary', '', lazy: true)) !== '') {
$command = [
$this->config->getAppValueString('nice_binary'),
"-" . $this->config->getAppValueString('nice_value', '0'),
$this->config->getAppValueString('nice_binary', lazy: true),
"-" . $this->config->getAppValueString('nice_value', '0', lazy: true),
...$command,
];
}
Expand All @@ -179,7 +179,7 @@ public function classifyFiles(string $model, array $queueFiles, int $timeout): \
if ($this->config->getAppValueString('tensorflow.gpu', 'false') === 'true') {
$env['RECOGNIZE_GPU'] = 'true';
}
if ($this->config->getAppValueString('tensorflow.purejs', 'false') === 'true') {
if ($this->config->getAppValueString('tensorflow.purejs', 'false', lazy: true) === 'true') {
$env['RECOGNIZE_PUREJS'] = 'true';
}
// Set cores
Expand Down
6 changes: 3 additions & 3 deletions lib/Classifiers/Images/ClusteringFaceClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ private function getUsersWithFileAccess(Node $node): array {

#[Override]
public function classify(array $queueFiles): void {
if ($this->config->getAppValueString('tensorflow.purejs', 'false') === 'true') {
if ($this->config->getAppValueString('tensorflow.purejs', 'false', lazy: true) === 'true') {
$timeout = self::IMAGE_PUREJS_TIMEOUT;
} else {
$timeout = self::IMAGE_TIMEOUT;
Expand Down Expand Up @@ -134,8 +134,8 @@ public function classify(array $queueFiles): void {
$this->logger->debug('scheduling ClusterFacesJob for user ' . $userId);
$this->jobList->add(ClusterFacesJob::class, ['userId' => $userId]);
}
$this->config->setAppValueString(self::MODEL_NAME . '.status', 'true');
$this->config->setAppValueString(self::MODEL_NAME . '.lastFile', (string)time());
$this->config->setAppValueString(self::MODEL_NAME . '.status', 'true', lazy: true);
$this->config->setAppValueString(self::MODEL_NAME . '.lastFile', (string)time(), lazy: true);
}
}
$this->logger->debug('face classifier end');
Expand Down
6 changes: 3 additions & 3 deletions lib/Classifiers/Images/ImagenetClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __construct(Logger $logger, IAppConfig $config, TagManager $tagM

#[Override]
public function classify(array $queueFiles): void {
if ($this->config->getAppValueString('tensorflow.purejs', 'false') === 'true') {
if ($this->config->getAppValueString('tensorflow.purejs', 'false', lazy: true) === 'true') {
$timeout = self::IMAGE_PUREJS_TIMEOUT;
} else {
$timeout = self::IMAGE_TIMEOUT;
Expand All @@ -47,8 +47,8 @@ public function classify(array $queueFiles): void {
$landmarkTags = array_filter($results, static function ($tagName) {
return in_array($tagName, LandmarksClassifier::PRECONDITION_TAGS);
});
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true');
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time());
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true', lazy: true);
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time(), lazy: true);

if (count($landmarkTags) > 0) {
try {
Expand Down
6 changes: 3 additions & 3 deletions lib/Classifiers/Images/LandmarksClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __construct(Logger $logger, IAppConfig $config, TagManager $tagM

#[Override]
public function classify(array $queueFiles): void {
if ($this->config->getAppValueString('tensorflow.purejs', 'false') === 'true') {
if ($this->config->getAppValueString('tensorflow.purejs', 'false', lazy: true) === 'true') {
$timeout = self::IMAGE_PUREJS_TIMEOUT;
} else {
$timeout = self::IMAGE_TIMEOUT;
Expand All @@ -44,8 +44,8 @@ public function classify(array $queueFiles): void {
/** @var list<string> $results */
foreach ($classifierProcess as $queueFile => $results) {
$this->tagManager->assignTags($queueFile->getFileId(), $results);
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true');
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time());
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true', lazy: true);
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time(), lazy: true);
}
}
}
6 changes: 3 additions & 3 deletions lib/Classifiers/Video/MovinetClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function __construct(Logger $logger, IAppConfig $config, TagManager $tagM

#[Override]
public function classify(array $queueFiles): void {
if ($this->config->getAppValueString('tensorflow.purejs', 'false') === 'true') {
if ($this->config->getAppValueString('tensorflow.purejs', 'false', lazy: true) === 'true') {
throw new Exception('Movinet does not support WASM mode');
} else {
$timeout = self::VIDEO_TIMEOUT;
Expand All @@ -42,8 +42,8 @@ public function classify(array $queueFiles): void {
/** @var list<string> $results */
foreach ($classifierProcess as $queueFile => $results) {
$this->tagManager->assignTags($queueFile->getFileId(), $results);
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true');
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time());
$this->config->setAppValueString(self::MODEL_NAME.'.status', 'true', lazy: true);
$this->config->setAppValueString(self::MODEL_NAME.'.lastFile', (string)time(), lazy: true);
}
}
}
8 changes: 4 additions & 4 deletions lib/Controller/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,17 @@ public function musl(): JSONResponse {

public function nice(): JSONResponse {
/* use nice binary from settings if available */
if ($this->config->getAppValueString('nice_binary', '') !== '') {
$nice_path = $this->config->getAppValueString('nice_binary');
if ($this->config->getAppValueString('nice_binary', '', lazy: true) !== '') {
$nice_path = $this->config->getAppValueString('nice_binary', lazy: true);
} else {
/* returns the path to the nice binary or false if not found */
$nice_path = $this->binaryFinder->findBinaryPath('nice');
}

if ($nice_path !== false) {
$this->config->setAppValueString('nice_binary', $nice_path);
$this->config->setAppValueString('nice_binary', $nice_path, lazy: true);
} else {
$this->config->setAppValueString('nice_binary', '');
$this->config->setAppValueString('nice_binary', '', lazy: true);
return new JSONResponse(['nice' => false]);
}

Expand Down
5 changes: 5 additions & 0 deletions lib/Dav/Faces/PropFindPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use OCA\Recognize\Db\FaceDetectionWithTitle;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\AppFramework\Services\IAppConfig;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\DB\Exception;
use OCP\Files\DavUtil;
Expand Down Expand Up @@ -47,6 +48,7 @@ public function __construct(
private ICrypto $crypto,
private LoggerInterface $logger,
private ITimeFactory $timeFactory,
private IAppConfig $appConfig,
) {
}

Expand Down Expand Up @@ -130,6 +132,9 @@ public function beforeMethod(RequestInterface $request, ResponseInterface $respo
if (!str_starts_with($request->getPath(), 'recognize')) {
return;
}
if ($this->appConfig->getAppValueString('require_api_key', 'true') !== 'true') {
return;
}
$key = $request->getHeader('X-Recognize-Api-Key');
if ($key === null) {
throw new Forbidden('You must provide a valid X-Recognize-Api-Key');
Expand Down
24 changes: 12 additions & 12 deletions lib/Migration/InstallDeps.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function getName(): string {

public function run(IOutput $output): void {
try {
$existingBinary = $this->config->getAppValueString('node_binary', '');
$existingBinary = $this->config->getAppValueString('node_binary', '', lazy: true);
if ($existingBinary !== '') {
$version = $this->testBinary($existingBinary);
if ($version === null) {
Expand All @@ -86,7 +86,7 @@ public function run(IOutput $output): void {

$this->setBinariesPermissions();

$binaryPath = $this->config->getAppValueString('node_binary', '');
$binaryPath = $this->config->getAppValueString('node_binary', '', lazy: true);

$this->runTfjsInstall($binaryPath);
$this->runFfmpegInstall($binaryPath);
Expand All @@ -102,17 +102,17 @@ public function run(IOutput $output): void {

protected function setNiceBinaryPath() : void {
/* use nice binary from settings if available */
if ($this->config->getAppValueString('nice_binary', '') !== '') {
$nice_path = $this->config->getAppValueString('nice_binary');
if ($this->config->getAppValueString('nice_binary', '', lazy: true) !== '') {
$nice_path = $this->config->getAppValueString('nice_binary', lazy: true);
} else {
/* returns the path to the nice binary or false if not found */
$nice_path = $this->binaryFinder->findBinaryPath('nice');
}

if ($nice_path !== false) {
$this->config->setAppValueString('nice_binary', $nice_path);
$this->config->setAppValueString('nice_binary', $nice_path, lazy: true);
} else {
$this->config->setAppValueString('nice_binary', '');
$this->config->setAppValueString('nice_binary', '', lazy: true);
}
}

Expand Down Expand Up @@ -155,12 +155,12 @@ protected function installNodeBinary(IOutput $output) : void {
}

// Write the app config
$this->config->setAppValueString('node_binary', $binaryPath);
$this->config->setAppValueString('node_binary', $binaryPath, lazy: true);

$supportsAVX = $this->isAVXSupported();
if ($isARM || $isMusl || !$supportsAVX) {
$output->info('Enabling purejs mode (isMusl='.$isMusl.', isARM='.$isARM.', supportsAVX='.$supportsAVX.')');
$this->config->setAppValueString('tensorflow.purejs', 'true');
$this->config->setAppValueString('tensorflow.purejs', 'true', lazy: true);
}
}

Expand Down Expand Up @@ -238,17 +238,17 @@ protected function runFfmpegInstall(string $nodeBinary): void {

protected function setFfmpegBinaryPath() : void {
/* use nice binary from settings if available */
if ($this->config->getAppValueString('ffmpeg_binary', '') !== '') {
$ffmpeg_path = $this->config->getAppValueString('ffmpeg_binary');
if ($this->config->getAppValueString('ffmpeg_binary', '', lazy: true) !== '') {
$ffmpeg_path = $this->config->getAppValueString('ffmpeg_binary', lazy: true);
} else {
/* returns the path to the nice binary or false if not found */
$ffmpeg_path = $this->binaryFinder->findBinaryPath('ffmpeg');
}

if ($ffmpeg_path !== false) {
$this->config->setAppValueString('ffmpeg_binary', $ffmpeg_path);
$this->config->setAppValueString('ffmpeg_binary', $ffmpeg_path, lazy: true);
} else {
$this->config->setAppValueString('ffmpeg_binary', __DIR__ . '/../../node_modules/ffmpeg-static/ffmpeg');
$this->config->setAppValueString('ffmpeg_binary', __DIR__ . '/../../node_modules/ffmpeg-static/ffmpeg', lazy: true);
}
}

Expand Down
32 changes: 32 additions & 0 deletions lib/Migration/Version011000002Date20260129094821.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/*
* Copyright (c) 2020-2025 The Recognize contributors.
* This file is licensed under the Affero General Public License version 3 or later. See the COPYING file.
*/
declare(strict_types=1);
namespace OCA\Recognize\Migration;

use Closure;
use OCA\Recognize\Service\SettingsService;
use OCP\AppFramework\Services\IAppConfig;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

final class Version011000002Date20260129094821 extends SimpleMigrationStep {

public function __construct(
private IAppConfig $appConfig,
) {
}

public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
foreach (SettingsService::LAZY_SETTINGS as $settingsKey) {
if ($this->appConfig->hasAppKey($settingsKey, lazy: false)) {
$value = $this->appConfig->getAppValueString($settingsKey);
$this->appConfig->deleteAppValue($settingsKey);
$this->appConfig->setAppValueString($settingsKey, $value, lazy: true);
}
}
}
}
37 changes: 35 additions & 2 deletions lib/Service/SettingsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,31 @@ final class SettingsService {
'movinet.batchSize' => '5',
'musicnn.batchSize' => '20',
];
public const LAZY_SETTINGS = [
'tensorflow.purejs',
'node_binary',
'nice_binary',
'nice_value',
'ffmpeg_binary',
'clusterFaces.status',
'faces.status',
'imagenet.status',
'landmarks.status',
'movinet.status',
'musicnn.status',
'faces.lastFile',
'imagenet.lastFile',
'landmarks.lastFile',
'movinet.lastFile',
'musicnn.lastFile',
'clusterFaces.lastRun',
'faces.batchSize',
'imagenet.batchSize',
'landmarks.batchSize',
'movinet.batchSize',
'musicnn.batchSize',
'concurrency.enabled'
];

private IAppConfig $config;
private IJobList $jobList;
Expand All @@ -80,7 +105,11 @@ public function getSetting(string $key): string {
if (strpos($key, 'batchSize') !== false) {
return $this->config->getAppValueString($key, $this->getSetting('tensorflow.purejs') === 'false' ? self::DEFAULTS[$key] : self::PUREJS_DEFAULTS[$key]);
}
return $this->config->getAppValueString($key, self::DEFAULTS[$key]);
$lazy = false;
if (in_array($key, self::LAZY_SETTINGS, true)) {
$lazy = true;
}
return $this->config->getAppValueString($key, self::DEFAULTS[$key], lazy: $lazy);
}

/**
Expand Down Expand Up @@ -115,7 +144,11 @@ public function setSetting(string $key, string $value): void {
break;
}
}
$this->config->setAppValueString($key, $value);
$lazy = false;
if (in_array($key, self::LAZY_SETTINGS, true)) {
$lazy = true;
}
$this->config->setAppValueString($key, $value, lazy: $lazy);
}

/**
Expand Down
Loading
Loading