Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
32175e1
feat(api): add SequenceGroup table + sequence_group_id FK
MateoLostanlen May 10, 2026
02cbfe1
feat(api): expose GET /sequence_groups/{id} + assign endpoint
MateoLostanlen May 10, 2026
d96f0b1
feat(api): add POST /annotations/sequences/bulk
MateoLostanlen May 10, 2026
b3bffcf
feat(scripts): add assign_groups script and chain into make pull-sequ…
MateoLostanlen May 10, 2026
0ececf5
feat(frontend): add minimal sequence group review page
MateoLostanlen May 10, 2026
24e4b02
test: cover assign-groups + bulk-annotate flow
MateoLostanlen May 10, 2026
409bffc
fix: address codex review on sequence-groups
MateoLostanlen May 10, 2026
c0eebc2
feat(api): list sequence groups + expose first-detection bbox per member
MateoLostanlen May 10, 2026
57ba2fe
feat(frontend): groups list page + bbox overlay on review thumbnails
MateoLostanlen May 10, 2026
0adf544
fix(api): pass unique=False to apaginate on the groups list
MateoLostanlen May 10, 2026
5a01716
feat: validated groups + per-sequence annotation propagation
MateoLostanlen May 10, 2026
8af08bd
fix(api): assign-groups inherits label even when import.py created a …
MateoLostanlen May 10, 2026
4f7d009
tweak: cross-sequence grouping IoU 0.5 -> 0.3
MateoLostanlen May 10, 2026
fc3f450
feat(api): hide singleton groups from the list endpoint
MateoLostanlen May 10, 2026
ff70439
fix: address codex review on sequence-groups (round 3)
MateoLostanlen May 11, 2026
f363e37
ux(frontend): groups-first nav, default unlabeled filter, bigger thum…
MateoLostanlen May 11, 2026
74f6554
fix: address codex review on sequence-groups (round 4)
MateoLostanlen May 11, 2026
55c52a7
fix: address reviewer findings on sequence-groups
MateoLostanlen May 11, 2026
82b6f4c
fix(frontend): surface group_propagation_warning to the annotator
MateoLostanlen May 11, 2026
e146e28
fix(frontend): make group_propagation_warning sticky, block auto-advance
MateoLostanlen May 11, 2026
fc5b52f
fix(frontend): address codex on the propagation-warning banner
MateoLostanlen May 11, 2026
c0b45fa
fix: address review findings on sequence-groups PR
MateoLostanlen May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions annotation_api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ migrate-up:

# --- 1A. Sequence annotation workflow ---

# Duplicate N sequences from the remote annotation API into the local one.
# Duplicate N sequences from the remote annotation API into the local one,
# then run assign-groups so newly-pulled sequences get clustered and inherit
# any existing group's label automatically.
# Usage: make pull-sequences [MAX_SEQUENCES=10] [CLONE_STAGE=ready_to_annotate]
pull-sequences:
uv run python -m scripts.data_transfer.ingestion.platform.import \
Expand All @@ -135,6 +137,15 @@ pull-sequences:
--max-sequences $(MAX_SEQUENCES) \
--clone-processing-stage $(CLONE_STAGE) \
--loglevel $(LOGLEVEL)
$(MAKE) assign-groups

# Compute group memberships and inherit labels for unassigned sequences.
# Single-threaded by contract — only safe to run sequentially after an import.
# Usage: make assign-groups [LOCAL_API=http://localhost:5050]
assign-groups:
uv run python -m scripts.data_transfer.ingestion.platform.assign_groups \
--url-api-annotation $(LOCAL_API) \
--loglevel $(LOGLEVEL)

# Push locally-annotated sequences back to the remote API.
# Usage: make push-annotations [MAX_SEQUENCES=10]
Expand Down Expand Up @@ -328,4 +339,4 @@ import-platform:
pull-fp visual-check-fp apply-review-fp \
export-dataset import-yolo-sequence import-local-yolo \
update-stage-remote update-stage-local \
import-platform
import-platform assign-groups
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""Trigger the annotation API's `POST /sequence_groups/assign` endpoint and
print the result. Single-threaded by contract — meant to run sequentially
after `import-platform`, not concurrently with it.

Usage (from `annotation_api/`):
uv run python -m scripts.data_transfer.ingestion.platform.assign_groups \
--url-api-annotation http://localhost:5050
"""

from __future__ import annotations

import argparse
import logging
import sys

import requests

from .shared import get_annotation_credentials


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--url-api-annotation",
default="http://localhost:5050",
help="Annotation API URL (default: http://localhost:5050)",
)
parser.add_argument(
"--loglevel",
default="info",
choices=["debug", "info", "warning", "error"],
)
return parser.parse_args()


def main() -> None:
args = parse_args()
logging.basicConfig(level=args.loglevel.upper())

base_url = args.url_api_annotation.rstrip("/")
login, password = get_annotation_credentials(base_url)

auth = requests.post(
f"{base_url}/api/v1/auth/login",
json={"username": login, "password": password},
timeout=30,
)
auth.raise_for_status()
token = auth.json()["access_token"]

response = requests.post(
f"{base_url}/api/v1/sequence_groups/assign",
headers={"Authorization": f"Bearer {token}"},
timeout=600,
)
if response.status_code != 200:
logging.error(
"assign-groups failed: HTTP %s — %s", response.status_code, response.text
)
sys.exit(1)

summary = response.json()
print(
"assign-groups: "
f"processed={summary['processed']} "
f"new_groups={summary['new_groups']} "
f"joined_existing={summary['joined_existing']} "
f"inherited_annotations={summary['inherited_annotations']} "
f"skipped_no_bbox={summary['skipped_no_bbox']}"
)


if __name__ == "__main__":
main()
Loading
Loading