From 3cb946927e81fee2fda17d288cf4d5d1ca0ef2fd Mon Sep 17 00:00:00 2001 From: Jason Hoku Date: Mon, 18 May 2026 01:12:01 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20florence2=5Fhires=20=E2=80=94=20mask-se?= =?UTF-8?q?lect=20index=20parser=20+=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- florence2_hires.py | 49 ++++++++++++++++++++++ tests/test_florence2_mask_select.py | 63 +++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 tests/test_florence2_mask_select.py diff --git a/florence2_hires.py b/florence2_hires.py index cb1fe5d..4f85ec8 100644 --- a/florence2_hires.py +++ b/florence2_hires.py @@ -62,3 +62,52 @@ def compute_target_dims(src_w, src_h, target_megapixels): new_w = max(64, min(4096, int(round(src_w * scale)) // 8 * 8)) new_h = max(64, min(4096, int(round(src_h * scale)) // 8 * 8)) return new_w, new_h + + +def parse_mask_select_indices(user_input, detected_count): + """Parse user's output_mask_select string against detected region count. + + Args: + user_input: string from UI; "" = use all, "0" = first, "0,2" = specific indices. + detected_count: how many regions Florence2 actually returned. + + Returns: + Tuple (indices: list[int], mode: str) where mode is one of: + - "all": use all detected regions (caller should union) + - "select": use the listed indices + - "no_detection": no valid selection possible (caller should treat as miss) + """ + if detected_count <= 0: + return [], "no_detection" + + stripped = (user_input or "").strip() + if not stripped: + return [], "all" + + raw_tokens = [t.strip() for t in stripped.split(",") if t.strip()] + if not raw_tokens: + return [], "all" + + parsed = [] + for tok in raw_tokens: + try: + n = int(tok) + except ValueError: + return [], "no_detection" + if n < 0: + return [], "no_detection" + if n < detected_count: + parsed.append(n) + # OOR indices silently dropped + + if not parsed: + return [], "no_detection" + + # Stable dedupe preserving order + seen = set() + out = [] + for n in parsed: + if n not in seen: + seen.add(n) + out.append(n) + return out, "select" diff --git a/tests/test_florence2_mask_select.py b/tests/test_florence2_mask_select.py new file mode 100644 index 0000000..4149393 --- /dev/null +++ b/tests/test_florence2_mask_select.py @@ -0,0 +1,63 @@ +"""Tests for parse_mask_select_indices() — converts user string to (indices, mode).""" +import pytest + +from florence2_hires import parse_mask_select_indices + + +def test_empty_string_means_all(): + """Empty string -> mode='all', indices=[].""" + indices, mode = parse_mask_select_indices("", detected_count=3) + assert mode == "all" + assert indices == [] + + +def test_whitespace_only_means_all(): + indices, mode = parse_mask_select_indices(" ", detected_count=3) + assert mode == "all" + + +def test_single_index(): + indices, mode = parse_mask_select_indices("0", detected_count=3) + assert mode == "select" + assert indices == [0] + + +def test_multiple_indices(): + indices, mode = parse_mask_select_indices("0,2", detected_count=3) + assert mode == "select" + assert indices == [0, 2] + + +def test_spaces_between_indices(): + indices, mode = parse_mask_select_indices("0, 1 , 2", detected_count=3) + assert mode == "select" + assert indices == [0, 1, 2] + + +def test_out_of_range_index_returns_no_detection(): + """Index >= detected_count -> mode='no_detection' (don't crash).""" + indices, mode = parse_mask_select_indices("5", detected_count=3) + assert mode == "no_detection" + + +def test_some_in_range_some_out_keeps_in_range(): + """Partial OOR -> keep the valid ones.""" + indices, mode = parse_mask_select_indices("0,5,1", detected_count=3) + assert mode == "select" + assert indices == [0, 1] + + +def test_negative_index_treated_as_invalid(): + indices, mode = parse_mask_select_indices("-1", detected_count=3) + assert mode == "no_detection" + + +def test_garbage_input_returns_no_detection(): + indices, mode = parse_mask_select_indices("foo", detected_count=3) + assert mode == "no_detection" + + +def test_zero_detected_with_empty_request(): + """Empty request + no detections -> no_detection.""" + indices, mode = parse_mask_select_indices("", detected_count=0) + assert mode == "no_detection"