nextcloud-custom-apps-face-.../git_facerecognition/lib/Service/FaceManagementService.php
2024-09-03 09:12:12 +05:00

235 lines
7.0 KiB
PHP

<?php
/**
* @copyright Copyright (c) 2020, Matias De lellis <mati86dl@gmail.com>
* @copyright Copyright (c) 2019, Branko Kokanovic <branko@kokanovic.org>
*
* @author Branko Kokanovic <branko@kokanovic.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\FaceRecognition\Service;
use OCP\IUser;
use OCP\IUserManager;
use OCA\FaceRecognition\Db\FaceMapper;
use OCA\FaceRecognition\Db\ImageMapper;
use OCA\FaceRecognition\Db\PersonMapper;
use OCA\FaceRecognition\Service\SettingsService;
/**
* Background service. Both command and cron job are calling this service for long-running background operations.
* Background processing for face recognition is comprised of several steps, called tasks. Each task is independent,
* idempotent, DI-aware logic unit that yields. Since tasks are non-preemptive, they should yield from time to time, so we son't end up
* working for more than given timeout.
*
* Tasks can be seen as normal sequential functions, but they are easier to work with,
* reason about them and test them independently. Other than that, they are really glorified functions.
*/
class FaceManagementService {
/** @var IUserManager */
private $userManager;
/** @var FaceMapper */
private $faceMapper;
/** @var ImageMapper */
private $imageMapper;
/** @var PersonMapper */
private $personMapper;
/** @var SettingsService */
private $settingsService;
public function __construct(IUserManager $userManager,
FaceMapper $faceMapper,
ImageMapper $imageMapper,
PersonMapper $personMapper,
SettingsService $settingsService)
{
$this->userManager = $userManager;
$this->faceMapper = $faceMapper;
$this->imageMapper = $imageMapper;
$this->personMapper = $personMapper;
$this->settingsService = $settingsService;
}
/**
* Check if the current model has data on db
*
* @param IUser|null $user Optional user to check
* @param Int $modelId Optional model to check
*
* @return bool
*/
public function hasData(IUser $user = null, int $modelId = -1): bool {
if ($modelId === -1) {
$modelId = $this->settingsService->getCurrentFaceModel();
}
$eligible_users = $this->getEligiblesUserId($user);
foreach ($eligible_users as $userId) {
if ($this->hasDataForUser($userId, $modelId)) {
return true;
}
}
return false;
}
/**
* Check if the current model has data on db for user
*
* @param string $user ID of user to check
* @param Int $modelId model to check
*
* @return bool
*/
public function hasDataForUser(string $userId, int $modelId): bool {
$facesCount = $this->faceMapper->countFaces($userId, $modelId);
return ($facesCount > 0);
}
/**
* Deletes all faces, images and persons found. IF no user is given, resetting is executed for all users.
*
* @param IUser|null $user Optional user to execute resetting for
*
* @return void
*/
public function resetAll(IUser $user = null): void {
$eligible_users = $this->getEligiblesUserId($user);
foreach($eligible_users as $user) {
$this->resetAllForUser($user);
}
}
/**
* Deletes all faces, images and persons found for a given user.
*
* @param string $user ID of user to execute resetting for
*
* @return void
*/
public function resetAllForUser(string $userId): void {
$this->faceMapper->deleteUserFaces($userId);
$this->personMapper->deleteUserPersons($userId);
$this->imageMapper->deleteUserImages($userId);
$this->settingsService->setUserFullScanDone(false, $userId);
}
/**
* Deletes all faces, images and persons found. If no user is given, resetting is executed for all users.
*
* @param IUser|null $user Optional user to execute resetting for
* @param Int $modelId Optional model to clean
*
* @return void
*/
public function resetModel(IUser $user = null, int $modelId = -1): void {
if ($modelId === -1) {
$modelId = $this->settingsService->getCurrentFaceModel();
}
$eligible_users = $this->getEligiblesUserId($user);
foreach($eligible_users as $userId) {
$this->resetModelForUser($userId, $modelId);
}
}
/**
* Deletes all faces, images and persons found for a given user.
*
* @param string $user ID of user to execute resetting for
* @param Int $modelId model to clean
*
* @return void
*/
public function resetModelForUser(string $userId, $modelId): void {
$this->personMapper->deleteUserModel($userId, $modelId);
$this->faceMapper->deleteUserModel($userId, $modelId);
$this->imageMapper->deleteUserModel($userId, $modelId);
$this->settingsService->setUserFullScanDone(false, $userId);
}
/**
* Reset error in images in order to re-analyze again.
* If no user is given, resetting is executed for all users.
*
* @param IUser|null $user Optional user to execute resetting for
*
* @return void
*/
public function resetImageErrors(IUser $user = null): void {
$eligible_users = $this->getEligiblesUserId($user);
foreach($eligible_users as $userId) {
$this->imageMapper->resetErrors($userId);
$this->settingsService->setUserFullScanDone(false, $userId);
}
}
/**
* Eliminate all faces relations with person.
* If no user is given, resetting is executed for all users.
*
* @param IUser|null $user Optional user to execute resetting for
*
* @return void
*/
public function resetClusters(IUser $user = null): void {
$eligible_users = $this->getEligiblesUserId($user);
foreach($eligible_users as $user) {
$this->resetClustersForUser($user);
}
}
/**
* Eliminate all faces relations with person.
*
* @param string $user ID of user to execute resetting for
*
* @return void
*/
public function resetClustersForUser(string $userId): void {
$model = $this->settingsService->getCurrentFaceModel();
$this->faceMapper->unsetPersonsRelationForUser($userId, $model);
$this->personMapper->deleteUserPersons($userId);
}
/**
* Get an array with the eligibles users taking into account the user argument,
* or all users.
*
* @param IUser|null $user Optional user to get specific user.
*/
private function getEligiblesUserId(IUser $user = null): array {
$eligible_users = array();
if (is_null($user)) {
$this->userManager->callForAllUsers(function (IUser $user) use (&$eligible_users) {
$eligible_users[] = $user->getUID();
});
} else {
$eligible_users[] = $user->getUID();
}
return $eligible_users;
}
}