2021-09-18 15:32:39 +02:00
|
|
|
package search
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/photoprism/photoprism/internal/entity"
|
|
|
|
"github.com/photoprism/photoprism/internal/form"
|
|
|
|
"github.com/photoprism/photoprism/pkg/txt"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Faces searches faces and returns them.
|
|
|
|
func Faces(f form.FaceSearch) (results FaceResults, err error) {
|
|
|
|
if err := f.ParseQueryString(); err != nil {
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
2021-10-06 11:19:07 +02:00
|
|
|
facesTable := entity.Face{}.TableName()
|
|
|
|
|
2021-09-18 15:32:39 +02:00
|
|
|
// Base query.
|
2021-10-06 11:19:07 +02:00
|
|
|
s := UnscopedDb().Table(facesTable)
|
|
|
|
|
|
|
|
if f.Markers {
|
|
|
|
s = s.Select(fmt.Sprintf(`%s.*, m.marker_uid, m.file_uid, m.marker_name, m.subj_src, m.marker_src,
|
|
|
|
m.marker_type, m.marker_review, m.marker_invalid, m.size, m.score, m.thumb, m.face_dist`, facesTable))
|
|
|
|
|
|
|
|
if txt.Yes(f.Unknown) {
|
|
|
|
s = s.Joins(`JOIN (
|
|
|
|
SELECT face_id, MIN(marker_uid) AS marker_uid FROM markers
|
|
|
|
WHERE face_id <> '' AND subj_uid = '' AND marker_name = '' AND marker_type = 'face' AND marker_src = 'image'
|
|
|
|
AND marker_invalid = 0 AND face_dist <= 0.64 AND size >= 80 AND score >= 15
|
|
|
|
GROUP BY face_id) fm
|
|
|
|
ON faces.id = fm.face_id`)
|
|
|
|
} else if txt.No(f.Unknown) {
|
|
|
|
s = s.Joins(`JOIN (
|
|
|
|
SELECT face_id, MIN(marker_uid) AS marker_uid FROM markers
|
|
|
|
WHERE face_id <> '' AND subj_uid <> '' AND marker_name <> '' AND marker_type = 'face' AND marker_src = 'image'
|
|
|
|
AND marker_invalid = 0 AND face_dist <= 0.64 AND size >= 80 AND score >= 15
|
|
|
|
GROUP BY face_id) fm
|
|
|
|
ON faces.id = fm.face_id`)
|
|
|
|
} else {
|
|
|
|
s = s.Joins(`JOIN (
|
|
|
|
SELECT face_id, MIN(marker_uid) AS marker_uid FROM markers
|
|
|
|
WHERE face_id <> '' AND marker_type = 'face' AND marker_src = 'image'
|
|
|
|
AND marker_invalid = 0 AND face_dist <= 0.64 AND size >= 80 AND score >= 15
|
|
|
|
GROUP BY face_id) fm
|
|
|
|
ON faces.id = fm.face_id`)
|
|
|
|
}
|
|
|
|
|
|
|
|
s = s.Joins("JOIN markers m ON m.marker_uid = fm.marker_uid")
|
|
|
|
} else {
|
|
|
|
s = s.Select(fmt.Sprintf(`%s.*`, facesTable))
|
|
|
|
}
|
2021-09-18 15:32:39 +02:00
|
|
|
|
|
|
|
// Limit result count.
|
|
|
|
if f.Count > 0 && f.Count <= MaxResults {
|
|
|
|
s = s.Limit(f.Count).Offset(f.Offset)
|
|
|
|
} else {
|
|
|
|
s = s.Limit(MaxResults).Offset(f.Offset)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set sort order.
|
|
|
|
switch f.Order {
|
|
|
|
case "subject":
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Order(fmt.Sprintf("%s.subj_uid", facesTable))
|
2021-09-18 15:32:39 +02:00
|
|
|
case "added":
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Order(fmt.Sprintf("%s.created_at DESC", facesTable))
|
2021-10-05 20:28:08 +02:00
|
|
|
case "samples":
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Order(fmt.Sprintf("%s.samples DESC, %s.id", facesTable, facesTable))
|
2021-09-18 15:32:39 +02:00
|
|
|
default:
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Order(fmt.Sprintf("%s.samples DESC, %s.id", facesTable, facesTable))
|
2021-10-05 20:28:08 +02:00
|
|
|
}
|
|
|
|
|
2021-09-18 15:32:39 +02:00
|
|
|
// Find specific IDs?
|
|
|
|
if f.ID != "" {
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Where(fmt.Sprintf("%s.id IN (?)", facesTable), strings.Split(strings.ToUpper(f.ID), txt.Or))
|
2021-09-18 15:32:39 +02:00
|
|
|
|
|
|
|
if result := s.Scan(&results); result.Error != nil {
|
|
|
|
return results, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
2021-09-18 20:41:30 +02:00
|
|
|
// Exclude unknown faces?
|
|
|
|
if txt.Yes(f.Unknown) {
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Where(fmt.Sprintf("%s.subj_uid = '' OR %s.subj_uid IS NULL", facesTable, facesTable))
|
2021-09-18 20:41:30 +02:00
|
|
|
} else if txt.No(f.Unknown) {
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Where(fmt.Sprintf("%s.subj_uid <> '' AND %s.subj_uid IS NOT NULL", facesTable, facesTable))
|
2021-09-18 20:41:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exclude hidden faces?
|
|
|
|
if f.Hidden == "" || txt.No(f.Hidden) {
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Where(fmt.Sprintf("%s.face_hidden = 0 OR %s.face_hidden IS NULL", facesTable, facesTable))
|
2021-09-18 20:41:30 +02:00
|
|
|
} else if txt.Yes(f.Hidden) {
|
2021-10-06 11:19:07 +02:00
|
|
|
s = s.Where(fmt.Sprintf("%s.face_hidden = 1", facesTable))
|
2021-09-18 15:32:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Perform query.
|
|
|
|
if res := s.Scan(&results); res.Error != nil {
|
|
|
|
return results, res.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|