label-studio-sdk 2.0.6__py3-none-any.whl → 2.0.8__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.
Files changed (67) hide show
  1. label_studio_sdk/__init__.py +32 -2
  2. label_studio_sdk/base_client.py +4 -0
  3. label_studio_sdk/converter/exports/yolo.py +89 -74
  4. label_studio_sdk/core/client_wrapper.py +1 -1
  5. label_studio_sdk/import_storage/azure_spi/client.py +30 -0
  6. label_studio_sdk/label_interface/control_tags.py +38 -0
  7. label_studio_sdk/label_interface/data_examples.json +10 -0
  8. label_studio_sdk/label_interface/interface.py +13 -0
  9. label_studio_sdk/label_interface/object_tags.py +9 -0
  10. label_studio_sdk/ml/client.py +124 -0
  11. label_studio_sdk/organizations/__init__.py +3 -2
  12. label_studio_sdk/organizations/client.py +540 -1
  13. label_studio_sdk/organizations/invites/__init__.py +2 -0
  14. label_studio_sdk/organizations/invites/client.py +368 -0
  15. label_studio_sdk/organizations/permissions/__init__.py +2 -0
  16. label_studio_sdk/organizations/permissions/client.py +1129 -0
  17. label_studio_sdk/organizations/types/__init__.py +5 -0
  18. label_studio_sdk/organizations/types/patched_default_role_request_custom_scripts_editable_by.py +7 -0
  19. label_studio_sdk/project_templates/__init__.py +2 -0
  20. label_studio_sdk/project_templates/client.py +909 -0
  21. label_studio_sdk/projects/__init__.py +30 -0
  22. label_studio_sdk/projects/client.py +355 -0
  23. label_studio_sdk/projects/stats/__init__.py +28 -0
  24. label_studio_sdk/projects/stats/client.py +1002 -43
  25. label_studio_sdk/projects/stats/types/__init__.py +30 -0
  26. label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py +26 -0
  27. label_studio_sdk/projects/stats/types/stats_data_filters_response.py +23 -0
  28. label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py +34 -0
  29. label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py +22 -0
  30. label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py +32 -0
  31. label_studio_sdk/projects/stats/types/stats_lead_time_response.py +23 -0
  32. label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py +37 -0
  33. label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py +20 -0
  34. label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py +5 -0
  35. label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py +24 -0
  36. label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py +5 -0
  37. label_studio_sdk/projects/stats/types/stats_user_review_score_response.py +22 -0
  38. label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py +5 -0
  39. label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py +5 -0
  40. label_studio_sdk/projects/types/__init__.py +2 -0
  41. label_studio_sdk/projects/types/projects_import_predictions_response.py +26 -0
  42. label_studio_sdk/prompts/versions/client.py +4 -16
  43. label_studio_sdk/types/__init__.py +26 -2
  44. label_studio_sdk/types/azure_service_principal_import_storage.py +5 -0
  45. label_studio_sdk/types/azure_service_principal_import_storage_request.py +5 -0
  46. label_studio_sdk/types/configurable_permission_option.py +25 -0
  47. label_studio_sdk/types/configurable_permission_option_default.py +7 -0
  48. label_studio_sdk/types/default_role.py +75 -0
  49. label_studio_sdk/types/default_role_custom_scripts_editable_by.py +7 -0
  50. label_studio_sdk/types/lse_organization.py +2 -2
  51. label_studio_sdk/types/lse_project.py +223 -0
  52. label_studio_sdk/types/lse_project_counts.py +46 -0
  53. label_studio_sdk/types/lse_project_sampling.py +7 -0
  54. label_studio_sdk/types/lse_project_skip_queue.py +7 -0
  55. label_studio_sdk/types/lse_task.py +1 -1
  56. label_studio_sdk/types/lse_task_serializer_for_reviewers.py +1 -1
  57. label_studio_sdk/types/organization_permission.py +31 -0
  58. label_studio_sdk/types/organization_permission_request.py +24 -0
  59. label_studio_sdk/types/paginated_lse_project_counts_list.py +23 -0
  60. label_studio_sdk/types/project_template.py +41 -0
  61. label_studio_sdk/types/project_template_request.py +38 -0
  62. label_studio_sdk/types/who_am_i_user.py +1 -0
  63. {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/METADATA +1 -1
  64. {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/RECORD +66 -31
  65. label_studio_sdk/types/default_role_enum.py +0 -5
  66. {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/LICENSE +0 -0
  67. {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/WHEEL +0 -0
@@ -8,7 +8,14 @@ from ...core.jsonable_encoder import jsonable_encoder
8
8
  from ...core.unchecked_base_model import construct_type
9
9
  from json.decoder import JSONDecodeError
10
10
  from ...core.api_error import ApiError
11
+ from .types.stats_agreement_annotator_response import StatsAgreementAnnotatorResponse
12
+ from .types.stats_data_filters_response import StatsDataFiltersResponse
13
+ from .types.stats_finished_tasks_response import StatsFinishedTasksResponse
14
+ from .types.stats_lead_time_response import StatsLeadTimeResponse
11
15
  from .types.stats_total_agreement_response import StatsTotalAgreementResponse
16
+ from .types.stats_user_prediction_agreement_response import StatsUserPredictionAgreementResponse
17
+ from .types.stats_user_review_score_response import StatsUserReviewScoreResponse
18
+ from .types.stats_user_ground_truth_agreement_response import StatsUserGroundTruthAgreementResponse
12
19
  from ...core.client_wrapper import AsyncClientWrapper
13
20
 
14
21
 
@@ -89,6 +96,205 @@ class StatsClient:
89
96
  raise ApiError(status_code=_response.status_code, body=_response.text)
90
97
  raise ApiError(status_code=_response.status_code, body=_response_json)
91
98
 
99
+ def agreement_annotator(
100
+ self, id: int, user_id: int, *, request_options: typing.Optional[RequestOptions] = None
101
+ ) -> StatsAgreementAnnotatorResponse:
102
+ """
103
+ Get agreement statistics for a specific annotator within a project.
104
+
105
+ Parameters
106
+ ----------
107
+ id : int
108
+
109
+ user_id : int
110
+
111
+ request_options : typing.Optional[RequestOptions]
112
+ Request-specific configuration.
113
+
114
+ Returns
115
+ -------
116
+ StatsAgreementAnnotatorResponse
117
+ Individual annotator agreement statistics
118
+
119
+ Examples
120
+ --------
121
+ from label_studio_sdk import LabelStudio
122
+
123
+ client = LabelStudio(
124
+ api_key="YOUR_API_KEY",
125
+ )
126
+ client.projects.stats.agreement_annotator(
127
+ id=1,
128
+ user_id=1,
129
+ )
130
+ """
131
+ _response = self._client_wrapper.httpx_client.request(
132
+ f"api/projects/{jsonable_encoder(id)}/stats/agreement_annotator/{jsonable_encoder(user_id)}",
133
+ method="GET",
134
+ request_options=request_options,
135
+ )
136
+ try:
137
+ if 200 <= _response.status_code < 300:
138
+ return typing.cast(
139
+ StatsAgreementAnnotatorResponse,
140
+ construct_type(
141
+ type_=StatsAgreementAnnotatorResponse, # type: ignore
142
+ object_=_response.json(),
143
+ ),
144
+ )
145
+ _response_json = _response.json()
146
+ except JSONDecodeError:
147
+ raise ApiError(status_code=_response.status_code, body=_response.text)
148
+ raise ApiError(status_code=_response.status_code, body=_response_json)
149
+
150
+ def data_filters(
151
+ self, id: int, *, request_options: typing.Optional[RequestOptions] = None
152
+ ) -> StatsDataFiltersResponse:
153
+ """
154
+ Get statistics about user data filters and their usage within a project.
155
+
156
+ Parameters
157
+ ----------
158
+ id : int
159
+
160
+ request_options : typing.Optional[RequestOptions]
161
+ Request-specific configuration.
162
+
163
+ Returns
164
+ -------
165
+ StatsDataFiltersResponse
166
+ User data filter statistics
167
+
168
+ Examples
169
+ --------
170
+ from label_studio_sdk import LabelStudio
171
+
172
+ client = LabelStudio(
173
+ api_key="YOUR_API_KEY",
174
+ )
175
+ client.projects.stats.data_filters(
176
+ id=1,
177
+ )
178
+ """
179
+ _response = self._client_wrapper.httpx_client.request(
180
+ f"api/projects/{jsonable_encoder(id)}/stats/data_filter",
181
+ method="GET",
182
+ request_options=request_options,
183
+ )
184
+ try:
185
+ if 200 <= _response.status_code < 300:
186
+ return typing.cast(
187
+ StatsDataFiltersResponse,
188
+ construct_type(
189
+ type_=StatsDataFiltersResponse, # type: ignore
190
+ object_=_response.json(),
191
+ ),
192
+ )
193
+ _response_json = _response.json()
194
+ except JSONDecodeError:
195
+ raise ApiError(status_code=_response.status_code, body=_response.text)
196
+ raise ApiError(status_code=_response.status_code, body=_response_json)
197
+
198
+ def finished_tasks(
199
+ self, id: int, *, user_pk: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None
200
+ ) -> StatsFinishedTasksResponse:
201
+ """
202
+ Get statistics about finished tasks for a project.
203
+
204
+ Parameters
205
+ ----------
206
+ id : int
207
+
208
+ user_pk : typing.Optional[int]
209
+ User ID to filter statistics by (optional)
210
+
211
+ request_options : typing.Optional[RequestOptions]
212
+ Request-specific configuration.
213
+
214
+ Returns
215
+ -------
216
+ StatsFinishedTasksResponse
217
+ Finished tasks statistics
218
+
219
+ Examples
220
+ --------
221
+ from label_studio_sdk import LabelStudio
222
+
223
+ client = LabelStudio(
224
+ api_key="YOUR_API_KEY",
225
+ )
226
+ client.projects.stats.finished_tasks(
227
+ id=1,
228
+ )
229
+ """
230
+ _response = self._client_wrapper.httpx_client.request(
231
+ f"api/projects/{jsonable_encoder(id)}/stats/finished",
232
+ method="GET",
233
+ params={
234
+ "user_pk": user_pk,
235
+ },
236
+ request_options=request_options,
237
+ )
238
+ try:
239
+ if 200 <= _response.status_code < 300:
240
+ return typing.cast(
241
+ StatsFinishedTasksResponse,
242
+ construct_type(
243
+ type_=StatsFinishedTasksResponse, # type: ignore
244
+ object_=_response.json(),
245
+ ),
246
+ )
247
+ _response_json = _response.json()
248
+ except JSONDecodeError:
249
+ raise ApiError(status_code=_response.status_code, body=_response.text)
250
+ raise ApiError(status_code=_response.status_code, body=_response_json)
251
+
252
+ def lead_time(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> StatsLeadTimeResponse:
253
+ """
254
+ Get lead time statistics across the project, including average annotation time.
255
+
256
+ Parameters
257
+ ----------
258
+ id : int
259
+
260
+ request_options : typing.Optional[RequestOptions]
261
+ Request-specific configuration.
262
+
263
+ Returns
264
+ -------
265
+ StatsLeadTimeResponse
266
+ Lead time statistics
267
+
268
+ Examples
269
+ --------
270
+ from label_studio_sdk import LabelStudio
271
+
272
+ client = LabelStudio(
273
+ api_key="YOUR_API_KEY",
274
+ )
275
+ client.projects.stats.lead_time(
276
+ id=1,
277
+ )
278
+ """
279
+ _response = self._client_wrapper.httpx_client.request(
280
+ f"api/projects/{jsonable_encoder(id)}/stats/lead_time",
281
+ method="GET",
282
+ request_options=request_options,
283
+ )
284
+ try:
285
+ if 200 <= _response.status_code < 300:
286
+ return typing.cast(
287
+ StatsLeadTimeResponse,
288
+ construct_type(
289
+ type_=StatsLeadTimeResponse, # type: ignore
290
+ object_=_response.json(),
291
+ ),
292
+ )
293
+ _response_json = _response.json()
294
+ except JSONDecodeError:
295
+ raise ApiError(status_code=_response.status_code, body=_response.text)
296
+ raise ApiError(status_code=_response.status_code, body=_response_json)
297
+
92
298
  def total_agreement(
93
299
  self,
94
300
  id: int,
@@ -118,16 +324,647 @@ class StatsClient:
118
324
 
119
325
  Examples
120
326
  --------
121
- from label_studio_sdk import LabelStudio
327
+ from label_studio_sdk import LabelStudio
328
+
329
+ client = LabelStudio(
330
+ api_key="YOUR_API_KEY",
331
+ )
332
+ client.projects.stats.total_agreement(
333
+ id=1,
334
+ )
335
+ """
336
+ _response = self._client_wrapper.httpx_client.request(
337
+ f"api/projects/{jsonable_encoder(id)}/stats/total_agreement",
338
+ method="GET",
339
+ params={
340
+ "per_label": per_label,
341
+ },
342
+ request_options=request_options,
343
+ )
344
+ try:
345
+ if 200 <= _response.status_code < 300:
346
+ return typing.cast(
347
+ StatsTotalAgreementResponse,
348
+ construct_type(
349
+ type_=StatsTotalAgreementResponse, # type: ignore
350
+ object_=_response.json(),
351
+ ),
352
+ )
353
+ _response_json = _response.json()
354
+ except JSONDecodeError:
355
+ raise ApiError(status_code=_response.status_code, body=_response.text)
356
+ raise ApiError(status_code=_response.status_code, body=_response_json)
357
+
358
+ def update_stats(
359
+ self,
360
+ id: int,
361
+ *,
362
+ stat_type: typing.Optional[str] = None,
363
+ request_options: typing.Optional[RequestOptions] = None,
364
+ ) -> typing.Dict[str, typing.Optional[typing.Any]]:
365
+ """
366
+ Start stats recalculation for given project
367
+
368
+ Parameters
369
+ ----------
370
+ id : int
371
+
372
+ stat_type : typing.Optional[str]
373
+ Stat type to recalculate. Possible values: label, stats
374
+
375
+ request_options : typing.Optional[RequestOptions]
376
+ Request-specific configuration.
377
+
378
+ Returns
379
+ -------
380
+ typing.Dict[str, typing.Optional[typing.Any]]
381
+ Successful response returns job id
382
+
383
+ Examples
384
+ --------
385
+ from label_studio_sdk import LabelStudio
386
+
387
+ client = LabelStudio(
388
+ api_key="YOUR_API_KEY",
389
+ )
390
+ client.projects.stats.update_stats(
391
+ id=1,
392
+ )
393
+ """
394
+ _response = self._client_wrapper.httpx_client.request(
395
+ f"api/projects/{jsonable_encoder(id)}/update-stats",
396
+ method="GET",
397
+ params={
398
+ "stat_type": stat_type,
399
+ },
400
+ request_options=request_options,
401
+ )
402
+ try:
403
+ if 200 <= _response.status_code < 300:
404
+ return typing.cast(
405
+ typing.Dict[str, typing.Optional[typing.Any]],
406
+ construct_type(
407
+ type_=typing.Dict[str, typing.Optional[typing.Any]], # type: ignore
408
+ object_=_response.json(),
409
+ ),
410
+ )
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
+ def user_prediction_agreement(
417
+ self,
418
+ id: int,
419
+ user_pk: int,
420
+ *,
421
+ per_label: typing.Optional[bool] = None,
422
+ request_options: typing.Optional[RequestOptions] = None,
423
+ ) -> StatsUserPredictionAgreementResponse:
424
+ """
425
+ Get prediction agreement statistics for a specific user within a project.
426
+
427
+ Parameters
428
+ ----------
429
+ id : int
430
+
431
+ user_pk : int
432
+
433
+ per_label : typing.Optional[bool]
434
+ Calculate agreement per label
435
+
436
+ request_options : typing.Optional[RequestOptions]
437
+ Request-specific configuration.
438
+
439
+ Returns
440
+ -------
441
+ StatsUserPredictionAgreementResponse
442
+ Individual user prediction agreement statistics
443
+
444
+ Examples
445
+ --------
446
+ from label_studio_sdk import LabelStudio
447
+
448
+ client = LabelStudio(
449
+ api_key="YOUR_API_KEY",
450
+ )
451
+ client.projects.stats.user_prediction_agreement(
452
+ id=1,
453
+ user_pk=1,
454
+ )
455
+ """
456
+ _response = self._client_wrapper.httpx_client.request(
457
+ f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/prediction",
458
+ method="GET",
459
+ params={
460
+ "per_label": per_label,
461
+ },
462
+ request_options=request_options,
463
+ )
464
+ try:
465
+ if 200 <= _response.status_code < 300:
466
+ return typing.cast(
467
+ StatsUserPredictionAgreementResponse,
468
+ construct_type(
469
+ type_=StatsUserPredictionAgreementResponse, # type: ignore
470
+ object_=_response.json(),
471
+ ),
472
+ )
473
+ _response_json = _response.json()
474
+ except JSONDecodeError:
475
+ raise ApiError(status_code=_response.status_code, body=_response.text)
476
+ raise ApiError(status_code=_response.status_code, body=_response_json)
477
+
478
+ def user_review_score(
479
+ self,
480
+ id: int,
481
+ user_pk: int,
482
+ *,
483
+ per_label: typing.Optional[bool] = None,
484
+ request_options: typing.Optional[RequestOptions] = None,
485
+ ) -> StatsUserReviewScoreResponse:
486
+ """
487
+ Get review score statistics for a specific user within a project.
488
+
489
+ Parameters
490
+ ----------
491
+ id : int
492
+
493
+ user_pk : int
494
+
495
+ per_label : typing.Optional[bool]
496
+ Calculate agreement per label
497
+
498
+ request_options : typing.Optional[RequestOptions]
499
+ Request-specific configuration.
500
+
501
+ Returns
502
+ -------
503
+ StatsUserReviewScoreResponse
504
+ Individual user review score statistics
505
+
506
+ Examples
507
+ --------
508
+ from label_studio_sdk import LabelStudio
509
+
510
+ client = LabelStudio(
511
+ api_key="YOUR_API_KEY",
512
+ )
513
+ client.projects.stats.user_review_score(
514
+ id=1,
515
+ user_pk=1,
516
+ )
517
+ """
518
+ _response = self._client_wrapper.httpx_client.request(
519
+ f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/review_score",
520
+ method="GET",
521
+ params={
522
+ "per_label": per_label,
523
+ },
524
+ request_options=request_options,
525
+ )
526
+ try:
527
+ if 200 <= _response.status_code < 300:
528
+ return typing.cast(
529
+ StatsUserReviewScoreResponse,
530
+ construct_type(
531
+ type_=StatsUserReviewScoreResponse, # type: ignore
532
+ object_=_response.json(),
533
+ ),
534
+ )
535
+ _response_json = _response.json()
536
+ except JSONDecodeError:
537
+ raise ApiError(status_code=_response.status_code, body=_response.text)
538
+ raise ApiError(status_code=_response.status_code, body=_response_json)
539
+
540
+ def user_ground_truth_agreement(
541
+ self,
542
+ id: int,
543
+ user_pk: int,
544
+ *,
545
+ per_label: typing.Optional[bool] = None,
546
+ request_options: typing.Optional[RequestOptions] = None,
547
+ ) -> StatsUserGroundTruthAgreementResponse:
548
+ """
549
+ Get ground truth agreement statistics for a specific user within a project.
550
+
551
+ Parameters
552
+ ----------
553
+ id : int
554
+
555
+ user_pk : int
556
+
557
+ per_label : typing.Optional[bool]
558
+ Calculate agreement per label
559
+
560
+ request_options : typing.Optional[RequestOptions]
561
+ Request-specific configuration.
562
+
563
+ Returns
564
+ -------
565
+ StatsUserGroundTruthAgreementResponse
566
+ Individual user ground truth agreement statistics
567
+
568
+ Examples
569
+ --------
570
+ from label_studio_sdk import LabelStudio
571
+
572
+ client = LabelStudio(
573
+ api_key="YOUR_API_KEY",
574
+ )
575
+ client.projects.stats.user_ground_truth_agreement(
576
+ id=1,
577
+ user_pk=1,
578
+ )
579
+ """
580
+ _response = self._client_wrapper.httpx_client.request(
581
+ f"api/projects/{jsonable_encoder(id)}/users/{jsonable_encoder(user_pk)}/stats/agreement-groundtruth",
582
+ method="GET",
583
+ params={
584
+ "per_label": per_label,
585
+ },
586
+ request_options=request_options,
587
+ )
588
+ try:
589
+ if 200 <= _response.status_code < 300:
590
+ return typing.cast(
591
+ StatsUserGroundTruthAgreementResponse,
592
+ construct_type(
593
+ type_=StatsUserGroundTruthAgreementResponse, # type: ignore
594
+ object_=_response.json(),
595
+ ),
596
+ )
597
+ _response_json = _response.json()
598
+ except JSONDecodeError:
599
+ raise ApiError(status_code=_response.status_code, body=_response.text)
600
+ raise ApiError(status_code=_response.status_code, body=_response_json)
601
+
602
+
603
+ class AsyncStatsClient:
604
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
605
+ self._client_wrapper = client_wrapper
606
+
607
+ async def iaa(
608
+ self,
609
+ id: int,
610
+ *,
611
+ expand: typing.Optional[str] = None,
612
+ per_label: typing.Optional[bool] = None,
613
+ std: typing.Optional[bool] = None,
614
+ task: typing.Optional[str] = None,
615
+ request_options: typing.Optional[RequestOptions] = None,
616
+ ) -> StatsIaaResponse:
617
+ """
618
+ Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators.
619
+
620
+ Parameters
621
+ ----------
622
+ id : int
623
+
624
+ expand : typing.Optional[str]
625
+ Comma-separated list of fields to expand
626
+
627
+ per_label : typing.Optional[bool]
628
+ Calculate IAA per label
629
+
630
+ std : typing.Optional[bool]
631
+ Include standard deviation in results
632
+
633
+ task : typing.Optional[str]
634
+ Comma-separated list of task IDs to filter by
635
+
636
+ request_options : typing.Optional[RequestOptions]
637
+ Request-specific configuration.
638
+
639
+ Returns
640
+ -------
641
+ StatsIaaResponse
642
+ Inter-Annotator Agreement matrix
643
+
644
+ Examples
645
+ --------
646
+ import asyncio
647
+
648
+ from label_studio_sdk import AsyncLabelStudio
649
+
650
+ client = AsyncLabelStudio(
651
+ api_key="YOUR_API_KEY",
652
+ )
653
+
654
+
655
+ async def main() -> None:
656
+ await client.projects.stats.iaa(
657
+ id=1,
658
+ )
659
+
660
+
661
+ asyncio.run(main())
662
+ """
663
+ _response = await self._client_wrapper.httpx_client.request(
664
+ f"api/projects/{jsonable_encoder(id)}/stats/IAA",
665
+ method="GET",
666
+ params={
667
+ "expand": expand,
668
+ "per_label": per_label,
669
+ "std": std,
670
+ "task": task,
671
+ },
672
+ request_options=request_options,
673
+ )
674
+ try:
675
+ if 200 <= _response.status_code < 300:
676
+ return typing.cast(
677
+ StatsIaaResponse,
678
+ construct_type(
679
+ type_=StatsIaaResponse, # type: ignore
680
+ object_=_response.json(),
681
+ ),
682
+ )
683
+ _response_json = _response.json()
684
+ except JSONDecodeError:
685
+ raise ApiError(status_code=_response.status_code, body=_response.text)
686
+ raise ApiError(status_code=_response.status_code, body=_response_json)
687
+
688
+ async def agreement_annotator(
689
+ self, id: int, user_id: int, *, request_options: typing.Optional[RequestOptions] = None
690
+ ) -> StatsAgreementAnnotatorResponse:
691
+ """
692
+ Get agreement statistics for a specific annotator within a project.
693
+
694
+ Parameters
695
+ ----------
696
+ id : int
697
+
698
+ user_id : int
699
+
700
+ request_options : typing.Optional[RequestOptions]
701
+ Request-specific configuration.
702
+
703
+ Returns
704
+ -------
705
+ StatsAgreementAnnotatorResponse
706
+ Individual annotator agreement statistics
707
+
708
+ Examples
709
+ --------
710
+ import asyncio
711
+
712
+ from label_studio_sdk import AsyncLabelStudio
713
+
714
+ client = AsyncLabelStudio(
715
+ api_key="YOUR_API_KEY",
716
+ )
717
+
718
+
719
+ async def main() -> None:
720
+ await client.projects.stats.agreement_annotator(
721
+ id=1,
722
+ user_id=1,
723
+ )
724
+
725
+
726
+ asyncio.run(main())
727
+ """
728
+ _response = await self._client_wrapper.httpx_client.request(
729
+ f"api/projects/{jsonable_encoder(id)}/stats/agreement_annotator/{jsonable_encoder(user_id)}",
730
+ method="GET",
731
+ request_options=request_options,
732
+ )
733
+ try:
734
+ if 200 <= _response.status_code < 300:
735
+ return typing.cast(
736
+ StatsAgreementAnnotatorResponse,
737
+ construct_type(
738
+ type_=StatsAgreementAnnotatorResponse, # type: ignore
739
+ object_=_response.json(),
740
+ ),
741
+ )
742
+ _response_json = _response.json()
743
+ except JSONDecodeError:
744
+ raise ApiError(status_code=_response.status_code, body=_response.text)
745
+ raise ApiError(status_code=_response.status_code, body=_response_json)
746
+
747
+ async def data_filters(
748
+ self, id: int, *, request_options: typing.Optional[RequestOptions] = None
749
+ ) -> StatsDataFiltersResponse:
750
+ """
751
+ Get statistics about user data filters and their usage within a project.
752
+
753
+ Parameters
754
+ ----------
755
+ id : int
756
+
757
+ request_options : typing.Optional[RequestOptions]
758
+ Request-specific configuration.
759
+
760
+ Returns
761
+ -------
762
+ StatsDataFiltersResponse
763
+ User data filter statistics
764
+
765
+ Examples
766
+ --------
767
+ import asyncio
768
+
769
+ from label_studio_sdk import AsyncLabelStudio
770
+
771
+ client = AsyncLabelStudio(
772
+ api_key="YOUR_API_KEY",
773
+ )
774
+
775
+
776
+ async def main() -> None:
777
+ await client.projects.stats.data_filters(
778
+ id=1,
779
+ )
780
+
781
+
782
+ asyncio.run(main())
783
+ """
784
+ _response = await self._client_wrapper.httpx_client.request(
785
+ f"api/projects/{jsonable_encoder(id)}/stats/data_filter",
786
+ method="GET",
787
+ request_options=request_options,
788
+ )
789
+ try:
790
+ if 200 <= _response.status_code < 300:
791
+ return typing.cast(
792
+ StatsDataFiltersResponse,
793
+ construct_type(
794
+ type_=StatsDataFiltersResponse, # type: ignore
795
+ object_=_response.json(),
796
+ ),
797
+ )
798
+ _response_json = _response.json()
799
+ except JSONDecodeError:
800
+ raise ApiError(status_code=_response.status_code, body=_response.text)
801
+ raise ApiError(status_code=_response.status_code, body=_response_json)
802
+
803
+ async def finished_tasks(
804
+ self, id: int, *, user_pk: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None
805
+ ) -> StatsFinishedTasksResponse:
806
+ """
807
+ Get statistics about finished tasks for a project.
808
+
809
+ Parameters
810
+ ----------
811
+ id : int
812
+
813
+ user_pk : typing.Optional[int]
814
+ User ID to filter statistics by (optional)
815
+
816
+ request_options : typing.Optional[RequestOptions]
817
+ Request-specific configuration.
818
+
819
+ Returns
820
+ -------
821
+ StatsFinishedTasksResponse
822
+ Finished tasks statistics
823
+
824
+ Examples
825
+ --------
826
+ import asyncio
827
+
828
+ from label_studio_sdk import AsyncLabelStudio
829
+
830
+ client = AsyncLabelStudio(
831
+ api_key="YOUR_API_KEY",
832
+ )
833
+
834
+
835
+ async def main() -> None:
836
+ await client.projects.stats.finished_tasks(
837
+ id=1,
838
+ )
839
+
840
+
841
+ asyncio.run(main())
842
+ """
843
+ _response = await self._client_wrapper.httpx_client.request(
844
+ f"api/projects/{jsonable_encoder(id)}/stats/finished",
845
+ method="GET",
846
+ params={
847
+ "user_pk": user_pk,
848
+ },
849
+ request_options=request_options,
850
+ )
851
+ try:
852
+ if 200 <= _response.status_code < 300:
853
+ return typing.cast(
854
+ StatsFinishedTasksResponse,
855
+ construct_type(
856
+ type_=StatsFinishedTasksResponse, # type: ignore
857
+ object_=_response.json(),
858
+ ),
859
+ )
860
+ _response_json = _response.json()
861
+ except JSONDecodeError:
862
+ raise ApiError(status_code=_response.status_code, body=_response.text)
863
+ raise ApiError(status_code=_response.status_code, body=_response_json)
864
+
865
+ async def lead_time(
866
+ self, id: int, *, request_options: typing.Optional[RequestOptions] = None
867
+ ) -> StatsLeadTimeResponse:
868
+ """
869
+ Get lead time statistics across the project, including average annotation time.
870
+
871
+ Parameters
872
+ ----------
873
+ id : int
874
+
875
+ request_options : typing.Optional[RequestOptions]
876
+ Request-specific configuration.
877
+
878
+ Returns
879
+ -------
880
+ StatsLeadTimeResponse
881
+ Lead time statistics
882
+
883
+ Examples
884
+ --------
885
+ import asyncio
886
+
887
+ from label_studio_sdk import AsyncLabelStudio
888
+
889
+ client = AsyncLabelStudio(
890
+ api_key="YOUR_API_KEY",
891
+ )
892
+
893
+
894
+ async def main() -> None:
895
+ await client.projects.stats.lead_time(
896
+ id=1,
897
+ )
898
+
899
+
900
+ asyncio.run(main())
901
+ """
902
+ _response = await self._client_wrapper.httpx_client.request(
903
+ f"api/projects/{jsonable_encoder(id)}/stats/lead_time",
904
+ method="GET",
905
+ request_options=request_options,
906
+ )
907
+ try:
908
+ if 200 <= _response.status_code < 300:
909
+ return typing.cast(
910
+ StatsLeadTimeResponse,
911
+ construct_type(
912
+ type_=StatsLeadTimeResponse, # type: ignore
913
+ object_=_response.json(),
914
+ ),
915
+ )
916
+ _response_json = _response.json()
917
+ except JSONDecodeError:
918
+ raise ApiError(status_code=_response.status_code, body=_response.text)
919
+ raise ApiError(status_code=_response.status_code, body=_response_json)
920
+
921
+ async def total_agreement(
922
+ self,
923
+ id: int,
924
+ *,
925
+ per_label: typing.Optional[bool] = None,
926
+ request_options: typing.Optional[RequestOptions] = None,
927
+ ) -> StatsTotalAgreementResponse:
928
+ """
929
+ Overall or per-label total agreement across the project.
930
+
931
+ NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block.
932
+
933
+ Parameters
934
+ ----------
935
+ id : int
936
+
937
+ per_label : typing.Optional[bool]
938
+ Return agreement per label
939
+
940
+ request_options : typing.Optional[RequestOptions]
941
+ Request-specific configuration.
942
+
943
+ Returns
944
+ -------
945
+ StatsTotalAgreementResponse
946
+ Total agreement
947
+
948
+ Examples
949
+ --------
950
+ import asyncio
122
951
 
123
- client = LabelStudio(
952
+ from label_studio_sdk import AsyncLabelStudio
953
+
954
+ client = AsyncLabelStudio(
124
955
  api_key="YOUR_API_KEY",
125
956
  )
126
- client.projects.stats.total_agreement(
127
- id=1,
128
- )
957
+
958
+
959
+ async def main() -> None:
960
+ await client.projects.stats.total_agreement(
961
+ id=1,
962
+ )
963
+
964
+
965
+ asyncio.run(main())
129
966
  """
130
- _response = self._client_wrapper.httpx_client.request(
967
+ _response = await self._client_wrapper.httpx_client.request(
131
968
  f"api/projects/{jsonable_encoder(id)}/stats/total_agreement",
132
969
  method="GET",
133
970
  params={
@@ -149,47 +986,169 @@ class StatsClient:
149
986
  raise ApiError(status_code=_response.status_code, body=_response.text)
150
987
  raise ApiError(status_code=_response.status_code, body=_response_json)
151
988
 
989
+ async def update_stats(
990
+ self,
991
+ id: int,
992
+ *,
993
+ stat_type: typing.Optional[str] = None,
994
+ request_options: typing.Optional[RequestOptions] = None,
995
+ ) -> typing.Dict[str, typing.Optional[typing.Any]]:
996
+ """
997
+ Start stats recalculation for given project
152
998
 
153
- class AsyncStatsClient:
154
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
155
- self._client_wrapper = client_wrapper
999
+ Parameters
1000
+ ----------
1001
+ id : int
156
1002
 
157
- async def iaa(
1003
+ stat_type : typing.Optional[str]
1004
+ Stat type to recalculate. Possible values: label, stats
1005
+
1006
+ request_options : typing.Optional[RequestOptions]
1007
+ Request-specific configuration.
1008
+
1009
+ Returns
1010
+ -------
1011
+ typing.Dict[str, typing.Optional[typing.Any]]
1012
+ Successful response returns job id
1013
+
1014
+ Examples
1015
+ --------
1016
+ import asyncio
1017
+
1018
+ from label_studio_sdk import AsyncLabelStudio
1019
+
1020
+ client = AsyncLabelStudio(
1021
+ api_key="YOUR_API_KEY",
1022
+ )
1023
+
1024
+
1025
+ async def main() -> None:
1026
+ await client.projects.stats.update_stats(
1027
+ id=1,
1028
+ )
1029
+
1030
+
1031
+ asyncio.run(main())
1032
+ """
1033
+ _response = await self._client_wrapper.httpx_client.request(
1034
+ f"api/projects/{jsonable_encoder(id)}/update-stats",
1035
+ method="GET",
1036
+ params={
1037
+ "stat_type": stat_type,
1038
+ },
1039
+ request_options=request_options,
1040
+ )
1041
+ try:
1042
+ if 200 <= _response.status_code < 300:
1043
+ return typing.cast(
1044
+ typing.Dict[str, typing.Optional[typing.Any]],
1045
+ construct_type(
1046
+ type_=typing.Dict[str, typing.Optional[typing.Any]], # type: ignore
1047
+ object_=_response.json(),
1048
+ ),
1049
+ )
1050
+ _response_json = _response.json()
1051
+ except JSONDecodeError:
1052
+ raise ApiError(status_code=_response.status_code, body=_response.text)
1053
+ raise ApiError(status_code=_response.status_code, body=_response_json)
1054
+
1055
+ async def user_prediction_agreement(
158
1056
  self,
159
1057
  id: int,
1058
+ user_pk: int,
160
1059
  *,
161
- expand: typing.Optional[str] = None,
162
1060
  per_label: typing.Optional[bool] = None,
163
- std: typing.Optional[bool] = None,
164
- task: typing.Optional[str] = None,
165
1061
  request_options: typing.Optional[RequestOptions] = None,
166
- ) -> StatsIaaResponse:
1062
+ ) -> StatsUserPredictionAgreementResponse:
167
1063
  """
168
- Get Inter-Annotator Agreement (IAA) matrix for a project, showing agreement between all annotators.
1064
+ Get prediction agreement statistics for a specific user within a project.
169
1065
 
170
1066
  Parameters
171
1067
  ----------
172
1068
  id : int
173
1069
 
174
- expand : typing.Optional[str]
175
- Comma-separated list of fields to expand
1070
+ user_pk : int
176
1071
 
177
1072
  per_label : typing.Optional[bool]
178
- Calculate IAA per label
1073
+ Calculate agreement per label
179
1074
 
180
- std : typing.Optional[bool]
181
- Include standard deviation in results
1075
+ request_options : typing.Optional[RequestOptions]
1076
+ Request-specific configuration.
182
1077
 
183
- task : typing.Optional[str]
184
- Comma-separated list of task IDs to filter by
1078
+ Returns
1079
+ -------
1080
+ StatsUserPredictionAgreementResponse
1081
+ Individual user prediction agreement statistics
1082
+
1083
+ Examples
1084
+ --------
1085
+ import asyncio
1086
+
1087
+ from label_studio_sdk import AsyncLabelStudio
1088
+
1089
+ client = AsyncLabelStudio(
1090
+ api_key="YOUR_API_KEY",
1091
+ )
1092
+
1093
+
1094
+ async def main() -> None:
1095
+ await client.projects.stats.user_prediction_agreement(
1096
+ id=1,
1097
+ user_pk=1,
1098
+ )
1099
+
1100
+
1101
+ asyncio.run(main())
1102
+ """
1103
+ _response = await self._client_wrapper.httpx_client.request(
1104
+ f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/prediction",
1105
+ method="GET",
1106
+ params={
1107
+ "per_label": per_label,
1108
+ },
1109
+ request_options=request_options,
1110
+ )
1111
+ try:
1112
+ if 200 <= _response.status_code < 300:
1113
+ return typing.cast(
1114
+ StatsUserPredictionAgreementResponse,
1115
+ construct_type(
1116
+ type_=StatsUserPredictionAgreementResponse, # type: ignore
1117
+ object_=_response.json(),
1118
+ ),
1119
+ )
1120
+ _response_json = _response.json()
1121
+ except JSONDecodeError:
1122
+ raise ApiError(status_code=_response.status_code, body=_response.text)
1123
+ raise ApiError(status_code=_response.status_code, body=_response_json)
1124
+
1125
+ async def user_review_score(
1126
+ self,
1127
+ id: int,
1128
+ user_pk: int,
1129
+ *,
1130
+ per_label: typing.Optional[bool] = None,
1131
+ request_options: typing.Optional[RequestOptions] = None,
1132
+ ) -> StatsUserReviewScoreResponse:
1133
+ """
1134
+ Get review score statistics for a specific user within a project.
1135
+
1136
+ Parameters
1137
+ ----------
1138
+ id : int
1139
+
1140
+ user_pk : int
1141
+
1142
+ per_label : typing.Optional[bool]
1143
+ Calculate agreement per label
185
1144
 
186
1145
  request_options : typing.Optional[RequestOptions]
187
1146
  Request-specific configuration.
188
1147
 
189
1148
  Returns
190
1149
  -------
191
- StatsIaaResponse
192
- Inter-Annotator Agreement matrix
1150
+ StatsUserReviewScoreResponse
1151
+ Individual user review score statistics
193
1152
 
194
1153
  Examples
195
1154
  --------
@@ -203,30 +1162,28 @@ class AsyncStatsClient:
203
1162
 
204
1163
 
205
1164
  async def main() -> None:
206
- await client.projects.stats.iaa(
1165
+ await client.projects.stats.user_review_score(
207
1166
  id=1,
1167
+ user_pk=1,
208
1168
  )
209
1169
 
210
1170
 
211
1171
  asyncio.run(main())
212
1172
  """
213
1173
  _response = await self._client_wrapper.httpx_client.request(
214
- f"api/projects/{jsonable_encoder(id)}/stats/IAA",
1174
+ f"api/projects/{jsonable_encoder(id)}/user-stats/{jsonable_encoder(user_pk)}/review_score",
215
1175
  method="GET",
216
1176
  params={
217
- "expand": expand,
218
1177
  "per_label": per_label,
219
- "std": std,
220
- "task": task,
221
1178
  },
222
1179
  request_options=request_options,
223
1180
  )
224
1181
  try:
225
1182
  if 200 <= _response.status_code < 300:
226
1183
  return typing.cast(
227
- StatsIaaResponse,
1184
+ StatsUserReviewScoreResponse,
228
1185
  construct_type(
229
- type_=StatsIaaResponse, # type: ignore
1186
+ type_=StatsUserReviewScoreResponse, # type: ignore
230
1187
  object_=_response.json(),
231
1188
  ),
232
1189
  )
@@ -235,32 +1192,33 @@ class AsyncStatsClient:
235
1192
  raise ApiError(status_code=_response.status_code, body=_response.text)
236
1193
  raise ApiError(status_code=_response.status_code, body=_response_json)
237
1194
 
238
- async def total_agreement(
1195
+ async def user_ground_truth_agreement(
239
1196
  self,
240
1197
  id: int,
1198
+ user_pk: int,
241
1199
  *,
242
1200
  per_label: typing.Optional[bool] = None,
243
1201
  request_options: typing.Optional[RequestOptions] = None,
244
- ) -> StatsTotalAgreementResponse:
1202
+ ) -> StatsUserGroundTruthAgreementResponse:
245
1203
  """
246
- Overall or per-label total agreement across the project.
247
-
248
- NOTE: due to an open issue in Fern, SDK clients will raise ApiError upon handling a 204 response. As a workaround, wrap call to this function in a try-except block.
1204
+ Get ground truth agreement statistics for a specific user within a project.
249
1205
 
250
1206
  Parameters
251
1207
  ----------
252
1208
  id : int
253
1209
 
1210
+ user_pk : int
1211
+
254
1212
  per_label : typing.Optional[bool]
255
- Return agreement per label
1213
+ Calculate agreement per label
256
1214
 
257
1215
  request_options : typing.Optional[RequestOptions]
258
1216
  Request-specific configuration.
259
1217
 
260
1218
  Returns
261
1219
  -------
262
- StatsTotalAgreementResponse
263
- Total agreement
1220
+ StatsUserGroundTruthAgreementResponse
1221
+ Individual user ground truth agreement statistics
264
1222
 
265
1223
  Examples
266
1224
  --------
@@ -274,15 +1232,16 @@ class AsyncStatsClient:
274
1232
 
275
1233
 
276
1234
  async def main() -> None:
277
- await client.projects.stats.total_agreement(
1235
+ await client.projects.stats.user_ground_truth_agreement(
278
1236
  id=1,
1237
+ user_pk=1,
279
1238
  )
280
1239
 
281
1240
 
282
1241
  asyncio.run(main())
283
1242
  """
284
1243
  _response = await self._client_wrapper.httpx_client.request(
285
- f"api/projects/{jsonable_encoder(id)}/stats/total_agreement",
1244
+ f"api/projects/{jsonable_encoder(id)}/users/{jsonable_encoder(user_pk)}/stats/agreement-groundtruth",
286
1245
  method="GET",
287
1246
  params={
288
1247
  "per_label": per_label,
@@ -292,9 +1251,9 @@ class AsyncStatsClient:
292
1251
  try:
293
1252
  if 200 <= _response.status_code < 300:
294
1253
  return typing.cast(
295
- StatsTotalAgreementResponse,
1254
+ StatsUserGroundTruthAgreementResponse,
296
1255
  construct_type(
297
- type_=StatsTotalAgreementResponse, # type: ignore
1256
+ type_=StatsUserGroundTruthAgreementResponse, # type: ignore
298
1257
  object_=_response.json(),
299
1258
  ),
300
1259
  )