feat: add counting bench, triage, and dataset modules

This commit includes major additions and updates to the frontend and backend architectures, introducing new dataset management, live counting features, batch processing, and triage logic. Includes new UI pages, components, and API routes.
This commit is contained in:
asus committed 2026-08-14 16:28:52 +07:00
1 parent 8285400254
commit 5c7c122105
80 files changed
+20074 -1412

No files matched your search

+39
View File
@@ -220,6 +220,45 @@ def delete(annotation_id: int) -> bool:
return cur.rowcount > 0
def delete_many(annotation_ids: List[int]) -> int:
"""Drop a marquee's worth of shapes in one statement.
One DELETE per shape would be one request per shape from the editor, and a
marquee over a dense frame routinely covers a hundred (REQ-045a)."""
if not annotation_ids:
return 0
marks = ",".join("?" * len(annotation_ids))
with db.cursor() as cur:
cur.execute(f"DELETE FROM annotations WHERE id IN ({marks})", annotation_ids)
return cur.rowcount
def reclass_many(annotation_ids: List[int], class_id: int) -> int:
if not annotation_ids:
return 0
with db.cursor() as cur:
cur.execute(
"""SELECT DISTINCT b.project_id FROM annotations a
JOIN frames f ON f.id = a.frame_id
JOIN batches b ON b.id = f.batch_id
WHERE a.id IN (%s)""" % ",".join("?" * len(annotation_ids)),
annotation_ids,
)
projects = [row[0] for row in cur.fetchall()]
for project_id in projects:
_check_class(project_id, class_id)
marks = ",".join("?" * len(annotation_ids))
with db.cursor() as cur:
# Same rule as update(): a hand decision makes these the user's shapes,
# so a re-run of auto-annotation leaves them alone (REQ-034).
cur.execute(
f"UPDATE annotations SET class_id = ?, source = 'manual' WHERE id IN ({marks})",
[class_id, *annotation_ids],
)
return cur.rowcount
def replace_auto(frame_id: int, items: List[dict]) -> int:
"""Swap this frame's automatic shapes for a fresh set, leaving manual ones."""
with db.cursor() as cur: