Skip to content

Commit

Permalink
Export Scale task info (#308)
Browse files Browse the repository at this point in the history
* add slice and dataset export methods; helper util

* semver bump and changelog
  • Loading branch information
drakejwong authored Jun 2, 2022
1 parent 19fc293 commit 84bbd4a
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 2 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to the [Nucleus Python Client](https://github.com/scaleapi/n
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.12.3](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.12.3) - 2022-06-02

### Added

- New methods to export associated Scale task info at either the item or scene level.
- `Dataset.export_scale_task_info`
- `Slice.export_scale_task_info`


## [0.12.2](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.12.2) - 2022-06-02

### Added
Expand Down
3 changes: 3 additions & 0 deletions nucleus/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
AUTOTAGS_KEY = "autotags"
AUTOTAG_SCORE_THRESHOLD = "score_threshold"
EXPORTED_ROWS = "exportedRows"
EXPORTED_SCALE_TASK_INFO_ROWS = "exportedScaleTaskInfoRows"
CAMERA_MODEL_KEY = "camera_model"
CAMERA_PARAMS_KEY = "camera_params"
CLASS_PDF_KEY = "class_pdf"
Expand Down Expand Up @@ -111,6 +112,8 @@
REFERENCE_ID_KEY = "reference_id"
BACKEND_REFERENCE_ID_KEY = "ref_id" # TODO(355762): Our backend returns this instead of the "proper" key sometimes.
REQUEST_ID_KEY = "requestId"
SCALE_TASK_INFO_KEY = "scale_task_info"
SCENE_KEY = "scene"
SCENES_KEY = "scenes"
SERIALIZED_REQUEST_KEY = "serialized_request"
SEGMENTATIONS_KEY = "segmentations"
Expand Down
31 changes: 31 additions & 0 deletions nucleus/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
convert_export_payload,
format_dataset_item_response,
format_prediction_response,
format_scale_task_info_response,
paginate_generator,
serialize_and_write_to_presigned_url,
)
Expand Down Expand Up @@ -1278,6 +1279,36 @@ def export_predictions(self, model):
)
return format_prediction_response({ANNOTATIONS_KEY: json_response})

def export_scale_task_info(self):
"""Fetches info for all linked Scale tasks of items/scenes in the dataset.
Returns:
A list of dicts, each with two keys, respectively mapping to items/scenes
and info on their corresponding Scale tasks within the dataset::
List[{
"item" | "scene": Union[:class:`DatasetItem`, :class:`Scene`],
"scale_task_info": {
"task_id": str,
"subtask_id": str,
"task_status": str,
"task_audit_status": str,
"task_audit_review_comment": Optional[str],
"project_name": str,
"batch": str,
"created_at": str,
"completed_at": Optional[str]
}[]
}]
"""
response = self._client.make_request(
payload=None,
route=f"dataset/{self.id}/exportScaleTaskInfo",
requests_command=requests.get,
)
return format_scale_task_info_response(response)

def calculate_evaluation_metrics(self, model, options: dict = None):
"""Starts computation of evaluation metrics for a model on the dataset.
Expand Down
32 changes: 32 additions & 0 deletions nucleus/slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
KeyErrorDict,
convert_export_payload,
format_dataset_item_response,
format_scale_task_info_response,
paginate_generator,
)

Expand Down Expand Up @@ -265,6 +266,37 @@ def export_predictions(
)
return convert_export_payload(api_payload[EXPORTED_ROWS], True)

def export_scale_task_info(self):
"""Fetches info for all linked Scale tasks of items/scenes in the slice.
Returns:
A list of dicts, each with two keys, respectively mapping to items/scenes
and info on their corresponding Scale tasks within the dataset::
List[{
"item" | "scene": Union[:class:`DatasetItem`, :class:`Scene`],
"scale_task_info": {
"task_id": str,
"subtask_id": str,
"task_status": str,
"task_audit_status": str,
"task_audit_review_comment": Optional[str],
"project_name": str,
"batch": str,
"created_at": str,
"completed_at": Optional[str]
}[]
}]
"""
response = self._client.make_request(
payload=None,
route=f"slice/{self.id}/exportScaleTaskInfo",
requests_command=requests.get,
)
# TODO: implement format function with nice keying
return format_scale_task_info_response(response)

def send_to_labeling(self, project_id: str):
"""Send items in the Slice as tasks to a Scale labeling project.
Expand Down
32 changes: 31 additions & 1 deletion nucleus/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
BOX_TYPE,
CATEGORY_TYPE,
CUBOID_TYPE,
EXPORTED_SCALE_TASK_INFO_ROWS,
ITEM_KEY,
KEYPOINTS_TYPE,
LAST_PAGE,
Expand All @@ -39,6 +40,8 @@
POLYGON_TYPE,
PREDICTIONS_KEY,
REFERENCE_ID_KEY,
SCALE_TASK_INFO_KEY,
SCENE_KEY,
SEGMENTATION_TYPE,
)
from .dataset_item import DatasetItem
Expand Down Expand Up @@ -161,7 +164,7 @@ def format_dataset_item_response(response: dict) -> dict:
Args:
response: JSON dictionary response from REST endpoint
Returns:
item_dict: A dictionary with two entries, one for the dataset item, and annother
item_dict: A dictionary with two entries, one for the dataset item, and another
for all of the associated annotations.
"""
if ANNOTATIONS_KEY not in response:
Expand All @@ -188,6 +191,33 @@ def format_dataset_item_response(response: dict) -> dict:
}


def format_scale_task_info_response(response: dict) -> Union[Dict, List[Dict]]:
"""Format the raw client response into api objects.
Args:
response: JSON dictionary response from REST endpoint
Returns:
A dictionary with two entries, one for the dataset item, and another
for all of the associated Scale tasks.
"""
if EXPORTED_SCALE_TASK_INFO_ROWS not in response:
# Payload is empty so an error occurred
return response

ret = []
for row in response[EXPORTED_SCALE_TASK_INFO_ROWS]:
if ITEM_KEY in row:
ret.append(
{
ITEM_KEY: DatasetItem.from_json(row[ITEM_KEY]),
SCALE_TASK_INFO_KEY: row[SCALE_TASK_INFO_KEY],
}
)
elif SCENE_KEY in row:
ret.append(row)
return ret


def convert_export_payload(api_payload, has_predictions: bool = False):
"""Helper function to convert raw JSON to API objects
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ exclude = '''

[tool.poetry]
name = "scale-nucleus"
version = "0.12.2"
version = "0.12.3"
description = "The official Python client library for Nucleus, the Data Platform for AI"
license = "MIT"
authors = ["Scale AI Nucleus Team <nucleusapi@scaleapi.com>"]
Expand Down

0 comments on commit 84bbd4a

Please sign in to comment.