fix: API endpoints for file_uuid filtering of pending identities

- get_file_identities: UNION face_detections + file_identities
- list_identities: add file_bindings from file_identities table
- Add back /api/v1/traces/unassigned route
- Total count query now includes file_identities

Frontend can now:
- Filter pending identities by file_uuid
- Filter pending faces (unassigned traces) by file_uuid
This commit is contained in:
Accusys
2026-06-26 14:26:36 +08:00
parent bd7d8c77bf
commit d791d138f2
3 changed files with 245 additions and 18 deletions
+36 -12
View File
@@ -3836,26 +3836,50 @@ sqlx::query(
let id_table = schema::table_name("identities");
let fd_table = schema::table_name("face_detections");
let video_table = schema::table_name("videos");
let fi_table = schema::table_name("file_identities");
use sqlx::Row;
let rows = sqlx::query(&format!(
"SELECT i.id, i.uuid::text, i.name, i.metadata, \
COUNT(fd.id)::int4 as face_count, 0::int4 as speaker_count, \
MIN(fd.frame_number)::int4 as start_frame, MAX(fd.frame_number)::int4 as end_frame, \
MIN(fd.frame_number::float8 / NULLIF(v.fps, 0)) as start_time, \
MAX(fd.frame_number::float8 / NULLIF(v.fps, 0)) as end_time, \
AVG(fd.confidence)::float8 as confidence \
FROM {} fd JOIN {} i ON i.id = fd.identity_id \
JOIN {} v ON v.file_uuid = fd.file_uuid \
WHERE fd.file_uuid = $1 AND fd.identity_id IS NOT NULL \
GROUP BY i.id, i.uuid, i.name, i.metadata \
ORDER BY face_count DESC LIMIT $2 OFFSET $3",
fd_table, id_table, video_table
r#"WITH face_matched AS (
SELECT i.id, i.uuid::text, i.name, i.metadata, i.status, i.source,
COUNT(fd.id)::int4 as face_count, 0::int4 as speaker_count,
MIN(fd.frame_number)::int4 as start_frame, MAX(fd.frame_number)::int4 as end_frame,
MIN(fd.frame_number::float8 / NULLIF(v.fps, 0)) as start_time,
MAX(fd.frame_number::float8 / NULLIF(v.fps, 0)) as end_time,
AVG(fd.confidence)::float8 as confidence
FROM {} fd JOIN {} i ON i.id = fd.identity_id
JOIN {} v ON v.file_uuid = fd.file_uuid
WHERE fd.file_uuid = $1 AND fd.identity_id IS NOT NULL
GROUP BY i.id, i.uuid, i.name, i.metadata, i.status, i.source
),
file_linked AS (
SELECT i.id, i.uuid::text, i.name, i.metadata, i.status, i.source,
0::int4 as face_count, 0::int4 as speaker_count,
NULL::int4 as start_frame, NULL::int4 as end_frame,
NULL::float8 as start_time, NULL::float8 as end_time,
fi.confidence::float8 as confidence
FROM {} fi JOIN {} i ON i.id = fi.identity_id
WHERE fi.file_uuid = $1
),
combined AS (
SELECT * FROM face_matched
UNION
SELECT * FROM file_linked WHERE id NOT IN (SELECT id FROM face_matched)
)
SELECT id, uuid, name, metadata, status, source,
face_count, speaker_count, start_frame, end_frame,
start_time, end_time, confidence
FROM combined
ORDER BY face_count DESC, name ASC
LIMIT $2 OFFSET $3"#,
fd_table, id_table, video_table, fi_table, id_table
))
.bind(uuid)
.bind(limit)
.bind(offset)
.fetch_all(&self.pool)
.await?;
Ok(rows
.into_iter()
.map(|r| super::FileIdentityRecord {