diff --git a/generated/docs/DetectorCreationInputRequest.md b/generated/docs/DetectorCreationInputRequest.md index 16adba94..630aca57 100644 --- a/generated/docs/DetectorCreationInputRequest.md +++ b/generated/docs/DetectorCreationInputRequest.md @@ -14,6 +14,7 @@ Name | Type | Description | Notes **metadata** | **str** | Base64-encoded metadata for the detector. This should be a JSON object with string keys. The size after encoding should not exceed 1362 bytes, corresponding to 1KiB before encoding. | [optional] **mode** | **bool, date, datetime, dict, float, int, list, str, none_type** | Mode in which this detector will work. * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS * `TEXT` - TEXT * `BOUNDING_BOX` - BOUNDING_BOX | [optional] **mode_configuration** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional] +**priming_group_id** | **str, none_type** | ID of an existing PrimingGroup to associate with this detector (optional). | [optional] **any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/generated/docs/DetectorsApi.md b/generated/docs/DetectorsApi.md index 9f5355e5..acd3761b 100644 --- a/generated/docs/DetectorsApi.md +++ b/generated/docs/DetectorsApi.md @@ -62,6 +62,7 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: metadata="metadata_example", mode=None, mode_configuration=None, + priming_group_id="priming_group_id_example", ) # DetectorCreationInputRequest | # example passing only required values which don't have defaults set diff --git a/generated/groundlight_openapi_client/model/detector_creation_input_request.py b/generated/groundlight_openapi_client/model/detector_creation_input_request.py index ca1b1563..ce1cbcec 100644 --- a/generated/groundlight_openapi_client/model/detector_creation_input_request.py +++ b/generated/groundlight_openapi_client/model/detector_creation_input_request.py @@ -97,6 +97,10 @@ class DetectorCreationInputRequest(ModelNormal): "max_length": 1362, "min_length": 1, }, + ("priming_group_id",): { + "max_length": 44, + "min_length": 1, + }, } @cached_property @@ -164,6 +168,10 @@ def openapi_types(): str, none_type, ), # noqa: E501 + "priming_group_id": ( + str, + none_type, + ), # noqa: E501 } @cached_property @@ -180,6 +188,7 @@ def discriminator(): "metadata": "metadata", # noqa: E501 "mode": "mode", # noqa: E501 "mode_configuration": "mode_configuration", # noqa: E501 + "priming_group_id": "priming_group_id", # noqa: E501 } read_only_vars = {} @@ -233,6 +242,7 @@ def _from_openapi_data(cls, name, query, *args, **kwargs): # noqa: E501 metadata (str): Base64-encoded metadata for the detector. This should be a JSON object with string keys. The size after encoding should not exceed 1362 bytes, corresponding to 1KiB before encoding.. [optional] # noqa: E501 mode (bool, date, datetime, dict, float, int, list, str, none_type): Mode in which this detector will work. * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS * `TEXT` - TEXT * `BOUNDING_BOX` - BOUNDING_BOX. [optional] # noqa: E501 mode_configuration (bool, date, datetime, dict, float, int, list, str, none_type): [optional] # noqa: E501 + priming_group_id (str, none_type): ID of an existing PrimingGroup to associate with this detector (optional).. [optional] # noqa: E501 """ _check_type = kwargs.pop("_check_type", True) @@ -330,6 +340,7 @@ def __init__(self, name, query, *args, **kwargs): # noqa: E501 metadata (str): Base64-encoded metadata for the detector. This should be a JSON object with string keys. The size after encoding should not exceed 1362 bytes, corresponding to 1KiB before encoding.. [optional] # noqa: E501 mode (bool, date, datetime, dict, float, int, list, str, none_type): Mode in which this detector will work. * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS * `TEXT` - TEXT * `BOUNDING_BOX` - BOUNDING_BOX. [optional] # noqa: E501 mode_configuration (bool, date, datetime, dict, float, int, list, str, none_type): [optional] # noqa: E501 + priming_group_id (str, none_type): ID of an existing PrimingGroup to associate with this detector (optional).. [optional] # noqa: E501 """ _check_type = kwargs.pop("_check_type", True) diff --git a/generated/model.py b/generated/model.py index 7b3636f5..726a0548 100644 --- a/generated/model.py +++ b/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: public-api.yaml -# timestamp: 2026-01-13T18:34:24+00:00 +# timestamp: 2026-03-10T18:06:07+00:00 from __future__ import annotations @@ -429,6 +429,9 @@ class DetectorCreationInputRequest(BaseModel): mode_configuration: Optional[ Union[CountModeConfiguration, MultiClassModeConfiguration, TextModeConfiguration, BoundingBoxModeConfiguration] ] = None + priming_group_id: Optional[constr(min_length=1, max_length=44)] = Field( + None, description="ID of an existing PrimingGroup to associate with this detector (optional)." + ) class ImageQuery(BaseModel): diff --git a/package-lock.json b/package-lock.json index 7db9430a..51c40fa1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -184,6 +184,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.6.tgz", "integrity": "sha512-krKwLLcFmeuKDqngG2N/RuZHCs2ycsKcxWIDgcm7i1lf3sQ0iG03ci+DsP/r3FcT/eJDFsIHnKtNta2LIi7PzQ==", "license": "MIT", + "peer": true, "dependencies": { "file-type": "21.0.0", "iterare": "1.2.1", @@ -473,6 +474,7 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", "license": "MIT", + "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -2569,7 +2571,8 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/rehype-katex": { "version": "7.0.1", @@ -2648,6 +2651,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } diff --git a/spec/public-api.yaml b/spec/public-api.yaml index bb58a6ef..c60e03b0 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -1084,6 +1084,13 @@ components: - $ref: '#/components/schemas/TextModeConfiguration' - $ref: '#/components/schemas/BoundingBoxModeConfiguration' nullable: true + priming_group_id: + type: string + nullable: true + minLength: 1 + description: ID of an existing PrimingGroup to associate with this detector + (optional). + maxLength: 44 required: - name - query diff --git a/src/groundlight/client.py b/src/groundlight/client.py index 669d3a7c..c4609bf5 100644 --- a/src/groundlight/client.py +++ b/src/groundlight/client.py @@ -352,6 +352,7 @@ def _prep_create_detector( # noqa: PLR0913 # pylint: disable=too-many-arguments patience_time: Optional[float] = None, pipeline_config: Optional[str] = None, metadata: Union[dict, str, None] = None, + priming_group_id: Optional[str] = None, ) -> Detector: """ A helper function to prepare the input for creating a detector. Individual create_detector @@ -372,6 +373,8 @@ def _prep_create_detector( # noqa: PLR0913 # pylint: disable=too-many-arguments patience_time = float(patience_time) if patience_time: detector_creation_input.patience_time = patience_time + if priming_group_id is not None: + detector_creation_input.priming_group_id = priming_group_id return detector_creation_input def create_detector( # noqa: PLR0913 @@ -386,6 +389,7 @@ def create_detector( # noqa: PLR0913 pipeline_config: Optional[str] = None, metadata: Union[dict, str, None] = None, class_names: Optional[Union[List[str], str]] = None, + priming_group_id: Optional[str] = None, ) -> Detector: """ Create a new Detector with a given name and query. @@ -443,6 +447,7 @@ def create_detector( # noqa: PLR0913 metadata later by calling `get_detector()`. :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. :return: The created Detector object """ @@ -458,6 +463,7 @@ def create_detector( # noqa: PLR0913 patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) if mode == ModeEnum.COUNT: if class_names is None: @@ -473,6 +479,7 @@ def create_detector( # noqa: PLR0913 patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) if mode == ModeEnum.MULTI_CLASS: if class_names is None: @@ -488,6 +495,7 @@ def create_detector( # noqa: PLR0913 patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) raise ValueError( f"Unsupported mode: {mode}, check if your desired mode is only supported in the ExperimentalApi" @@ -1557,6 +1565,7 @@ def create_counting_detector( # noqa: PLR0913 # pylint: disable=too-many-argume 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 counting detector that can count objects in images up to a specified maximum count. @@ -1595,6 +1604,7 @@ def create_counting_detector( # noqa: PLR0913 # pylint: disable=too-many-argume 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 """ @@ -1607,6 +1617,7 @@ def create_counting_detector( # noqa: PLR0913 # pylint: disable=too-many-argume patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) detector_creation_input.mode = ModeEnum.COUNT @@ -1629,6 +1640,7 @@ def create_binary_detector( # noqa: PLR0913 # pylint: disable=too-many-argument 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 binary detector with the given name and query. @@ -1656,6 +1668,7 @@ def create_binary_detector( # noqa: PLR0913 # pylint: disable=too-many-argument patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) obj = self.detectors_api.create_detector(detector_creation_input, _request_timeout=DEFAULT_REQUEST_TIMEOUT) return Detector.parse_obj(obj.to_dict()) @@ -1671,6 +1684,7 @@ def create_multiclass_detector( # noqa: PLR0913 # pylint: disable=too-many-argu 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 multiclass detector with the given name and query. @@ -1705,6 +1719,7 @@ def create_multiclass_detector( # noqa: PLR0913 # pylint: disable=too-many-argu 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 """ @@ -1717,6 +1732,7 @@ def create_multiclass_detector( # noqa: PLR0913 # pylint: disable=too-many-argu patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) detector_creation_input.mode = ModeEnum.MULTI_CLASS mode_config = MultiClassModeConfiguration(class_names=class_names) diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index 90ef7470..5282871d 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -644,6 +644,7 @@ def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-ar 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 @@ -684,6 +685,7 @@ def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-ar 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 """ @@ -696,6 +698,7 @@ def create_bounding_box_detector( # noqa: PLR0913 # pylint: disable=too-many-ar patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) detector_creation_input.mode = ModeEnum.BOUNDING_BOX @@ -718,6 +721,7 @@ def create_text_recognition_detector( # noqa: PLR0913 # pylint: disable=too-man 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 text recognition detector that can read specified spans of text from images. @@ -742,6 +746,10 @@ def create_text_recognition_detector( # noqa: PLR0913 # pylint: disable=too-man :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 """ @@ -754,6 +762,7 @@ def create_text_recognition_detector( # noqa: PLR0913 # pylint: disable=too-man patience_time=patience_time, pipeline_config=pipeline_config, metadata=metadata, + priming_group_id=priming_group_id, ) detector_creation_input.mode = ModeEnum.TEXT mode_config = TextModeConfiguration() diff --git a/test/integration/test_groundlight.py b/test/integration/test_groundlight.py index 902774eb..988386a1 100644 --- a/test/integration/test_groundlight.py +++ b/test/integration/test_groundlight.py @@ -937,3 +937,24 @@ def test_delete_detector(gl: Groundlight): fake_detector_id = "det_fake123456789" with pytest.raises(NotFoundError): gl.delete_detector(fake_detector_id) # type: ignore + + +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. + """ + name = f"Test invalid priming {datetime.utcnow()}" + query = "Is there a dog?" + pipeline_config = "never-review" + priming_group_id = "prgrp_nonexistent12345678901234567890" + + with pytest.raises(NotFoundException) as exc_info: + gl.create_detector( + name=name, + query=query, + pipeline_config=pipeline_config, + priming_group_id=priming_group_id, + ) + + # Verify the error message mentions PrimingGroup + assert "PrimingGroup" in str(exc_info.value)