From 9e316a5b3a98b9c9d1f442e2167601e1d4f7d8ee Mon Sep 17 00:00:00 2001 From: CoreyEWood Date: Wed, 4 Dec 2024 16:52:56 -0800 Subject: [PATCH 1/6] include confidence_threshold in submit_image_query params --- src/groundlight/client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/groundlight/client.py b/src/groundlight/client.py index 14ab15af..b45300bc 100644 --- a/src/groundlight/client.py +++ b/src/groundlight/client.py @@ -669,6 +669,9 @@ def submit_image_query( # noqa: PLR0913 # pylint: disable=too-many-arguments, t if patience_time is not None: params["patience_time"] = patience_time + if confidence_threshold is not None: + params["confidence_threshold"] = confidence_threshold + if human_review is not None: params["human_review"] = human_review From aa1ba6ef5c5a5b900e614b065f4aec302492bf63 Mon Sep 17 00:00:00 2001 From: CoreyEWood Date: Wed, 4 Dec 2024 17:14:35 -0800 Subject: [PATCH 2/6] update spec file --- spec/public-api.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spec/public-api.yaml b/spec/public-api.yaml index b227293d..bf1cf58b 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -347,6 +347,12 @@ paths: --data-binary @path/to/filename.jpeg ``` parameters: + - in: query + name: confidence_threshold + schema: + type: number + format: float + description: The confidence threshold for the image query. - in: query name: detector_id schema: @@ -1367,8 +1373,7 @@ components: - ALGORITHM count: type: integer - minimum: null - maximum: null + minimum: 0 greater_than_max: type: boolean required: @@ -1400,7 +1405,6 @@ components: type: integer minimum: 1 maximum: 50 - required: [] MultiClassModeConfiguration: type: object properties: @@ -1410,8 +1414,6 @@ components: type: string num_classes: type: integer - minimum: null - maximum: null required: - class_names ChannelEnum: From 893fb326d3573666826ab1c336e5e02afbd73c13 Mon Sep 17 00:00:00 2001 From: CoreyEWood Date: Thu, 5 Dec 2024 21:03:52 +0000 Subject: [PATCH 3/6] add test for confidence threshold --- test/integration/test_groundlight.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/integration/test_groundlight.py b/test/integration/test_groundlight.py index a47b6088..01a22bc2 100644 --- a/test/integration/test_groundlight.py +++ b/test/integration/test_groundlight.py @@ -320,6 +320,18 @@ def test_submit_image_query_png(gl: Groundlight, detector: Detector): assert is_valid_display_result(_image_query.result) +def test_submit_image_query_with_confidence_threshold(gl: Groundlight, detector: Detector): + confidence_threshold = 0.5234 # Arbitrary specific value + _image_query = gl.submit_image_query( + detector=detector.id, + image="test/assets/dog.jpeg", + wait=10, + confidence_threshold=confidence_threshold, + human_review="NEVER", + ) + assert _image_query.confidence_threshold == confidence_threshold + + @pytest.mark.skip_for_edge_endpoint(reason="The edge-endpoint does not support passing an image query ID.") def test_submit_image_query_with_id(gl: Groundlight, detector: Detector): # submit_image_query From aa95638ec6f1755262bca1a31b9141b1546a0468 Mon Sep 17 00:00:00 2001 From: CoreyEWood Date: Thu, 5 Dec 2024 23:53:40 +0000 Subject: [PATCH 4/6] update spec with confidence threshold bounds --- spec/public-api.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/public-api.yaml b/spec/public-api.yaml index bf1cf58b..bd3392a3 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -352,6 +352,8 @@ paths: schema: type: number format: float + minimum: 0 + maximum: 1 description: The confidence threshold for the image query. - in: query name: detector_id From 357f40c128d90903fb11a36a981da6abd108bfab Mon Sep 17 00:00:00 2001 From: CoreyEWood Date: Thu, 5 Dec 2024 23:54:27 +0000 Subject: [PATCH 5/6] updated generated code --- generated/docs/ImageQueriesApi.md | 4 +- .../api/image_queries_api.py | 16 +- .../model/counting_result.py | 3 + .../model/patched_detector_request.py | 151 +++++++----------- generated/model.py | 4 +- 5 files changed, 80 insertions(+), 98 deletions(-) diff --git a/generated/docs/ImageQueriesApi.md b/generated/docs/ImageQueriesApi.md index 3d6cd5b8..7f39a4da 100644 --- a/generated/docs/ImageQueriesApi.md +++ b/generated/docs/ImageQueriesApi.md @@ -282,6 +282,7 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = image_queries_api.ImageQueriesApi(api_client) detector_id = "detector_id_example" # str | Choose a detector by its ID. + confidence_threshold = 0 # float | The confidence threshold for the image query. (optional) human_review = "human_review_example" # str | If set to `DEFAULT`, use the regular escalation logic (i.e., send the image query for human review if the ML model is not confident). If set to `ALWAYS`, always send the image query for human review even if the ML model is confident. If set to `NEVER`, never send the image query for human review even if the ML model is not confident. (optional) image_query_id = "image_query_id_example" # str | The ID to assign to the created image query. (optional) inspection_id = "inspection_id_example" # str | Associate the image query with an inspection. (optional) @@ -300,7 +301,7 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: # example passing only required values which don't have defaults set # and optional values try: - api_response = api_instance.submit_image_query(detector_id, human_review=human_review, image_query_id=image_query_id, inspection_id=inspection_id, metadata=metadata, patience_time=patience_time, want_async=want_async, body=body) + api_response = api_instance.submit_image_query(detector_id, confidence_threshold=confidence_threshold, human_review=human_review, image_query_id=image_query_id, inspection_id=inspection_id, metadata=metadata, patience_time=patience_time, want_async=want_async, body=body) pprint(api_response) except groundlight_openapi_client.ApiException as e: print("Exception when calling ImageQueriesApi->submit_image_query: %s\n" % e) @@ -312,6 +313,7 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **detector_id** | **str**| Choose a detector by its ID. | + **confidence_threshold** | **float**| The confidence threshold for the image query. | [optional] **human_review** | **str**| If set to `DEFAULT`, use the regular escalation logic (i.e., send the image query for human review if the ML model is not confident). If set to `ALWAYS`, always send the image query for human review even if the ML model is confident. If set to `NEVER`, never send the image query for human review even if the ML model is not confident. | [optional] **image_query_id** | **str**| The ID to assign to the created image query. | [optional] **inspection_id** | **str**| Associate the image query with an inspection. | [optional] diff --git a/generated/groundlight_openapi_client/api/image_queries_api.py b/generated/groundlight_openapi_client/api/image_queries_api.py index d9925f9d..cd8d0577 100644 --- a/generated/groundlight_openapi_client/api/image_queries_api.py +++ b/generated/groundlight_openapi_client/api/image_queries_api.py @@ -170,6 +170,7 @@ def __init__(self, api_client=None): params_map={ "all": [ "detector_id", + "confidence_threshold", "human_review", "image_query_id", "inspection_id", @@ -183,13 +184,21 @@ def __init__(self, api_client=None): ], "nullable": [], "enum": [], - "validation": [], + "validation": [ + "confidence_threshold", + ], }, root_map={ - "validations": {}, + "validations": { + ("confidence_threshold",): { + "inclusive_maximum": 1, + "inclusive_minimum": 0, + }, + }, "allowed_values": {}, "openapi_types": { "detector_id": (str,), + "confidence_threshold": (float,), "human_review": (str,), "image_query_id": (str,), "inspection_id": (str,), @@ -200,6 +209,7 @@ def __init__(self, api_client=None): }, "attribute_map": { "detector_id": "detector_id", + "confidence_threshold": "confidence_threshold", "human_review": "human_review", "image_query_id": "image_query_id", "inspection_id": "inspection_id", @@ -209,6 +219,7 @@ def __init__(self, api_client=None): }, "location_map": { "detector_id": "query", + "confidence_threshold": "query", "human_review": "query", "image_query_id": "query", "inspection_id": "query", @@ -421,6 +432,7 @@ def submit_image_query(self, detector_id, **kwargs): detector_id (str): Choose a detector by its ID. Keyword Args: + confidence_threshold (float): The confidence threshold for the image query.. [optional] human_review (str): If set to `DEFAULT`, use the regular escalation logic (i.e., send the image query for human review if the ML model is not confident). If set to `ALWAYS`, always send the image query for human review even if the ML model is confident. If set to `NEVER`, never send the image query for human review even if the ML model is not confident.. [optional] image_query_id (str): The ID to assign to the created image query.. [optional] inspection_id (str): Associate the image query with an inspection.. [optional] diff --git a/generated/groundlight_openapi_client/model/counting_result.py b/generated/groundlight_openapi_client/model/counting_result.py index 1bc61441..774cabce 100644 --- a/generated/groundlight_openapi_client/model/counting_result.py +++ b/generated/groundlight_openapi_client/model/counting_result.py @@ -64,6 +64,9 @@ class CountingResult(ModelNormal): } validations = { + ("count",): { + "inclusive_minimum": 0, + }, ("confidence",): { "inclusive_maximum": 1.0, "inclusive_minimum": 0.0, diff --git a/generated/groundlight_openapi_client/model/patched_detector_request.py b/generated/groundlight_openapi_client/model/patched_detector_request.py index 251cb75d..64534047 100644 --- a/generated/groundlight_openapi_client/model/patched_detector_request.py +++ b/generated/groundlight_openapi_client/model/patched_detector_request.py @@ -8,6 +8,7 @@ Generated by: https://openapi-generator.tech """ + import re # noqa: F401 import sys # noqa: F401 @@ -24,7 +25,7 @@ file_type, none_type, validate_get_composed_info, - OpenApiModel, + OpenApiModel ) from groundlight_openapi_client.exceptions import ApiAttributeError @@ -33,10 +34,9 @@ def lazy_import(): from groundlight_openapi_client.model.blank_enum import BlankEnum from groundlight_openapi_client.model.escalation_type_enum import EscalationTypeEnum from groundlight_openapi_client.model.status_enum import StatusEnum - - globals()["BlankEnum"] = BlankEnum - globals()["EscalationTypeEnum"] = EscalationTypeEnum - globals()["StatusEnum"] = StatusEnum + globals()['BlankEnum'] = BlankEnum + globals()['EscalationTypeEnum'] = EscalationTypeEnum + globals()['StatusEnum'] = StatusEnum class PatchedDetectorRequest(ModelNormal): @@ -63,20 +63,21 @@ class PatchedDetectorRequest(ModelNormal): as additional properties values. """ - allowed_values = {} + allowed_values = { + } validations = { - ("name",): { - "max_length": 200, - "min_length": 1, + ('name',): { + 'max_length': 200, + 'min_length': 1, }, - ("confidence_threshold",): { - "inclusive_maximum": 1.0, - "inclusive_minimum": 0.0, + ('confidence_threshold',): { + 'inclusive_maximum': 1.0, + 'inclusive_minimum': 0.0, }, - ("patience_time",): { - "inclusive_maximum": 3600, - "inclusive_minimum": 0, + ('patience_time',): { + 'inclusive_maximum': 3600, + 'inclusive_minimum': 0, }, } @@ -87,17 +88,7 @@ def additional_properties_type(): of type self, this must run after the class is loaded """ lazy_import() - return ( - bool, - date, - datetime, - dict, - float, - int, - list, - str, - none_type, - ) # noqa: E501 + return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501 _nullable = False @@ -113,46 +104,28 @@ def openapi_types(): """ lazy_import() return { - "name": (str,), # noqa: E501 - "confidence_threshold": (float,), # noqa: E501 - "patience_time": (float,), # noqa: E501 - "status": ( - bool, - date, - datetime, - dict, - float, - int, - list, - str, - none_type, - ), # noqa: E501 - "escalation_type": ( - bool, - date, - datetime, - dict, - float, - int, - list, - str, - none_type, - ), # noqa: E501 + 'name': (str,), # noqa: E501 + 'confidence_threshold': (float,), # noqa: E501 + 'patience_time': (float,), # noqa: E501 + 'status': (bool, date, datetime, dict, float, int, list, str, none_type,), # noqa: E501 + 'escalation_type': (bool, date, datetime, dict, float, int, list, str, none_type,), # noqa: E501 } @cached_property def discriminator(): return None + attribute_map = { - "name": "name", # noqa: E501 - "confidence_threshold": "confidence_threshold", # noqa: E501 - "patience_time": "patience_time", # noqa: E501 - "status": "status", # noqa: E501 - "escalation_type": "escalation_type", # noqa: E501 + 'name': 'name', # noqa: E501 + 'confidence_threshold': 'confidence_threshold', # noqa: E501 + 'patience_time': 'patience_time', # noqa: E501 + 'status': 'status', # noqa: E501 + 'escalation_type': 'escalation_type', # noqa: E501 } - read_only_vars = {} + read_only_vars = { + } _composed_schemas = {} @@ -199,18 +172,17 @@ def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 escalation_type (bool, date, datetime, dict, float, int, list, str, none_type): Category that define internal proccess for labeling image queries * `STANDARD` - STANDARD * `NO_HUMAN_LABELING` - NO_HUMAN_LABELING. [optional] # noqa: E501 """ - _check_type = kwargs.pop("_check_type", True) - _spec_property_naming = kwargs.pop("_spec_property_naming", False) - _path_to_item = kwargs.pop("_path_to_item", ()) - _configuration = kwargs.pop("_configuration", None) - _visited_composed_classes = kwargs.pop("_visited_composed_classes", ()) + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) self = super(OpenApiModel, cls).__new__(cls) if args: raise ApiTypeError( - "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." - % ( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( args, self.__class__.__name__, ), @@ -226,24 +198,22 @@ def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 self._visited_composed_classes = _visited_composed_classes + (self.__class__,) for var_name, var_value in kwargs.items(): - if ( - var_name not in self.attribute_map - and self._configuration is not None - and self._configuration.discard_unknown_keys - and self.additional_properties_type is None - ): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: # discard variable. continue setattr(self, var_name, var_value) return self required_properties = set([ - "_data_store", - "_check_type", - "_spec_property_naming", - "_path_to_item", - "_configuration", - "_visited_composed_classes", + '_data_store', + '_check_type', + '_spec_property_naming', + '_path_to_item', + '_configuration', + '_visited_composed_classes', ]) @convert_js_args_to_python_args @@ -288,16 +258,15 @@ def __init__(self, *args, **kwargs): # noqa: E501 escalation_type (bool, date, datetime, dict, float, int, list, str, none_type): Category that define internal proccess for labeling image queries * `STANDARD` - STANDARD * `NO_HUMAN_LABELING` - NO_HUMAN_LABELING. [optional] # noqa: E501 """ - _check_type = kwargs.pop("_check_type", True) - _spec_property_naming = kwargs.pop("_spec_property_naming", False) - _path_to_item = kwargs.pop("_path_to_item", ()) - _configuration = kwargs.pop("_configuration", None) - _visited_composed_classes = kwargs.pop("_visited_composed_classes", ()) + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) if args: raise ApiTypeError( - "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." - % ( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( args, self.__class__.__name__, ), @@ -313,17 +282,13 @@ def __init__(self, *args, **kwargs): # noqa: E501 self._visited_composed_classes = _visited_composed_classes + (self.__class__,) for var_name, var_value in kwargs.items(): - if ( - var_name not in self.attribute_map - and self._configuration is not None - and self._configuration.discard_unknown_keys - and self.additional_properties_type is None - ): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: # discard variable. continue setattr(self, var_name, var_value) if var_name in self.read_only_vars: - raise ApiAttributeError( - f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " - "class with read only attributes." - ) + raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " + f"class with read only attributes.") diff --git a/generated/model.py b/generated/model.py index a6de6439..205300f6 100644 --- a/generated/model.py +++ b/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: public-api.yaml -# timestamp: 2024-12-05T21:27:07+00:00 +# timestamp: 2024-12-05T23:53:32+00:00 from __future__ import annotations @@ -200,7 +200,7 @@ class BinaryClassificationResult(BaseModel): class CountingResult(BaseModel): confidence: Optional[confloat(ge=0.0, le=1.0)] = None source: Optional[Source] = None - count: int + count: conint(ge=0) greater_than_max: Optional[bool] = None From 5307dd98fe6d1cbd4271c89a42ab6392326ee1a4 Mon Sep 17 00:00:00 2001 From: CoreyEWood Date: Mon, 9 Dec 2024 18:29:37 +0000 Subject: [PATCH 6/6] re-generate, new timestamp --- generated/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generated/model.py b/generated/model.py index dab8884e..25027f04 100644 --- a/generated/model.py +++ b/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: public-api.yaml -# timestamp: 2024-12-07T00:51:02+00:00 +# timestamp: 2024-12-09T18:29:17+00:00 from __future__ import annotations