From d45396cc4f92d763f2c1d6bbda3f18fcd8e57551 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 10 Mar 2026 20:39:36 +0000 Subject: [PATCH 1/4] bbox mode as first class --- src/groundlight/client.py | 86 ++++++++++++++++++++++++++++- src/groundlight/experimental_api.py | 19 ++----- 2 files changed, 89 insertions(+), 16 deletions(-) diff --git a/src/groundlight/client.py b/src/groundlight/client.py index c4609bf5..e7884731 100644 --- a/src/groundlight/client.py +++ b/src/groundlight/client.py @@ -16,6 +16,7 @@ from groundlight_openapi_client.api.user_api import UserApi from groundlight_openapi_client.exceptions import NotFoundException, UnauthorizedException from groundlight_openapi_client.model.b_box_geometry_request import BBoxGeometryRequest +from groundlight_openapi_client.model.bounding_box_mode_configuration import BoundingBoxModeConfiguration from groundlight_openapi_client.model.count_mode_configuration import CountModeConfiguration from groundlight_openapi_client.model.detector_creation_input_request import DetectorCreationInputRequest from groundlight_openapi_client.model.detector_group_request import DetectorGroupRequest @@ -396,9 +397,9 @@ def create_detector( # noqa: PLR0913 By default will create a binary detector but alternate modes can be created by passing in a mode argument. - Text and Bounding box detectors are in Beta, and can be created through the - ExperimentalApi via the :meth:`ExperimentalApi.create_text_recognition_detector` and - :meth:`ExperimentalApi.create_bounding_box_detector` methods. + Text recognition detectors are in Beta, and can be created through the + ExperimentalApi via the :meth:`ExperimentalApi.create_text_recognition_detector` method. + Bounding box detectors can be created using the :meth:`create_bounding_box_detector` method. **Example usage**:: @@ -1739,3 +1740,82 @@ def create_multiclass_detector( # noqa: PLR0913 # pylint: disable=too-many-argu detector_creation_input.mode_configuration = mode_config obj = self.detectors_api.create_detector(detector_creation_input, _request_timeout=DEFAULT_REQUEST_TIMEOUT) return Detector.parse_obj(obj.to_dict()) + + def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-arguments, too-many-locals + self, + name: str, + query: str, + class_name: str, + *, + max_num_bboxes: Optional[int] = None, + group_name: Optional[str] = None, + confidence_threshold: Optional[float] = None, + patience_time: Optional[float] = None, + pipeline_config: Optional[str] = None, + metadata: Union[dict, str, None] = None, + priming_group_id: Optional[str] = None, + ) -> Detector: + """ + Creates a bounding box detector that can detect objects in images up to a specified maximum number of bounding + boxes. + + **Example usage**:: + + gl = Groundlight() + + # Create a detector that counts people up to 5 + detector = gl.create_bounding_box_detector( + name="people_counter", + query="Draw a bounding box around each person in the image", + class_name="person", + max_num_bboxes=5, + confidence_threshold=0.9, + patience_time=30.0 + ) + + # Use the detector to find people in an image + image_query = gl.ask_ml(detector, "path/to/image.jpg") + print(f"Confidence: {image_query.result.confidence}") + print(f"Label: {image_query.result.label}") + print(f"Bounding boxes: {image_query.rois}") + + :param name: A short, descriptive name for the detector. + :param query: A question about the object to detect in the image. + :param class_name: The class name of the object to detect. + :param max_num_bboxes: Maximum number of bounding boxes to detect (default: 10) + :param group_name: Optional name of a group to organize related detectors together. + :param confidence_threshold: A value that sets the minimum confidence level required for the ML model's + predictions. If confidence is below this threshold, the query may be sent for human review. + :param patience_time: The maximum time in seconds that Groundlight will attempt to generate a + confident prediction before falling back to human review. Defaults to 30 seconds. + :param pipeline_config: Advanced usage only. Configuration string needed to instantiate a specific + prediction pipeline for this detector. + :param metadata: A dictionary or JSON string containing custom key/value pairs to associate with + the detector (limited to 1KB). This metadata can be used to store additional + information like location, purpose, or related system IDs. You can retrieve this + metadata later by calling `get_detector()`. + :param priming_group_id: Optional ID of an existing PrimingGroup to associate with this detector. + + :return: The created Detector object + """ + + detector_creation_input = self._prep_create_detector( + name=name, + query=query, + group_name=group_name, + confidence_threshold=confidence_threshold, + patience_time=patience_time, + pipeline_config=pipeline_config, + metadata=metadata, + priming_group_id=priming_group_id, + ) + detector_creation_input.mode = ModeEnum.BOUNDING_BOX + + if max_num_bboxes is None: + mode_config = BoundingBoxModeConfiguration(class_name=class_name) + else: + mode_config = BoundingBoxModeConfiguration(max_num_bboxes=max_num_bboxes, class_name=class_name) + + detector_creation_input.mode_configuration = mode_config + obj = self.detectors_api.create_detector(detector_creation_input, _request_timeout=DEFAULT_REQUEST_TIMEOUT) + return Detector.parse_obj(obj.to_dict()) diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index 5282871d..9f1e13e5 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -19,7 +19,6 @@ from groundlight_openapi_client.api.edge_api import EdgeApi from groundlight_openapi_client.api.notes_api import NotesApi from groundlight_openapi_client.model.action_request import ActionRequest -from groundlight_openapi_client.model.bounding_box_mode_configuration import BoundingBoxModeConfiguration from groundlight_openapi_client.model.channel_enum import ChannelEnum from groundlight_openapi_client.model.condition_request import ConditionRequest from groundlight_openapi_client.model.patched_detector_request import PatchedDetectorRequest @@ -650,6 +649,8 @@ def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-ar Creates a bounding box detector that can detect objects in images up to a specified maximum number of bounding boxes. + This method is now available in the base Groundlight class and is maintained here for backward compatibility. + **Example usage**:: gl = ExperimentalApi() @@ -689,10 +690,12 @@ def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-ar :return: The created Detector object """ - - detector_creation_input = self._prep_create_detector( + # Delegate to the parent class implementation + return super().create_bounding_box_detector( name=name, query=query, + class_name=class_name, + max_num_bboxes=max_num_bboxes, group_name=group_name, confidence_threshold=confidence_threshold, patience_time=patience_time, @@ -700,16 +703,6 @@ def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-ar metadata=metadata, priming_group_id=priming_group_id, ) - detector_creation_input.mode = ModeEnum.BOUNDING_BOX - - if max_num_bboxes is None: - mode_config = BoundingBoxModeConfiguration(class_name=class_name) - else: - mode_config = BoundingBoxModeConfiguration(max_num_bboxes=max_num_bboxes, class_name=class_name) - - detector_creation_input.mode_configuration = mode_config - obj = self.detectors_api.create_detector(detector_creation_input, _request_timeout=DEFAULT_REQUEST_TIMEOUT) - return Detector.parse_obj(obj.to_dict()) def create_text_recognition_detector( # noqa: PLR0913 # pylint: disable=too-many-arguments, too-many-locals self, From ae3b6f9977524974869c673a27681b5fff3652a5 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 10 Mar 2026 20:43:53 +0000 Subject: [PATCH 2/4] remove explicit super call --- src/groundlight/experimental_api.py | 73 ----------------------------- 1 file changed, 73 deletions(-) diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index 9f1e13e5..f15e88d8 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -631,79 +631,6 @@ def update_detector_name(self, detector: Union[str, Detector], name: str) -> Non detector = detector.id self.detectors_api.update_detector(detector, patched_detector_request=PatchedDetectorRequest(name=name)) - def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-arguments, too-many-locals - self, - name: str, - query: str, - class_name: str, - *, - max_num_bboxes: Optional[int] = None, - group_name: Optional[str] = None, - confidence_threshold: Optional[float] = None, - patience_time: Optional[float] = None, - pipeline_config: Optional[str] = None, - metadata: Union[dict, str, None] = None, - priming_group_id: Optional[str] = None, - ) -> Detector: - """ - Creates a bounding box detector that can detect objects in images up to a specified maximum number of bounding - boxes. - - This method is now available in the base Groundlight class and is maintained here for backward compatibility. - - **Example usage**:: - - gl = ExperimentalApi() - - # Create a detector that counts people up to 5 - detector = gl.create_bounding_box_detector( - name="people_counter", - query="Draw a bounding box around each person in the image", - class_name="person", - max_num_bboxes=5, - confidence_threshold=0.9, - patience_time=30.0 - ) - - # Use the detector to find people in an image - image_query = gl.ask_ml(detector, "path/to/image.jpg") - print(f"Confidence: {image_query.result.confidence}") - print(f"Label: {image_query.result.label}") - print(f"Bounding boxes: {image_query.rois}") - - :param name: A short, descriptive name for the detector. - :param query: A question about the object to detect in the image. - :param class_name: The class name of the object to detect. - :param max_num_bboxes: Maximum number of bounding boxes to detect (default: 10) - :param group_name: Optional name of a group to organize related detectors together. - :param confidence_threshold: A value that sets the minimum confidence level required for the ML model's - predictions. If confidence is below this threshold, the query may be sent for human review. - :param patience_time: The maximum time in seconds that Groundlight will attempt to generate a - confident prediction before falling back to human review. Defaults to 30 seconds. - :param pipeline_config: Advanced usage only. Configuration string needed to instantiate a specific - prediction pipeline for this detector. - :param metadata: A dictionary or JSON string containing custom key/value pairs to associate with - the detector (limited to 1KB). This metadata can be used to store additional - information like location, purpose, or related system IDs. You can retrieve this - metadata later by calling `get_detector()`. - :param priming_group_id: Optional ID of an existing PrimingGroup to associate with this detector. - - :return: The created Detector object - """ - # Delegate to the parent class implementation - return super().create_bounding_box_detector( - name=name, - query=query, - class_name=class_name, - max_num_bboxes=max_num_bboxes, - group_name=group_name, - confidence_threshold=confidence_threshold, - patience_time=patience_time, - pipeline_config=pipeline_config, - metadata=metadata, - priming_group_id=priming_group_id, - ) - def create_text_recognition_detector( # noqa: PLR0913 # pylint: disable=too-many-arguments, too-many-locals self, name: str, From 6abff37bb7a8d5555d74d9ca9b78b3849d14bef3 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 10 Mar 2026 23:03:41 +0000 Subject: [PATCH 3/4] improve docs --- src/groundlight/client.py | 8 ++++++++ src/groundlight/experimental_api.py | 2 ++ test/integration/test_groundlight.py | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/groundlight/client.py b/src/groundlight/client.py index e7884731..ec513ba9 100644 --- a/src/groundlight/client.py +++ b/src/groundlight/client.py @@ -449,6 +449,8 @@ def create_detector( # noqa: PLR0913 :param class_names: The name or names of the class to use for the detector. Only used for multi-class and counting detectors. :param priming_group_id: Optional ID of an existing PrimingGroup to associate with this detector. + PrimingGroup IDs are provided by Groundlight representatives. If you would like + to use a priming_group_id, please reach out to your Groundlight representative. :return: The created Detector object """ @@ -1606,6 +1608,8 @@ def create_counting_detector( # noqa: PLR0913 # pylint: disable=too-many-argume information like location, purpose, or related system IDs. You can retrieve this metadata later by calling `get_detector()`. :param priming_group_id: Optional ID of an existing PrimingGroup to associate with this detector. + PrimingGroup IDs are provided by Groundlight representatives. If you would like + to use a priming_group_id, please reach out to your Groundlight representative. :return: The created Detector object """ @@ -1721,6 +1725,8 @@ def create_multiclass_detector( # noqa: PLR0913 # pylint: disable=too-many-argu information like location, purpose, or related system IDs. You can retrieve this metadata later by calling `get_detector()`. :param priming_group_id: Optional ID of an existing PrimingGroup to associate with this detector. + PrimingGroup IDs are provided by Groundlight representatives. If you would like + to use a priming_group_id, please reach out to your Groundlight representative. :return: The created Detector object """ @@ -1795,6 +1801,8 @@ def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-ar information like location, purpose, or related system IDs. You can retrieve this metadata later by calling `get_detector()`. :param priming_group_id: Optional ID of an existing PrimingGroup to associate with this detector. + PrimingGroup IDs are provided by Groundlight representatives. If you would like + to use a priming_group_id, please reach out to your Groundlight representative. :return: The created Detector object """ diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index f15e88d8..b50d7fb0 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -670,6 +670,8 @@ def create_text_recognition_detector( # noqa: PLR0913 # pylint: disable=too-man information like location, purpose, or related system IDs. You can retrieve this metadata later by calling `get_detector()`. :param priming_group_id: Optional ID of an existing PrimingGroup to associate with this detector. + PrimingGroup IDs are provided by Groundlight representatives. If you would like + to use a priming_group_id, please reach out to your Groundlight representative. :return: The created Detector object """ diff --git a/test/integration/test_groundlight.py b/test/integration/test_groundlight.py index 988386a1..8f06251a 100644 --- a/test/integration/test_groundlight.py +++ b/test/integration/test_groundlight.py @@ -942,6 +942,9 @@ def test_delete_detector(gl: Groundlight): def test_create_detector_with_invalid_priming_group_id(gl: Groundlight): """ Test that creating a detector with a non-existent priming_group_id returns an appropriate error. + + Note: PrimingGroup IDs are provided by Groundlight representatives. If you would like to + use a priming_group_id, please reach out to your Groundlight representative. """ name = f"Test invalid priming {datetime.utcnow()}" query = "Is there a dog?" From 49978612a0f64f6829bffef3504b01f994b809fa Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 10 Mar 2026 23:06:06 +0000 Subject: [PATCH 4/4] fix comment --- src/groundlight/client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/groundlight/client.py b/src/groundlight/client.py index ec513ba9..38e9df29 100644 --- a/src/groundlight/client.py +++ b/src/groundlight/client.py @@ -399,7 +399,6 @@ def create_detector( # noqa: PLR0913 Text recognition detectors are in Beta, and can be created through the ExperimentalApi via the :meth:`ExperimentalApi.create_text_recognition_detector` method. - Bounding box detectors can be created using the :meth:`create_bounding_box_detector` method. **Example usage**::