From 25d646a783fa5f9e2920895d1d738763a2e1240a Mon Sep 17 00:00:00 2001 From: Brandon <132288221+brandon-groundlight@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:22:24 -0700 Subject: [PATCH 1/7] Reset detector (#242) * add reset detector code --------- Co-authored-by: Auto-format Bot --- generated/.openapi-generator/FILES | 5 + generated/README.md | 2 + generated/docs/Detector.md | 2 +- generated/docs/DetectorResetApi.md | 84 +++++++++++ generated/docs/ModeEnum.md | 3 +- generated/docs/NoteRequest.md | 1 + generated/docs/NotesApi.md | 23 ++- .../api/detector_reset_api.py | 134 ++++++++++++++++++ .../api/notes_api.py | 45 +++--- .../apis/__init__.py | 1 + .../model/detector.py | 16 ++- .../model/mode_enum.py | 8 +- .../model/note_request.py | 7 + .../models/__init__.py | 1 + generated/model.py | 10 +- generated/test/test_detector_reset_api.py | 32 +++++ spec/public-api.yaml | 30 +++- src/groundlight/experimental_api.py | 14 +- test/unit/test_detector_reset.py | 33 +++++ 19 files changed, 385 insertions(+), 66 deletions(-) create mode 100644 generated/docs/DetectorResetApi.md create mode 100644 generated/groundlight_openapi_client/api/detector_reset_api.py create mode 100644 generated/test/test_detector_reset_api.py create mode 100644 test/unit/test_detector_reset.py diff --git a/generated/.openapi-generator/FILES b/generated/.openapi-generator/FILES index fd6931f8..b50ee923 100644 --- a/generated/.openapi-generator/FILES +++ b/generated/.openapi-generator/FILES @@ -19,6 +19,7 @@ docs/DetectorCreationInputRequest.md docs/DetectorGroup.md docs/DetectorGroupRequest.md docs/DetectorGroupsApi.md +docs/DetectorResetApi.md docs/DetectorTypeEnum.md docs/DetectorsApi.md docs/ImageQueriesApi.md @@ -30,6 +31,7 @@ docs/LabelValueRequest.md docs/LabelsApi.md docs/ModeEnum.md docs/Note.md +docs/NoteRequest.md docs/NotesApi.md docs/PaginatedDetectorList.md docs/PaginatedImageQueryList.md @@ -48,6 +50,7 @@ groundlight_openapi_client/__init__.py groundlight_openapi_client/api/__init__.py groundlight_openapi_client/api/actions_api.py groundlight_openapi_client/api/detector_groups_api.py +groundlight_openapi_client/api/detector_reset_api.py groundlight_openapi_client/api/detectors_api.py groundlight_openapi_client/api/image_queries_api.py groundlight_openapi_client/api/labels_api.py @@ -81,6 +84,7 @@ groundlight_openapi_client/model/label_value.py groundlight_openapi_client/model/label_value_request.py groundlight_openapi_client/model/mode_enum.py groundlight_openapi_client/model/note.py +groundlight_openapi_client/model/note_request.py groundlight_openapi_client/model/paginated_detector_list.py groundlight_openapi_client/model/paginated_image_query_list.py groundlight_openapi_client/model/paginated_rule_list.py @@ -100,4 +104,5 @@ setup.cfg setup.py test-requirements.txt test/__init__.py +test/test_detector_reset_api.py tox.ini diff --git a/generated/README.md b/generated/README.md index 33bdaaf2..3c94e2ab 100644 --- a/generated/README.md +++ b/generated/README.md @@ -116,6 +116,7 @@ Class | Method | HTTP request | Description *ActionsApi* | [**list_rules**](docs/ActionsApi.md#list_rules) | **GET** /v1/actions/rules | *DetectorGroupsApi* | [**create_detector_group**](docs/DetectorGroupsApi.md#create_detector_group) | **POST** /v1/detector-groups | *DetectorGroupsApi* | [**get_detector_groups**](docs/DetectorGroupsApi.md#get_detector_groups) | **GET** /v1/detector-groups | +*DetectorResetApi* | [**reset_detector**](docs/DetectorResetApi.md#reset_detector) | **DELETE** /v1/detector-reset/{id} | *DetectorsApi* | [**create_detector**](docs/DetectorsApi.md#create_detector) | **POST** /v1/detectors | *DetectorsApi* | [**create_detector_group2**](docs/DetectorsApi.md#create_detector_group2) | **POST** /v1/detectors/detector-groups | *DetectorsApi* | [**delete_detector**](docs/DetectorsApi.md#delete_detector) | **DELETE** /v1/detectors/{id} | @@ -157,6 +158,7 @@ Class | Method | HTTP request | Description - [LabelValueRequest](docs/LabelValueRequest.md) - [ModeEnum](docs/ModeEnum.md) - [Note](docs/Note.md) + - [NoteRequest](docs/NoteRequest.md) - [PaginatedDetectorList](docs/PaginatedDetectorList.md) - [PaginatedImageQueryList](docs/PaginatedImageQueryList.md) - [PaginatedRuleList](docs/PaginatedRuleList.md) diff --git a/generated/docs/Detector.md b/generated/docs/Detector.md index 0902c379..831cc759 100644 --- a/generated/docs/Detector.md +++ b/generated/docs/Detector.md @@ -12,7 +12,7 @@ Name | Type | Description | Notes **query** | **str** | A question about the image. | [readonly] **group_name** | **str** | Which group should this detector be part of? | [readonly] **metadata** | **{str: (bool, date, datetime, dict, float, int, list, str, none_type)}, none_type** | Metadata about the detector. | [readonly] -**mode** | **str** | | [readonly] +**mode** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [readonly] **mode_configuration** | **{str: (bool, date, datetime, dict, float, int, list, str, none_type)}, none_type** | | [readonly] **confidence_threshold** | **float** | If the detector's prediction is below this confidence threshold, send the image query for human review. | [optional] if omitted the server will use the default value of 0.9 **patience_time** | **float** | How long Groundlight will attempt to generate a confident prediction | [optional] if omitted the server will use the default value of 30.0 diff --git a/generated/docs/DetectorResetApi.md b/generated/docs/DetectorResetApi.md new file mode 100644 index 00000000..087d781c --- /dev/null +++ b/generated/docs/DetectorResetApi.md @@ -0,0 +1,84 @@ +# groundlight_openapi_client.DetectorResetApi + +All URIs are relative to *https://api.groundlight.ai/device-api* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**reset_detector**](DetectorResetApi.md#reset_detector) | **DELETE** /v1/detector-reset/{id} | + + +# **reset_detector** +> reset_detector(id) + + + +Deletes all image queries on the detector + +### Example + +* Api Key Authentication (ApiToken): + +```python +import time +import groundlight_openapi_client +from groundlight_openapi_client.api import detector_reset_api +from pprint import pprint +# Defining the host is optional and defaults to https://api.groundlight.ai/device-api +# See configuration.py for a list of all supported configuration parameters. +configuration = groundlight_openapi_client.Configuration( + host = "https://api.groundlight.ai/device-api" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure API key authorization: ApiToken +configuration.api_key['ApiToken'] = 'YOUR_API_KEY' + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['ApiToken'] = 'Bearer' + +# Enter a context with an instance of the API client +with groundlight_openapi_client.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = detector_reset_api.DetectorResetApi(api_client) + id = "id_example" # str | + + # example passing only required values which don't have defaults set + try: + api_instance.reset_detector(id) + except groundlight_openapi_client.ApiException as e: + print("Exception when calling DetectorResetApi->reset_detector: %s\n" % e) +``` + + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **str**| | + +### Return type + +void (empty response body) + +### Authorization + +[ApiToken](../README.md#ApiToken) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: Not defined + + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**204** | No response body | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/generated/docs/ModeEnum.md b/generated/docs/ModeEnum.md index 670fef49..178498d0 100644 --- a/generated/docs/ModeEnum.md +++ b/generated/docs/ModeEnum.md @@ -1,11 +1,10 @@ # ModeEnum -* `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**value** | **str** | * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS | must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] +**value** | **str** | | must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] [[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/NoteRequest.md b/generated/docs/NoteRequest.md index 730546a8..4410b952 100644 --- a/generated/docs/NoteRequest.md +++ b/generated/docs/NoteRequest.md @@ -5,6 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **content** | **str** | Text content of the note. | +**image** | **file_type, none_type** | | [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/NotesApi.md b/generated/docs/NotesApi.md index 5e0a4a0b..877f4f8b 100644 --- a/generated/docs/NotesApi.md +++ b/generated/docs/NotesApi.md @@ -9,7 +9,7 @@ Method | HTTP request | Description # **create_note** -> create_note(detector_id, content) +> create_note(detector_id, note_request) @@ -23,6 +23,7 @@ Create a new note import time import groundlight_openapi_client from groundlight_openapi_client.api import notes_api +from groundlight_openapi_client.model.note_request import NoteRequest from pprint import pprint # Defining the host is optional and defaults to https://api.groundlight.ai/device-api # See configuration.py for a list of all supported configuration parameters. @@ -46,19 +47,14 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = notes_api.NotesApi(api_client) detector_id = "detector_id_example" # str | the detector to associate the new note with - content = "content_example" # str | Text content of the note. - image = open('/path/to/file', 'rb') # file_type, none_type | (optional) + note_request = NoteRequest( + content="content_example", + image=open('/path/to/file', 'rb'), + ) # NoteRequest | # example passing only required values which don't have defaults set try: - api_instance.create_note(detector_id, content) - except groundlight_openapi_client.ApiException as e: - print("Exception when calling NotesApi->create_note: %s\n" % e) - - # example passing only required values which don't have defaults set - # and optional values - try: - api_instance.create_note(detector_id, content, image=image) + api_instance.create_note(detector_id, note_request) except groundlight_openapi_client.ApiException as e: print("Exception when calling NotesApi->create_note: %s\n" % e) ``` @@ -69,8 +65,7 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **detector_id** | **str**| the detector to associate the new note with | - **content** | **str**| Text content of the note. | - **image** | **file_type, none_type**| | [optional] + **note_request** | [**NoteRequest**](NoteRequest.md)| | ### Return type @@ -82,7 +77,7 @@ void (empty response body) ### HTTP request headers - - **Content-Type**: multipart/form-data + - **Content-Type**: application/json, application/x-www-form-urlencoded, multipart/form-data - **Accept**: Not defined diff --git a/generated/groundlight_openapi_client/api/detector_reset_api.py b/generated/groundlight_openapi_client/api/detector_reset_api.py new file mode 100644 index 00000000..6940a302 --- /dev/null +++ b/generated/groundlight_openapi_client/api/detector_reset_api.py @@ -0,0 +1,134 @@ +""" + Groundlight API + + Groundlight makes it simple to understand images. You can easily create computer vision detectors just by describing what you want to know using natural language. # noqa: E501 + + The version of the OpenAPI document: 0.15.3 + Contact: support@groundlight.ai + Generated by: https://openapi-generator.tech +""" + +import re # noqa: F401 +import sys # noqa: F401 + +from groundlight_openapi_client.api_client import ApiClient, Endpoint as _Endpoint +from groundlight_openapi_client.model_utils import ( # noqa: F401 + check_allowed_values, + check_validations, + date, + datetime, + file_type, + none_type, + validate_and_convert_types, +) + + +class DetectorResetApi(object): + """NOTE: This class is auto generated by OpenAPI Generator + Ref: https://openapi-generator.tech + + Do not edit the class manually. + """ + + def __init__(self, api_client=None): + if api_client is None: + api_client = ApiClient() + self.api_client = api_client + self.reset_detector_endpoint = _Endpoint( + settings={ + "response_type": None, + "auth": ["ApiToken"], + "endpoint_path": "/v1/detector-reset/{id}", + "operation_id": "reset_detector", + "http_method": "DELETE", + "servers": None, + }, + params_map={ + "all": [ + "id", + ], + "required": [ + "id", + ], + "nullable": [], + "enum": [], + "validation": [], + }, + root_map={ + "validations": {}, + "allowed_values": {}, + "openapi_types": { + "id": (str,), + }, + "attribute_map": { + "id": "id", + }, + "location_map": { + "id": "path", + }, + "collection_format_map": {}, + }, + headers_map={ + "accept": [], + "content_type": [], + }, + api_client=api_client, + ) + + def reset_detector(self, id, **kwargs): + """reset_detector # noqa: E501 + + Deletes all image queries on the detector # noqa: E501 + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.reset_detector(id, async_req=True) + >>> result = thread.get() + + Args: + id (str): + + Keyword Args: + _return_http_data_only (bool): response data without head status + code and headers. Default is True. + _preload_content (bool): if False, the urllib3.HTTPResponse object + will be returned without reading/decoding response data. + Default is True. + _request_timeout (int/float/tuple): timeout setting for this request. If + one number provided, it will be total request timeout. It can also + be a pair (tuple) of (connection, read) timeouts. + Default is None. + _check_input_type (bool): specifies if type checking + should be done one the data sent to the server. + Default is True. + _check_return_type (bool): specifies if type checking + should be done one the data received from the server. + Default is True. + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _content_type (str/None): force body content-type. + Default is None and content-type will be predicted by allowed + content-types and body. + _host_index (int/None): specifies the index of the server + that we want to use. + Default is read from the configuration. + async_req (bool): execute request asynchronously + + Returns: + None + If the method is called asynchronously, returns the request + thread. + """ + kwargs["async_req"] = kwargs.get("async_req", False) + kwargs["_return_http_data_only"] = kwargs.get("_return_http_data_only", True) + kwargs["_preload_content"] = kwargs.get("_preload_content", True) + kwargs["_request_timeout"] = kwargs.get("_request_timeout", None) + kwargs["_check_input_type"] = kwargs.get("_check_input_type", True) + kwargs["_check_return_type"] = kwargs.get("_check_return_type", True) + kwargs["_spec_property_naming"] = kwargs.get("_spec_property_naming", False) + kwargs["_content_type"] = kwargs.get("_content_type") + kwargs["_host_index"] = kwargs.get("_host_index") + kwargs["id"] = id + return self.reset_detector_endpoint.call_with_http_info(**kwargs) diff --git a/generated/groundlight_openapi_client/api/notes_api.py b/generated/groundlight_openapi_client/api/notes_api.py index 14377076..00b937e7 100644 --- a/generated/groundlight_openapi_client/api/notes_api.py +++ b/generated/groundlight_openapi_client/api/notes_api.py @@ -22,6 +22,7 @@ validate_and_convert_types, ) from groundlight_openapi_client.model.all_notes import AllNotes +from groundlight_openapi_client.model.note_request import NoteRequest class NotesApi(object): @@ -47,49 +48,36 @@ def __init__(self, api_client=None): params_map={ "all": [ "detector_id", - "content", - "image", + "note_request", ], "required": [ "detector_id", - "content", - ], - "nullable": [ - "image", + "note_request", ], + "nullable": [], "enum": [], - "validation": [ - "content", - ], + "validation": [], }, root_map={ - "validations": { - ("content",): { - "min_length": 1, - }, - }, + "validations": {}, "allowed_values": {}, "openapi_types": { "detector_id": (str,), - "content": (str,), - "image": ( - file_type, - none_type, - ), + "note_request": (NoteRequest,), }, "attribute_map": { "detector_id": "detector_id", - "content": "content", - "image": "image", }, "location_map": { "detector_id": "query", - "content": "form", - "image": "form", + "note_request": "body", }, "collection_format_map": {}, }, - headers_map={"accept": [], "content_type": ["multipart/form-data"]}, + headers_map={ + "accept": [], + "content_type": ["application/json", "application/x-www-form-urlencoded", "multipart/form-data"], + }, api_client=api_client, ) self.get_notes_endpoint = _Endpoint( @@ -133,22 +121,21 @@ def __init__(self, api_client=None): api_client=api_client, ) - def create_note(self, detector_id, content, **kwargs): + def create_note(self, detector_id, note_request, **kwargs): """create_note # noqa: E501 Create a new note # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.create_note(detector_id, content, async_req=True) + >>> thread = api.create_note(detector_id, note_request, async_req=True) >>> result = thread.get() Args: detector_id (str): the detector to associate the new note with - content (str): Text content of the note. + note_request (NoteRequest): Keyword Args: - image (file_type, none_type): [optional] _return_http_data_only (bool): response data without head status code and headers. Default is True. _preload_content (bool): if False, the urllib3.HTTPResponse object @@ -191,7 +178,7 @@ def create_note(self, detector_id, content, **kwargs): kwargs["_content_type"] = kwargs.get("_content_type") kwargs["_host_index"] = kwargs.get("_host_index") kwargs["detector_id"] = detector_id - kwargs["content"] = content + kwargs["note_request"] = note_request return self.create_note_endpoint.call_with_http_info(**kwargs) def get_notes(self, detector_id, **kwargs): diff --git a/generated/groundlight_openapi_client/apis/__init__.py b/generated/groundlight_openapi_client/apis/__init__.py index 2015077b..ef5c1236 100644 --- a/generated/groundlight_openapi_client/apis/__init__.py +++ b/generated/groundlight_openapi_client/apis/__init__.py @@ -15,6 +15,7 @@ # Import APIs into API package: from groundlight_openapi_client.api.actions_api import ActionsApi from groundlight_openapi_client.api.detector_groups_api import DetectorGroupsApi +from groundlight_openapi_client.api.detector_reset_api import DetectorResetApi from groundlight_openapi_client.api.detectors_api import DetectorsApi from groundlight_openapi_client.api.image_queries_api import ImageQueriesApi from groundlight_openapi_client.api.labels_api import LabelsApi diff --git a/generated/groundlight_openapi_client/model/detector.py b/generated/groundlight_openapi_client/model/detector.py index 95248c0f..c97818c2 100644 --- a/generated/groundlight_openapi_client/model/detector.py +++ b/generated/groundlight_openapi_client/model/detector.py @@ -31,8 +31,10 @@ def lazy_import(): from groundlight_openapi_client.model.detector_type_enum import DetectorTypeEnum + from groundlight_openapi_client.model.mode_enum import ModeEnum globals()["DetectorTypeEnum"] = DetectorTypeEnum + globals()["ModeEnum"] = ModeEnum class Detector(ModelNormal): @@ -128,7 +130,17 @@ def openapi_types(): {str: (bool, date, datetime, dict, float, int, list, str, none_type)}, none_type, ), # noqa: E501 - "mode": (str,), # noqa: E501 + "mode": ( + bool, + date, + datetime, + dict, + float, + int, + list, + str, + none_type, + ), # noqa: E501 "mode_configuration": ( {str: (bool, date, datetime, dict, float, int, list, str, none_type)}, none_type, @@ -183,7 +195,7 @@ def _from_openapi_data( query (str): A question about the image. group_name (str): Which group should this detector be part of? metadata ({str: (bool, date, datetime, dict, float, int, list, str, none_type)}, none_type): Metadata about the detector. - mode (str): + mode (bool, date, datetime, dict, float, int, list, str, none_type): mode_configuration ({str: (bool, date, datetime, dict, float, int, list, str, none_type)}, none_type): Keyword Args: diff --git a/generated/groundlight_openapi_client/model/mode_enum.py b/generated/groundlight_openapi_client/model/mode_enum.py index 41f460b2..1ba41227 100644 --- a/generated/groundlight_openapi_client/model/mode_enum.py +++ b/generated/groundlight_openapi_client/model/mode_enum.py @@ -103,10 +103,10 @@ def __init__(self, *args, **kwargs): Note that value can be passed either in args or in kwargs, but not in both. Args: - args[0] (str): * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS., must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 + args[0] (str):, must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 Keyword Args: - value (str): * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS., must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 + value (str):, must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 _check_type (bool): if True, values for parameters in openapi_types will be type checked and a TypeError will be raised if the wrong type is input. @@ -195,10 +195,10 @@ def _from_openapi_data(cls, *args, **kwargs): Note that value can be passed either in args or in kwargs, but not in both. Args: - args[0] (str): * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS., must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 + args[0] (str):, must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 Keyword Args: - value (str): * `BINARY` - BINARY * `COUNT` - COUNT * `MULTI_CLASS` - MULTI_CLASS., must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 + value (str):, must be one of ["BINARY", "COUNT", "MULTI_CLASS", ] # noqa: E501 _check_type (bool): if True, values for parameters in openapi_types will be type checked and a TypeError will be raised if the wrong type is input. diff --git a/generated/groundlight_openapi_client/model/note_request.py b/generated/groundlight_openapi_client/model/note_request.py index bc4961a6..545cb56c 100644 --- a/generated/groundlight_openapi_client/model/note_request.py +++ b/generated/groundlight_openapi_client/model/note_request.py @@ -93,6 +93,10 @@ def openapi_types(): """ return { "content": (str,), # noqa: E501 + "image": ( + file_type, + none_type, + ), # noqa: E501 } @cached_property @@ -101,6 +105,7 @@ def discriminator(): attribute_map = { "content": "content", # noqa: E501 + "image": "image", # noqa: E501 } read_only_vars = {} @@ -146,6 +151,7 @@ def _from_openapi_data(cls, content, *args, **kwargs): # noqa: E501 Animal class but this time we won't travel through its discriminator because we passed in _visited_composed_classes = (Animal,) + image (file_type, none_type): [optional] # noqa: E501 """ _check_type = kwargs.pop("_check_type", True) @@ -234,6 +240,7 @@ def __init__(self, content, *args, **kwargs): # noqa: E501 Animal class but this time we won't travel through its discriminator because we passed in _visited_composed_classes = (Animal,) + image (file_type, none_type): [optional] # noqa: E501 """ _check_type = kwargs.pop("_check_type", True) diff --git a/generated/groundlight_openapi_client/models/__init__.py b/generated/groundlight_openapi_client/models/__init__.py index 95e2b851..0491cc60 100644 --- a/generated/groundlight_openapi_client/models/__init__.py +++ b/generated/groundlight_openapi_client/models/__init__.py @@ -32,6 +32,7 @@ from groundlight_openapi_client.model.label_value_request import LabelValueRequest from groundlight_openapi_client.model.mode_enum import ModeEnum from groundlight_openapi_client.model.note import Note +from groundlight_openapi_client.model.note_request import NoteRequest from groundlight_openapi_client.model.paginated_detector_list import PaginatedDetectorList from groundlight_openapi_client.model.paginated_image_query_list import PaginatedImageQueryList from groundlight_openapi_client.model.paginated_rule_list import PaginatedRuleList diff --git a/generated/model.py b/generated/model.py index 114ded38..fee8fe3c 100644 --- a/generated/model.py +++ b/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: public-api.yaml -# timestamp: 2024-08-14T20:35:47+00:00 +# timestamp: 2024-08-26T21:12:31+00:00 from __future__ import annotations @@ -73,12 +73,6 @@ class ImageQueryTypeEnum(Enum): class ModeEnum(Enum): - """ - * `BINARY` - BINARY - * `COUNT` - COUNT - * `MULTI_CLASS` - MULTI_CLASS - """ - BINARY = "BINARY" COUNT = "COUNT" MULTI_CLASS = "MULTI_CLASS" @@ -231,7 +225,7 @@ class Detector(BaseModel): 30.0, description="How long Groundlight will attempt to generate a confident prediction" ) metadata: Optional[Dict[str, Any]] = Field(..., description="Metadata about the detector.") - mode: str + mode: ModeEnum mode_configuration: Optional[Dict[str, Any]] = Field(...) diff --git a/generated/test/test_detector_reset_api.py b/generated/test/test_detector_reset_api.py new file mode 100644 index 00000000..6473da80 --- /dev/null +++ b/generated/test/test_detector_reset_api.py @@ -0,0 +1,32 @@ +""" + Groundlight API + + Groundlight makes it simple to understand images. You can easily create computer vision detectors just by describing what you want to know using natural language. # noqa: E501 + + The version of the OpenAPI document: 0.15.3 + Contact: support@groundlight.ai + Generated by: https://openapi-generator.tech +""" + +import unittest + +import groundlight_openapi_client +from groundlight_openapi_client.api.detector_reset_api import DetectorResetApi # noqa: E501 + + +class TestDetectorResetApi(unittest.TestCase): + """DetectorResetApi unit test stubs""" + + def setUp(self): + self.api = DetectorResetApi() # noqa: E501 + + def tearDown(self): + pass + + def test_reset_detector(self): + """Test case for reset_detector""" + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/spec/public-api.yaml b/spec/public-api.yaml index d775fe86..1db48358 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -175,6 +175,23 @@ paths: schema: $ref: '#/components/schemas/DetectorGroup' description: '' + /v1/detector-reset/{id}: + delete: + operationId: Reset detector + description: Deletes all image queries on the detector + parameters: + - in: path + name: id + schema: + type: string + required: true + tags: + - detector-reset + security: + - ApiToken: [] + responses: + '204': + description: No response body /v1/detectors: get: operationId: List detectors @@ -534,6 +551,12 @@ paths: - notes requestBody: content: + application/json: + schema: + $ref: '#/components/schemas/NoteRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/NoteRequest' multipart/form-data: schema: $ref: '#/components/schemas/NoteRequest' @@ -731,7 +754,8 @@ components: readOnly: true description: Metadata about the detector. mode: - type: string + allOf: + - $ref: '#/components/schemas/ModeEnum' readOnly: true mode_configuration: type: object @@ -991,10 +1015,6 @@ components: - COUNT - MULTI_CLASS type: string - description: |- - * `BINARY` - BINARY - * `COUNT` - COUNT - * `MULTI_CLASS` - MULTI_CLASS Note: type: object properties: diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index 2386dbe7..97ea089d 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -13,6 +13,7 @@ import requests from groundlight_openapi_client.api.actions_api import ActionsApi from groundlight_openapi_client.api.detector_groups_api import DetectorGroupsApi +from groundlight_openapi_client.api.detector_reset_api import DetectorResetApi from groundlight_openapi_client.api.image_queries_api import ImageQueriesApi from groundlight_openapi_client.api.notes_api import NotesApi from groundlight_openapi_client.model.action_request import ActionRequest @@ -45,6 +46,7 @@ def __init__(self, endpoint: Union[str, None] = None, api_token: Union[str, None self.images_api = ImageQueriesApi(self.api_client) self.notes_api = NotesApi(self.api_client) self.detector_group_api = DetectorGroupsApi(self.api_client) + self.detector_reset_api = DetectorResetApi(self.api_client) ITEMS_PER_PAGE = 100 @@ -207,7 +209,7 @@ def create_note( data = {"content": note} params = {"detector_id": det_id} headers = {"x-api-token": self.configuration.api_key["ApiToken"]} - requests.post(url, headers=headers, data=data, files=files, params=params, timeout=60) # type: ignore + requests.post(url, headers=headers, data=data, files=files, params=params) # type: ignore def create_detector_group(self, name: str) -> DetectorGroup: """ @@ -293,3 +295,13 @@ def add_label( ) request_params = LabelValueRequest(label=api_label, image_query_id=image_query_id, rois=roi_requests) self.labels_api.create_label(request_params) + + def reset_detector(self, detector: Union[str, Detector]) -> None: + """ + Removes all image queries for the given detector + + :param detector_id: the id of the detector to reset + """ + if isinstance(detector, Detector): + detector = detector.id + self.detector_reset_api.reset_detector(detector) diff --git a/test/unit/test_detector_reset.py b/test/unit/test_detector_reset.py new file mode 100644 index 00000000..1a69b468 --- /dev/null +++ b/test/unit/test_detector_reset.py @@ -0,0 +1,33 @@ +import time +from datetime import datetime + +import pytest +from groundlight import ExperimentalApi +from groundlight_openapi_client.exceptions import NotFoundException + + +def test_reset_retry(gl_experimental: ExperimentalApi): + # Reset the detector, retrying in case the reset is still ongoing + det = gl_experimental.create_detector(f"Test {datetime.utcnow()}", "test_query") + iq = gl_experimental.submit_image_query(det, "test/assets/cat.jpeg") + gl_experimental.reset_detector(det.id) + success = False + for _ in range(60): + try: + gl_experimental.get_image_query(iq.id) + except NotFoundException: + with pytest.raises(NotFoundException): + gl_experimental.get_image_query(iq.id) + success = True + break + time.sleep(10) + if not success: + raise Exception("Failed to reset detector") + + +def test_reset_training(gl_experimental: ExperimentalApi): + # If we reset a detector, we should have low confidence after the reset + low_confidence_threshold = 0.6 + det = gl_experimental.get_or_create_detector("Test Detector for Resets", "is this a cat?") + iq = gl_experimental.submit_image_query(det, "test/assets/cat.jpeg") + assert iq.result.confidence < low_confidence_threshold From 55eb6d055e0a258028992312adda6eec66589274 Mon Sep 17 00:00:00 2001 From: Brandon <132288221+brandon-groundlight@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:41:57 -0700 Subject: [PATCH 2/7] bumping version (#245) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bce2e760..53e0e062 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ packages = [ {include = "**/*.py", from = "src"}, ] readme = "README.md" -version = "0.17.4" +version = "0.17.5" [tool.poetry.dependencies] # For certifi, use ">=" instead of "^" since it upgrades its "major version" every year, not really following semver From 5813c601bde823ed14de8f73d9835d854e7ebfe7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:19:23 -0700 Subject: [PATCH 3/7] Bump webpack from 5.89.0 to 5.94.0 in /docs (#246) Bumps [webpack](https://github.com/webpack/webpack) from 5.89.0 to 5.94.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.89.0...v5.94.0) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 205 +++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 112 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 69180a16..949b1fd3 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -2917,30 +2917,30 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2952,12 +2952,12 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@leichtgewicht/ip-codec": { @@ -3535,24 +3535,6 @@ "@types/ms": "*" } }, - "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -3845,9 +3827,9 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -3864,9 +3846,9 @@ "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", @@ -3884,14 +3866,14 @@ "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { @@ -3916,26 +3898,26 @@ "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", "@webassemblyjs/leb128": "1.11.6", @@ -3943,22 +3925,22 @@ } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", @@ -3967,11 +3949,11 @@ } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -4027,10 +4009,10 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "peerDependencies": { "acorn": "^8" } @@ -5926,9 +5908,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -14224,12 +14206,12 @@ } }, "node_modules/terser": { - "version": "5.16.8", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz", - "integrity": "sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -14241,15 +14223,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -15062,9 +15044,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -15096,33 +15078,32 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { From 3eb19bece3fe8c71d69cd4a3fc332aef5db73b3b Mon Sep 17 00:00:00 2001 From: Brandon <132288221+brandon-groundlight@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:03:15 -0700 Subject: [PATCH 4/7] Fix reset test (#247) * actually reset detector during test --------- Co-authored-by: Auto-format Bot --- pyproject.toml | 2 +- test/unit/test_detector_reset.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 53e0e062..91e2e2ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ packages = [ {include = "**/*.py", from = "src"}, ] readme = "README.md" -version = "0.17.5" +version = "0.17.6" [tool.poetry.dependencies] # For certifi, use ">=" instead of "^" since it upgrades its "major version" every year, not really following semver diff --git a/test/unit/test_detector_reset.py b/test/unit/test_detector_reset.py index 1a69b468..db3ef1f0 100644 --- a/test/unit/test_detector_reset.py +++ b/test/unit/test_detector_reset.py @@ -29,5 +29,6 @@ def test_reset_training(gl_experimental: ExperimentalApi): # If we reset a detector, we should have low confidence after the reset low_confidence_threshold = 0.6 det = gl_experimental.get_or_create_detector("Test Detector for Resets", "is this a cat?") + gl_experimental.reset_detector(det.id) iq = gl_experimental.submit_image_query(det, "test/assets/cat.jpeg") assert iq.result.confidence < low_confidence_threshold From 99ed137d12524f83a6c4de82de5234f630449078 Mon Sep 17 00:00:00 2001 From: Brandon <132288221+brandon-groundlight@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:41:28 -0700 Subject: [PATCH 5/7] Fixing reset test (#248) * Human labels currently return with None confidence, account for this --- test/unit/test_detector_reset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_detector_reset.py b/test/unit/test_detector_reset.py index db3ef1f0..83393546 100644 --- a/test/unit/test_detector_reset.py +++ b/test/unit/test_detector_reset.py @@ -30,5 +30,5 @@ def test_reset_training(gl_experimental: ExperimentalApi): low_confidence_threshold = 0.6 det = gl_experimental.get_or_create_detector("Test Detector for Resets", "is this a cat?") gl_experimental.reset_detector(det.id) - iq = gl_experimental.submit_image_query(det, "test/assets/cat.jpeg") + iq = gl_experimental.submit_image_query(det, "test/assets/cat.jpeg", human_review="NEVER") assert iq.result.confidence < low_confidence_threshold From 329d86bcbf25fb315ea95bd885d45fc8ddb97ad8 Mon Sep 17 00:00:00 2001 From: Brandon <132288221+brandon-groundlight@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:58:52 -0700 Subject: [PATCH 6/7] testing against the same detector causes actions to fail (#249) --- test/unit/test_detector_reset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_detector_reset.py b/test/unit/test_detector_reset.py index 83393546..65f4d0f9 100644 --- a/test/unit/test_detector_reset.py +++ b/test/unit/test_detector_reset.py @@ -28,7 +28,7 @@ def test_reset_retry(gl_experimental: ExperimentalApi): def test_reset_training(gl_experimental: ExperimentalApi): # If we reset a detector, we should have low confidence after the reset low_confidence_threshold = 0.6 - det = gl_experimental.get_or_create_detector("Test Detector for Resets", "is this a cat?") + det = gl_experimental.create_detector(f"Test {datetime.utcnow()}", "is this a cat") gl_experimental.reset_detector(det.id) iq = gl_experimental.submit_image_query(det, "test/assets/cat.jpeg", human_review="NEVER") assert iq.result.confidence < low_confidence_threshold From 3e377f54b3e76e09e8d7d97ce00d9978287a521a Mon Sep 17 00:00:00 2001 From: Brandon <132288221+brandon-groundlight@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:26:35 -0700 Subject: [PATCH 7/7] Ocr support (#255) * Prioritizing OCR release, this api spec doesn't match any BE version. It skips the Actions update but contains the update for OCR * running the generator * Adding test with new functionality * Automatically reformatting code --------- Co-authored-by: Auto-format Bot --- generated/.openapi-generator/FILES | 1 - generated/docs/ImageQuery.md | 1 + generated/docs/LabelValue.md | 3 ++- generated/docs/ResultTypeEnum.md | 2 +- .../model/image_query.py | 9 +++++++++ .../model/label_value.py | 12 ++++++++++-- .../model/result_type_enum.py | 9 +++++---- generated/model.py | 9 +++++++-- package-lock.json | 8 ++++---- package.json | 4 ++-- spec/public-api.yaml | 15 ++++++++++++++- test/integration/test_groundlight.py | 9 +++++++++ 12 files changed, 64 insertions(+), 18 deletions(-) diff --git a/generated/.openapi-generator/FILES b/generated/.openapi-generator/FILES index b50ee923..1258ead7 100644 --- a/generated/.openapi-generator/FILES +++ b/generated/.openapi-generator/FILES @@ -104,5 +104,4 @@ setup.cfg setup.py test-requirements.txt test/__init__.py -test/test_detector_reset_api.py tox.ini diff --git a/generated/docs/ImageQuery.md b/generated/docs/ImageQuery.md index e75a620b..2d3d6c48 100644 --- a/generated/docs/ImageQuery.md +++ b/generated/docs/ImageQuery.md @@ -16,6 +16,7 @@ Name | Type | Description | Notes **patience_time** | **float** | How long to wait for a confident response. | [readonly] **confidence_threshold** | **float** | Min confidence needed to accept the response of the image query. | [readonly] **rois** | [**[ROI], none_type**](ROI.md) | An array of regions of interest (bounding boxes) collected on image | [readonly] +**text** | **str, none_type** | A text field on image query. | [readonly] **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/LabelValue.md b/generated/docs/LabelValue.md index a96d9ab6..acbb0e6f 100644 --- a/generated/docs/LabelValue.md +++ b/generated/docs/LabelValue.md @@ -5,11 +5,12 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **confidence** | **float, none_type** | | [readonly] -**class_name** | **str, none_type** | A human-readable class name for this label (e.g. YES/NO) | [readonly] +**class_name** | **str, none_type** | Return a human-readable class name for this label (e.g. YES/NO) | [readonly] **annotations_requested** | **[bool, date, datetime, dict, float, int, list, str, none_type]** | | [readonly] **created_at** | **datetime** | | [readonly] **detector_id** | **int, none_type** | | [readonly] **source** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [readonly] +**text** | **str, none_type** | Text annotations | [readonly] **rois** | [**[ROI], none_type**](ROI.md) | | [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] diff --git a/generated/docs/ResultTypeEnum.md b/generated/docs/ResultTypeEnum.md index d5292681..352f7694 100644 --- a/generated/docs/ResultTypeEnum.md +++ b/generated/docs/ResultTypeEnum.md @@ -4,7 +4,7 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**value** | **str** | | must be one of ["binary_classification", "counting", ] +**value** | **str** | | must be one of ["binary_classification", "counting", "multi_classification", ] [[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/groundlight_openapi_client/model/image_query.py b/generated/groundlight_openapi_client/model/image_query.py index aa6a5a1b..70cd6666 100644 --- a/generated/groundlight_openapi_client/model/image_query.py +++ b/generated/groundlight_openapi_client/model/image_query.py @@ -151,6 +151,10 @@ def openapi_types(): [ROI], none_type, ), # noqa: E501 + "text": ( + str, + none_type, + ), # noqa: E501 } @cached_property @@ -169,6 +173,7 @@ def discriminator(): "patience_time": "patience_time", # noqa: E501 "confidence_threshold": "confidence_threshold", # noqa: E501 "rois": "rois", # noqa: E501 + "text": "text", # noqa: E501 } read_only_vars = { @@ -183,6 +188,7 @@ def discriminator(): "patience_time", # noqa: E501 "confidence_threshold", # noqa: E501 "rois", # noqa: E501 + "text", # noqa: E501 } _composed_schemas = {} @@ -202,6 +208,7 @@ def _from_openapi_data( patience_time, confidence_threshold, rois, + text, *args, **kwargs, ): # noqa: E501 @@ -219,6 +226,7 @@ def _from_openapi_data( patience_time (float): How long to wait for a confident response. confidence_threshold (float): Min confidence needed to accept the response of the image query. rois ([ROI], none_type): An array of regions of interest (bounding boxes) collected on image + text (str, none_type): A text field on image query. Keyword Args: _check_type (bool): if True, values for parameters in openapi_types @@ -290,6 +298,7 @@ def _from_openapi_data( self.patience_time = patience_time self.confidence_threshold = confidence_threshold self.rois = rois + self.text = text for var_name, var_value in kwargs.items(): if ( var_name not in self.attribute_map diff --git a/generated/groundlight_openapi_client/model/label_value.py b/generated/groundlight_openapi_client/model/label_value.py index b6ac9148..1aaf7381 100644 --- a/generated/groundlight_openapi_client/model/label_value.py +++ b/generated/groundlight_openapi_client/model/label_value.py @@ -125,6 +125,10 @@ def openapi_types(): str, none_type, ), # noqa: E501 + "text": ( + str, + none_type, + ), # noqa: E501 "rois": ( [ROI], none_type, @@ -142,6 +146,7 @@ def discriminator(): "created_at": "created_at", # noqa: E501 "detector_id": "detector_id", # noqa: E501 "source": "source", # noqa: E501 + "text": "text", # noqa: E501 "rois": "rois", # noqa: E501 } @@ -152,6 +157,7 @@ def discriminator(): "created_at", # noqa: E501 "detector_id", # noqa: E501 "source", # noqa: E501 + "text", # noqa: E501 } _composed_schemas = {} @@ -159,17 +165,18 @@ def discriminator(): @classmethod @convert_js_args_to_python_args def _from_openapi_data( - cls, confidence, class_name, annotations_requested, created_at, detector_id, source, *args, **kwargs + cls, confidence, class_name, annotations_requested, created_at, detector_id, source, text, *args, **kwargs ): # noqa: E501 """LabelValue - a model defined in OpenAPI Args: confidence (float, none_type): - class_name (str, none_type): A human-readable class name for this label (e.g. YES/NO) + class_name (str, none_type): Return a human-readable class name for this label (e.g. YES/NO) annotations_requested ([bool, date, datetime, dict, float, int, list, str, none_type]): created_at (datetime): detector_id (int, none_type): source (bool, date, datetime, dict, float, int, list, str, none_type): + text (str, none_type): Text annotations Keyword Args: _check_type (bool): if True, values for parameters in openapi_types @@ -237,6 +244,7 @@ def _from_openapi_data( self.created_at = created_at self.detector_id = detector_id self.source = source + self.text = text for var_name, var_value in kwargs.items(): if ( var_name not in self.attribute_map diff --git a/generated/groundlight_openapi_client/model/result_type_enum.py b/generated/groundlight_openapi_client/model/result_type_enum.py index ea4702e4..8441a6c6 100644 --- a/generated/groundlight_openapi_client/model/result_type_enum.py +++ b/generated/groundlight_openapi_client/model/result_type_enum.py @@ -53,6 +53,7 @@ class ResultTypeEnum(ModelSimple): ("value",): { "BINARY_CLASSIFICATION": "binary_classification", "COUNTING": "counting", + "MULTI_CLASSIFICATION": "multi_classification", }, } @@ -102,10 +103,10 @@ def __init__(self, *args, **kwargs): Note that value can be passed either in args or in kwargs, but not in both. Args: - args[0] (str):, must be one of ["binary_classification", "counting", ] # noqa: E501 + args[0] (str):, must be one of ["binary_classification", "counting", "multi_classification", ] # noqa: E501 Keyword Args: - value (str):, must be one of ["binary_classification", "counting", ] # noqa: E501 + value (str):, must be one of ["binary_classification", "counting", "multi_classification", ] # noqa: E501 _check_type (bool): if True, values for parameters in openapi_types will be type checked and a TypeError will be raised if the wrong type is input. @@ -194,10 +195,10 @@ def _from_openapi_data(cls, *args, **kwargs): Note that value can be passed either in args or in kwargs, but not in both. Args: - args[0] (str):, must be one of ["binary_classification", "counting", ] # noqa: E501 + args[0] (str):, must be one of ["binary_classification", "counting", "multi_classification", ] # noqa: E501 Keyword Args: - value (str):, must be one of ["binary_classification", "counting", ] # noqa: E501 + value (str):, must be one of ["binary_classification", "counting", "multi_classification", ] # noqa: E501 _check_type (bool): if True, values for parameters in openapi_types will be type checked and a TypeError will be raised if the wrong type is input. diff --git a/generated/model.py b/generated/model.py index fee8fe3c..c63cfff5 100644 --- a/generated/model.py +++ b/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: public-api.yaml -# timestamp: 2024-08-26T21:12:31+00:00 +# timestamp: 2024-09-25T21:50:15+00:00 from __future__ import annotations @@ -110,6 +110,7 @@ class ROIRequest(BaseModel): class ResultTypeEnum(Enum): binary_classification = "binary_classification" counting = "counting" + multi_classification = "multi_classification" class SnoozeTimeUnitEnum(Enum): @@ -290,16 +291,20 @@ class ImageQuery(BaseModel): rois: Optional[List[ROI]] = Field( ..., description="An array of regions of interest (bounding boxes) collected on image" ) + text: Optional[str] = Field(..., description="A text field on image query.") class LabelValue(BaseModel): confidence: Optional[float] = Field(...) - class_name: Optional[str] = Field(..., description="A human-readable class name for this label (e.g. YES/NO)") + class_name: Optional[str] = Field( + ..., description="Return a human-readable class name for this label (e.g. YES/NO)" + ) rois: Optional[List[ROI]] = None annotations_requested: List[AnnotationsRequestedEnum] created_at: datetime detector_id: Optional[int] = Field(...) source: SourceEnum + text: Optional[str] = Field(..., description="Text annotations") class LabelValueRequest(BaseModel): diff --git a/package-lock.json b/package-lock.json index 36adb0f7..7d130a8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "name": "groundlight-sdk-generator", "dependencies": { "@openapitools/openapi-generator-cli": "^2.9.0", - "rehype-katex": "^7.0.0", + "rehype-katex": "^7.0.1", "remark-math": "^6.0.0" } }, @@ -1621,9 +1621,9 @@ "license": "Apache-2.0" }, "node_modules/rehype-katex": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.0.tgz", - "integrity": "sha512-h8FPkGE00r2XKU+/acgqwWUlyzve1IiOKwsEkg4pDL3k48PiE0Pt+/uLtVHDVkN1yA4iurZN6UES8ivHVEQV6Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", "dependencies": { "@types/hast": "^3.0.0", "@types/katex": "^0.16.0", diff --git a/package.json b/package.json index c279bd3e..baebe0b9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "groundlight-sdk-generator", "dependencies": { "@openapitools/openapi-generator-cli": "^2.9.0", - "rehype-katex": "^7.0.0", + "rehype-katex": "^7.0.1", "remark-math": "^6.0.0" } -} \ No newline at end of file +} diff --git a/spec/public-api.yaml b/spec/public-api.yaml index 1db48358..53febc53 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -925,6 +925,11 @@ components: nullable: true description: An array of regions of interest (bounding boxes) collected on image + text: + type: string + nullable: true + readOnly: true + description: A text field on image query. required: - confidence_threshold - created_at @@ -936,6 +941,7 @@ components: - result - result_type - rois + - text - type x-internal: true ImageQueryTypeEnum: @@ -953,7 +959,7 @@ components: class_name: type: string nullable: true - description: A human-readable class name for this label (e.g. YES/NO) + description: Return a human-readable class name for this label (e.g. YES/NO) readOnly: true rois: type: array @@ -983,6 +989,11 @@ components: allOf: - $ref: '#/components/schemas/SourceEnum' readOnly: true + text: + type: string + readOnly: true + nullable: true + description: Text annotations required: - annotations_requested - class_name @@ -990,6 +1001,7 @@ components: - created_at - detector_id - source + - text LabelValueRequest: type: object properties: @@ -1145,6 +1157,7 @@ components: enum: - binary_classification - counting + - multi_classification type: string Rule: type: object diff --git a/test/integration/test_groundlight.py b/test/integration/test_groundlight.py index c4c87d14..8240b607 100644 --- a/test/integration/test_groundlight.py +++ b/test/integration/test_groundlight.py @@ -297,6 +297,15 @@ def test_submit_image_query_returns_yes(gl: Groundlight): assert image_query.result.label == Label.YES +def test_submit_image_query_returns_text(gl: Groundlight): + # We use the "never-review" pipeline to guarantee a confident "yes" answer. + detector = gl.get_or_create_detector( + name="Always same text", query="Is there a dog?", pipeline_config="constant-text" + ) + image_query = gl.submit_image_query(detector=detector, image="test/assets/dog.jpeg", wait=10, human_review="NEVER") + assert isinstance(image_query.text, str) + + def test_submit_image_query_filename(gl: Groundlight, detector: Detector): _image_query = gl.submit_image_query(detector=detector.id, image="test/assets/dog.jpeg", human_review="NEVER") assert str(_image_query)