Bin
2025-12-17 262fecaa75b2909ad244f12c3b079ed3ff4ae329
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
"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
"""
import logging
 
from core.permissions import AllPermissions
from data_manager.actions import DataManagerAction
from django.utils.timezone import now
from tasks.models import Annotation, Prediction, Task
from tasks.serializers import TaskSerializerBulk
from webhooks.models import WebhookAction
from webhooks.utils import emit_webhooks_for_instance
 
all_permissions = AllPermissions()
logger = logging.getLogger(__name__)
 
 
def predictions_to_annotations(project, queryset, **kwargs):
    request = kwargs['request']
    user = request.user
    model_version = request.data.get('model_version')
    queryset = queryset.filter(predictions__isnull=False)
    predictions = Prediction.objects.filter(task__in=queryset, child_annotations__isnull=True)
 
    # model version filter
    if model_version is not None:
        if isinstance(model_version, list):
            predictions = predictions.filter(model_version__in=model_version).distinct()
        else:
            predictions = predictions.filter(model_version=model_version)
 
    predictions_values = list(predictions.values_list('result', 'model_version', 'task_id', 'id'))
 
    # prepare annotations
    annotations = []
    tasks_ids = []
    for result, model_version, task_id, prediction_id in predictions_values:
        tasks_ids.append(task_id)
        body = {
            'result': result,
            'completed_by_id': user.pk,
            'task_id': task_id,
            'parent_prediction_id': prediction_id,
            'project': project,
        }
        body = TaskSerializerBulk.add_annotation_fields(body, user, 'prediction')
        annotations.append(body)
 
    count = len(annotations)
    logger.debug(f'{count} predictions will be converter to annotations')
    db_annotations = [Annotation(**annotation) for annotation in annotations]
    db_annotations = Annotation.objects.bulk_create(db_annotations)
    Task.objects.filter(id__in=tasks_ids).update(updated_at=now(), updated_by=request.user)
 
    if db_annotations:
        TaskSerializerBulk.post_process_annotations(user, db_annotations, 'prediction')
        # Execute webhook for created annotations
        emit_webhooks_for_instance(
            user.active_organization, project, WebhookAction.ANNOTATIONS_CREATED, db_annotations
        )
        # Update counters for tasks and is_labeled. It should be a single operation as counters affect bulk is_labeled update
        project.update_tasks_counters_and_is_labeled(Task.objects.filter(id__in=tasks_ids))
 
        try:
            from stats.functions.stats import recalculate_stats_async_or_sync
 
            recalculate_stats_async_or_sync(project, all=False)
        except (ModuleNotFoundError, ImportError):
            logger.info('Predictions converted to annotations in LSO, stats recomputation skipped')
 
    return {'response_code': 200, 'detail': f'Created {count} annotations'}
 
 
def predictions_to_annotations_form(user, project):
    versions = project.get_model_versions()
 
    # put the current model version on the top of the list
    # if it exists
    first = project.model_version
    if first:
        try:
            versions.remove(first)
        except ValueError:
            pass
        versions = [first] + versions
 
    return [
        {
            'columnCount': 1,
            'fields': [
                {
                    'type': 'select',
                    'name': 'model_version',
                    'label': 'Choose predictions',
                    'options': versions,
                    'value': first,
                }
            ],
        }
    ]
 
 
actions: list[DataManagerAction] = [
    {
        'entry_point': predictions_to_annotations,
        'permission': all_permissions.tasks_change,
        'title': 'Create Annotations From Predictions',
        'order': 91,
        'dialog': {
            'title': 'Create Annotations From Predictions',
            'text': 'Create annotations from predictions using selected predictions set '
            'for each selected task. '
            'Your account will be assigned as an owner to those annotations. ',
            'type': 'confirm',
            'form': predictions_to_annotations_form,
        },
    }
]