Skip to content

Commit edad0b3

Browse files
authored
Merge pull request #15 from fastlabel/feature/add-multi-image
Feature/add multi image
2 parents 4336ca8 + 54b258c commit edad0b3

File tree

4 files changed

+213
-30
lines changed

4 files changed

+213
-30
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ annotation.json
1111
*.jpg
1212
*.jpeg
1313
*.png
14+
tests/

README.md

Lines changed: 131 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,21 @@ client = fastlabel.Client()
2727

2828
## Limitation
2929

30-
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.
30+
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.
3131

3232
## Task
3333

34-
### Create Task
34+
### Image
35+
36+
Supported following project types:
37+
38+
- Bounding Box
39+
- Polygon
40+
- Keypoint
41+
- Line
42+
- Segmentation
43+
44+
#### Create Task
3545

3646
- Create a new task.
3747

@@ -70,42 +80,27 @@ task_id = client.create_task(
7080

7181
> Check [examples/create_task.py](/examples/create_task.py).
7282
73-
### Update Task
83+
#### Update Task
7484

75-
- Update a single task status, tags, and annotations.
85+
- Update a single task status and tags.
7686

7787
```python
7888
task_id = client.update_task(
7989
task_id="YOUR_TASK_ID",
8090
status="approved",
81-
tags=["tag1", "tag2"],
82-
annotations=[{
83-
"value": "annotation-value",
84-
"attributes": [
85-
{
86-
"key": "attribute-key",
87-
"value": "attribute-value"
88-
}
89-
],
90-
"points": [
91-
100, # top-left x
92-
100, # top-left y
93-
200, # bottom-right x
94-
200 # bottom-right y
95-
]
96-
}]
91+
tags=["tag1", "tag2"]
9792
)
9893
```
9994

100-
### Find Task
95+
#### Find Task
10196

10297
- Find a single task.
10398

10499
```python
105100
task = client.find_task(task_id="YOUR_TASK_ID")
106101
```
107102

108-
### Get Tasks
103+
#### Get Tasks
109104

110105
- Get tasks. (Up to 1000 tasks)
111106

@@ -146,15 +141,15 @@ while True:
146141

147142
> Please wait a second before sending another requests!
148143
149-
### Delete Task
144+
#### Delete Task
150145

151146
- Delete a single task.
152147

153148
```python
154149
client.delete_task(task_id="YOUR_TASK_ID")
155150
```
156151

157-
### Task Response
152+
#### Task Response
158153

159154
- Example of a single task object
160155

@@ -187,6 +182,118 @@ client.delete_task(task_id="YOUR_TASK_ID")
187182
}
188183
```
189184

185+
### Multi Image
186+
187+
Supported following project types:
188+
189+
- Bounding Box
190+
- Polygon
191+
- Keypoint
192+
- Line
193+
- Segmentation
194+
195+
#### Create Task
196+
197+
- Create a new task.
198+
199+
```python
200+
task = client.create_multi_image_task(
201+
project="YOUR_PROJECT_SLUG",
202+
name="sample.jpg",
203+
folder_path="./sample",
204+
annotations=[{
205+
"value": "annotation-value",
206+
"attributes": [
207+
{
208+
"key": "attribute-key",
209+
"value": "attribute-value"
210+
}
211+
],
212+
"points": [[[
213+
100,
214+
100,
215+
300,
216+
100,
217+
300,
218+
300,
219+
100,
220+
300,
221+
100,
222+
100
223+
]]] # clockwise rotation
224+
}]
225+
)
226+
```
227+
228+
#### Update Task
229+
230+
- Same as image task.
231+
232+
#### Find Task
233+
234+
- Find a single task.
235+
236+
```python
237+
task = client.find_multi_image_task(task_id="YOUR_TASK_ID")
238+
```
239+
240+
#### Get Tasks
241+
242+
- Get tasks.
243+
244+
```python
245+
tasks = client.get_multi_image_tasks(project="YOUR_PROJECT_SLUG")
246+
```
247+
248+
#### Delete Task
249+
250+
- Same as image task.
251+
252+
#### Task Response
253+
254+
- Example of a single task object
255+
256+
```python
257+
{
258+
"id": "YOUR_TASK_ID",
259+
"name": "cat.jpg",
260+
"contents": [
261+
{
262+
"name": "content-name",
263+
"url": "content-url",
264+
"width": "content-width",
265+
"height": "content-height",
266+
}
267+
],
268+
"status": "registered",
269+
"tags": [],
270+
"annotations": [
271+
{
272+
"content": "content-name"
273+
"attributes": [],
274+
"color": "#b36d18",
275+
"points": [[[
276+
100,
277+
100,
278+
300,
279+
100,
280+
300,
281+
300,
282+
100,
283+
300,
284+
100,
285+
100
286+
]]]
287+
"title": "Cat",
288+
"type": "bbox",
289+
"value": "cat"
290+
}
291+
],
292+
"createdAt": "2021-02-22T11:25:27.158Z",
293+
"updatedAt": "2021-02-22T11:25:27.158Z"
294+
}
295+
```
296+
190297
## API Docs
191298

192299
Check [this](https://api.fastlabel.ai/docs/) for further information.

fastlabel/__init__.py

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import glob
23
from logging import getLogger
34

45
import requests
@@ -129,6 +130,13 @@ def find_task(self, task_id: str) -> dict:
129130
endpoint = "tasks/" + task_id
130131
return self._getrequest(endpoint)
131132

133+
def find_multi_image_task(self, task_id: str) -> dict:
134+
"""
135+
Find a signle multi image task.
136+
"""
137+
endpoint = "tasks/multi/image/" + task_id
138+
return self._getrequest(endpoint)
139+
132140
def get_tasks(
133141
self,
134142
project: str,
@@ -139,7 +147,6 @@ def get_tasks(
139147
) -> list:
140148
"""
141149
Returns a list of tasks.
142-
143150
Returns up to 1000 at a time, to get more, set offset as the starting position to fetch.
144151
145152
project is slug of your project. (Required)
@@ -160,6 +167,36 @@ def get_tasks(
160167
params["limit"] = limit
161168
return self._getrequest(endpoint, params=params)
162169

170+
def get_multi_image_tasks(
171+
self,
172+
project: str,
173+
status: str = None,
174+
tags: list = [],
175+
offset: int = None,
176+
limit: int = 100,
177+
) -> dict:
178+
"""
179+
Returns a list of tasks.
180+
Returns up to 1000 at a time, to get more, set offset as the starting position to fetch.
181+
182+
project is slug of your project. (Required)
183+
status can be 'registered', 'in_progress', 'completed', 'skipped', 'in_review', 'send_backed', 'approved', 'customer_in_review', 'customer_send_backed', 'customer_approved'. (Optional)
184+
tags is a list of tag. (Optional)
185+
offset is the starting position number to fetch. (Optional)
186+
limit is the max number to fetch. (Optional)
187+
"""
188+
endpoint = "tasks/multi/image"
189+
params = {"project": project}
190+
if status:
191+
params["status"] = status
192+
if tags:
193+
params["tags"] = tags
194+
if offset:
195+
params["offset"] = offset
196+
if limit:
197+
params["limit"] = limit
198+
return self._getrequest(endpoint, params=params)
199+
163200
def create_task(
164201
self,
165202
project: str,
@@ -185,6 +222,48 @@ def create_task(
185222
"Supported extensions are png, jpg, jpeg.", 422)
186223
file = self.__base64_encode(file_path)
187224
payload = {"project": project, "name": name, "file": file}
225+
if status:
226+
payload["status"] = status
227+
if annotations:
228+
for annotation in annotations:
229+
annotation["content"] = name
230+
payload["annotations"] = annotations
231+
if tags:
232+
payload["tags"] = tags
233+
return self._postrequest(endpoint, payload=payload)
234+
235+
def create_multi_image_task(
236+
self,
237+
project: str,
238+
name: str,
239+
folder_path: str,
240+
status: str = None,
241+
annotations: list = [],
242+
tags: list = [],
243+
) -> dict:
244+
"""
245+
Create a single multi image task.
246+
247+
project is slug of your project. (Required)
248+
name is an unique identifier of task in your project. (Required)
249+
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)
250+
status can be 'registered', 'in_progress', 'completed', 'skipped', 'in_review', 'send_backed', 'approved', 'customer_in_review', 'customer_send_backed', 'customer_approved'. (Optional)
251+
annotations is a list of annotation to be set in advance. (Optional)
252+
tags is a list of tag to be set in advance. (Optional)
253+
"""
254+
endpoint = "tasks/multi/image"
255+
file_paths = glob.glob(os.path.join(folder_path, "*"))
256+
contents = []
257+
for file_path in file_paths:
258+
if not self.__is_supported_ext(file_path):
259+
raise FastLabelInvalidException(
260+
"Supported extensions are png, jpg, jpeg.", 422)
261+
file = self.__base64_encode(file_path)
262+
contents.append({
263+
"name": os.path.basename(file_path),
264+
"file": file
265+
})
266+
payload = {"project": project, "name": name, "contents": contents}
188267
if status:
189268
payload["status"] = status
190269
if annotations:
@@ -197,23 +276,19 @@ def update_task(
197276
self,
198277
task_id: str,
199278
status: str = None,
200-
annotations: list = [],
201279
tags: list = [],
202280
) -> str:
203281
"""
204282
Update a single task.
205283
206284
task_id is an id of the task. (Required)
207285
status can be 'registered', 'in_progress', 'completed', 'skipped', 'in_review', 'send_backed', 'approved', 'customer_in_review', 'customer_send_backed', 'customer_approved'. (Optional)
208-
annotations is a list of annotation to be set. (Optional)
209286
tags is a list of tag to be set. (Optional)
210287
"""
211288
endpoint = "tasks/" + task_id
212289
payload = {}
213290
if status:
214291
payload["status"] = status
215-
if annotations:
216-
payload["annotations"] = annotations
217292
if tags:
218293
payload["tags"] = tags
219294
return self._putrequest(endpoint, payload=payload)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setuptools.setup(
1010
name="fastlabel",
11-
version="0.3.1",
11+
version="0.4.0",
1212
author="eisuke-ueta",
1313
author_email="eisuke.ueta@fastlabel.ai",
1414
description="The official Python SDK for FastLabel API, the Data Platform for AI",

0 commit comments

Comments
 (0)