Bin
2025-12-17 21f0498f62ada55651f4d232327e15fc47f498b1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import pytest
from label_studio_sdk.client import LabelStudio
from label_studio_sdk.label_interface import LabelInterface
 
 
@pytest.mark.django_db
def test_batch_predictions_single_prediction_per_task(django_live_url, business_client, ml_backend_for_test_predict):
    ls = LabelStudio(base_url=django_live_url, api_key=business_client.api_key)
    label_config = LabelInterface.create(
        {
            'text': ('Text', {'name': 'text', 'value': '$text'}, ()),
            'label': (
                'Choices',
                {'name': 'label', 'toName': 'text', 'choice': 'single'},
                (
                    ('Choice', {'value': 'label_A'}, ()),
                    ('Choice', {'value': 'label_B'}, ()),
                ),
            ),
        }
    )
    p = ls.projects.create(
        title='New Project',
        label_config=label_config,
    )
    ls.projects.import_tasks(
        p.id,
        request=[
            {'data': {'text': 'test 1'}},
            {'data': {'text': 'test 2'}},
            {'data': {'text': 'test 3'}},
        ],
    )
 
    tasks = [task for task in ls.tasks.list(project=p.id)]
    assert len(tasks) == 3
 
    # setup ML backend with single prediction per task
    ls.ml.create(url='http://test.ml.backend.for.sdk.com:9092', project=p.id, title='ModelSingle')
 
    # batch predict tasks via actions
    ls.actions.create(
        id='retrieve_tasks_predictions',
        project=p.id,
        selected_items={'all': True, 'excluded': [tasks[1].id]},
    )
 
    # get all predictions in project
    predictions = ls.predictions.list(project=p.id)
 
    # check that only 2 predictions were created
    assert len(predictions) == 2
 
    # check that the first prediction has the correct value
    assert predictions[0].result[0]['value']['choices'][0] == 'label_A'
    assert predictions[0].model_version == 'ModelSingle'
 
    # check that the second prediction has the correct value
    assert predictions[1].result[0]['value']['choices'][0] == 'label_A'
    assert predictions[1].model_version == 'ModelSingle'
 
    # additionally let's test actions: convert predictions to annotations
    ls.actions.create(
        id='predictions_to_annotations',
        project=p.id,
        selected_items={
            'all': False,
            'included': [
                predictions[0].task,
                predictions[1].task,
                # also emulate user error when trying to convert task with no predictions
                tasks[1].id,
            ],
        },
    )
 
    # get all annotations in project
    for task in ls.tasks.list(project=p.id, fields='all'):
        if task.id == tasks[1].id:
            assert not task.annotations
            assert not task.predictions
        else:
            assert len(task.annotations) == 1
            assert task.annotations[0]['result'][0]['value']['choices'][0] == 'label_A'
 
            assert len(task.predictions) == 1
            assert task.predictions[0].result[0]['value']['choices'][0] == 'label_A'
            assert task.predictions[0].model_version == 'ModelSingle'
            assert task.predictions[0].score == 0.1
 
 
@pytest.mark.django_db
def test_batch_predictions_multiple_predictions_per_task(
    django_live_url, business_client, ml_backend_for_test_predict
):
    ls = LabelStudio(base_url=django_live_url, api_key=business_client.api_key)
    li = LabelInterface(
        """
            <View>
              <Text name="text" value="$text"/>
              <Choices name="label" toName="text" choice="single">
                <Choice value="label_A"></Choice>
                <Choice value="label_B"></Choice>
              </Choices>
            </View>"""
    )
    p = ls.projects.create(
        title='New Project',
        label_config=li._config,
    )
    ls.projects.import_tasks(
        p.id,
        request=[
            {'data': {'text': 'test 1'}},
            {'data': {'text': 'test 2'}},
            {'data': {'text': 'test 3'}},
        ],
    )
 
    tasks = [task for task in ls.tasks.list(project=p.id)]
    assert len(tasks) == 3
 
    # setup ML backend with multiple predictions per task
    ls.ml.create(url='http://test.ml.backend.for.sdk.com:9093', project=p.id, title='ModelMultiple')
 
    # batch predict tasks via actions
    ls.actions.create(
        id='retrieve_tasks_predictions',
        project=p.id,
        selected_items={'all': False, 'included': [tasks[0].id, tasks[2].id]},
    )
 
    # get all predictions in project
    predictions = ls.predictions.list(project=p.id)
 
    # check that there are 4 predictions as 2 tasks were predicted
    assert len(predictions) == 4
 
    for task in ls.tasks.list(project=p.id, fields='all'):
        if task.id == tasks[1].id:
            assert not task.predictions
        else:
            assert len(task.predictions) == 2
 
            for i, prediction in enumerate(task.predictions):
                assert prediction.result[0]['value']['choices'][0] == f'label_{["A", "B"][i]}'
                assert prediction.model_version == f'Model{"AB"[i]}'
                assert prediction.score == 0.2 if i == 0 else 0.3