Exemple #1
0
    def post(self, request):
        """
        post:
        Post actions

        Perform an action with the selected items from a specific view.
        """
        pk = int_from_request(request.GET, "project", None)
        project = get_object_with_check_and_log(request, Project, pk=pk)
        self.check_object_permissions(request, project)

        queryset = get_prepared_queryset(request, project)

        # no selected items on tab
        if not queryset.exists():
            response = {'detail': 'No selected items for specified view'}
            return Response(response, status=404)

        # wrong action id
        action_id = request.GET.get('id', None)
        if action_id is None:
            response = {
                'detail':
                'No action id "' + str(action_id) + '", use ?id=<action-id>'
            }
            return Response(response, status=422)

        # perform action and return the result dict
        kwargs = {'request': request}  # pass advanced params to actions
        result = perform_action(action_id, project, queryset, **kwargs)
        code = result.pop('response_code', 200)

        return Response(result, status=code)
Exemple #2
0
    def post(self, request):
        pk = int_from_request(request.GET, "project", None)
        project = get_object_with_check_and_log(request, Project, pk=pk)
        self.check_object_permissions(request, project)

        queryset = get_prepared_queryset(request, project)

        # wrong action id
        action_id = request.GET.get('id', None)
        if action_id is None:
            response = {'detail': 'No action id "' + str(action_id) + '", use ?id=<action-id>'}
            return Response(response, status=422)

        # perform action and return the result dict
        kwargs = {'request': request}  # pass advanced params to actions
        result = perform_action(action_id, project, queryset, request.user, **kwargs)
        code = result.pop('response_code', 200)

        return Response(result, status=code)
Exemple #3
0
    def get(self, request, *args, **kwargs):
        project = self.get_object()
        dm_queue = filters_ordering_selected_items_exist(request.data)
        prepared_tasks = get_prepared_queryset(request, project)

        next_task, queue_info = get_next_task(request.user, prepared_tasks,
                                              project, dm_queue)

        if next_task is None:
            raise NotFound(
                f'There are still some tasks to complete for the user={request.user}, '
                f'but they seem to be locked by another user.')

        # serialize task
        context = {'request': request, 'project': project, 'resolve_uri': True}
        serializer = NextTaskSerializer(next_task, context=context)
        response = serializer.data

        response['queue'] = queue_info
        return Response(response)
Exemple #4
0
    def get(self, request, *args, **kwargs):
        project = get_object_with_check_and_log(request,
                                                Project,
                                                pk=self.kwargs['pk'])
        # TODO: LSE option
        # if not project.is_published:
        #     raise PermissionDenied('Project is not published.')
        self.check_object_permissions(request, project)
        user = request.user

        # support actions api call from actions/next_task.py
        if hasattr(self, 'prepared_tasks'):
            project.prepared_tasks = self.prepared_tasks
            external_prepared_tasks_used = True
        # get prepared tasks from request params (filters, selected items)
        else:
            project.prepared_tasks = get_prepared_queryset(
                self.request, project)
            external_prepared_tasks_used = False

        # detect solved and not solved tasks
        user_solved_tasks_array = user.annotations.filter(
            ground_truth=False).filter(Q(task__isnull=False)).values_list(
                'task__pk', flat=True)

        with conditional_atomic():
            not_solved_tasks = project.prepared_tasks.\
                exclude(pk__in=user_solved_tasks_array).filter(is_labeled=False)
            not_solved_tasks_count = not_solved_tasks.count()

            # return nothing if there are no tasks remain
            if not_solved_tasks_count == 0:
                raise NotFound(
                    f'There are no tasks remaining to be annotated by the user={user}'
                )
            logger.debug(
                f'{not_solved_tasks_count} tasks that still need to be annotated for user={user}'
            )

            # ordered by data manager
            if external_prepared_tasks_used:
                next_task = not_solved_tasks.first()
                if not next_task:
                    raise NotFound('No more tasks found')
                return self._make_response(next_task, request)

            # If current user has already lock one task - return it (without setting the lock again)
            next_task = Task.get_locked_by(user, project)
            if next_task:
                return self._make_response(next_task,
                                           request,
                                           use_task_lock=False)

            if project.show_ground_truth_first:
                logger.debug(
                    f'User={request.user} tries ground truth from {not_solved_tasks_count} tasks'
                )
                next_task = self._try_ground_truth(not_solved_tasks, project)
                if next_task:
                    return self._make_response(next_task, request)

            if project.show_overlap_first:
                # don't output anything - just filter tasks with overlap
                logger.debug(
                    f'User={request.user} tries overlap first from {not_solved_tasks_count} tasks'
                )
                _, not_solved_tasks = self._try_tasks_with_overlap(
                    not_solved_tasks)

            # if there any tasks in progress (with maximum number of annotations), randomly sampling from them
            logger.debug(
                f'User={request.user} tries depth first from {not_solved_tasks_count} tasks'
            )
            next_task = self._try_breadth_first(not_solved_tasks)
            if next_task:
                return self._make_response(next_task, request)

            if project.sampling == project.UNCERTAINTY:
                logger.debug(
                    f'User={request.user} tries uncertainty sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._try_uncertainty_sampling(
                    not_solved_tasks, project, user_solved_tasks_array)

            elif project.sampling == project.UNIFORM:
                logger.debug(
                    f'User={request.user} tries random sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._get_random_unlocked(not_solved_tasks)

            elif project.sampling == project.SEQUENCE:
                logger.debug(
                    f'User={request.user} tries sequence sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._get_first_unlocked(
                    not_solved_tasks.all().order_by('id'))

            if next_task:
                return self._make_response(next_task, request)
            else:
                raise NotFound(
                    f'There exist some unsolved tasks for the user={user}, but they seem to be locked by another users'
                )
Exemple #5
0
    def get(self, request, *args, **kwargs):
        project = get_object_with_check_and_log(request,
                                                Project,
                                                pk=self.kwargs['pk'])
        self.check_object_permissions(request, project)
        user = request.user

        # support actions api call from actions/next_task.py
        if hasattr(self, 'prepared_tasks'):
            project.prepared_tasks = self.prepared_tasks
        # get prepared tasks from request params (filters, selected items)
        else:
            project.prepared_tasks = get_prepared_queryset(
                self.request, project)

        # detect solved and not solved tasks
        user_solved_tasks_array = user.annotations.filter(
            ground_truth=False).filter(Q(task__isnull=False)).values_list(
                'task__pk', flat=True)

        with conditional_atomic():
            not_solved_tasks = project.prepared_tasks.\
                exclude(pk__in=user_solved_tasks_array)

            # if annotator is assigned for tasks, he must to solve it regardless of is_labeled=True
            assigned_flag = hasattr(self,
                                    'assignee_flag') and self.assignee_flag
            if not assigned_flag:
                not_solved_tasks = not_solved_tasks.annotate(
                    annotation_number=Count('annotations')).filter(
                        annotation_number__lte=project.maximum_annotations)

            not_solved_tasks_count = not_solved_tasks.count()

            # return nothing if there are no tasks remain
            if not_solved_tasks_count == 0:
                raise NotFound(
                    f'There are no tasks remaining to be annotated by the user={user}'
                )
            logger.debug(
                f'{not_solved_tasks_count} tasks that still need to be annotated for user={user}'
            )

            # ordered by data manager
            if assigned_flag:
                next_task = not_solved_tasks.first()
                if not next_task:
                    raise NotFound('No more tasks found')
                return self._make_response(next_task,
                                           request,
                                           use_task_lock=False)

            # If current user has already lock one task - return it (without setting the lock again)
            next_task = Task.get_locked_by(user, tasks=not_solved_tasks)
            if next_task:
                return self._make_response(next_task,
                                           request,
                                           use_task_lock=False)

            if project.show_ground_truth_first:
                logger.debug(
                    f'User={request.user} tries ground truth from {not_solved_tasks_count} tasks'
                )
                next_task = self._try_ground_truth(not_solved_tasks, project)
                if next_task:
                    return self._make_response(next_task, request)

            if project.show_overlap_first:
                # don't output anything - just filter tasks with overlap
                logger.debug(
                    f'User={request.user} tries overlap first from {not_solved_tasks_count} tasks'
                )
                _, not_solved_tasks = self._try_tasks_with_overlap(
                    not_solved_tasks)

            # don't use this mode for data manager sorting, because the sorting becomes not obvious
            if project.sampling != project.SEQUENCE:
                # if there any tasks in progress (with maximum number of annotations), randomly sampling from them
                logger.debug(
                    f'User={request.user} tries depth first from {not_solved_tasks_count} tasks'
                )
                next_task = self._try_breadth_first(not_solved_tasks)
                if next_task:
                    return self._make_response(next_task, request)

            if project.sampling == project.UNCERTAINTY:
                logger.debug(
                    f'User={request.user} tries uncertainty sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._try_uncertainty_sampling(
                    not_solved_tasks, project, user_solved_tasks_array)

            elif project.sampling == project.UNIFORM:
                logger.debug(
                    f'User={request.user} tries random sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._get_random_unlocked(not_solved_tasks)

            elif project.sampling == project.SEQUENCE:
                logger.debug(
                    f'User={request.user} tries sequence sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._get_first_unlocked(not_solved_tasks)

            if next_task:
                return self._make_response(next_task, request)
            else:
                raise NotFound(
                    f'There are still some tasks to complete for the user={user}, but they seem to be locked by another user.'
                )
Exemple #6
0
    def get(self, request, *args, **kwargs):
        project = get_object_with_check_and_log(request,
                                                Project,
                                                pk=self.kwargs['pk'])
        self.check_object_permissions(request, project)
        user = request.user
        self.current_user = user
        dm_queue = filters_ordering_selected_items_exist(request.data)

        # support actions api call from actions/next_task.py
        if hasattr(self, 'prepared_tasks'):
            project.prepared_tasks = self.prepared_tasks
        # get prepared tasks from request params (filters, selected items)
        else:
            project.prepared_tasks = get_prepared_queryset(
                self.request, project)

        # detect solved and not solved tasks
        assigned_flag = hasattr(self, 'assignee_flag') and self.assignee_flag
        user_solved_tasks_array = user.annotations.filter(ground_truth=False)
        user_solved_tasks_array = user_solved_tasks_array.filter(task__isnull=False)\
            .distinct().values_list('task__pk', flat=True)

        with conditional_atomic():
            not_solved_tasks = project.prepared_tasks.\
                exclude(pk__in=user_solved_tasks_array)

            # if annotator is assigned for tasks, he must to solve it regardless of is_labeled=True

            if not assigned_flag:
                not_solved_tasks = not_solved_tasks.filter(is_labeled=False)

            # used only for debug logging, disabled for performance reasons
            not_solved_tasks_count = 'unknown'

            next_task = None
            # ordered by data manager
            if assigned_flag and not dm_queue:
                next_task = not_solved_tasks.first()
                if not next_task:
                    raise NotFound('No more tasks found')
                return self._make_response(next_task,
                                           request,
                                           use_task_lock=False,
                                           queue='Manually assigned queue')

            # If current user has already lock one task - return it (without setting the lock again)
            next_task = Task.get_locked_by(user, tasks=not_solved_tasks)
            if next_task and not dm_queue:
                return self._make_response(next_task,
                                           request,
                                           use_task_lock=False,
                                           queue='Task lock')

            if project.show_ground_truth_first and not dm_queue:
                logger.debug(
                    f'User={request.user} tries ground truth from {not_solved_tasks_count} tasks'
                )
                next_task = self._try_ground_truth(not_solved_tasks, project)
                if next_task:
                    return self._make_response(next_task,
                                               request,
                                               queue='Ground truth queue')

            queue_info = ''

            # show tasks with overlap > 1 first
            if project.show_overlap_first and not dm_queue:
                # don't output anything - just filter tasks with overlap
                logger.debug(
                    f'User={request.user} tries overlap first from {not_solved_tasks_count} tasks'
                )
                _, not_solved_tasks = self._try_tasks_with_overlap(
                    not_solved_tasks)
                queue_info += 'Show overlap first'

            # if there any tasks in progress (with maximum number of annotations), randomly sampling from them
            logger.debug(
                f'User={request.user} tries depth first from {not_solved_tasks_count} tasks'
            )

            if project.maximum_annotations > 1 and not dm_queue:
                next_task = self._try_breadth_first(not_solved_tasks)
                if next_task:
                    queue_info += (' & ' if queue_info else
                                   '') + 'Breadth first queue'
                    return self._make_response(next_task,
                                               request,
                                               queue=queue_info)

            # data manager queue
            if dm_queue:
                queue_info += (' & '
                               if queue_info else '') + 'Data manager queue'
                logger.debug(
                    f'User={request.user} tries sequence sampling from {not_solved_tasks_count} tasks'
                )
                next_task = not_solved_tasks.first()

            elif project.sampling == project.SEQUENCE:
                queue_info += (' & ' if queue_info else '') + 'Sequence queue'
                logger.debug(
                    f'User={request.user} tries sequence sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._get_first_unlocked(not_solved_tasks)

            elif project.sampling == project.UNCERTAINTY:
                queue_info += (' & ' if queue_info else
                               '') + 'Active learning or random queue'
                logger.debug(
                    f'User={request.user} tries uncertainty sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._try_uncertainty_sampling(
                    not_solved_tasks, project, user_solved_tasks_array)

            elif project.sampling == project.UNIFORM:
                queue_info += (' & '
                               if queue_info else '') + 'Uniform random queue'
                logger.debug(
                    f'User={request.user} tries random sampling from {not_solved_tasks_count} tasks'
                )
                next_task = self._get_random_unlocked(not_solved_tasks)

            if next_task:
                return self._make_response(next_task,
                                           request,
                                           queue=queue_info)
            else:
                raise NotFound(
                    f'There are still some tasks to complete for the user={user}, '
                    f'but they seem to be locked by another user.')