diff --git a/generated/.openapi-generator/FILES b/generated/.openapi-generator/FILES index e97074f3..5b99bab8 100644 --- a/generated/.openapi-generator/FILES +++ b/generated/.openapi-generator/FILES @@ -22,6 +22,8 @@ docs/DetectorGroupsApi.md docs/DetectorResetApi.md docs/DetectorTypeEnum.md docs/DetectorsApi.md +docs/EdgeApi.md +docs/EdgeModelInfo.md docs/EscalationTypeEnum.md docs/ImageQueriesApi.md docs/ImageQuery.md @@ -60,6 +62,7 @@ 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/edge_api.py groundlight_openapi_client/api/image_queries_api.py groundlight_openapi_client/api/labels_api.py groundlight_openapi_client/api/notes_api.py @@ -87,6 +90,7 @@ groundlight_openapi_client/model/detector_creation_input_request.py groundlight_openapi_client/model/detector_group.py groundlight_openapi_client/model/detector_group_request.py groundlight_openapi_client/model/detector_type_enum.py +groundlight_openapi_client/model/edge_model_info.py groundlight_openapi_client/model/escalation_type_enum.py groundlight_openapi_client/model/image_query.py groundlight_openapi_client/model/image_query_type_enum.py @@ -122,7 +126,4 @@ setup.cfg setup.py test-requirements.txt test/__init__.py -test/test_text_recognition_result.py -test/test_webhook_action.py -test/test_webhook_action_request.py tox.ini diff --git a/generated/README.md b/generated/README.md index 881ceeaa..accfe08f 100644 --- a/generated/README.md +++ b/generated/README.md @@ -124,6 +124,7 @@ Class | Method | HTTP request | Description *DetectorsApi* | [**get_detector**](docs/DetectorsApi.md#get_detector) | **GET** /v1/detectors/{id} | *DetectorsApi* | [**list_detectors**](docs/DetectorsApi.md#list_detectors) | **GET** /v1/detectors | *DetectorsApi* | [**update_detector**](docs/DetectorsApi.md#update_detector) | **PATCH** /v1/detectors/{id} | +*EdgeApi* | [**get_model_urls**](docs/EdgeApi.md#get_model_urls) | **GET** /v1/edge/fetch-model-urls/{detector_id}/ | *ImageQueriesApi* | [**get_image**](docs/ImageQueriesApi.md#get_image) | **GET** /v1/image-queries/{id}/image | *ImageQueriesApi* | [**get_image_query**](docs/ImageQueriesApi.md#get_image_query) | **GET** /v1/image-queries/{id} | *ImageQueriesApi* | [**list_image_queries**](docs/ImageQueriesApi.md#list_image_queries) | **GET** /v1/image-queries | @@ -154,6 +155,7 @@ Class | Method | HTTP request | Description - [DetectorGroup](docs/DetectorGroup.md) - [DetectorGroupRequest](docs/DetectorGroupRequest.md) - [DetectorTypeEnum](docs/DetectorTypeEnum.md) + - [EdgeModelInfo](docs/EdgeModelInfo.md) - [EscalationTypeEnum](docs/EscalationTypeEnum.md) - [ImageQuery](docs/ImageQuery.md) - [ImageQueryTypeEnum](docs/ImageQueryTypeEnum.md) diff --git a/generated/docs/Detector.md b/generated/docs/Detector.md index 97d08359..133bfeba 100644 --- a/generated/docs/Detector.md +++ b/generated/docs/Detector.md @@ -1,6 +1,6 @@ # Detector -Spec for serializing a detector object in the public API. +Groundlight Detectors provide answers to natural language questions about images. Each detector can answer a single question, and multiple detectors can be strung together for more complex logic. Detectors can be created through the create_detector method, or through the create_[MODE]_detector methods for pro tier users ## Properties Name | Type | Description | Notes diff --git a/generated/docs/EdgeApi.md b/generated/docs/EdgeApi.md new file mode 100644 index 00000000..a702b352 --- /dev/null +++ b/generated/docs/EdgeApi.md @@ -0,0 +1,86 @@ +# groundlight_openapi_client.EdgeApi + +All URIs are relative to *https://api.groundlight.ai/device-api* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**get_model_urls**](EdgeApi.md#get_model_urls) | **GET** /v1/edge/fetch-model-urls/{detector_id}/ | + + +# **get_model_urls** +> EdgeModelInfo get_model_urls(detector_id) + + + +Gets time limited pre-authenticated URLs to download a detector's edge model and oodd model. + +### Example + +* Api Key Authentication (ApiToken): + +```python +import time +import groundlight_openapi_client +from groundlight_openapi_client.api import edge_api +from groundlight_openapi_client.model.edge_model_info import EdgeModelInfo +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 = edge_api.EdgeApi(api_client) + detector_id = "detector_id_example" # str | + + # example passing only required values which don't have defaults set + try: + api_response = api_instance.get_model_urls(detector_id) + pprint(api_response) + except groundlight_openapi_client.ApiException as e: + print("Exception when calling EdgeApi->get_model_urls: %s\n" % e) +``` + + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **detector_id** | **str**| | + +### Return type + +[**EdgeModelInfo**](EdgeModelInfo.md) + +### Authorization + +[ApiToken](../README.md#ApiToken) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | | - | + +[[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/EdgeModelInfo.md b/generated/docs/EdgeModelInfo.md new file mode 100644 index 00000000..3141373f --- /dev/null +++ b/generated/docs/EdgeModelInfo.md @@ -0,0 +1,19 @@ +# EdgeModelInfo + +Information for the model running on edge, including temporary presigned urls to the model binaries + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**model_binary_id** | **str** | | [optional] +**model_binary_url** | **str** | | [optional] +**oodd_model_binary_id** | **str** | | [optional] +**oodd_model_binary_url** | **str** | | [optional] +**pipeline_config** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional] +**oodd_pipeline_config** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional] +**predictor_metadata** | **bool, date, datetime, dict, float, int, list, str, 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/ImageQuery.md b/generated/docs/ImageQuery.md index 83920b20..f7999986 100644 --- a/generated/docs/ImageQuery.md +++ b/generated/docs/ImageQuery.md @@ -1,6 +1,6 @@ # ImageQuery -Spec for serializing a image-query object in the public API. +ImageQuery objects are the answers to natural language questions about images created by detectors. ## Properties Name | Type | Description | Notes diff --git a/generated/docs/PatchedDetectorRequest.md b/generated/docs/PatchedDetectorRequest.md index 24dc3363..819310b8 100644 --- a/generated/docs/PatchedDetectorRequest.md +++ b/generated/docs/PatchedDetectorRequest.md @@ -1,6 +1,6 @@ # PatchedDetectorRequest -Spec for serializing a detector object in the public API. +Groundlight Detectors provide answers to natural language questions about images. Each detector can answer a single question, and multiple detectors can be strung together for more complex logic. Detectors can be created through the create_detector method, or through the create_[MODE]_detector methods for pro tier users ## Properties Name | Type | Description | Notes diff --git a/generated/groundlight_openapi_client/api/edge_api.py b/generated/groundlight_openapi_client/api/edge_api.py new file mode 100644 index 00000000..7d6e4c85 --- /dev/null +++ b/generated/groundlight_openapi_client/api/edge_api.py @@ -0,0 +1,135 @@ +""" + 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.18.2 + 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, +) +from groundlight_openapi_client.model.edge_model_info import EdgeModelInfo + + +class EdgeApi(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.get_model_urls_endpoint = _Endpoint( + settings={ + "response_type": (EdgeModelInfo,), + "auth": ["ApiToken"], + "endpoint_path": "/v1/edge/fetch-model-urls/{detector_id}/", + "operation_id": "get_model_urls", + "http_method": "GET", + "servers": None, + }, + params_map={ + "all": [ + "detector_id", + ], + "required": [ + "detector_id", + ], + "nullable": [], + "enum": [], + "validation": [], + }, + root_map={ + "validations": {}, + "allowed_values": {}, + "openapi_types": { + "detector_id": (str,), + }, + "attribute_map": { + "detector_id": "detector_id", + }, + "location_map": { + "detector_id": "path", + }, + "collection_format_map": {}, + }, + headers_map={ + "accept": ["application/json"], + "content_type": [], + }, + api_client=api_client, + ) + + def get_model_urls(self, detector_id, **kwargs): + """get_model_urls # noqa: E501 + + Gets time limited pre-authenticated URLs to download a detector's edge model and oodd model. # noqa: E501 + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_model_urls(detector_id, async_req=True) + >>> result = thread.get() + + Args: + detector_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: + EdgeModelInfo + 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["detector_id"] = detector_id + return self.get_model_urls_endpoint.call_with_http_info(**kwargs) diff --git a/generated/groundlight_openapi_client/apis/__init__.py b/generated/groundlight_openapi_client/apis/__init__.py index ef5c1236..28edf7d0 100644 --- a/generated/groundlight_openapi_client/apis/__init__.py +++ b/generated/groundlight_openapi_client/apis/__init__.py @@ -17,6 +17,7 @@ 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.edge_api import EdgeApi from groundlight_openapi_client.api.image_queries_api import ImageQueriesApi from groundlight_openapi_client.api.labels_api import LabelsApi from groundlight_openapi_client.api.notes_api import NotesApi diff --git a/generated/groundlight_openapi_client/model/edge_model_info.py b/generated/groundlight_openapi_client/model/edge_model_info.py new file mode 100644 index 00000000..66826368 --- /dev/null +++ b/generated/groundlight_openapi_client/model/edge_model_info.py @@ -0,0 +1,322 @@ +""" + 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.18.2 + Contact: support@groundlight.ai + Generated by: https://openapi-generator.tech +""" + +import re # noqa: F401 +import sys # noqa: F401 + +from groundlight_openapi_client.model_utils import ( # noqa: F401 + ApiTypeError, + ModelComposed, + ModelNormal, + ModelSimple, + cached_property, + change_keys_js_to_python, + convert_js_args_to_python_args, + date, + datetime, + file_type, + none_type, + validate_get_composed_info, + OpenApiModel, +) +from groundlight_openapi_client.exceptions import ApiAttributeError + + +class EdgeModelInfo(ModelNormal): + """NOTE: This class is auto generated by OpenAPI Generator. + Ref: https://openapi-generator.tech + + Do not edit the class manually. + + Attributes: + allowed_values (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + with a capitalized key describing the allowed value and an allowed + value. These dicts store the allowed enum values. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + discriminator_value_class_map (dict): A dict to go from the discriminator + variable value to the discriminator class name. + validations (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + that stores validations for max_length, min_length, max_items, + min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum, + inclusive_minimum, and regex. + additional_properties_type (tuple): A tuple of classes accepted + as additional properties values. + """ + + allowed_values = {} + + validations = {} + + @cached_property + def additional_properties_type(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + """ + return ( + bool, + date, + datetime, + dict, + float, + int, + list, + str, + none_type, + ) # noqa: E501 + + _nullable = False + + @cached_property + def openapi_types(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + + Returns + openapi_types (dict): The key is attribute name + and the value is attribute type. + """ + return { + "model_binary_id": (str,), # noqa: E501 + "model_binary_url": (str,), # noqa: E501 + "oodd_model_binary_id": (str,), # noqa: E501 + "oodd_model_binary_url": (str,), # noqa: E501 + "pipeline_config": ( + bool, + date, + datetime, + dict, + float, + int, + list, + str, + none_type, + ), # noqa: E501 + "oodd_pipeline_config": ( + bool, + date, + datetime, + dict, + float, + int, + list, + str, + none_type, + ), # noqa: E501 + "predictor_metadata": ( + bool, + date, + datetime, + dict, + float, + int, + list, + str, + none_type, + ), # noqa: E501 + } + + @cached_property + def discriminator(): + return None + + attribute_map = { + "model_binary_id": "model_binary_id", # noqa: E501 + "model_binary_url": "model_binary_url", # noqa: E501 + "oodd_model_binary_id": "oodd_model_binary_id", # noqa: E501 + "oodd_model_binary_url": "oodd_model_binary_url", # noqa: E501 + "pipeline_config": "pipeline_config", # noqa: E501 + "oodd_pipeline_config": "oodd_pipeline_config", # noqa: E501 + "predictor_metadata": "predictor_metadata", # noqa: E501 + } + + read_only_vars = {} + + _composed_schemas = {} + + @classmethod + @convert_js_args_to_python_args + def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 + """EdgeModelInfo - a model defined in OpenAPI + + Keyword Args: + _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. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _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) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + model_binary_id (str): [optional] # noqa: E501 + model_binary_url (str): [optional] # noqa: E501 + oodd_model_binary_id (str): [optional] # noqa: E501 + oodd_model_binary_url (str): [optional] # noqa: E501 + pipeline_config (bool, date, datetime, dict, float, int, list, str, none_type): [optional] # noqa: E501 + oodd_pipeline_config (bool, date, datetime, dict, float, int, list, str, none_type): [optional] # noqa: E501 + predictor_metadata (bool, date, datetime, dict, float, int, list, str, none_type): [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", ()) + + self = super(OpenApiModel, cls).__new__(cls) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." + % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + 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 + ): + # 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", + ]) + + @convert_js_args_to_python_args + def __init__(self, *args, **kwargs): # noqa: E501 + """EdgeModelInfo - a model defined in OpenAPI + + Keyword Args: + _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. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _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) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + model_binary_id (str): [optional] # noqa: E501 + model_binary_url (str): [optional] # noqa: E501 + oodd_model_binary_id (str): [optional] # noqa: E501 + oodd_model_binary_url (str): [optional] # noqa: E501 + pipeline_config (bool, date, datetime, dict, float, int, list, str, none_type): [optional] # noqa: E501 + oodd_pipeline_config (bool, date, datetime, dict, float, int, list, str, none_type): [optional] # noqa: E501 + predictor_metadata (bool, date, datetime, dict, float, int, list, str, none_type): [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", ()) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." + % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + 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 + ): + # 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." + ) diff --git a/generated/groundlight_openapi_client/models/__init__.py b/generated/groundlight_openapi_client/models/__init__.py index a81ec9af..3528a1aa 100644 --- a/generated/groundlight_openapi_client/models/__init__.py +++ b/generated/groundlight_openapi_client/models/__init__.py @@ -27,6 +27,7 @@ from groundlight_openapi_client.model.detector_group import DetectorGroup from groundlight_openapi_client.model.detector_group_request import DetectorGroupRequest from groundlight_openapi_client.model.detector_type_enum import DetectorTypeEnum +from groundlight_openapi_client.model.edge_model_info import EdgeModelInfo from groundlight_openapi_client.model.escalation_type_enum import EscalationTypeEnum from groundlight_openapi_client.model.image_query import ImageQuery from groundlight_openapi_client.model.image_query_type_enum import ImageQueryTypeEnum diff --git a/generated/model.py b/generated/model.py index 60f81dcd..2a6062f9 100644 --- a/generated/model.py +++ b/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: public-api.yaml -# timestamp: 2025-01-17T23:47:47+00:00 +# timestamp: 2025-02-08T00:46:39+00:00 from __future__ import annotations @@ -62,6 +62,20 @@ class DetectorTypeEnum(str, Enum): detector = "detector" +class EdgeModelInfo(BaseModel): + """ + Information for the model running on edge, including temporary presigned urls to the model binaries + """ + + model_binary_id: Optional[str] = None + model_binary_url: Optional[str] = None + oodd_model_binary_id: Optional[str] = None + oodd_model_binary_url: Optional[str] = None + pipeline_config: Optional[Any] = None + oodd_pipeline_config: Optional[Any] = None + predictor_metadata: Optional[Any] = None + + class EscalationTypeEnum(str, Enum): """ * `STANDARD` - STANDARD @@ -282,7 +296,11 @@ class ConditionRequest(BaseModel): class Detector(BaseModel): """ - Spec for serializing a detector object in the public API. + Groundlight Detectors provide answers to natural language questions about images. + + Each detector can answer a single question, and multiple detectors can be strung together for + more complex logic. Detectors can be created through the create_detector method, or through the + create_[MODE]_detector methods for pro tier users """ id: str = Field(..., description="A unique ID for this object.") @@ -356,7 +374,7 @@ class DetectorCreationInputRequest(BaseModel): class ImageQuery(BaseModel): """ - Spec for serializing a image-query object in the public API. + ImageQuery objects are the answers to natural language questions about images created by detectors. """ metadata: Optional[Dict[str, Any]] = Field(..., description="Metadata about the image query.") @@ -414,7 +432,11 @@ class PaginatedImageQueryList(BaseModel): class PatchedDetectorRequest(BaseModel): """ - Spec for serializing a detector object in the public API. + Groundlight Detectors provide answers to natural language questions about images. + + Each detector can answer a single question, and multiple detectors can be strung together for + more complex logic. Detectors can be created through the create_detector method, or through the + create_[MODE]_detector methods for pro tier users """ name: Optional[constr(min_length=1, max_length=200)] = Field( diff --git a/generated/test/test_edge_api.py b/generated/test/test_edge_api.py new file mode 100644 index 00000000..5d116941 --- /dev/null +++ b/generated/test/test_edge_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.18.2 + Contact: support@groundlight.ai + Generated by: https://openapi-generator.tech +""" + +import unittest + +import groundlight_openapi_client +from groundlight_openapi_client.api.edge_api import EdgeApi # noqa: E501 + + +class TestEdgeApi(unittest.TestCase): + """EdgeApi unit test stubs""" + + def setUp(self): + self.api = EdgeApi() # noqa: E501 + + def tearDown(self): + pass + + def test_get_model_urls(self): + """Test case for get_model_urls""" + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/generated/test/test_edge_model_info.py b/generated/test/test_edge_model_info.py new file mode 100644 index 00000000..6165fcf8 --- /dev/null +++ b/generated/test/test_edge_model_info.py @@ -0,0 +1,35 @@ +""" + 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.18.2 + Contact: support@groundlight.ai + Generated by: https://openapi-generator.tech +""" + +import sys +import unittest + +import groundlight_openapi_client +from groundlight_openapi_client.model.edge_model_info import EdgeModelInfo + + +class TestEdgeModelInfo(unittest.TestCase): + """EdgeModelInfo unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testEdgeModelInfo(self): + """Test EdgeModelInfo""" + # FIXME: construct object with mandatory attributes with example values + # model = EdgeModelInfo() # noqa: E501 + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/generated/test/test_model_url.py b/generated/test/test_model_url.py new file mode 100644 index 00000000..f89649ef --- /dev/null +++ b/generated/test/test_model_url.py @@ -0,0 +1,35 @@ +""" + 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.18.2 + Contact: support@groundlight.ai + Generated by: https://openapi-generator.tech +""" + +import sys +import unittest + +import groundlight_openapi_client +from groundlight_openapi_client.model.model_url import ModelUrl + + +class TestModelUrl(unittest.TestCase): + """ModelUrl unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testModelUrl(self): + """Test ModelUrl""" + # FIXME: construct object with mandatory attributes with example values + # model = ModelUrl() # noqa: E501 + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/spec/public-api.yaml b/spec/public-api.yaml index 81b66670..78f51142 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -320,6 +320,28 @@ paths: responses: '204': description: No response body + /v1/edge/fetch-model-urls/{detector_id}/: + get: + operationId: Get Model URLs + description: Gets time limited pre-authenticated URLs to download a detector's + edge model and oodd model. + parameters: + - in: path + name: detector_id + schema: + type: string + required: true + tags: + - edge + security: + - ApiToken: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EdgeModelInfo' + description: '' /v1/image-queries: get: operationId: List image queries @@ -706,7 +728,12 @@ components: - verb Detector: type: object - description: Spec for serializing a detector object in the public API. + description: |- + Groundlight Detectors provide answers to natural language questions about images. + + Each detector can answer a single question, and multiple detectors can be strung together for + more complex logic. Detectors can be created through the create_detector method, or through the + create_[MODE]_detector methods for pro tier users properties: id: type: string @@ -880,6 +907,22 @@ components: enum: - detector type: string + EdgeModelInfo: + type: object + description: Information for the model running on edge, including temporary + presigned urls to the model binaries + properties: + model_binary_id: + type: string + model_binary_url: + type: string + oodd_model_binary_id: + type: string + oodd_model_binary_url: + type: string + pipeline_config: {} + oodd_pipeline_config: {} + predictor_metadata: {} EscalationTypeEnum: enum: - STANDARD @@ -890,7 +933,8 @@ components: * `NO_HUMAN_LABELING` - NO_HUMAN_LABELING ImageQuery: type: object - description: Spec for serializing a image-query object in the public API. + description: ImageQuery objects are the answers to natural language questions + about images created by detectors. properties: metadata: type: object @@ -1154,7 +1198,12 @@ components: $ref: '#/components/schemas/Rule' PatchedDetectorRequest: type: object - description: Spec for serializing a detector object in the public API. + description: |- + Groundlight Detectors provide answers to natural language questions about images. + + Each detector can answer a single question, and multiple detectors can be strung together for + more complex logic. Detectors can be created through the create_detector method, or through the + create_[MODE]_detector methods for pro tier users properties: name: type: string @@ -1543,4 +1592,4 @@ servers: - url: https://device.positronix.ai/device-api description: Device Prod - url: https://device.integ.positronix.ai/device-api - description: Device Integ \ No newline at end of file + description: Device Integ diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index 17f80d49..b9fecac2 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -8,12 +8,14 @@ import json from io import BufferedReader, BytesIO +from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union 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.edge_api import EdgeApi 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 @@ -36,6 +38,7 @@ Condition, Detector, DetectorGroup, + EdgeModelInfo, ModeEnum, PaginatedRuleList, Rule, @@ -45,7 +48,7 @@ from groundlight.images import parse_supported_image_types from groundlight.optional_imports import Image, np -from .client import DEFAULT_REQUEST_TIMEOUT, Groundlight, logger +from .client import DEFAULT_REQUEST_TIMEOUT, Groundlight, GroundlightClientError, logger class ExperimentalApi(Groundlight): # pylint: disable=too-many-public-methods @@ -104,6 +107,8 @@ def __init__( self.detector_group_api = DetectorGroupsApi(self.api_client) self.detector_reset_api = DetectorResetApi(self.api_client) + self.edge_api = EdgeApi(self.api_client) + ITEMS_PER_PAGE = 100 def make_condition(self, verb: str, parameters: dict) -> Condition: @@ -947,3 +952,48 @@ def create_multiclass_detector( # noqa: PLR0913 # pylint: disable=too-many-argu detector_creation_input.mode_configuration = mode_config obj = self.detectors_api.create_detector(detector_creation_input, _request_timeout=DEFAULT_REQUEST_TIMEOUT) return Detector.parse_obj(obj.to_dict()) + + def _download_mlbinary_url(self, detector: Union[str, Detector]) -> EdgeModelInfo: + """ + Gets a temporary presigned URL to download the model binaries for the given detector, along + with relevant metadata + """ + if isinstance(detector, Detector): + detector = detector.id + obj = self.edge_api.get_model_urls(detector) + return EdgeModelInfo.parse_obj(obj.to_dict()) + + def download_mlbinary(self, detector: Union[str, Detector], output_dir: str) -> None: + """ + Downloads the model binary files for the given detector to the specified output path. + + **Example usage**:: + + gl = ExperimentalApi() + + # Download the model binary for a detector + detector = gl.get_detector("det_abc123") + gl.download_mlbinary(detector, "path/to/output/model.bin") + + :param detector: The detector object or detector ID string to download the model binary for. + :param output_path: The path to save the model binary file to. + + :return: None + """ + + def _download_and_save(url: str, output_path: str) -> bytes: + try: + response = requests.get(url, timeout=10) + except Exception as e: + raise GroundlightClientError(f"Failed to retrieve data from {url}.") from e + with open(output_path, "wb") as file: + file.write(response.content) + return response.content + + if isinstance(detector, Detector): + detector = detector.id + edge_model_info = self._download_mlbinary_url(detector) + _download_and_save(edge_model_info.model_binary_url, Path(output_dir) / edge_model_info.model_binary_id) + _download_and_save( + edge_model_info.oodd_model_binary_url, Path(output_dir) / edge_model_info.oodd_model_binary_id + )