diff --git a/.gitignore b/.gitignore index 8c97b39..e5850f9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ annotation.json *.jpg *.jpeg *.png +tests/ \ No newline at end of file diff --git a/README.md b/README.md index dbbf349..bc3bc1f 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,21 @@ client = fastlabel.Client() ## Limitation -API is allowed to call 1000 times per 10 minutes. If you create/delete a large size of tasks, please wait a second for every requests. +API is allowed to call 10000 times per 10 minutes. If you create/delete a large size of tasks, please wait a second for every requests. ## Task -### Create Task +### Image + +Supported following project types: + +- Bounding Box +- Polygon +- Keypoint +- Line +- Segmentation + +#### Create Task - Create a new task. @@ -70,34 +80,19 @@ task_id = client.create_task( > Check [examples/create_task.py](/examples/create_task.py). -### Update Task +#### Update Task -- Update a single task status, tags, and annotations. +- Update a single task status and tags. ```python task_id = client.update_task( task_id="YOUR_TASK_ID", status="approved", - tags=["tag1", "tag2"], - annotations=[{ - "value": "annotation-value", - "attributes": [ - { - "key": "attribute-key", - "value": "attribute-value" - } - ], - "points": [ - 100, # top-left x - 100, # top-left y - 200, # bottom-right x - 200 # bottom-right y - ] - }] + tags=["tag1", "tag2"] ) ``` -### Find Task +#### Find Task - Find a single task. @@ -105,7 +100,7 @@ task_id = client.update_task( task = client.find_task(task_id="YOUR_TASK_ID") ``` -### Get Tasks +#### Get Tasks - Get tasks. (Up to 1000 tasks) @@ -146,7 +141,7 @@ while True: > Please wait a second before sending another requests! -### Delete Task +#### Delete Task - Delete a single task. @@ -154,7 +149,7 @@ while True: client.delete_task(task_id="YOUR_TASK_ID") ``` -### Task Response +#### Task Response - Example of a single task object @@ -187,6 +182,118 @@ client.delete_task(task_id="YOUR_TASK_ID") } ``` +### Multi Image + +Supported following project types: + +- Bounding Box +- Polygon +- Keypoint +- Line +- Segmentation + +#### Create Task + +- Create a new task. + +```python +task = client.create_multi_image_task( + project="YOUR_PROJECT_SLUG", + name="sample.jpg", + folder_path="./sample", + annotations=[{ + "value": "annotation-value", + "attributes": [ + { + "key": "attribute-key", + "value": "attribute-value" + } + ], + "points": [[[ + 100, + 100, + 300, + 100, + 300, + 300, + 100, + 300, + 100, + 100 + ]]] # clockwise rotation + }] +) +``` + +#### Update Task + +- Same as image task. + +#### Find Task + +- Find a single task. + +```python +task = client.find_multi_image_task(task_id="YOUR_TASK_ID") +``` + +#### Get Tasks + +- Get tasks. + +```python +tasks = client.get_multi_image_tasks(project="YOUR_PROJECT_SLUG") +``` + +#### Delete Task + +- Same as image task. + +#### Task Response + +- Example of a single task object + +```python +{ + "id": "YOUR_TASK_ID", + "name": "cat.jpg", + "contents": [ + { + "name": "content-name", + "url": "content-url", + "width": "content-width", + "height": "content-height", + } + ], + "status": "registered", + "tags": [], + "annotations": [ + { + "content": "content-name" + "attributes": [], + "color": "#b36d18", + "points": [[[ + 100, + 100, + 300, + 100, + 300, + 300, + 100, + 300, + 100, + 100 + ]]] + "title": "Cat", + "type": "bbox", + "value": "cat" + } + ], + "createdAt": "2021-02-22T11:25:27.158Z", + "updatedAt": "2021-02-22T11:25:27.158Z" +} +``` + ## API Docs Check [this](https://api.fastlabel.ai/docs/) for further information. diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 800650d..6d3b278 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -1,4 +1,5 @@ import os +import glob from logging import getLogger import requests @@ -129,6 +130,13 @@ def find_task(self, task_id: str) -> dict: endpoint = "tasks/" + task_id return self._getrequest(endpoint) + def find_multi_image_task(self, task_id: str) -> dict: + """ + Find a signle multi image task. + """ + endpoint = "tasks/multi/image/" + task_id + return self._getrequest(endpoint) + def get_tasks( self, project: str, @@ -139,7 +147,6 @@ def get_tasks( ) -> list: """ Returns a list of 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) @@ -160,6 +167,36 @@ def get_tasks( params["limit"] = limit return self._getrequest(endpoint, params=params) + def get_multi_image_tasks( + self, + project: str, + status: str = None, + tags: list = [], + offset: int = None, + limit: int = 100, + ) -> dict: + """ + Returns a list of 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', 'in_progress', 'completed', 'skipped', 'in_review', 'send_backed', 'approved', 'customer_in_review', 'customer_send_backed', 'customer_approved'. (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) + """ + endpoint = "tasks/multi/image" + params = {"project": project} + if status: + params["status"] = status + if tags: + params["tags"] = tags + if offset: + params["offset"] = offset + if limit: + params["limit"] = limit + return self._getrequest(endpoint, params=params) + def create_task( self, project: str, @@ -185,6 +222,48 @@ def create_task( "Supported extensions are png, jpg, jpeg.", 422) file = self.__base64_encode(file_path) payload = {"project": project, "name": name, "file": file} + if status: + payload["status"] = status + if annotations: + for annotation in annotations: + annotation["content"] = name + payload["annotations"] = annotations + if tags: + payload["tags"] = tags + return self._postrequest(endpoint, payload=payload) + + def create_multi_image_task( + self, + project: str, + name: str, + folder_path: str, + status: str = None, + annotations: list = [], + tags: list = [], + ) -> dict: + """ + Create a single 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', 'in_progress', 'completed', 'skipped', 'in_review', 'send_backed', 'approved', 'customer_in_review', 'customer_send_backed', 'customer_approved'. (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) + """ + endpoint = "tasks/multi/image" + file_paths = glob.glob(os.path.join(folder_path, "*")) + contents = [] + for file_path in file_paths: + if not self.__is_supported_ext(file_path): + raise FastLabelInvalidException( + "Supported extensions are png, jpg, jpeg.", 422) + file = self.__base64_encode(file_path) + contents.append({ + "name": os.path.basename(file_path), + "file": file + }) + payload = {"project": project, "name": name, "contents": contents} if status: payload["status"] = status if annotations: @@ -197,7 +276,6 @@ def update_task( self, task_id: str, status: str = None, - annotations: list = [], tags: list = [], ) -> str: """ @@ -205,15 +283,12 @@ def update_task( task_id is an id of the task. (Required) status can be 'registered', 'in_progress', 'completed', 'skipped', 'in_review', 'send_backed', 'approved', 'customer_in_review', 'customer_send_backed', 'customer_approved'. (Optional) - annotations is a list of annotation to be set. (Optional) tags is a list of tag to be set. (Optional) """ endpoint = "tasks/" + task_id payload = {} if status: payload["status"] = status - if annotations: - payload["annotations"] = annotations if tags: payload["tags"] = tags return self._putrequest(endpoint, payload=payload) diff --git a/setup.py b/setup.py index 6a62b00..b935c0c 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name="fastlabel", - version="0.3.1", + version="0.4.0", author="eisuke-ueta", author_email="eisuke.ueta@fastlabel.ai", description="The official Python SDK for FastLabel API, the Data Platform for AI",