Skip to content

Commit b35cca7

Browse files
brandon-wadaAuto-format Botbrandon
authored
feat: add PrimingGroup and MLPipeline SDK methods (#420)
## Summary Adds SDK methods for the new PrimingGroup public API. Priming Groups are groupings of detectors that share a common semantic query and can utilize a common base model. In the future, priming groups may allow for cross detector learning and other multi-task and meta-learning techniques. In introducing priming groups, we also expose MLPipelines. Every detector has one active MLPipeline but constantly runs multiple MLPipelines under the hood that are compared against the top performing active model. Whenever Groundlight determines that there is a better performing model, we will switch that model to be the active model. Currently, a priming group can be created from an existing and trained MLPipeline, which one can get given an active detector. The new PrimingGroup will use a frozen version of the MLPipeline for the first inference on a new detector created using the PrimingGroups. If shadow pipelines are disallowed on the PrimingGroup, that frozen model will be used indefinitely by the detector. Otherwise, the frozen model will be used until one of the other MLPipelines on the detector is evaluated to be a better fit. We add the following methods in this PR - `list_detector_pipelines(detector)` — list all MLPipelines for a detector - `create_priming_group(name, source_ml_pipeline_id, ...)` — create a PrimingGroup seeded from an existing trained model - `list_priming_groups()` — list all priming groups owned by this account - `get_priming_group(priming_group_id)` — retrieve by ID - `delete_priming_group(priming_group_id)` — soft-delete We also add new pydantic models: `MLPipeline`, `PrimingGroup` in `generated/model.py`. ## Usage \`\`\`python gl = Groundlight() pipelines = gl.list_detector_pipelines(detector) active = next(p for p in pipelines if p.is_active_pipeline) pg = gl.create_priming_group( name="door-detector-primer", source_ml_pipeline_id=active.id, canonical_query="Is the door open?", disable_shadow_pipelines=True, ) new_detector = gl.create_detector( name="new-door-detector", query="Is the door open?", priming_group_id=pg.id, ) \`\`\` --------- Co-authored-by: Auto-format Bot <autoformatbot@groundlight.ai> Co-authored-by: brandon <brandon@axon.com>
1 parent 44f1732 commit b35cca7

33 files changed

Lines changed: 3682 additions & 31 deletions

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ PYTEST=poetry run pytest -v
3838
# `make test TEST_ARGS="-k some_filter"`
3939
TEST_ARGS=
4040

41-
CLOUD_FILTERS = -m "not run_only_for_edge_endpoint"
42-
EDGE_FILTERS = -m "not skip_for_edge_endpoint"
41+
CLOUD_FILTERS = -m "not run_only_for_edge_endpoint and not expensive"
42+
EDGE_FILTERS = -m "not skip_for_edge_endpoint and not expensive"
4343

4444
# Record information about the slowest 25 tests (but don't show anything slower than 0.1 seconds)
4545
PROFILING_ARGS = \

generated/.openapi-generator/FILES

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ docs/Label.md
4242
docs/LabelValue.md
4343
docs/LabelValueRequest.md
4444
docs/LabelsApi.md
45+
docs/MLPipeline.md
4546
docs/ModeEnum.md
4647
docs/MonthToDateAccountInfoApi.md
4748
docs/MultiClassModeConfiguration.md
@@ -51,10 +52,15 @@ docs/NoteRequest.md
5152
docs/NotesApi.md
5253
docs/PaginatedDetectorList.md
5354
docs/PaginatedImageQueryList.md
55+
docs/PaginatedMLPipelineList.md
56+
docs/PaginatedPrimingGroupList.md
5457
docs/PaginatedRuleList.md
5558
docs/PatchedDetectorRequest.md
5659
docs/PayloadTemplate.md
5760
docs/PayloadTemplateRequest.md
61+
docs/PrimingGroup.md
62+
docs/PrimingGroupCreationInputRequest.md
63+
docs/PrimingGroupsApi.md
5864
docs/ROI.md
5965
docs/ROIRequest.md
6066
docs/ResultTypeEnum.md
@@ -82,6 +88,7 @@ groundlight_openapi_client/api/image_queries_api.py
8288
groundlight_openapi_client/api/labels_api.py
8389
groundlight_openapi_client/api/month_to_date_account_info_api.py
8490
groundlight_openapi_client/api/notes_api.py
91+
groundlight_openapi_client/api/priming_groups_api.py
8592
groundlight_openapi_client/api/user_api.py
8693
groundlight_openapi_client/api_client.py
8794
groundlight_openapi_client/apis/__init__.py
@@ -123,17 +130,22 @@ groundlight_openapi_client/model/inline_response200_summary_class_counts.py
123130
groundlight_openapi_client/model/label.py
124131
groundlight_openapi_client/model/label_value.py
125132
groundlight_openapi_client/model/label_value_request.py
133+
groundlight_openapi_client/model/ml_pipeline.py
126134
groundlight_openapi_client/model/mode_enum.py
127135
groundlight_openapi_client/model/multi_class_mode_configuration.py
128136
groundlight_openapi_client/model/multi_classification_result.py
129137
groundlight_openapi_client/model/note.py
130138
groundlight_openapi_client/model/note_request.py
131139
groundlight_openapi_client/model/paginated_detector_list.py
132140
groundlight_openapi_client/model/paginated_image_query_list.py
141+
groundlight_openapi_client/model/paginated_ml_pipeline_list.py
142+
groundlight_openapi_client/model/paginated_priming_group_list.py
133143
groundlight_openapi_client/model/paginated_rule_list.py
134144
groundlight_openapi_client/model/patched_detector_request.py
135145
groundlight_openapi_client/model/payload_template.py
136146
groundlight_openapi_client/model/payload_template_request.py
147+
groundlight_openapi_client/model/priming_group.py
148+
groundlight_openapi_client/model/priming_group_creation_input_request.py
137149
groundlight_openapi_client/model/result_type_enum.py
138150
groundlight_openapi_client/model/roi.py
139151
groundlight_openapi_client/model/roi_request.py

generated/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ Class | Method | HTTP request | Description
128128
*DetectorsApi* | [**get_detector**](docs/DetectorsApi.md#get_detector) | **GET** /v1/detectors/{id} |
129129
*DetectorsApi* | [**get_detector_evaluation**](docs/DetectorsApi.md#get_detector_evaluation) | **GET** /v1/detectors/{id}/evaluation |
130130
*DetectorsApi* | [**get_detector_metrics**](docs/DetectorsApi.md#get_detector_metrics) | **GET** /v1/detectors/{detector_id}/metrics |
131+
*DetectorsApi* | [**list_detector_pipelines**](docs/DetectorsApi.md#list_detector_pipelines) | **GET** /v1/detectors/{detector_id}/pipelines |
131132
*DetectorsApi* | [**list_detectors**](docs/DetectorsApi.md#list_detectors) | **GET** /v1/detectors |
132133
*DetectorsApi* | [**update_detector**](docs/DetectorsApi.md#update_detector) | **PATCH** /v1/detectors/{id} |
133134
*EdgeApi* | [**edge_report_metrics_create**](docs/EdgeApi.md#edge_report_metrics_create) | **POST** /v1/edge/report-metrics |
@@ -140,6 +141,10 @@ Class | Method | HTTP request | Description
140141
*MonthToDateAccountInfoApi* | [**month_to_date_account_info**](docs/MonthToDateAccountInfoApi.md#month_to_date_account_info) | **GET** /v1/month-to-date-account-info |
141142
*NotesApi* | [**create_note**](docs/NotesApi.md#create_note) | **POST** /v1/notes |
142143
*NotesApi* | [**get_notes**](docs/NotesApi.md#get_notes) | **GET** /v1/notes |
144+
*PrimingGroupsApi* | [**create_priming_group**](docs/PrimingGroupsApi.md#create_priming_group) | **POST** /v1/priming-groups |
145+
*PrimingGroupsApi* | [**delete_priming_group**](docs/PrimingGroupsApi.md#delete_priming_group) | **DELETE** /v1/priming-groups/{id} |
146+
*PrimingGroupsApi* | [**get_priming_group**](docs/PrimingGroupsApi.md#get_priming_group) | **GET** /v1/priming-groups/{id} |
147+
*PrimingGroupsApi* | [**list_priming_groups**](docs/PrimingGroupsApi.md#list_priming_groups) | **GET** /v1/priming-groups |
143148
*UserApi* | [**who_am_i**](docs/UserApi.md#who_am_i) | **GET** /v1/me |
144149

145150

@@ -180,17 +185,22 @@ Class | Method | HTTP request | Description
180185
- [Label](docs/Label.md)
181186
- [LabelValue](docs/LabelValue.md)
182187
- [LabelValueRequest](docs/LabelValueRequest.md)
188+
- [MLPipeline](docs/MLPipeline.md)
183189
- [ModeEnum](docs/ModeEnum.md)
184190
- [MultiClassModeConfiguration](docs/MultiClassModeConfiguration.md)
185191
- [MultiClassificationResult](docs/MultiClassificationResult.md)
186192
- [Note](docs/Note.md)
187193
- [NoteRequest](docs/NoteRequest.md)
188194
- [PaginatedDetectorList](docs/PaginatedDetectorList.md)
189195
- [PaginatedImageQueryList](docs/PaginatedImageQueryList.md)
196+
- [PaginatedMLPipelineList](docs/PaginatedMLPipelineList.md)
197+
- [PaginatedPrimingGroupList](docs/PaginatedPrimingGroupList.md)
190198
- [PaginatedRuleList](docs/PaginatedRuleList.md)
191199
- [PatchedDetectorRequest](docs/PatchedDetectorRequest.md)
192200
- [PayloadTemplate](docs/PayloadTemplate.md)
193201
- [PayloadTemplateRequest](docs/PayloadTemplateRequest.md)
202+
- [PrimingGroup](docs/PrimingGroup.md)
203+
- [PrimingGroupCreationInputRequest](docs/PrimingGroupCreationInputRequest.md)
194204
- [ROI](docs/ROI.md)
195205
- [ROIRequest](docs/ROIRequest.md)
196206
- [ResultTypeEnum](docs/ResultTypeEnum.md)

generated/docs/DetectorsApi.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Method | HTTP request | Description
99
[**get_detector**](DetectorsApi.md#get_detector) | **GET** /v1/detectors/{id} |
1010
[**get_detector_evaluation**](DetectorsApi.md#get_detector_evaluation) | **GET** /v1/detectors/{id}/evaluation |
1111
[**get_detector_metrics**](DetectorsApi.md#get_detector_metrics) | **GET** /v1/detectors/{detector_id}/metrics |
12+
[**list_detector_pipelines**](DetectorsApi.md#list_detector_pipelines) | **GET** /v1/detectors/{detector_id}/pipelines |
1213
[**list_detectors**](DetectorsApi.md#list_detectors) | **GET** /v1/detectors |
1314
[**update_detector**](DetectorsApi.md#update_detector) | **PATCH** /v1/detectors/{id} |
1415

@@ -401,6 +402,99 @@ Name | Type | Description | Notes
401402
- **Accept**: application/json
402403

403404

405+
### HTTP response details
406+
407+
| Status code | Description | Response headers |
408+
|-------------|-------------|------------------|
409+
**200** | | - |
410+
411+
[[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)
412+
413+
# **list_detector_pipelines**
414+
> PaginatedMLPipelineList list_detector_pipelines(detector_id)
415+
416+
417+
418+
List all MLPipelines for a detector.
419+
420+
### Example
421+
422+
* Api Key Authentication (ApiToken):
423+
424+
```python
425+
import time
426+
import groundlight_openapi_client
427+
from groundlight_openapi_client.api import detectors_api
428+
from groundlight_openapi_client.model.paginated_ml_pipeline_list import PaginatedMLPipelineList
429+
from pprint import pprint
430+
# Defining the host is optional and defaults to https://api.groundlight.ai/device-api
431+
# See configuration.py for a list of all supported configuration parameters.
432+
configuration = groundlight_openapi_client.Configuration(
433+
host = "https://api.groundlight.ai/device-api"
434+
)
435+
436+
# The client must configure the authentication and authorization parameters
437+
# in accordance with the API server security policy.
438+
# Examples for each auth method are provided below, use the example that
439+
# satisfies your auth use case.
440+
441+
# Configure API key authorization: ApiToken
442+
configuration.api_key['ApiToken'] = 'YOUR_API_KEY'
443+
444+
# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
445+
# configuration.api_key_prefix['ApiToken'] = 'Bearer'
446+
447+
# Enter a context with an instance of the API client
448+
with groundlight_openapi_client.ApiClient(configuration) as api_client:
449+
# Create an instance of the API class
450+
api_instance = detectors_api.DetectorsApi(api_client)
451+
detector_id = "detector_id_example" # str |
452+
ordering = "ordering_example" # str | Which field to use when ordering the results. (optional)
453+
page = 1 # int | A page number within the paginated result set. (optional)
454+
page_size = 1 # int | Number of results to return per page. (optional)
455+
search = "search_example" # str | A search term. (optional)
456+
457+
# example passing only required values which don't have defaults set
458+
try:
459+
api_response = api_instance.list_detector_pipelines(detector_id)
460+
pprint(api_response)
461+
except groundlight_openapi_client.ApiException as e:
462+
print("Exception when calling DetectorsApi->list_detector_pipelines: %s\n" % e)
463+
464+
# example passing only required values which don't have defaults set
465+
# and optional values
466+
try:
467+
api_response = api_instance.list_detector_pipelines(detector_id, ordering=ordering, page=page, page_size=page_size, search=search)
468+
pprint(api_response)
469+
except groundlight_openapi_client.ApiException as e:
470+
print("Exception when calling DetectorsApi->list_detector_pipelines: %s\n" % e)
471+
```
472+
473+
474+
### Parameters
475+
476+
Name | Type | Description | Notes
477+
------------- | ------------- | ------------- | -------------
478+
**detector_id** | **str**| |
479+
**ordering** | **str**| Which field to use when ordering the results. | [optional]
480+
**page** | **int**| A page number within the paginated result set. | [optional]
481+
**page_size** | **int**| Number of results to return per page. | [optional]
482+
**search** | **str**| A search term. | [optional]
483+
484+
### Return type
485+
486+
[**PaginatedMLPipelineList**](PaginatedMLPipelineList.md)
487+
488+
### Authorization
489+
490+
[ApiToken](../README.md#ApiToken)
491+
492+
### HTTP request headers
493+
494+
- **Content-Type**: Not defined
495+
- **Accept**: application/json
496+
497+
404498
### HTTP response details
405499

406500
| Status code | Description | Response headers |

generated/docs/MLPipeline.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# MLPipeline
2+
3+
A single ML pipeline attached to a detector.
4+
5+
## Properties
6+
Name | Type | Description | Notes
7+
------------ | ------------- | ------------- | -------------
8+
**id** | **str** | | [readonly]
9+
**pipeline_config** | **str, none_type** | configuration needed to instantiate a prediction pipeline. | [readonly]
10+
**is_active_pipeline** | **bool** | If True, this is the pipeline is used for inference, active learning, etc. for its parent Predictor. | [readonly]
11+
**is_edge_pipeline** | **bool** | If True, this pipeline is enabled for edge inference. | [readonly]
12+
**is_unclear_pipeline** | **bool** | If True, this pipeline is used to train classifier for human unclear label prediction. | [readonly]
13+
**is_oodd_pipeline** | **bool** | If True, this pipeline is used for OODD. | [readonly]
14+
**is_enabled** | **bool** | If False, this pipeline will not be run for any use case. | [readonly]
15+
**created_at** | **datetime** | | [readonly]
16+
**trained_at** | **datetime, none_type** | | [readonly]
17+
**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]
18+
19+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
20+
21+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# PaginatedMLPipelineList
2+
3+
4+
## Properties
5+
Name | Type | Description | Notes
6+
------------ | ------------- | ------------- | -------------
7+
**count** | **int** | |
8+
**results** | [**[MLPipeline]**](MLPipeline.md) | |
9+
**next** | **str, none_type** | | [optional]
10+
**previous** | **str, none_type** | | [optional]
11+
**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]
12+
13+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
14+
15+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# PaginatedPrimingGroupList
2+
3+
4+
## Properties
5+
Name | Type | Description | Notes
6+
------------ | ------------- | ------------- | -------------
7+
**count** | **int** | |
8+
**results** | [**[PrimingGroup]**](PrimingGroup.md) | |
9+
**next** | **str, none_type** | | [optional]
10+
**previous** | **str, none_type** | | [optional]
11+
**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]
12+
13+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
14+
15+

generated/docs/PrimingGroup.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# PrimingGroup
2+
3+
A PrimingGroup owned by the authenticated user.
4+
5+
## Properties
6+
Name | Type | Description | Notes
7+
------------ | ------------- | ------------- | -------------
8+
**id** | **str** | | [readonly]
9+
**name** | **str** | |
10+
**is_global** | **bool** | If True, this priming group is shared to all Groundlight users. Can only be set by Groundlight admins. | [readonly]
11+
**created_at** | **datetime** | | [readonly]
12+
**canonical_query** | **str, none_type** | Canonical semantic query for this priming group | [optional]
13+
**active_pipeline_config** | **str, none_type** | Active pipeline config override for new detectors created in this priming group. If set, this overrides the default active pipeline config at creation time.Can be either a pipeline name or full config string. | [optional]
14+
**priming_group_specific_shadow_pipeline_configs** | **bool, date, datetime, dict, float, int, list, str, none_type** | Configs for shadow pipelines to create for detectors in this priming group. These are added to the default shadow pipeline configs for a detector of the given mode. Each entry is either a pipeline name or full config string. | [optional]
15+
**disable_shadow_pipelines** | **bool** | If True, new detectors added to this priming group will not receive the mode-specific default shadow pipelines from INITIAL_SHADOW_PIPELINE_CONFIG_SET. Priming-group-specific shadow configs still apply. Use this to guarantee the primed active MLBinary is never switched off by a shadow pipeline being promoted. | [optional]
16+
**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]
17+
18+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
19+
20+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# PrimingGroupCreationInputRequest
2+
3+
Input for creating a new user-owned PrimingGroup seeded from an existing MLPipeline.
4+
5+
## Properties
6+
Name | Type | Description | Notes
7+
------------ | ------------- | ------------- | -------------
8+
**name** | **str** | Name for the new priming group. |
9+
**source_ml_pipeline_id** | **str** | ID of an MLPipeline owned by this account whose trained model will seed the priming group. |
10+
**canonical_query** | **str, none_type** | Optional canonical semantic query describing this priming group. | [optional]
11+
**disable_shadow_pipelines** | **bool** | If true, new detectors added to this priming group will not receive the default shadow pipelines. This guarantees the primed active model is never switched off. | [optional] if omitted the server will use the default value of False
12+
**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]
13+
14+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
15+
16+

0 commit comments

Comments
 (0)