label-studio-sdk 1.0.5__py3-none-any.whl → 1.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- label_studio_sdk/__init__.py +70 -0
- label_studio_sdk/_extensions/eval/categorical.py +83 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +35 -17
- label_studio_sdk/annotations/__init__.py +3 -0
- label_studio_sdk/annotations/client.py +109 -0
- label_studio_sdk/annotations/types/__init__.py +5 -0
- label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +29 -0
- label_studio_sdk/base_client.py +9 -0
- label_studio_sdk/comments/__init__.py +2 -0
- label_studio_sdk/comments/client.py +512 -0
- label_studio_sdk/converter/converter.py +2 -0
- label_studio_sdk/converter/imports/coco.py +14 -13
- label_studio_sdk/converter/utils.py +72 -3
- label_studio_sdk/core/client_wrapper.py +1 -1
- label_studio_sdk/files/client.py +26 -16
- label_studio_sdk/label_interface/interface.py +38 -5
- label_studio_sdk/model_providers/__init__.py +2 -0
- label_studio_sdk/model_providers/client.py +190 -0
- label_studio_sdk/projects/client.py +32 -16
- label_studio_sdk/projects/exports/client.py +133 -40
- label_studio_sdk/prompts/__init__.py +21 -0
- label_studio_sdk/prompts/client.py +862 -0
- label_studio_sdk/prompts/indicators/__init__.py +2 -0
- label_studio_sdk/prompts/indicators/client.py +194 -0
- label_studio_sdk/prompts/runs/__init__.py +5 -0
- label_studio_sdk/prompts/runs/client.py +354 -0
- label_studio_sdk/prompts/runs/types/__init__.py +5 -0
- label_studio_sdk/prompts/runs/types/runs_list_request_project_subset.py +5 -0
- label_studio_sdk/prompts/types/__init__.py +15 -0
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +42 -0
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +29 -0
- label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +62 -0
- label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +29 -0
- label_studio_sdk/prompts/versions/__init__.py +2 -0
- label_studio_sdk/prompts/versions/client.py +921 -0
- label_studio_sdk/types/__init__.py +52 -0
- label_studio_sdk/types/comment.py +39 -0
- label_studio_sdk/types/comment_created_by.py +5 -0
- label_studio_sdk/types/inference_run.py +43 -0
- label_studio_sdk/types/inference_run_created_by.py +5 -0
- label_studio_sdk/types/inference_run_organization.py +5 -0
- label_studio_sdk/types/inference_run_project_subset.py +5 -0
- label_studio_sdk/types/inference_run_status.py +7 -0
- label_studio_sdk/types/key_indicator_value.py +30 -0
- label_studio_sdk/types/key_indicators.py +7 -0
- label_studio_sdk/types/key_indicators_item.py +51 -0
- label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +37 -0
- label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +37 -0
- label_studio_sdk/types/model_provider_connection.py +41 -0
- label_studio_sdk/types/model_provider_connection_created_by.py +5 -0
- label_studio_sdk/types/model_provider_connection_organization.py +5 -0
- label_studio_sdk/types/model_provider_connection_provider.py +5 -0
- label_studio_sdk/types/model_provider_connection_scope.py +5 -0
- label_studio_sdk/types/prompt.py +79 -0
- label_studio_sdk/types/prompt_created_by.py +5 -0
- label_studio_sdk/types/prompt_organization.py +5 -0
- label_studio_sdk/types/prompt_version.py +41 -0
- label_studio_sdk/types/prompt_version_created_by.py +5 -0
- label_studio_sdk/types/prompt_version_organization.py +5 -0
- label_studio_sdk/types/prompt_version_provider.py +5 -0
- label_studio_sdk/types/refined_prompt_response.py +64 -0
- label_studio_sdk/types/refined_prompt_response_refinement_status.py +7 -0
- label_studio_sdk/webhooks/client.py +245 -36
- label_studio_sdk/workspaces/client.py +20 -20
- label_studio_sdk-1.0.7.dist-info/LICENSE +201 -0
- {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.7.dist-info}/METADATA +17 -3
- {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.7.dist-info}/RECORD +68 -19
- {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.7.dist-info}/WHEEL +1 -1
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
from json.decoder import JSONDecodeError
|
|
5
|
+
|
|
6
|
+
from ..core.api_error import ApiError
|
|
7
|
+
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
8
|
+
from ..core.jsonable_encoder import jsonable_encoder
|
|
9
|
+
from ..core.pydantic_utilities import pydantic_v1
|
|
10
|
+
from ..core.request_options import RequestOptions
|
|
11
|
+
from ..types.comment import Comment
|
|
12
|
+
|
|
13
|
+
# this is used as the default value for optional parameters
|
|
14
|
+
OMIT = typing.cast(typing.Any, ...)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CommentsClient:
|
|
18
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
|
19
|
+
self._client_wrapper = client_wrapper
|
|
20
|
+
|
|
21
|
+
def list(
|
|
22
|
+
self,
|
|
23
|
+
*,
|
|
24
|
+
project: typing.Optional[int] = None,
|
|
25
|
+
expand_created_by: typing.Optional[bool] = None,
|
|
26
|
+
annotation: typing.Optional[int] = None,
|
|
27
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
28
|
+
) -> typing.List[Comment]:
|
|
29
|
+
"""
|
|
30
|
+
Get a list of comments for a specific project.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
project : typing.Optional[int]
|
|
35
|
+
Project ID
|
|
36
|
+
|
|
37
|
+
expand_created_by : typing.Optional[bool]
|
|
38
|
+
Expand the created_by field with object instead of ID
|
|
39
|
+
|
|
40
|
+
annotation : typing.Optional[int]
|
|
41
|
+
Annotation ID
|
|
42
|
+
|
|
43
|
+
request_options : typing.Optional[RequestOptions]
|
|
44
|
+
Request-specific configuration.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
typing.List[Comment]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
Examples
|
|
52
|
+
--------
|
|
53
|
+
from label_studio_sdk.client import LabelStudio
|
|
54
|
+
|
|
55
|
+
client = LabelStudio(
|
|
56
|
+
api_key="YOUR_API_KEY",
|
|
57
|
+
)
|
|
58
|
+
client.comments.list()
|
|
59
|
+
"""
|
|
60
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
61
|
+
"api/comments/",
|
|
62
|
+
method="GET",
|
|
63
|
+
params={"project": project, "expand_created_by": expand_created_by, "annotation": annotation},
|
|
64
|
+
request_options=request_options,
|
|
65
|
+
)
|
|
66
|
+
try:
|
|
67
|
+
if 200 <= _response.status_code < 300:
|
|
68
|
+
return pydantic_v1.parse_obj_as(typing.List[Comment], _response.json()) # type: ignore
|
|
69
|
+
_response_json = _response.json()
|
|
70
|
+
except JSONDecodeError:
|
|
71
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
72
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
73
|
+
|
|
74
|
+
def create(
|
|
75
|
+
self,
|
|
76
|
+
*,
|
|
77
|
+
annotation: typing.Optional[int] = OMIT,
|
|
78
|
+
project: typing.Optional[int] = OMIT,
|
|
79
|
+
text: typing.Optional[str] = OMIT,
|
|
80
|
+
is_resolved: typing.Optional[bool] = OMIT,
|
|
81
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
82
|
+
) -> Comment:
|
|
83
|
+
"""
|
|
84
|
+
Create a new comment.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
annotation : typing.Optional[int]
|
|
89
|
+
|
|
90
|
+
project : typing.Optional[int]
|
|
91
|
+
|
|
92
|
+
text : typing.Optional[str]
|
|
93
|
+
|
|
94
|
+
is_resolved : typing.Optional[bool]
|
|
95
|
+
|
|
96
|
+
request_options : typing.Optional[RequestOptions]
|
|
97
|
+
Request-specific configuration.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
Comment
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
Examples
|
|
105
|
+
--------
|
|
106
|
+
from label_studio_sdk.client import LabelStudio
|
|
107
|
+
|
|
108
|
+
client = LabelStudio(
|
|
109
|
+
api_key="YOUR_API_KEY",
|
|
110
|
+
)
|
|
111
|
+
client.comments.create()
|
|
112
|
+
"""
|
|
113
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
114
|
+
"api/comments/",
|
|
115
|
+
method="POST",
|
|
116
|
+
json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
|
|
117
|
+
request_options=request_options,
|
|
118
|
+
omit=OMIT,
|
|
119
|
+
)
|
|
120
|
+
try:
|
|
121
|
+
if 200 <= _response.status_code < 300:
|
|
122
|
+
return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
|
|
123
|
+
_response_json = _response.json()
|
|
124
|
+
except JSONDecodeError:
|
|
125
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
126
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
127
|
+
|
|
128
|
+
def get(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> Comment:
|
|
129
|
+
"""
|
|
130
|
+
Get a specific comment.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
id : int
|
|
135
|
+
Comment ID
|
|
136
|
+
|
|
137
|
+
request_options : typing.Optional[RequestOptions]
|
|
138
|
+
Request-specific configuration.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
Comment
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
Examples
|
|
146
|
+
--------
|
|
147
|
+
from label_studio_sdk.client import LabelStudio
|
|
148
|
+
|
|
149
|
+
client = LabelStudio(
|
|
150
|
+
api_key="YOUR_API_KEY",
|
|
151
|
+
)
|
|
152
|
+
client.comments.get(
|
|
153
|
+
id=1,
|
|
154
|
+
)
|
|
155
|
+
"""
|
|
156
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
157
|
+
f"api/comments/{jsonable_encoder(id)}", method="GET", request_options=request_options
|
|
158
|
+
)
|
|
159
|
+
try:
|
|
160
|
+
if 200 <= _response.status_code < 300:
|
|
161
|
+
return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
|
|
162
|
+
_response_json = _response.json()
|
|
163
|
+
except JSONDecodeError:
|
|
164
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
165
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
166
|
+
|
|
167
|
+
def delete(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
|
|
168
|
+
"""
|
|
169
|
+
Delete a specific comment.
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
id : int
|
|
174
|
+
Comment ID
|
|
175
|
+
|
|
176
|
+
request_options : typing.Optional[RequestOptions]
|
|
177
|
+
Request-specific configuration.
|
|
178
|
+
|
|
179
|
+
Returns
|
|
180
|
+
-------
|
|
181
|
+
None
|
|
182
|
+
|
|
183
|
+
Examples
|
|
184
|
+
--------
|
|
185
|
+
from label_studio_sdk.client import LabelStudio
|
|
186
|
+
|
|
187
|
+
client = LabelStudio(
|
|
188
|
+
api_key="YOUR_API_KEY",
|
|
189
|
+
)
|
|
190
|
+
client.comments.delete(
|
|
191
|
+
id=1,
|
|
192
|
+
)
|
|
193
|
+
"""
|
|
194
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
195
|
+
f"api/comments/{jsonable_encoder(id)}", method="DELETE", request_options=request_options
|
|
196
|
+
)
|
|
197
|
+
try:
|
|
198
|
+
if 200 <= _response.status_code < 300:
|
|
199
|
+
return
|
|
200
|
+
_response_json = _response.json()
|
|
201
|
+
except JSONDecodeError:
|
|
202
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
203
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
204
|
+
|
|
205
|
+
def update(
|
|
206
|
+
self,
|
|
207
|
+
id: int,
|
|
208
|
+
*,
|
|
209
|
+
annotation: typing.Optional[int] = OMIT,
|
|
210
|
+
project: typing.Optional[int] = OMIT,
|
|
211
|
+
text: typing.Optional[str] = OMIT,
|
|
212
|
+
is_resolved: typing.Optional[bool] = OMIT,
|
|
213
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
214
|
+
) -> Comment:
|
|
215
|
+
"""
|
|
216
|
+
Update a specific comment.
|
|
217
|
+
|
|
218
|
+
Parameters
|
|
219
|
+
----------
|
|
220
|
+
id : int
|
|
221
|
+
Comment ID
|
|
222
|
+
|
|
223
|
+
annotation : typing.Optional[int]
|
|
224
|
+
|
|
225
|
+
project : typing.Optional[int]
|
|
226
|
+
|
|
227
|
+
text : typing.Optional[str]
|
|
228
|
+
|
|
229
|
+
is_resolved : typing.Optional[bool]
|
|
230
|
+
|
|
231
|
+
request_options : typing.Optional[RequestOptions]
|
|
232
|
+
Request-specific configuration.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
Comment
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
Examples
|
|
240
|
+
--------
|
|
241
|
+
from label_studio_sdk.client import LabelStudio
|
|
242
|
+
|
|
243
|
+
client = LabelStudio(
|
|
244
|
+
api_key="YOUR_API_KEY",
|
|
245
|
+
)
|
|
246
|
+
client.comments.update(
|
|
247
|
+
id=1,
|
|
248
|
+
)
|
|
249
|
+
"""
|
|
250
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
251
|
+
f"api/comments/{jsonable_encoder(id)}",
|
|
252
|
+
method="PATCH",
|
|
253
|
+
json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
|
|
254
|
+
request_options=request_options,
|
|
255
|
+
omit=OMIT,
|
|
256
|
+
)
|
|
257
|
+
try:
|
|
258
|
+
if 200 <= _response.status_code < 300:
|
|
259
|
+
return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
|
|
260
|
+
_response_json = _response.json()
|
|
261
|
+
except JSONDecodeError:
|
|
262
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
263
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class AsyncCommentsClient:
|
|
267
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
268
|
+
self._client_wrapper = client_wrapper
|
|
269
|
+
|
|
270
|
+
async def list(
|
|
271
|
+
self,
|
|
272
|
+
*,
|
|
273
|
+
project: typing.Optional[int] = None,
|
|
274
|
+
expand_created_by: typing.Optional[bool] = None,
|
|
275
|
+
annotation: typing.Optional[int] = None,
|
|
276
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
277
|
+
) -> typing.List[Comment]:
|
|
278
|
+
"""
|
|
279
|
+
Get a list of comments for a specific project.
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
project : typing.Optional[int]
|
|
284
|
+
Project ID
|
|
285
|
+
|
|
286
|
+
expand_created_by : typing.Optional[bool]
|
|
287
|
+
Expand the created_by field with object instead of ID
|
|
288
|
+
|
|
289
|
+
annotation : typing.Optional[int]
|
|
290
|
+
Annotation ID
|
|
291
|
+
|
|
292
|
+
request_options : typing.Optional[RequestOptions]
|
|
293
|
+
Request-specific configuration.
|
|
294
|
+
|
|
295
|
+
Returns
|
|
296
|
+
-------
|
|
297
|
+
typing.List[Comment]
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
Examples
|
|
301
|
+
--------
|
|
302
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
303
|
+
|
|
304
|
+
client = AsyncLabelStudio(
|
|
305
|
+
api_key="YOUR_API_KEY",
|
|
306
|
+
)
|
|
307
|
+
await client.comments.list()
|
|
308
|
+
"""
|
|
309
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
310
|
+
"api/comments/",
|
|
311
|
+
method="GET",
|
|
312
|
+
params={"project": project, "expand_created_by": expand_created_by, "annotation": annotation},
|
|
313
|
+
request_options=request_options,
|
|
314
|
+
)
|
|
315
|
+
try:
|
|
316
|
+
if 200 <= _response.status_code < 300:
|
|
317
|
+
return pydantic_v1.parse_obj_as(typing.List[Comment], _response.json()) # type: ignore
|
|
318
|
+
_response_json = _response.json()
|
|
319
|
+
except JSONDecodeError:
|
|
320
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
321
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
322
|
+
|
|
323
|
+
async def create(
|
|
324
|
+
self,
|
|
325
|
+
*,
|
|
326
|
+
annotation: typing.Optional[int] = OMIT,
|
|
327
|
+
project: typing.Optional[int] = OMIT,
|
|
328
|
+
text: typing.Optional[str] = OMIT,
|
|
329
|
+
is_resolved: typing.Optional[bool] = OMIT,
|
|
330
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
331
|
+
) -> Comment:
|
|
332
|
+
"""
|
|
333
|
+
Create a new comment.
|
|
334
|
+
|
|
335
|
+
Parameters
|
|
336
|
+
----------
|
|
337
|
+
annotation : typing.Optional[int]
|
|
338
|
+
|
|
339
|
+
project : typing.Optional[int]
|
|
340
|
+
|
|
341
|
+
text : typing.Optional[str]
|
|
342
|
+
|
|
343
|
+
is_resolved : typing.Optional[bool]
|
|
344
|
+
|
|
345
|
+
request_options : typing.Optional[RequestOptions]
|
|
346
|
+
Request-specific configuration.
|
|
347
|
+
|
|
348
|
+
Returns
|
|
349
|
+
-------
|
|
350
|
+
Comment
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
Examples
|
|
354
|
+
--------
|
|
355
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
356
|
+
|
|
357
|
+
client = AsyncLabelStudio(
|
|
358
|
+
api_key="YOUR_API_KEY",
|
|
359
|
+
)
|
|
360
|
+
await client.comments.create()
|
|
361
|
+
"""
|
|
362
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
363
|
+
"api/comments/",
|
|
364
|
+
method="POST",
|
|
365
|
+
json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
|
|
366
|
+
request_options=request_options,
|
|
367
|
+
omit=OMIT,
|
|
368
|
+
)
|
|
369
|
+
try:
|
|
370
|
+
if 200 <= _response.status_code < 300:
|
|
371
|
+
return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
|
|
372
|
+
_response_json = _response.json()
|
|
373
|
+
except JSONDecodeError:
|
|
374
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
375
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
376
|
+
|
|
377
|
+
async def get(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> Comment:
|
|
378
|
+
"""
|
|
379
|
+
Get a specific comment.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
id : int
|
|
384
|
+
Comment ID
|
|
385
|
+
|
|
386
|
+
request_options : typing.Optional[RequestOptions]
|
|
387
|
+
Request-specific configuration.
|
|
388
|
+
|
|
389
|
+
Returns
|
|
390
|
+
-------
|
|
391
|
+
Comment
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
Examples
|
|
395
|
+
--------
|
|
396
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
397
|
+
|
|
398
|
+
client = AsyncLabelStudio(
|
|
399
|
+
api_key="YOUR_API_KEY",
|
|
400
|
+
)
|
|
401
|
+
await client.comments.get(
|
|
402
|
+
id=1,
|
|
403
|
+
)
|
|
404
|
+
"""
|
|
405
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
406
|
+
f"api/comments/{jsonable_encoder(id)}", method="GET", request_options=request_options
|
|
407
|
+
)
|
|
408
|
+
try:
|
|
409
|
+
if 200 <= _response.status_code < 300:
|
|
410
|
+
return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
|
|
411
|
+
_response_json = _response.json()
|
|
412
|
+
except JSONDecodeError:
|
|
413
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
414
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
415
|
+
|
|
416
|
+
async def delete(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
|
|
417
|
+
"""
|
|
418
|
+
Delete a specific comment.
|
|
419
|
+
|
|
420
|
+
Parameters
|
|
421
|
+
----------
|
|
422
|
+
id : int
|
|
423
|
+
Comment ID
|
|
424
|
+
|
|
425
|
+
request_options : typing.Optional[RequestOptions]
|
|
426
|
+
Request-specific configuration.
|
|
427
|
+
|
|
428
|
+
Returns
|
|
429
|
+
-------
|
|
430
|
+
None
|
|
431
|
+
|
|
432
|
+
Examples
|
|
433
|
+
--------
|
|
434
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
435
|
+
|
|
436
|
+
client = AsyncLabelStudio(
|
|
437
|
+
api_key="YOUR_API_KEY",
|
|
438
|
+
)
|
|
439
|
+
await client.comments.delete(
|
|
440
|
+
id=1,
|
|
441
|
+
)
|
|
442
|
+
"""
|
|
443
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
444
|
+
f"api/comments/{jsonable_encoder(id)}", method="DELETE", request_options=request_options
|
|
445
|
+
)
|
|
446
|
+
try:
|
|
447
|
+
if 200 <= _response.status_code < 300:
|
|
448
|
+
return
|
|
449
|
+
_response_json = _response.json()
|
|
450
|
+
except JSONDecodeError:
|
|
451
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
452
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
453
|
+
|
|
454
|
+
async def update(
|
|
455
|
+
self,
|
|
456
|
+
id: int,
|
|
457
|
+
*,
|
|
458
|
+
annotation: typing.Optional[int] = OMIT,
|
|
459
|
+
project: typing.Optional[int] = OMIT,
|
|
460
|
+
text: typing.Optional[str] = OMIT,
|
|
461
|
+
is_resolved: typing.Optional[bool] = OMIT,
|
|
462
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
463
|
+
) -> Comment:
|
|
464
|
+
"""
|
|
465
|
+
Update a specific comment.
|
|
466
|
+
|
|
467
|
+
Parameters
|
|
468
|
+
----------
|
|
469
|
+
id : int
|
|
470
|
+
Comment ID
|
|
471
|
+
|
|
472
|
+
annotation : typing.Optional[int]
|
|
473
|
+
|
|
474
|
+
project : typing.Optional[int]
|
|
475
|
+
|
|
476
|
+
text : typing.Optional[str]
|
|
477
|
+
|
|
478
|
+
is_resolved : typing.Optional[bool]
|
|
479
|
+
|
|
480
|
+
request_options : typing.Optional[RequestOptions]
|
|
481
|
+
Request-specific configuration.
|
|
482
|
+
|
|
483
|
+
Returns
|
|
484
|
+
-------
|
|
485
|
+
Comment
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
Examples
|
|
489
|
+
--------
|
|
490
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
491
|
+
|
|
492
|
+
client = AsyncLabelStudio(
|
|
493
|
+
api_key="YOUR_API_KEY",
|
|
494
|
+
)
|
|
495
|
+
await client.comments.update(
|
|
496
|
+
id=1,
|
|
497
|
+
)
|
|
498
|
+
"""
|
|
499
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
500
|
+
f"api/comments/{jsonable_encoder(id)}",
|
|
501
|
+
method="PATCH",
|
|
502
|
+
json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
|
|
503
|
+
request_options=request_options,
|
|
504
|
+
omit=OMIT,
|
|
505
|
+
)
|
|
506
|
+
try:
|
|
507
|
+
if 200 <= _response.status_code < 300:
|
|
508
|
+
return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
|
|
509
|
+
_response_json = _response.json()
|
|
510
|
+
except JSONDecodeError:
|
|
511
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
512
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
@@ -346,6 +346,8 @@ class Converter(object):
|
|
|
346
346
|
and "TextArea" in output_tag_types
|
|
347
347
|
):
|
|
348
348
|
all_formats.remove(Format.ASR_MANIFEST.name)
|
|
349
|
+
if 'Video' in input_tag_types and 'TimelineLabels' in output_tag_types:
|
|
350
|
+
all_formats.remove(Format.YOLO_OBB.name)
|
|
349
351
|
|
|
350
352
|
return all_formats
|
|
351
353
|
|
|
@@ -48,10 +48,9 @@ def create_bbox(annotation, categories, from_name, image_height, image_width, to
|
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
def create_segmentation(
|
|
51
|
-
|
|
51
|
+
category_id, segmentation, categories, from_name, image_height, image_width, to_name
|
|
52
52
|
):
|
|
53
|
-
label = categories[int(
|
|
54
|
-
segmentation = annotation["segmentation"][0]
|
|
53
|
+
label = categories[int(category_id)]
|
|
55
54
|
points = [list(x) for x in zip(*[iter(segmentation)] * 2)]
|
|
56
55
|
|
|
57
56
|
for i in range(len(points)):
|
|
@@ -216,15 +215,17 @@ def convert_coco_to_ls(
|
|
|
216
215
|
task[out_type][0]["result"].append(item)
|
|
217
216
|
|
|
218
217
|
if "segmentation" in annotation and len(annotation["segmentation"]):
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
218
|
+
for single_segmentation in annotation["segmentation"]:
|
|
219
|
+
item = create_segmentation(
|
|
220
|
+
annotation["category_id"],
|
|
221
|
+
single_segmentation,
|
|
222
|
+
categories,
|
|
223
|
+
segmentation_from_name,
|
|
224
|
+
image_height,
|
|
225
|
+
image_width,
|
|
226
|
+
to_name,
|
|
227
|
+
)
|
|
228
|
+
task[out_type][0]["result"].append(item)
|
|
228
229
|
|
|
229
230
|
if "keypoints" in annotation:
|
|
230
231
|
items = create_keypoints(
|
|
@@ -270,7 +271,7 @@ def add_parser(subparsers):
|
|
|
270
271
|
"--input",
|
|
271
272
|
dest="input",
|
|
272
273
|
required=True,
|
|
273
|
-
help="
|
|
274
|
+
help="input COCO json file",
|
|
274
275
|
action=ExpandFullPath,
|
|
275
276
|
)
|
|
276
277
|
coco.add_argument(
|
|
@@ -17,10 +17,11 @@ from urllib.parse import urlparse
|
|
|
17
17
|
import numpy as np
|
|
18
18
|
import requests
|
|
19
19
|
from PIL import Image
|
|
20
|
-
from label_studio_sdk._extensions.label_studio_tools.core.utils.params import get_env
|
|
21
20
|
from lxml import etree
|
|
22
21
|
from nltk.tokenize.treebank import TreebankWordTokenizer
|
|
23
22
|
|
|
23
|
+
from label_studio_sdk._extensions.label_studio_tools.core.utils.params import get_env
|
|
24
|
+
|
|
24
25
|
logger = logging.getLogger(__name__)
|
|
25
26
|
|
|
26
27
|
_LABEL_TAGS = {"Label", "Choice"}
|
|
@@ -422,7 +423,7 @@ def convert_annotation_to_yolo(label):
|
|
|
422
423
|
return x, y, w, h
|
|
423
424
|
|
|
424
425
|
|
|
425
|
-
def convert_annotation_to_yolo_obb(label):
|
|
426
|
+
def convert_annotation_to_yolo_obb(label, normalize=True):
|
|
426
427
|
"""
|
|
427
428
|
Convert LS annotation to Yolo OBB format.
|
|
428
429
|
|
|
@@ -435,6 +436,7 @@ def convert_annotation_to_yolo_obb(label):
|
|
|
435
436
|
- width (float): Width of the object in percentage of the original width.
|
|
436
437
|
- height (float): Height of the object in percentage of the original height.
|
|
437
438
|
- rotation (float, optional): Rotation angle of the object in degrees (default is 0).
|
|
439
|
+
normalize (bool, optional): Whether to normalize the coordinates to the range [0, 1] (default is True).
|
|
438
440
|
|
|
439
441
|
Returns:
|
|
440
442
|
list of tuple or None: List of tuples containing the coordinates of the object in Yolo OBB format.
|
|
@@ -470,4 +472,71 @@ def convert_annotation_to_yolo_obb(label):
|
|
|
470
472
|
]
|
|
471
473
|
|
|
472
474
|
# Normalize coordinates
|
|
473
|
-
|
|
475
|
+
if normalize:
|
|
476
|
+
return [(coord[0] / org_width, coord[1] / org_height) for coord in coords]
|
|
477
|
+
else:
|
|
478
|
+
return coords
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def convert_yolo_obb_to_annotation(xyxyxyxy, original_width, original_height):
|
|
482
|
+
"""
|
|
483
|
+
Convert YOLO Oriented Bounding Box (OBB) format to Label Studio format.
|
|
484
|
+
|
|
485
|
+
Args:
|
|
486
|
+
xyxyxyxy (list): List of 8 float values representing the absolute pixel coordinates
|
|
487
|
+
of the OBB in the format [x1, y1, x2, y2, x3, y3, x4, y4].
|
|
488
|
+
original_width (int): Original width of the image.
|
|
489
|
+
original_height (int): Original height of the image.
|
|
490
|
+
|
|
491
|
+
Returns:
|
|
492
|
+
dict: Dictionary containing the converted bounding box with the following keys:
|
|
493
|
+
- x: X-coordinate of the top-left corner of the bounding box in percentage.
|
|
494
|
+
- y: Y-coordinate of the top-left corner of the bounding box in percentage.
|
|
495
|
+
- width: Width of the bounding box in percentage.
|
|
496
|
+
- height: Height of the bounding box in percentage.
|
|
497
|
+
- rotation: Rotation angle of the bounding box in degrees.
|
|
498
|
+
"""
|
|
499
|
+
# Reshape the coordinates into a 4x2 matrix
|
|
500
|
+
coords = np.array(xyxyxyxy, dtype=np.float64).reshape((4, 2))
|
|
501
|
+
|
|
502
|
+
# Calculate the center of the bounding box
|
|
503
|
+
center_x = np.mean(coords[:, 0])
|
|
504
|
+
center_y = np.mean(coords[:, 1])
|
|
505
|
+
|
|
506
|
+
# Calculate the width and height of the bounding box
|
|
507
|
+
width = np.linalg.norm(coords[0] - coords[1])
|
|
508
|
+
height = np.linalg.norm(coords[0] - coords[3])
|
|
509
|
+
|
|
510
|
+
# Calculate the rotation angle
|
|
511
|
+
dx = coords[1, 0] - coords[0, 0]
|
|
512
|
+
dy = coords[1, 1] - coords[0, 1]
|
|
513
|
+
r = np.degrees(np.arctan2(dy, dx))
|
|
514
|
+
|
|
515
|
+
# Find the top-left corner (x, y)
|
|
516
|
+
top_left_x = (
|
|
517
|
+
center_x
|
|
518
|
+
- (width / 2) * np.cos(np.radians(r))
|
|
519
|
+
+ (height / 2) * np.sin(np.radians(r))
|
|
520
|
+
)
|
|
521
|
+
top_left_y = (
|
|
522
|
+
center_y
|
|
523
|
+
- (width / 2) * np.sin(np.radians(r))
|
|
524
|
+
- (height / 2) * np.cos(np.radians(r))
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
# Normalize the values
|
|
528
|
+
x = (top_left_x / original_width) * 100
|
|
529
|
+
y = (top_left_y / original_height) * 100
|
|
530
|
+
width = (width / original_width) * 100
|
|
531
|
+
height = (height / original_height) * 100
|
|
532
|
+
|
|
533
|
+
# Create the dictionary for Label Studio
|
|
534
|
+
return {
|
|
535
|
+
"x": x,
|
|
536
|
+
"y": y,
|
|
537
|
+
"width": width,
|
|
538
|
+
"height": height,
|
|
539
|
+
"rotation": r,
|
|
540
|
+
"original_width": original_width,
|
|
541
|
+
"original_height": original_height,
|
|
542
|
+
}
|
|
@@ -17,7 +17,7 @@ class BaseClientWrapper:
|
|
|
17
17
|
headers: typing.Dict[str, str] = {
|
|
18
18
|
"X-Fern-Language": "Python",
|
|
19
19
|
"X-Fern-SDK-Name": "label-studio-sdk",
|
|
20
|
-
"X-Fern-SDK-Version": "1.0.
|
|
20
|
+
"X-Fern-SDK-Version": "1.0.6",
|
|
21
21
|
}
|
|
22
22
|
headers["Authorization"] = f"Token {self.api_key}"
|
|
23
23
|
return headers
|