label-studio-sdk 1.0.8__py3-none-any.whl → 1.0.11__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.

Potentially problematic release.


This version of label-studio-sdk might be problematic. Click here for more details.

Files changed (218) hide show
  1. label_studio_sdk/__init__.py +37 -8
  2. label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +16 -4
  3. label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +5 -0
  4. label_studio_sdk/_extensions/pager_ext.py +8 -0
  5. label_studio_sdk/actions/client.py +91 -40
  6. label_studio_sdk/actions/types/actions_create_request_filters.py +14 -24
  7. label_studio_sdk/actions/types/actions_create_request_filters_items_item.py +16 -26
  8. label_studio_sdk/actions/types/actions_create_request_filters_items_item_value.py +3 -1
  9. label_studio_sdk/actions/types/actions_create_request_selected_items.py +1 -2
  10. label_studio_sdk/actions/types/actions_create_request_selected_items_excluded.py +15 -25
  11. label_studio_sdk/actions/types/actions_create_request_selected_items_included.py +15 -25
  12. label_studio_sdk/annotations/__init__.py +2 -2
  13. label_studio_sdk/annotations/client.py +278 -104
  14. label_studio_sdk/annotations/types/__init__.py +2 -1
  15. label_studio_sdk/annotations/types/annotations_create_bulk_request_selected_items.py +34 -0
  16. label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +11 -21
  17. label_studio_sdk/base_client.py +54 -27
  18. label_studio_sdk/client.py +1 -0
  19. label_studio_sdk/comments/client.py +190 -44
  20. label_studio_sdk/converter/converter.py +56 -13
  21. label_studio_sdk/converter/imports/yolo.py +1 -1
  22. label_studio_sdk/converter/utils.py +3 -2
  23. label_studio_sdk/core/__init__.py +21 -4
  24. label_studio_sdk/core/client_wrapper.py +37 -19
  25. label_studio_sdk/core/file.py +37 -8
  26. label_studio_sdk/core/http_client.py +52 -28
  27. label_studio_sdk/core/jsonable_encoder.py +33 -31
  28. label_studio_sdk/core/pagination.py +5 -4
  29. label_studio_sdk/core/pydantic_utilities.py +272 -4
  30. label_studio_sdk/core/query_encoder.py +38 -13
  31. label_studio_sdk/core/request_options.py +3 -0
  32. label_studio_sdk/core/serialization.py +272 -0
  33. label_studio_sdk/errors/__init__.py +3 -1
  34. label_studio_sdk/errors/bad_request_error.py +2 -3
  35. label_studio_sdk/errors/not_found_error.py +9 -0
  36. label_studio_sdk/errors/unauthorized_error.py +9 -0
  37. label_studio_sdk/export_storage/azure/client.py +228 -58
  38. label_studio_sdk/export_storage/azure/types/azure_create_response.py +19 -29
  39. label_studio_sdk/export_storage/azure/types/azure_update_response.py +19 -29
  40. label_studio_sdk/export_storage/client.py +48 -18
  41. label_studio_sdk/export_storage/gcs/client.py +228 -58
  42. label_studio_sdk/export_storage/gcs/types/gcs_create_response.py +19 -29
  43. label_studio_sdk/export_storage/gcs/types/gcs_update_response.py +19 -29
  44. label_studio_sdk/export_storage/local/client.py +222 -56
  45. label_studio_sdk/export_storage/local/types/local_create_response.py +17 -27
  46. label_studio_sdk/export_storage/local/types/local_update_response.py +17 -27
  47. label_studio_sdk/export_storage/redis/client.py +228 -58
  48. label_studio_sdk/export_storage/redis/types/redis_create_response.py +20 -30
  49. label_studio_sdk/export_storage/redis/types/redis_update_response.py +20 -30
  50. label_studio_sdk/export_storage/s3/client.py +228 -58
  51. label_studio_sdk/export_storage/s3/types/s3create_response.py +27 -35
  52. label_studio_sdk/export_storage/s3/types/s3update_response.py +27 -35
  53. label_studio_sdk/export_storage/s3s/client.py +187 -43
  54. label_studio_sdk/export_storage/types/export_storage_list_types_response_item.py +11 -21
  55. label_studio_sdk/files/client.py +172 -56
  56. label_studio_sdk/import_storage/azure/client.py +223 -53
  57. label_studio_sdk/import_storage/azure/types/azure_create_response.py +22 -32
  58. label_studio_sdk/import_storage/azure/types/azure_update_response.py +22 -32
  59. label_studio_sdk/import_storage/client.py +48 -18
  60. label_studio_sdk/import_storage/gcs/client.py +223 -53
  61. label_studio_sdk/import_storage/gcs/types/gcs_create_response.py +22 -32
  62. label_studio_sdk/import_storage/gcs/types/gcs_update_response.py +22 -32
  63. label_studio_sdk/import_storage/local/client.py +223 -53
  64. label_studio_sdk/import_storage/local/types/local_create_response.py +17 -27
  65. label_studio_sdk/import_storage/local/types/local_update_response.py +17 -27
  66. label_studio_sdk/import_storage/redis/client.py +223 -53
  67. label_studio_sdk/import_storage/redis/types/redis_create_response.py +20 -30
  68. label_studio_sdk/import_storage/redis/types/redis_update_response.py +20 -30
  69. label_studio_sdk/import_storage/s3/client.py +223 -53
  70. label_studio_sdk/import_storage/s3/types/s3create_response.py +31 -39
  71. label_studio_sdk/import_storage/s3/types/s3update_response.py +31 -39
  72. label_studio_sdk/import_storage/s3s/client.py +222 -52
  73. label_studio_sdk/import_storage/types/import_storage_list_types_response_item.py +11 -21
  74. label_studio_sdk/jwt_settings/__init__.py +2 -0
  75. label_studio_sdk/jwt_settings/client.py +259 -0
  76. label_studio_sdk/label_interface/control_tags.py +16 -3
  77. label_studio_sdk/label_interface/interface.py +80 -1
  78. label_studio_sdk/label_interface/object_tags.py +2 -2
  79. label_studio_sdk/ml/client.py +280 -78
  80. label_studio_sdk/ml/types/ml_create_response.py +21 -31
  81. label_studio_sdk/ml/types/ml_update_response.py +21 -31
  82. label_studio_sdk/model_providers/client.py +173 -56
  83. label_studio_sdk/predictions/client.py +247 -101
  84. label_studio_sdk/projects/__init__.py +5 -1
  85. label_studio_sdk/projects/client.py +313 -115
  86. label_studio_sdk/projects/client_ext.py +16 -0
  87. label_studio_sdk/projects/exports/__init__.py +3 -0
  88. label_studio_sdk/projects/exports/client.py +447 -296
  89. label_studio_sdk/projects/exports/client_ext.py +200 -0
  90. label_studio_sdk/projects/exports/types/__init__.py +6 -0
  91. label_studio_sdk/projects/exports/types/exports_convert_response.py +24 -0
  92. label_studio_sdk/projects/exports/types/exports_list_formats_response_item.py +44 -0
  93. label_studio_sdk/projects/pauses/__init__.py +2 -0
  94. label_studio_sdk/projects/pauses/client.py +704 -0
  95. label_studio_sdk/projects/types/projects_create_response.py +29 -34
  96. label_studio_sdk/projects/types/projects_import_tasks_response.py +19 -29
  97. label_studio_sdk/projects/types/projects_list_response.py +11 -21
  98. label_studio_sdk/projects/types/projects_update_response.py +34 -34
  99. label_studio_sdk/prompts/client.py +309 -92
  100. label_studio_sdk/prompts/indicators/client.py +67 -23
  101. label_studio_sdk/prompts/runs/client.py +95 -40
  102. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +14 -24
  103. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +11 -21
  104. label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +26 -29
  105. label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +11 -21
  106. label_studio_sdk/prompts/versions/client.py +277 -88
  107. label_studio_sdk/tasks/client.py +263 -90
  108. label_studio_sdk/tasks/types/tasks_list_response.py +15 -25
  109. label_studio_sdk/tokens/__init__.py +2 -0
  110. label_studio_sdk/tokens/client.py +470 -0
  111. label_studio_sdk/tokens/client_ext.py +94 -0
  112. label_studio_sdk/types/__init__.py +20 -6
  113. label_studio_sdk/types/access_token_response.py +22 -0
  114. label_studio_sdk/types/annotation.py +29 -38
  115. label_studio_sdk/types/annotation_filter_options.py +14 -24
  116. label_studio_sdk/types/annotations_dm_field.py +30 -39
  117. label_studio_sdk/types/api_token_response.py +32 -0
  118. label_studio_sdk/types/azure_blob_export_storage.py +28 -37
  119. label_studio_sdk/types/azure_blob_import_storage.py +28 -37
  120. label_studio_sdk/types/base_task.py +30 -39
  121. label_studio_sdk/types/base_task_updated_by.py +3 -1
  122. label_studio_sdk/types/base_user.py +14 -21
  123. label_studio_sdk/types/comment.py +12 -21
  124. label_studio_sdk/types/comment_created_by.py +1 -1
  125. label_studio_sdk/types/converted_format.py +12 -22
  126. label_studio_sdk/types/data_manager_task_serializer.py +31 -40
  127. label_studio_sdk/types/data_manager_task_serializer_annotators_item.py +1 -1
  128. label_studio_sdk/types/data_manager_task_serializer_drafts_item.py +13 -22
  129. label_studio_sdk/types/data_manager_task_serializer_predictions_item.py +15 -24
  130. label_studio_sdk/types/export.py +17 -26
  131. label_studio_sdk/types/export_format.py +25 -0
  132. label_studio_sdk/types/export_snapshot.py +45 -0
  133. label_studio_sdk/types/export_snapshot_status.py +5 -0
  134. label_studio_sdk/types/file_upload.py +11 -21
  135. label_studio_sdk/types/filter.py +16 -26
  136. label_studio_sdk/types/filter_group.py +12 -22
  137. label_studio_sdk/types/gcs_export_storage.py +28 -37
  138. label_studio_sdk/types/gcs_import_storage.py +28 -37
  139. label_studio_sdk/types/inference_run.py +14 -23
  140. label_studio_sdk/types/inference_run_cost_estimate.py +17 -27
  141. label_studio_sdk/types/inference_run_created_by.py +1 -1
  142. label_studio_sdk/types/inference_run_organization.py +1 -1
  143. label_studio_sdk/types/jwt_settings_response.py +32 -0
  144. label_studio_sdk/types/key_indicator_value.py +12 -22
  145. label_studio_sdk/types/key_indicators.py +0 -1
  146. label_studio_sdk/types/key_indicators_item.py +15 -25
  147. label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +13 -23
  148. label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +13 -23
  149. label_studio_sdk/types/local_files_export_storage.py +25 -34
  150. label_studio_sdk/types/local_files_import_storage.py +24 -33
  151. label_studio_sdk/types/ml_backend.py +23 -32
  152. label_studio_sdk/types/model_provider_connection.py +22 -31
  153. label_studio_sdk/types/model_provider_connection_created_by.py +1 -1
  154. label_studio_sdk/types/model_provider_connection_organization.py +1 -1
  155. label_studio_sdk/types/model_provider_connection_provider.py +3 -1
  156. label_studio_sdk/types/pause.py +34 -0
  157. label_studio_sdk/types/pause_paused_by.py +5 -0
  158. label_studio_sdk/types/prediction.py +21 -30
  159. label_studio_sdk/types/project.py +58 -55
  160. label_studio_sdk/types/project_import.py +21 -30
  161. label_studio_sdk/types/project_label_config.py +12 -22
  162. label_studio_sdk/types/prompt.py +24 -32
  163. label_studio_sdk/types/prompt_associated_projects_item.py +6 -0
  164. label_studio_sdk/types/prompt_associated_projects_item_id.py +20 -0
  165. label_studio_sdk/types/prompt_created_by.py +1 -1
  166. label_studio_sdk/types/prompt_organization.py +1 -1
  167. label_studio_sdk/types/prompt_version.py +13 -22
  168. label_studio_sdk/types/prompt_version_created_by.py +1 -1
  169. label_studio_sdk/types/prompt_version_organization.py +1 -1
  170. label_studio_sdk/types/prompt_version_provider.py +3 -1
  171. label_studio_sdk/types/redis_export_storage.py +29 -38
  172. label_studio_sdk/types/redis_import_storage.py +28 -37
  173. label_studio_sdk/types/refined_prompt_response.py +19 -29
  174. label_studio_sdk/types/s3export_storage.py +36 -43
  175. label_studio_sdk/types/s3import_storage.py +37 -44
  176. label_studio_sdk/types/s3s_export_storage.py +26 -33
  177. label_studio_sdk/types/s3s_import_storage.py +35 -42
  178. label_studio_sdk/types/serialization_option.py +12 -22
  179. label_studio_sdk/types/serialization_options.py +18 -28
  180. label_studio_sdk/types/task.py +44 -47
  181. label_studio_sdk/types/task_annotators_item.py +1 -1
  182. label_studio_sdk/types/task_comment_authors_item.py +1 -1
  183. label_studio_sdk/types/task_filter_options.py +15 -25
  184. label_studio_sdk/types/user_simple.py +11 -21
  185. label_studio_sdk/types/view.py +16 -26
  186. label_studio_sdk/types/webhook.py +19 -28
  187. label_studio_sdk/types/webhook_serializer_for_update.py +19 -28
  188. label_studio_sdk/types/workspace.py +22 -31
  189. label_studio_sdk/users/client.py +257 -63
  190. label_studio_sdk/users/types/users_get_token_response.py +12 -22
  191. label_studio_sdk/users/types/users_reset_token_response.py +12 -22
  192. label_studio_sdk/version.py +0 -1
  193. label_studio_sdk/versions/__init__.py +5 -0
  194. label_studio_sdk/versions/client.py +112 -0
  195. label_studio_sdk/versions/types/__init__.py +6 -0
  196. label_studio_sdk/versions/types/versions_get_response.py +73 -0
  197. label_studio_sdk/versions/types/versions_get_response_edition.py +5 -0
  198. label_studio_sdk/views/client.py +219 -52
  199. label_studio_sdk/views/types/views_create_request_data.py +13 -23
  200. label_studio_sdk/views/types/views_create_request_data_filters.py +14 -24
  201. label_studio_sdk/views/types/views_create_request_data_filters_items_item.py +16 -26
  202. label_studio_sdk/views/types/views_create_request_data_filters_items_item_value.py +3 -1
  203. label_studio_sdk/views/types/views_update_request_data.py +13 -23
  204. label_studio_sdk/views/types/views_update_request_data_filters.py +14 -24
  205. label_studio_sdk/views/types/views_update_request_data_filters_items_item.py +16 -26
  206. label_studio_sdk/views/types/views_update_request_data_filters_items_item_value.py +3 -1
  207. label_studio_sdk/webhooks/client.py +191 -61
  208. label_studio_sdk/workspaces/client.py +164 -41
  209. label_studio_sdk/workspaces/members/client.py +109 -31
  210. label_studio_sdk/workspaces/members/types/members_create_response.py +12 -22
  211. label_studio_sdk/workspaces/members/types/members_list_response_item.py +12 -22
  212. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/METADATA +8 -5
  213. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/RECORD +215 -188
  214. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/WHEEL +1 -1
  215. label_studio_sdk/types/export_convert.py +0 -32
  216. label_studio_sdk/types/export_create.py +0 -54
  217. label_studio_sdk/types/export_create_status.py +0 -5
  218. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/LICENSE +0 -0
@@ -0,0 +1,259 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+ from ..core.client_wrapper import SyncClientWrapper
5
+ from ..core.request_options import RequestOptions
6
+ from ..types.jwt_settings_response import JwtSettingsResponse
7
+ from ..core.pydantic_utilities import parse_obj_as
8
+ from json.decoder import JSONDecodeError
9
+ from ..core.api_error import ApiError
10
+ from ..core.client_wrapper import AsyncClientWrapper
11
+
12
+ # this is used as the default value for optional parameters
13
+ OMIT = typing.cast(typing.Any, ...)
14
+
15
+
16
+ class JwtSettingsClient:
17
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
18
+ self._client_wrapper = client_wrapper
19
+
20
+ def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> JwtSettingsResponse:
21
+ """
22
+ Retrieve JWT settings for the currently active organization.
23
+
24
+ Parameters
25
+ ----------
26
+ request_options : typing.Optional[RequestOptions]
27
+ Request-specific configuration.
28
+
29
+ Returns
30
+ -------
31
+ JwtSettingsResponse
32
+ JWT settings retrieved successfully
33
+
34
+ Examples
35
+ --------
36
+ from label_studio_sdk import LabelStudio
37
+
38
+ client = LabelStudio(
39
+ api_key="YOUR_API_KEY",
40
+ )
41
+ client.jwt_settings.get()
42
+ """
43
+ _response = self._client_wrapper.httpx_client.request(
44
+ "api/jwt/settings",
45
+ method="GET",
46
+ request_options=request_options,
47
+ )
48
+ try:
49
+ if 200 <= _response.status_code < 300:
50
+ return typing.cast(
51
+ JwtSettingsResponse,
52
+ parse_obj_as(
53
+ type_=JwtSettingsResponse, # type: ignore
54
+ object_=_response.json(),
55
+ ),
56
+ )
57
+ _response_json = _response.json()
58
+ except JSONDecodeError:
59
+ raise ApiError(status_code=_response.status_code, body=_response.text)
60
+ raise ApiError(status_code=_response.status_code, body=_response_json)
61
+
62
+ def create(
63
+ self,
64
+ *,
65
+ api_tokens_enabled: bool,
66
+ legacy_api_tokens_enabled: bool,
67
+ api_token_ttl_days: int,
68
+ request_options: typing.Optional[RequestOptions] = None,
69
+ ) -> JwtSettingsResponse:
70
+ """
71
+ Update JWT settings for the currently active organization.
72
+
73
+ Parameters
74
+ ----------
75
+ api_tokens_enabled : bool
76
+ Whether JWT API tokens are enabled
77
+
78
+ legacy_api_tokens_enabled : bool
79
+ Whether legacy API tokens are enabled
80
+
81
+ api_token_ttl_days : int
82
+ Number of days before API tokens expire
83
+
84
+ request_options : typing.Optional[RequestOptions]
85
+ Request-specific configuration.
86
+
87
+ Returns
88
+ -------
89
+ JwtSettingsResponse
90
+ JWT settings updated successfully
91
+
92
+ Examples
93
+ --------
94
+ from label_studio_sdk import LabelStudio
95
+
96
+ client = LabelStudio(
97
+ api_key="YOUR_API_KEY",
98
+ )
99
+ client.jwt_settings.create(
100
+ api_tokens_enabled=True,
101
+ legacy_api_tokens_enabled=True,
102
+ api_token_ttl_days=1,
103
+ )
104
+ """
105
+ _response = self._client_wrapper.httpx_client.request(
106
+ "api/jwt/settings",
107
+ method="POST",
108
+ json={
109
+ "api_tokens_enabled": api_tokens_enabled,
110
+ "legacy_api_tokens_enabled": legacy_api_tokens_enabled,
111
+ "api_token_ttl_days": api_token_ttl_days,
112
+ },
113
+ request_options=request_options,
114
+ omit=OMIT,
115
+ )
116
+ try:
117
+ if 200 <= _response.status_code < 300:
118
+ return typing.cast(
119
+ JwtSettingsResponse,
120
+ parse_obj_as(
121
+ type_=JwtSettingsResponse, # type: ignore
122
+ object_=_response.json(),
123
+ ),
124
+ )
125
+ _response_json = _response.json()
126
+ except JSONDecodeError:
127
+ raise ApiError(status_code=_response.status_code, body=_response.text)
128
+ raise ApiError(status_code=_response.status_code, body=_response_json)
129
+
130
+
131
+ class AsyncJwtSettingsClient:
132
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
133
+ self._client_wrapper = client_wrapper
134
+
135
+ async def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> JwtSettingsResponse:
136
+ """
137
+ Retrieve JWT settings for the currently active organization.
138
+
139
+ Parameters
140
+ ----------
141
+ request_options : typing.Optional[RequestOptions]
142
+ Request-specific configuration.
143
+
144
+ Returns
145
+ -------
146
+ JwtSettingsResponse
147
+ JWT settings retrieved successfully
148
+
149
+ Examples
150
+ --------
151
+ import asyncio
152
+
153
+ from label_studio_sdk import AsyncLabelStudio
154
+
155
+ client = AsyncLabelStudio(
156
+ api_key="YOUR_API_KEY",
157
+ )
158
+
159
+
160
+ async def main() -> None:
161
+ await client.jwt_settings.get()
162
+
163
+
164
+ asyncio.run(main())
165
+ """
166
+ _response = await self._client_wrapper.httpx_client.request(
167
+ "api/jwt/settings",
168
+ method="GET",
169
+ request_options=request_options,
170
+ )
171
+ try:
172
+ if 200 <= _response.status_code < 300:
173
+ return typing.cast(
174
+ JwtSettingsResponse,
175
+ parse_obj_as(
176
+ type_=JwtSettingsResponse, # type: ignore
177
+ object_=_response.json(),
178
+ ),
179
+ )
180
+ _response_json = _response.json()
181
+ except JSONDecodeError:
182
+ raise ApiError(status_code=_response.status_code, body=_response.text)
183
+ raise ApiError(status_code=_response.status_code, body=_response_json)
184
+
185
+ async def create(
186
+ self,
187
+ *,
188
+ api_tokens_enabled: bool,
189
+ legacy_api_tokens_enabled: bool,
190
+ api_token_ttl_days: int,
191
+ request_options: typing.Optional[RequestOptions] = None,
192
+ ) -> JwtSettingsResponse:
193
+ """
194
+ Update JWT settings for the currently active organization.
195
+
196
+ Parameters
197
+ ----------
198
+ api_tokens_enabled : bool
199
+ Whether JWT API tokens are enabled
200
+
201
+ legacy_api_tokens_enabled : bool
202
+ Whether legacy API tokens are enabled
203
+
204
+ api_token_ttl_days : int
205
+ Number of days before API tokens expire
206
+
207
+ request_options : typing.Optional[RequestOptions]
208
+ Request-specific configuration.
209
+
210
+ Returns
211
+ -------
212
+ JwtSettingsResponse
213
+ JWT settings updated successfully
214
+
215
+ Examples
216
+ --------
217
+ import asyncio
218
+
219
+ from label_studio_sdk import AsyncLabelStudio
220
+
221
+ client = AsyncLabelStudio(
222
+ api_key="YOUR_API_KEY",
223
+ )
224
+
225
+
226
+ async def main() -> None:
227
+ await client.jwt_settings.create(
228
+ api_tokens_enabled=True,
229
+ legacy_api_tokens_enabled=True,
230
+ api_token_ttl_days=1,
231
+ )
232
+
233
+
234
+ asyncio.run(main())
235
+ """
236
+ _response = await self._client_wrapper.httpx_client.request(
237
+ "api/jwt/settings",
238
+ method="POST",
239
+ json={
240
+ "api_tokens_enabled": api_tokens_enabled,
241
+ "legacy_api_tokens_enabled": legacy_api_tokens_enabled,
242
+ "api_token_ttl_days": api_token_ttl_days,
243
+ },
244
+ request_options=request_options,
245
+ omit=OMIT,
246
+ )
247
+ try:
248
+ if 200 <= _response.status_code < 300:
249
+ return typing.cast(
250
+ JwtSettingsResponse,
251
+ parse_obj_as(
252
+ type_=JwtSettingsResponse, # type: ignore
253
+ object_=_response.json(),
254
+ ),
255
+ )
256
+ _response_json = _response.json()
257
+ except JSONDecodeError:
258
+ raise ApiError(status_code=_response.status_code, body=_response.text)
259
+ raise ApiError(status_code=_response.status_code, body=_response_json)
@@ -92,6 +92,12 @@ class ControlTag(LabelStudioTag):
92
92
  and tag.attrib.get("toName")
93
93
  and tag.tag not in _NOT_CONTROL_TAGS
94
94
  )
95
+
96
+ @property
97
+ def is_output_required(self):
98
+ # TextArea can be blank unless user specifies "required"="true" in the attribute
99
+ required_in_attr = str(self.attr.get("required", "false")).lower() == "true"
100
+ return required_in_attr or False
95
101
 
96
102
  def to_json_schema(self):
97
103
  """
@@ -475,7 +481,7 @@ class ControlTag(LabelStudioTag):
475
481
  for value in values:
476
482
  if len(value) == 1 and self._label_attr_name in value:
477
483
  v = value[self._label_attr_name]
478
- labels.append(v[0] if len(v) == 1 else v)
484
+ labels.append(v[0] if type(v) == list and len(v) == 1 else v)
479
485
  else:
480
486
  labels.append(value)
481
487
  return labels[0] if len(labels) == 1 else labels
@@ -566,6 +572,7 @@ class LabelsTag(ControlTag):
566
572
  "properties": {
567
573
  "start": {
568
574
  "type": "integer",
575
+ # TODO: this is incompatible with the OpenAI API using PredictedOutputs
569
576
  "minimum": 0
570
577
  },
571
578
  "end": {
@@ -985,8 +992,14 @@ class TextAreaTag(ControlTag):
985
992
  dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
986
993
  """
987
994
  return {
988
- "type": "string",
989
- "description": f"Text for {self.to_name[0]}"
995
+ "oneOf": [
996
+ {"type": "string"},
997
+ {
998
+ "type": "array",
999
+ "items": {"type": "string"}
1000
+ }
1001
+ ],
1002
+ "description": f"Text or list of texts for {self.to_name[0]}"
990
1003
  }
991
1004
 
992
1005
 
@@ -312,6 +312,15 @@ class LabelInterface:
312
312
  """
313
313
  regions = []
314
314
  for control_tag_name, payload in data.items():
315
+
316
+ if payload is None:
317
+ logger.warning(
318
+ f"Payload for control tag '{control_tag_name}' is None: "
319
+ "it can be ok if this payload is autogenerated by LLMs - "
320
+ "try to adjust the prompt to generate valid payloads. "
321
+ "Otherwise, it can signify an error")
322
+ continue
323
+
315
324
  if control_tag_name not in self._controls:
316
325
  logger.info(f"Control tag '{control_tag_name}' not found in the config")
317
326
  continue
@@ -545,12 +554,16 @@ class LabelInterface:
545
554
  Returns:
546
555
  dict: A dictionary representing the JSON Schema.
547
556
  """
557
+ required_outputs = [
558
+ name for name, control in self._controls.items()
559
+ if control.is_output_required
560
+ ]
548
561
  return {
549
562
  "type": "object",
550
563
  "properties": {
551
564
  name: control.to_json_schema() for name, control in self._controls.items()
552
565
  },
553
- "required": list(self._controls.keys())
566
+ "required": required_outputs
554
567
  }
555
568
 
556
569
  def parse(self, config_string: str) -> Tuple[Dict, Dict, Dict, etree._Element]:
@@ -902,6 +915,72 @@ class LabelInterface:
902
915
  logger.debug(f'Sample annotation {annotation_dct} failed validation for label config {self.config}')
903
916
  return None
904
917
 
918
+ def generate_complete_sample_task(self, raise_on_failure: bool = False) -> Optional[dict]:
919
+ """Generate a complete sample task with annotations and predictions.
920
+
921
+ This method combines the generation of a sample task, sample prediction, and sample annotation
922
+ into a single method call, returning a complete task structure.
923
+
924
+ Args:
925
+ raise_on_failure: If True, will raise ValueError when any step
926
+ (including annotation/prediction generation) fails
927
+
928
+ Raises:
929
+ ValueError: If raise_on_failure is True and any generation step fails.
930
+
931
+ Example:
932
+ {
933
+ 'data': {'text': 'Sample text for labeling'},
934
+ 'annotations': [
935
+ {'was_cancelled': False,
936
+ 'ground_truth': False,
937
+ 'completed_by': -1,
938
+ 'result': [
939
+ {'id': 'b05da11d-3ffc-4657-8b8d-f5bc37cd59ac',
940
+ 'from_name': 'sentiment',
941
+ 'to_name': 'text',
942
+ 'type': 'choices',
943
+ 'value': {'choices': ['Negative']}}
944
+ ]
945
+ }
946
+ ],
947
+ 'predictions': [
948
+ {'model_version': 'sample model version',
949
+ 'score': 0.95,
950
+ 'result': [
951
+ {'id': 'e7bd76e6-4e88-4eb3-b433-55e03661bf5d',
952
+ 'from_name': 'sentiment',
953
+ 'to_name': 'text',
954
+ 'type': 'choices',
955
+ 'value': {'choices': ['Neutral']}}
956
+ ]
957
+ }
958
+ ]
959
+ }
960
+
961
+ NOTE: `id` field in result is not required when importing predictions; it will be generated automatically.
962
+ NOTE: for each control tag, depends on tag.to_json_schema() being implemented correctly
963
+ """
964
+ sample_task = self.generate_sample_task()
965
+ if not sample_task:
966
+ if raise_on_failure:
967
+ raise ValueError("LabelInterface.generate_sample_task failed to generate a valid sample task")
968
+ return None
969
+
970
+ sample_prediction = self.generate_sample_prediction()
971
+ if not sample_prediction and raise_on_failure:
972
+ raise ValueError("LabelInterface.generate_sample_prediction failed to generate a valid prediction")
973
+
974
+ sample_annotation = self.generate_sample_annotation()
975
+ if not sample_annotation and raise_on_failure:
976
+ raise ValueError("LabelInterface.generate_sample_annotation failed to generate a valid annotation")
977
+
978
+ return {
979
+ "data": sample_task,
980
+ "annotations": [sample_annotation] if sample_annotation else [],
981
+ "predictions": [sample_prediction] if sample_prediction else []
982
+ }
983
+
905
984
  #####
906
985
  ##### COMPATIBILITY LAYER
907
986
  #####
@@ -119,7 +119,7 @@ class ObjectTag(LabelStudioTag):
119
119
  tag=tag.tag,
120
120
  attr=dict(tag.attrib),
121
121
  name=tag.attrib.get("name"),
122
- value=tag.attrib["value"],
122
+ value=tag.attrib.get('valueList', tag.attrib.get('value')),
123
123
  )
124
124
 
125
125
  @classmethod
@@ -127,7 +127,7 @@ class ObjectTag(LabelStudioTag):
127
127
  """
128
128
  Check if tag is input
129
129
  """
130
- return bool(tag.attrib.get("name") and tag.attrib.get("value"))
130
+ return bool(tag.attrib.get("name") and (tag.attrib.get("value") or tag.attrib.get("valueList")))
131
131
 
132
132
  @property
133
133
  def value_type(self):