From cb4a308f82830ed5906581393c713dd2a13f7433 Mon Sep 17 00:00:00 2001 From: ueta-eisuke Date: Mon, 9 Aug 2021 16:38:33 +0900 Subject: [PATCH 1/3] update external status --- README.md | 19 +++++++---- fastlabel/__init__.py | 74 +++++++++++++++++++++++++++++++++---------- setup.py | 2 +- 3 files changed, 72 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 7f172d4..c6a3572 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ tasks = client.get_image_tasks(project="YOUR_PROJECT_SLUG") ```python tasks = client.get_image_tasks( project="YOUR_PROJECT_SLUG", - status="approved", # status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved' + status="approved", # status can be 'pending', 'registered', 'completed', 'skipped', 'sent_back', 'approved' tags=["tag1", "tag2"] # up to 10 tags ) ``` @@ -169,10 +169,12 @@ Example of a single image task object "height": 100, # image height "url": "YOUR_TASK_URL", "status": "registered", + "externalStatus": "registered", "tags": [], "assignee": "ASSIGNEE_NAME", "reviewer": "REVIEWER_NAME", - "customerReviewer": "CUSTOMER_REVIEWER_NAME", + "externalAssignee": "EXTERNAL_ASSIGNEE_NAME", + "externalReviewer": "EXTERNAL_REVIEWER_NAME", "annotations": [ { "attributes": [ @@ -265,10 +267,12 @@ Example of a single image classification task object "height": 100, # image height "url": "YOUR_TASK_URL", "status": "registered", + "externalStatus": "registered", "tags": [], "assignee": "ASSIGNEE_NAME", "reviewer": "REVIEWER_NAME", - "customerReviewer": "CUSTOMER_REVIEWER_NAME", + "externalAssignee": "EXTERNAL_ASSIGNEE_NAME", + "externalReviewer": "EXTERNAL_REVIEWER_NAME", "attributes": [ { "key": "kind", @@ -360,10 +364,12 @@ Example of a single task object } ], "status": "registered", + "externalStatus": "registered", "tags": [], "assignee": "ASSIGNEE_NAME", "reviewer": "REVIEWER_NAME", - "customerReviewer": "CUSTOMER_REVIEWER_NAME", + "externalAssignee": "EXTERNAL_ASSIGNEE_NAME", + "externalReviewer": "EXTERNAL_REVIEWER_NAME", "annotations": [ { "content": "content-name" @@ -485,10 +491,12 @@ Example of a single image classification task object "duration": 16.0, # total duration of video "url": "YOUR_TASK_URL", "status": "registered", + "externalStatus": "registered", "tags": [], "assignee": "ASSIGNEE_NAME", "reviewer": "REVIEWER_NAME", - "customerReviewer": "CUSTOMER_REVIEWER_NAME", + "externalAssignee": "EXTERNAL_ASSIGNEE_NAME", + "externalReviewer": "EXTERNAL_REVIEWER_NAME", "annotations": [ { "attributes": [], @@ -807,7 +815,6 @@ Example of a project object "name": "YOUR_PROJECT_NAME", "isBitmap": False, "jobSize": 10, - "useAnnotationService": False, "status": "active", "createdAt": "2021-04-20T03:20:41.427Z", "updatedAt": "2021-04-20T03:20:41.427Z", diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 93ef0da..950a9cf 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -111,6 +111,7 @@ def get_image_tasks( self, project: str, status: str = None, + external_status: str = None, tags: list = [], task_name: str = None, offset: int = None, @@ -121,7 +122,8 @@ def get_image_tasks( Returns up to 1000 at a time, to get more, set offset as the starting position to fetch. project is slug of your project. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) tags is a list of tag. (Optional) task_name is a task name. (Optional) offset is the starting position number to fetch. (Optional) @@ -134,6 +136,8 @@ def get_image_tasks( params = {"project": project} if status: params["status"] = status + if external_status: + params["externalStatus"] = external_status if tags: params["tags"] = tags if task_name: @@ -148,6 +152,7 @@ def get_image_classification_tasks( self, project: str, status: str = None, + external_status: str = None, tags: list = [], task_name: str = None, offset: int = None, @@ -158,7 +163,8 @@ def get_image_classification_tasks( Returns up to 1000 at a time, to get more, set offset as the starting position to fetch. project is slug of your project. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) tags is a list of tag. (Optional) offset is the starting position number to fetch. (Optional) limit is the max number to fetch. (Optional) @@ -167,6 +173,8 @@ def get_image_classification_tasks( params = {"project": project} if status: params["status"] = status + if external_status: + params["externalStatus"] = external_status if tags: params["tags"] = tags if task_name: @@ -181,6 +189,7 @@ def get_multi_image_tasks( self, project: str, status: str = None, + external_status: str = None, tags: list = [], task_name: str = None, offset: int = None, @@ -191,7 +200,8 @@ def get_multi_image_tasks( Returns up to 10 at a time, to get more, set offset as the starting position to fetch. project is slug of your project. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) tags is a list of tag. (Optional) offset is the starting position number to fetch. (Optional) limit is the max number to fetch. (Optional) @@ -203,6 +213,8 @@ def get_multi_image_tasks( params = {"project": project} if status: params["status"] = status + if external_status: + params["externalStatus"] = external_status if tags: params["tags"] = tags if task_name: @@ -217,6 +229,7 @@ def get_video_tasks( self, project: str, status: str = None, + external_status: str = None, tags: list = [], task_name: str = None, offset: int = None, @@ -227,7 +240,8 @@ def get_video_tasks( Returns up to 10 at a time, to get more, set offset as the starting position to fetch. project is slug of your project. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) tags is a list of tag. (Optional) task_name is a task name. (Optional) offset is the starting position number to fetch. (Optional) @@ -240,6 +254,8 @@ def get_video_tasks( params = {"project": project} if status: params["status"] = status + if external_status: + params["externalStatus"] = external_status if tags: params["tags"] = tags if task_name: @@ -254,6 +270,7 @@ def get_video_classification_tasks( self, project: str, status: str = None, + external_status: str = None, tags: list = [], task_name: str = None, offset: int = None, @@ -264,7 +281,8 @@ def get_video_classification_tasks( Returns up to 1000 at a time, to get more, set offset as the starting position to fetch. project is slug of your project. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) tags is a list of tag. (Optional) offset is the starting position number to fetch. (Optional) limit is the max number to fetch. (Optional) @@ -273,6 +291,8 @@ def get_video_classification_tasks( params = {"project": project} if status: params["status"] = status + if external_status: + params["externalStatus"] = external_status if tags: params["tags"] = tags if task_name: @@ -319,6 +339,7 @@ def create_image_task( name: str, file_path: str, status: str = None, + external_status: str = None, annotations: list = [], tags: list = [], ) -> str: @@ -328,7 +349,8 @@ def create_image_task( project is slug of your project. (Required) name is an unique identifier of task in your project. (Required) file_path is a path to data. Supported extensions are png, jpg, jpeg. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) annotations is a list of annotation to be set in advance. (Optional) tags is a list of tag to be set in advance. (Optional) """ @@ -340,6 +362,8 @@ def create_image_task( payload = {"project": project, "name": name, "file": file} if status: payload["status"] = status + if external_status: + payload["externalStatus"] = external_status if annotations: for annotation in annotations: annotation["content"] = name @@ -354,6 +378,7 @@ def create_image_classification_task( name: str, file_path: str, status: str = None, + external_status: str = None, attributes: list = [], tags: list = [], ) -> str: @@ -363,7 +388,8 @@ def create_image_classification_task( project is slug of your project. (Required) name is an unique identifier of task in your project. (Required) file_path is a path to data. Supported extensions are png, jpg, jpeg. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) attributes is a list of attribute to be set in advance. (Optional) tags is a list of tag to be set in advance. (Optional) """ @@ -387,6 +413,7 @@ def create_multi_image_task( name: str, folder_path: str, status: str = None, + external_status: str = None, annotations: list = [], tags: list = [], ) -> str: @@ -396,7 +423,8 @@ def create_multi_image_task( project is slug of your project. (Required) name is an unique identifier of task in your project. (Required) folder_path is a path to data folder. Files should be under the folder. Nested folder structure is not supported. Supported extensions of files are png, jpg, jpeg. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) annotations is a list of annotation to be set in advance. (Optional) tags is a list of tag to be set in advance. (Optional) """ @@ -422,6 +450,8 @@ def create_multi_image_task( payload = {"project": project, "name": name, "contents": contents} if status: payload["status"] = status + if external_status: + payload["externalStatus"] = external_status if annotations: payload["annotations"] = annotations if tags: @@ -434,6 +464,7 @@ def create_video_task( name: str, file_path: str, status: str = None, + external_status: str = None, annotations: list = [], tags: list = [], ) -> str: @@ -443,7 +474,8 @@ def create_video_task( project is slug of your project. (Required) name is an unique identifier of task in your project. (Required) file_path is a path to data. Supported extensions are png, jpg, jpeg. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) annotations is a list of annotation to be set in advance. (Optional) tags is a list of tag to be set in advance. (Optional) """ @@ -455,6 +487,8 @@ def create_video_task( payload = {"project": project, "name": name, "file": file} if status: payload["status"] = status + if external_status: + payload["externalStatus"] = external_status if annotations: for annotation in annotations: annotation["content"] = name @@ -469,19 +503,23 @@ def update_task( self, task_id: str, status: str = None, + external_status: str = None, tags: list = [], ) -> str: """ Update a single task. task_id is an id of the task. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) tags is a list of tag to be set. (Optional) """ endpoint = "tasks/" + task_id payload = {} if status: payload["status"] = status + if external_status: + payload["externalStatus"] = external_status if tags: payload["tags"] = tags return self.api.put_request(endpoint, payload=payload) @@ -490,6 +528,7 @@ def update_image_classification_task( self, task_id: str, status: str = None, + external_status: str = None, attributes: list = [], tags: list = [], ) -> str: @@ -497,7 +536,8 @@ def update_image_classification_task( Create a single image classification task. task_id is an id of the task. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) attributes is a list of attribute to be set in advance. (Optional) tags is a list of tag to be set in advance. (Optional) """ @@ -505,6 +545,8 @@ def update_image_classification_task( payload = {} if status: payload["status"] = status + if external_status: + payload["externalStatus"] = external_status if attributes: payload["attributes"] = attributes if tags: @@ -515,6 +557,7 @@ def update_video_classification_task( self, task_id: str, status: str = None, + external_status: str = None, attributes: list = [], tags: list = [], ) -> str: @@ -522,7 +565,8 @@ def update_video_classification_task( Create a single video classification task. task_id is an id of the task. (Required) - status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back', 'customer_approved'. (Optional) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) attributes is a list of attribute to be set in advance. (Optional) tags is a list of tag to be set in advance. (Optional) """ @@ -530,6 +574,8 @@ def update_video_classification_task( payload = {} if status: payload["status"] = status + if external_status: + payload["externalStatus"] = external_status if attributes: payload["attributes"] = attributes if tags: @@ -956,7 +1002,6 @@ def create_project( slug: str, is_bitmap: bool = False, job_size: int = 10, - use_annotation_service: bool = False ) -> str: """ Create a project. @@ -966,7 +1011,6 @@ def create_project( slug is slug of your project. (Required) is_bitmap is whether to be annotated by pixel. (Optional) job_size is the number of tasks the annotator gets at one time. (Optional) - use_annotation_service is whether to request FastLabel to provide annotation service or not. (Optional) """ endpoint = "projects" payload = { @@ -978,8 +1022,6 @@ def create_project( payload["isBitmap"] = is_bitmap if job_size: payload["jobSize"] = job_size - if use_annotation_service: - payload["useAnnotationService"] = use_annotation_service return self.api.post_request(endpoint, payload=payload) def update_project( diff --git a/setup.py b/setup.py index 84a93bc..2e5a4cd 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name="fastlabel", - version="0.9.10", + version="0.10.0", author="eisuke-ueta", author_email="eisuke.ueta@fastlabel.ai", description="The official Python SDK for FastLabel API, the Data Platform for AI", From e4a6a737164ac74ee70a920df90858c4a346231b Mon Sep 17 00:00:00 2001 From: ueta-eisuke Date: Mon, 9 Aug 2021 17:00:35 +0900 Subject: [PATCH 2/3] add video classification --- README.md | 26 ++++++++++++++++++++++++ fastlabel/__init__.py | 47 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c6a3572..50ed13c 100644 --- a/README.md +++ b/README.md @@ -546,6 +546,32 @@ Supported following project types: - Video - Classification (Single) +#### Create Task + +Create a new task. + +```python +task_id = client.create_video_classification_task( + project="YOUR_PROJECT_SLUG", + name="sample.mp4", + file_path="./sample.mp4", + attributes=[ + { + "key": "attribute-key", + "value": "attribute-value" + } + ], +) +``` + +#### Find Task + +Find a single task. + +```python +task = client.find_video_classification_task(task_id="YOUR_TASK_ID") +``` + #### Get Tasks Get tasks. (Up to 1000 tasks) diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 950a9cf..4e6a343 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -92,6 +92,13 @@ def find_video_task(self, task_id: str) -> dict: endpoint = "tasks/video/" + task_id return self.api.get_request(endpoint) + def find_video_classification_task(self, task_id: str) -> dict: + """ + Find a signle video classification task. + """ + endpoint = "tasks/video/classification/" + task_id + return self.api.get_request(endpoint) + def find_video_task_by_name(self, project: str, task_name: str) -> dict: """ Find a signle video task by name. @@ -401,6 +408,8 @@ def create_image_classification_task( payload = {"project": project, "name": name, "file": file} if status: payload["status"] = status + if external_status: + payload["externalStatus"] = external_status if attributes: payload["attributes"] = attributes if tags: @@ -473,7 +482,7 @@ def create_video_task( project is slug of your project. (Required) name is an unique identifier of task in your project. (Required) - file_path is a path to data. Supported extensions are png, jpg, jpeg. (Required) + file_path is a path to data. Supported extensions are mp4. (Required) status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) annotations is a list of annotation to be set in advance. (Optional) @@ -497,6 +506,42 @@ def create_video_task( payload["tags"] = tags return self.api.post_request(endpoint, payload=payload) + def create_video_classification_task( + self, + project: str, + name: str, + file_path: str, + status: str = None, + external_status: str = None, + attributes: list = [], + tags: list = [], + ) -> str: + """ + Create a single video classification task. + + project is slug of your project. (Required) + name is an unique identifier of task in your project. (Required) + file_path is a path to data. Supported extensions are mp4. (Required) + status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved'. (Optional) + external_status can be 'registered', 'completed', 'skipped', 'sent_back', 'approved', 'customer_sent_back'. (Optional) + attributes is a list of attribute to be set in advance. (Optional) + tags is a list of tag to be set in advance. (Optional) + """ + endpoint = "tasks/video/classification" + if not utils.is_video_supported_ext(file_path): + raise FastLabelInvalidException("Supported extensions are mp4.", 422) + file = utils.base64_encode(file_path) + payload = {"project": project, "name": name, "file": file} + if status: + payload["status"] = status + if external_status: + payload["externalStatus"] = external_status + if attributes: + payload["attributes"] = attributes + if tags: + payload["tags"] = tags + return self.api.post_request(endpoint, payload=payload) + # Task Update def update_task( From 3b487129105219cdeeac1bb60cc66d88e3824a19 Mon Sep 17 00:00:00 2001 From: ueta-eisuke Date: Mon, 9 Aug 2021 21:36:33 +0900 Subject: [PATCH 3/3] fix bitmap to pixel --- README.md | 2 +- fastlabel/__init__.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 50ed13c..2f2796d 100644 --- a/README.md +++ b/README.md @@ -839,7 +839,7 @@ Example of a project object "type": "image_bbox", "slug": "YOUR_PROJECT_SLUG", "name": "YOUR_PROJECT_NAME", - "isBitmap": False, + "isPixel": False, "jobSize": 10, "status": "active", "createdAt": "2021-04-20T03:20:41.427Z", diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 4e6a343..bb92c7f 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -1045,7 +1045,7 @@ def create_project( type: str, name: str, slug: str, - is_bitmap: bool = False, + is_pixel: bool = False, job_size: int = 10, ) -> str: """ @@ -1054,7 +1054,7 @@ def create_project( type can be 'image_bbox', 'image_polygon', 'image_keypoint', 'image_line', 'image_segmentation', 'image_classification', 'image_all', 'multi_image_bbox', 'multi_image_polygon', 'multi_image_keypoint', 'multi_image_line', 'multi_image_segmentation', 'video_bbox', 'video_single_classification'. (Required) name is name of your project. (Required) slug is slug of your project. (Required) - is_bitmap is whether to be annotated by pixel. (Optional) + is_pixel is whether to annotate image with pixel level. (Optional) job_size is the number of tasks the annotator gets at one time. (Optional) """ endpoint = "projects" @@ -1063,8 +1063,8 @@ def create_project( "name": name, "slug": slug, } - if is_bitmap: - payload["isBitmap"] = is_bitmap + if is_pixel: + payload["isPixel"] = is_pixel if job_size: payload["jobSize"] = job_size return self.api.post_request(endpoint, payload=payload)