recognize: fix compat with 3.6 (fix #500)

Signed-off-by: Varun Patil <varunpatil@ucla.edu>
pull/504/head
Varun Patil 2023-03-18 19:03:17 -07:00
parent 1e424d7e46
commit 47e2d9197f
2 changed files with 39 additions and 23 deletions

View File

@ -39,8 +39,9 @@ class PeopleController extends ApiBase
*/
public function recognizePeople(): JSONResponse
{
$user = $this->userSession->getUser();
if (null === $user) {
try {
$uid = $this->getUID();
} catch (\Exception $e) {
return Errors::NotLoggedIn();
}
@ -57,7 +58,7 @@ class PeopleController extends ApiBase
// Run actual query
$list = $this->timelineQuery->getPeopleRecognize(
$root,
$root, $uid
);
return new JSONResponse($list, Http::STATUS_OK);
@ -74,8 +75,9 @@ class PeopleController extends ApiBase
*/
public function recognizePeoplePreview(int $id): Http\Response
{
$user = $this->userSession->getUser();
if (null === $user) {
try {
$uid = $this->getUID();
} catch (\Exception $e) {
return Errors::NotLoggedIn();
}
@ -91,13 +93,13 @@ class PeopleController extends ApiBase
}
// Run actual query
$detections = $this->timelineQuery->getPeopleRecognizePreview($root, $id);
$detections = $this->timelineQuery->getPeopleRecognizePreview($root, $id, $uid);
if (null === $detections || 0 === \count($detections)) {
if (0 === \count($detections)) {
return Errors::NotFound('detections');
}
return $this->getPreviewResponse($detections, $user, 1.5);
return $this->getPreviewResponse($detections, 1.5);
}
/**
@ -183,7 +185,7 @@ class PeopleController extends ApiBase
return Errors::NotFound('detections');
}
return $this->getPreviewResponse($detections, $user, 1.8);
return $this->getPreviewResponse($detections, 1.8);
}
/**
@ -195,16 +197,17 @@ class PeopleController extends ApiBase
*/
private function getPreviewResponse(
array $detections,
\OCP\IUser $user,
float $padding
): Http\Response {
// Get preview manager
$previewManager = \OC::$server->get(\OCP\IPreview::class);
// Find the first detection that has a preview
/** @var \Imagick */
$image = null;
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
// Find the first detection that has a preview
$userFolder = $this->rootFolder->getUserFolder($this->getUID());
foreach ($detections as &$detection) {
// Get the file (also checks permissions)
$files = $userFolder->getById($detection['file_id']);

View File

@ -11,14 +11,19 @@ trait TimelineQueryPeopleRecognize
{
protected IDBConnection $connection;
public function transformPeopleRecognitionFilter(IQueryBuilder &$query, string $userId, string $faceStr, bool $isAggregate)
public function transformPeopleRecognitionFilter(IQueryBuilder $query, string $userId, string $faceStr, bool $isAggregate)
{
// Get name and uid of face user
$faceNames = explode('/', $faceStr);
if (2 !== \count($faceNames)) {
throw new \Exception('Invalid face query');
}
$faceUid = $faceNames[0];
// Starting with Recognize v3.6, the detections are duplicated for each user
// So we don't need to use the user ID provided by the user, but retain
// this here for backwards compatibility + API consistency with Face Recognition
// $faceUid = $faceNames[0];
$faceName = $faceNames[1];
if (!$isAggregate) {
@ -28,15 +33,15 @@ trait TimelineQueryPeopleRecognize
// Join with cluster
$clusterQuery = null;
if ('NULL' !== $faceName) {
if ('NULL' === $faceName) {
$clusterQuery = $query->expr()->isNull('rfd.cluster_id');
} else {
$nameField = is_numeric($faceName) ? 'rfc.id' : 'rfc.title';
$query->innerJoin('m', 'recognize_face_clusters', 'rfc', $query->expr()->andX(
$query->expr()->eq('rfc.user_id', $query->createNamedParameter($faceUid)),
$query->expr()->eq('rfc.user_id', $query->createNamedParameter($userId)),
$query->expr()->eq($nameField, $query->createNamedParameter($faceName)),
));
$clusterQuery = $query->expr()->eq('rfd.cluster_id', 'rfc.id');
} else {
$clusterQuery = $query->expr()->isNull('rfd.cluster_id');
}
// Join with detections
@ -57,7 +62,7 @@ trait TimelineQueryPeopleRecognize
);
}
public function getPeopleRecognize(TimelineRoot &$root)
public function getPeopleRecognize(TimelineRoot &$root, string $uid)
{
$query = $this->connection->getQueryBuilder();
@ -74,6 +79,9 @@ trait TimelineQueryPeopleRecognize
// WHERE these photos are in the user's requested folder recursively
$query = $this->joinFilecache($query, $root, true, false);
// WHERE this cluster belongs to the user
$query->where($query->expr()->eq('rfc.user_id', $query->createNamedParameter($uid)));
// GROUP by ID of face cluster
$query->groupBy('rfc.id');
@ -89,15 +97,15 @@ trait TimelineQueryPeopleRecognize
// Post process
foreach ($faces as &$row) {
$row['id'] = (int) $row['id'];
$row['count'] = (int) $row['count'];
$row['name'] = $row['title'];
unset($row['title']);
$row['count'] = (int) $row['count'];
}
return $faces;
}
public function getPeopleRecognizePreview(TimelineRoot &$root, int $id)
public function getPeopleRecognizePreview(TimelineRoot &$root, int $id, string $uid): array
{
$query = $this->connection->getQueryBuilder();
@ -113,7 +121,12 @@ trait TimelineQueryPeopleRecognize
'm.fileid',
'm.datetaken', // Just in case, for postgres
)->from('recognize_face_detections', 'rfd');
$query->where($query->expr()->eq('rfd.cluster_id', $query->createNamedParameter($id)));
// WHERE detection belongs to this cluster AND user
$query->where($query->expr()->andX(
$query->expr()->eq('rfd.cluster_id', $query->createNamedParameter($id)),
$query->expr()->eq('rfd.user_id', $query->createNamedParameter($uid)),
));
// WHERE these photos are memories indexed
$query->innerJoin('rfd', 'memories', 'm', $query->expr()->eq('m.fileid', 'rfd.file_id'));
@ -132,7 +145,7 @@ trait TimelineQueryPeopleRecognize
$cursor = $this->executeQueryWithCTEs($query);
$previews = $cursor->fetchAll();
if (empty($previews)) {
return null;
return [];
}
// Score the face detections