Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/new assisted tagging #1388

Merged
merged 19 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions apps/assisted_tagging/admin.py
sudan45 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1 +1,52 @@
# Register your models here.
from admin_auto_filters.filters import AutocompleteFilterFactory
from django.contrib import admin

from assisted_tagging.models import AssistedTaggingModelPredictionTag, AssistedTaggingPrediction, DraftEntry
from deep.admin import VersionAdmin


@admin.register(DraftEntry)
class DraftEntryAdmin(VersionAdmin):
search_fields = ['lead']
list_display = [
'lead',
'prediction_status',
]
list_filter = (
AutocompleteFilterFactory('Lead', 'lead'),
AutocompleteFilterFactory('Project', 'project'),
'type'
)

autocomplete_fields = ('project', 'lead', 'related_geoareas',)


@admin.register(AssistedTaggingPrediction)
class AssistedTaggingPredictionAdmin(VersionAdmin):
search_fields = ['draft_entry']
list_display = [
"data_type",
"draft_entry",
"value",
"is_selected",
"tag",
]
list_filter = (
AutocompleteFilterFactory('DraftEntry', 'draft_entry'),

)
# NOTE: Skipping model_version. Only few of them exists
autocomplete_fields = ('draft_entry', 'category', 'tag')


@admin.register(AssistedTaggingModelPredictionTag)
class AssistedTaggingModelPredictionTagAdmin(VersionAdmin):
search_fields = ['parent_tag']
list_display = [
'name',
'is_category',
'tag_id',
'parent_tag',
]
sudan45 marked this conversation as resolved.
Show resolved Hide resolved
autocomplete_fields = ('parent_tag',)
4 changes: 4 additions & 0 deletions apps/assisted_tagging/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@
DraftEntry.PredictionStatus, name='DraftEntryPredictionStatusEnum')
AssistedTaggingPredictionDataTypeEnum = convert_enum_to_graphene_enum(
AssistedTaggingPrediction.DataType, name='AssistedTaggingPredictionDataTypeEnum')
DraftEntryTypeEnum = convert_enum_to_graphene_enum(
DraftEntry.Type, name="DraftEntryTypeEnum"
)

enum_map = {
get_enum_name_from_django_field(field): enum
for field, enum in (
(DraftEntry.prediction_status, DraftEntryPredictionStatusEnum),
(AssistedTaggingPrediction.data_type, AssistedTaggingPredictionDataTypeEnum),
(DraftEntry.type, DraftEntryTypeEnum),
)
}

Expand Down
18 changes: 17 additions & 1 deletion apps/assisted_tagging/filters.py
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
#
import django_filters

from .models import DraftEntry
from utils.graphene.filters import IDFilter, MultipleInputFilter
from .enums import (
DraftEntryTypeEnum
)


class DraftEntryFilterSet(django_filters.FilterSet):
lead = IDFilter(field_name='lead')
draft_entry_types = MultipleInputFilter(DraftEntryTypeEnum, field_name='type')
is_discarded = django_filters.BooleanFilter()

class Meta:
model = DraftEntry
fields = ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.17 on 2023-11-06 10:06

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('assisted_tagging', '0010_draftentry_related_geoareas'),
]

operations = [
migrations.AddField(
model_name='draftentry',
name='draft_entry_type',
field=models.SmallIntegerField(choices=[(0, 'Auto Extraction'), (1, 'Manual Extraction')], default=1),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 3.2.17 on 2023-12-21 11:42

from django.db import migrations, models


class Migration(migrations.Migration):

replaces = [('assisted_tagging', '0011_draftentry_draft_entry_type'), ('assisted_tagging', '0012_draftentry_is_discarded'), ('assisted_tagging', '0013_rename_draft_entry_type_draftentry_type')]

dependencies = [
('assisted_tagging', '0010_draftentry_related_geoareas'),
]

operations = [
migrations.AddField(
model_name='draftentry',
name='is_discarded',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='draftentry',
name='type',
field=models.SmallIntegerField(choices=[(0, 'Auto Extraction'), (1, 'Manual Extraction')], default=1),
),
]
18 changes: 18 additions & 0 deletions apps/assisted_tagging/migrations/0012_draftentry_is_discarded.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.17 on 2023-12-11 05:40

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('assisted_tagging', '0011_draftentry_draft_entry_type'),
]

operations = [
migrations.AddField(
model_name='draftentry',
name='is_discarded',
field=models.BooleanField(default=False),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.17 on 2023-12-20 11:34

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('assisted_tagging', '0012_draftentry_is_discarded'),
]

operations = [
migrations.RenameField(
model_name='draftentry',
old_name='draft_entry_type',
new_name='type',
),
]
11 changes: 10 additions & 1 deletion apps/assisted_tagging/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ class PredictionStatus(models.IntegerChoices):
DONE = 2, 'Done'
SEND_FAILED = 3, 'Send Failed'

class Type(models.IntegerChoices):
AUTO = 0, 'Auto Extraction' # NLP defiend extraction text
thenav56 marked this conversation as resolved.
Show resolved Hide resolved
MANUAL = 1, 'Manual Extraction' # manual defined extraction text

project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='+')
lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name='+')
excerpt = models.TextField()
Expand All @@ -98,6 +102,11 @@ class PredictionStatus(models.IntegerChoices):
prediction_received_at = models.DateTimeField(null=True, blank=True)
# Additional attribues
related_geoareas = models.ManyToManyField(GeoArea, blank=True)
type = models.SmallIntegerField(choices=Type.choices, default=Type.MANUAL)
is_discarded = models.BooleanField(default=False)

def __str__(self):
return f'{self.id}'

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -176,7 +185,7 @@ class DataType(models.IntegerChoices):
id: int

def __str__(self):
return self.id
return str(self.id)


class WrongPredictionReview(UserResource):
Expand Down
44 changes: 44 additions & 0 deletions apps/assisted_tagging/mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
generate_input_type_for_serializer,
PsGrapheneMutation,
PsDeleteMutation,
mutation_is_not_valid
)
from deep.permissions import ProjectPermissions as PP

Expand All @@ -21,6 +22,8 @@
DraftEntryGqlSerializer,
WrongPredictionReviewGqlSerializer,
MissingPredictionReviewGqlSerializer,
TriggerDraftEntryGqlSerializer,
UpdateDraftEntrySerializer
)


Expand All @@ -39,6 +42,16 @@
serializer_class=MissingPredictionReviewGqlSerializer,
)

TriggerAutoDraftEntryInputType = generate_input_type_for_serializer(
"TriggerAutoDraftEntryInputType",
serializer_class=TriggerDraftEntryGqlSerializer
)

UpdateDraftEntryInputType = generate_input_type_for_serializer(
"UpdateDraftEntryInputType",
serializer_class=UpdateDraftEntrySerializer
)


class CreateDraftEntry(PsGrapheneMutation):
class Arguments:
Expand Down Expand Up @@ -96,10 +109,41 @@ def filter_queryset(cls, qs, info):
created_by=info.context.user,
)

# auto draft_entry_create


class TriggerAutoDraftEntry(PsGrapheneMutation):
class Arguments:
data = TriggerAutoDraftEntryInputType(required=True)
model = DraftEntry
serializer_class = TriggerDraftEntryGqlSerializer
permissions = [PP.Permission.CREATE_ENTRY]

@classmethod
def perform_mutate(cls, root, info, **kwargs):
data = kwargs['data']
serializer = cls.serializer_class(data=data, context={'request': info.context.request})
if errors := mutation_is_not_valid(serializer):
return cls(errors=errors, ok=False)
serializer.save()
return cls(errors=None, ok=True)


class UpdateDraftEntry(PsGrapheneMutation):
class Arguments:
data = UpdateDraftEntryInputType(required=True)
id = graphene.ID(required=True)
model = DraftEntry
serializer_class = UpdateDraftEntrySerializer
result = graphene.Field(DraftEntryType)
permissions = [PP.Permission.CREATE_ENTRY]


class AssistedTaggingMutationType(graphene.ObjectType):
draft_entry_create = CreateDraftEntry.Field()
missing_prediction_review_create = CreateMissingPredictionReview.Field()
wrong_prediction_review_create = CreateWrongPredictionReview.Field()
missing_prediction_review_delete = DeleteMissingPredictionReview.Field()
wrong_prediction_review_delete = DeleteWrongPredictionReview.Field()
trigger_auto_draft_entry = TriggerAutoDraftEntry.Field()
update_draft_entry = UpdateDraftEntry.Field()
67 changes: 48 additions & 19 deletions apps/assisted_tagging/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from graphene_django import DjangoObjectType
from graphene_django_extras import DjangoObjectField
from django.db.models import Prefetch
from assisted_tagging.filters import DraftEntryFilterSet

from utils.graphene.enums import EnumDescription
from user_resource.schema import UserResourceMixin
Expand All @@ -11,6 +12,9 @@
ProjectGeoAreaType,
get_geo_area_queryset_for_project_geo_area_type,
)
from utils.graphene.fields import DjangoPaginatedListObjectField
from utils.graphene.pagination import NoOrderingPageGraphqlPagination
from utils.graphene.types import CustomDjangoListObjectType
from .models import (
DraftEntry,
AssistedTaggingModel,
Expand Down Expand Up @@ -96,10 +100,31 @@ def resolve_prediction_tags(root, info, **kwargs):


# -- Project Level
def get_draft_entry_qs(info):
def get_draft_entry_qs(info): # TODO use dataloder
qs = DraftEntry.objects.filter(project=info.context.active_project)
if PP.check_permission(info, PP.Permission.VIEW_ENTRY):
return qs
return qs.prefetch_related(
Prefetch(
'predictions',
queryset=AssistedTaggingPrediction.objects.filter(is_selected=True).order_by('id'),
),
Prefetch(
'related_geoareas',
queryset=get_geo_area_queryset_for_project_geo_area_type().order_by('id'),
),
'predictions__model_version',
'predictions__model_version__model',
'predictions__wrong_prediction_reviews',
'missing_prediction_reviews',
'related_geoareas',
)
return qs.none()


def get_draft_entry_with_filter_qs(info, filters):
qs = DraftEntry.objects.filter(project=info.context.active_project)
if PP.check_permission(info, PP.Permission.VIEW_ENTRY):
return DraftEntryFilterSet(queryset=qs, data=filters).qs
return qs.none()


Expand Down Expand Up @@ -178,22 +203,8 @@ class Meta:
)

@staticmethod
def get_custom_queryset(queryset, info, **kwargs):
return get_draft_entry_qs(info).prefetch_related(
Prefetch(
'predictions',
queryset=AssistedTaggingPrediction.objects.order_by('id'),
),
Prefetch(
'related_geoareas',
queryset=get_geo_area_queryset_for_project_geo_area_type().order_by('id'),
),
'predictions__model_version',
'predictions__model_version__model',
'predictions__wrong_prediction_reviews',
'missing_prediction_reviews',
'related_geoareas',
)
def get_custom_queryset(root, info, **kwargs):
return get_draft_entry_qs(info)

@staticmethod
def resolve_predictions(root, info, **kwargs):
Expand All @@ -205,9 +216,27 @@ def resolve_missing_prediction_reviews(root, info, **kwargs):

@staticmethod
def resolve_related_geoareas(root, info, **kwargs):
return root.related_geoareas.all() # NOTE: Prefetched by DraftEntry
return root.related_geoareas.all() # NOTE: Prefetched by DraftEntry


class DraftEntryListType(CustomDjangoListObjectType):
class Meta:
model = DraftEntry
filterset_class = DraftEntryFilterSet


# This is attached to project type.


class AssistedTaggingQueryType(graphene.ObjectType):
draft_entry = DjangoObjectField(DraftEntryType)
draft_entries = DjangoPaginatedListObjectField(
DraftEntryListType,
pagination=NoOrderingPageGraphqlPagination(
page_size_query_param='pageSize',
),
)

@staticmethod
def resolve_draft_entries(root, info, **_):
return get_draft_entry_qs(info)
Loading
Loading