-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/user problems #53
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
Merged
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
8747bf2
Remove unused random parameter
XanderVertegaal 06e4a93
User-added problems WIP
XanderVertegaal 6be3d10
Merge branch 'develop' into feature/user-problems
XanderVertegaal 9c11b77
Clean up templates
XanderVertegaal c2eb6ed
Avoid NotImplemented error when gold param is not provided
XanderVertegaal 579f5e1
Show toasts upon saving a problem
XanderVertegaal 6f2db84
Rename problem to problemResponse
XanderVertegaal 508991d
Move route watching to parent AnnotateComponent
XanderVertegaal cc0bbde
Add AppMode service
XanderVertegaal c22a67b
Properly separate problemResponse from problem
XanderVertegaal 978a35e
Return KBs from backend; update in frontend
XanderVertegaal 5d83ce6
Use consistent str for ID
XanderVertegaal 289c622
Consistent casing for KB Relationship
XanderVertegaal fb23d19
Display KB items in browsing mode
XanderVertegaal 830a3d8
Cleanup
XanderVertegaal 49b03d4
Reuse sentences when creating new problem
XanderVertegaal cf339b8
Fix failing tests
XanderVertegaal 9d70ffa
Show error message upon omitting hypothesis
XanderVertegaal 51b235d
Add more tests
XanderVertegaal 483c0f8
Use int for IDs
XanderVertegaal d144eb6
Fix failing tests
XanderVertegaal 619439c
Avoid unnecessary requests
XanderVertegaal 52b775a
Use serializers for input validation
XanderVertegaal 4e8c4a9
Sensible naming for urls
XanderVertegaal aa0b009
Only update User problems
XanderVertegaal 4c30ea7
Regular dict access
XanderVertegaal 8e24695
Indentation
XanderVertegaal 4f4576e
More intuitive related property access
XanderVertegaal b7f040c
Allow exceptions to bubble up to post()
XanderVertegaal 83dbee6
Let Django crash hard if no KB items can be created
XanderVertegaal 2c39be6
Remove appModeService, integrate logic into ProblemService
XanderVertegaal bd6b8ce
Let more exceptions bubble up
XanderVertegaal 2663a29
Remove unused import
XanderVertegaal c4a387b
Refactor serializer tests to use pytest
XanderVertegaal a826af9
Reinstate Request type annotations
XanderVertegaal cf4a202
Replace manual serialization with ModelViewSet
XanderVertegaal 1bfb7f8
Remove unused validation code
XanderVertegaal 75146f9
Use serializer create/update methods
XanderVertegaal 90b0668
Remove unused fields
XanderVertegaal f064c00
Replace routing buttons with anchor tags
XanderVertegaal a7b09f3
Add template veriable for shorthand
XanderVertegaal ad76efa
Fix failing tests
XanderVertegaal 2ba0c98
Fix backend tests
XanderVertegaal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| from rest_framework import serializers | ||
| from problem.services import FracasData, SNLIData, SickData | ||
| from problem.models import Problem, KnowledgeBase, Sentence | ||
|
|
||
|
|
||
| class KnowledgeBaseSerializer(serializers.ModelSerializer): | ||
|
|
||
| class Meta: | ||
| model = KnowledgeBase | ||
| fields = ["id", "entity1", "entity2", "relationship"] | ||
| extra_kwargs = { | ||
| # Without this, the relationship field is not required during validation. | ||
| "relationship": {"required": True}, | ||
| } | ||
|
|
||
| def validate_id(self, value): | ||
| """Validate that the KnowledgeBase ID exists if provided.""" | ||
| if value is not None: | ||
| if not KnowledgeBase.objects.filter(id=value).exists(): | ||
| raise serializers.ValidationError( | ||
| f"KnowledgeBase item with ID {value} does not exist." | ||
| ) | ||
| return value | ||
|
|
||
| def create_for_problem( | ||
| self, validated_data: dict, problem: Problem | ||
| ) -> KnowledgeBase: | ||
| """Create a new KnowledgeBase item for a problem.""" | ||
| return KnowledgeBase.objects.create( | ||
| **validated_data, | ||
| problem=problem, | ||
| ) | ||
|
|
||
| def update(self, instance: KnowledgeBase, validated_data: dict) -> KnowledgeBase: | ||
| """Update an existing KnowledgeBase item.""" | ||
| instance.entity1 = validated_data["entity1"] | ||
| instance.relationship = validated_data["relationship"] | ||
| instance.entity2 = validated_data["entity2"] | ||
| instance.save() | ||
| return instance | ||
|
|
||
|
|
||
| class ProblemSerializer(serializers.ModelSerializer): | ||
| """ | ||
| Serializer for Problem model output. | ||
| Handles serialization of problems with all related data including labels. | ||
| """ | ||
|
|
||
| premises = serializers.SerializerMethodField() | ||
| hypothesis = serializers.SerializerMethodField() | ||
| entailmentLabel = serializers.CharField(source="entailment_label") | ||
| extraData = serializers.SerializerMethodField() | ||
| kbItems = serializers.SerializerMethodField() | ||
|
|
||
| class Meta: | ||
| model = Problem | ||
| fields = [ | ||
| "id", | ||
| "dataset", | ||
| "premises", | ||
| "hypothesis", | ||
| "entailmentLabel", | ||
| "extraData", | ||
| "kbItems", | ||
| ] | ||
|
|
||
| def get_premises(self, problem): | ||
| """Get list of premise texts.""" | ||
| return [premise.text for premise in problem.premises.all()] | ||
|
|
||
| def get_hypothesis(self, problem): | ||
| """Get hypothesis text.""" | ||
| return problem.hypothesis.text | ||
|
|
||
| def get_extraData(self, problem): | ||
| """Get dataset-specific extra data.""" | ||
| match problem.dataset: | ||
| case Problem.Dataset.SICK: | ||
| return SickData.serialize(problem.extra_data) | ||
| case Problem.Dataset.FRACAS: | ||
| return FracasData.serialize(problem.extra_data) | ||
| case Problem.Dataset.SNLI: | ||
| return SNLIData.serialize(problem.extra_data) | ||
| case _: | ||
| return {} | ||
|
|
||
| def get_kbItems(self, problem): | ||
| """Get knowledge base items.""" | ||
| kb_items = problem.knowledge_bases.all() | ||
| return KnowledgeBaseSerializer(kb_items, many=True).data | ||
|
|
||
| def create(self, validated_data: dict) -> Problem: | ||
| """ | ||
| Create a new Problem instance from validated input data. | ||
| Handles creation of related Sentence and KnowledgeBase objects. | ||
| """ | ||
| premise_sentences = [ | ||
| Sentence.objects.get_or_create(text=premise)[0] | ||
| for premise in validated_data["premises"] | ||
| ] | ||
|
|
||
| hypothesis_sentence = Sentence.objects.get_or_create( | ||
| text=validated_data["hypothesis"] | ||
| )[0] | ||
|
|
||
| problem = Problem.objects.create( | ||
| hypothesis=hypothesis_sentence, | ||
| dataset=Problem.Dataset.USER, | ||
| # TODO: Determine entailment label based on LangPro parser output. | ||
| entailment_label=Problem.EntailmentLabel.UNKNOWN, | ||
| extra_data={}, | ||
| ) | ||
|
|
||
| problem.premises.set(premise_sentences) | ||
|
|
||
| kb_items = validated_data.get("kbItems", []) | ||
| if kb_items: | ||
| self._update_or_create_kb_items(problem, kb_items) | ||
|
|
||
| return problem | ||
|
|
||
| def update(self, instance: Problem, validated_data: dict) -> Problem: | ||
| """ | ||
| Update an existing Problem instance from validated input data. | ||
| Handles updating of related Sentence and KnowledgeBase objects. | ||
| """ | ||
| if instance.dataset != Problem.Dataset.USER: | ||
| raise serializers.ValidationError( | ||
| "Cannot update a problem that is not a user-created problem." | ||
| ) | ||
|
|
||
| instance.hypothesis = Sentence.objects.get_or_create( | ||
| text=validated_data["hypothesis"], | ||
| )[0] | ||
| instance.save() | ||
|
|
||
| premise_sentences = [ | ||
| Sentence.objects.get_or_create(text=premise)[0] | ||
| for premise in validated_data["premises"] | ||
| ] | ||
| instance.premises.set(premise_sentences) | ||
|
|
||
| self._update_or_create_kb_items(instance, validated_data.get("kbItems", [])) | ||
|
|
||
| return instance | ||
|
|
||
| def _update_or_create_kb_items( | ||
| self, problem: Problem, kb_items: list[dict] | ||
| ) -> None: | ||
| """Create or update KnowledgeBase items for a problem.""" | ||
| kb_ids: list[int] = [] | ||
| kb_serializer = KnowledgeBaseSerializer() | ||
|
|
||
| for item in kb_items: | ||
| kb_id = item.get("id", None) | ||
|
|
||
| if kb_id is None: | ||
| kb = kb_serializer.create_for_problem(item, problem=problem) # type: ignore | ||
| else: | ||
| kb_instance = KnowledgeBase.objects.get(id=kb_id, problem_id=problem.pk) | ||
| kb = kb_serializer.update(kb_instance, item) | ||
|
|
||
| kb_ids.append(kb.pk) | ||
|
|
||
| # Delete existing knowledge bases associated to this problem that are | ||
| # not included in the input. | ||
| KnowledgeBase.objects.filter(problem_id=problem.pk).exclude( | ||
| id__in=kb_ids | ||
| ).delete() | ||
|
|
||
|
|
||
| class ProblemInputSerializer(serializers.Serializer): | ||
| """ | ||
| Serializer for validating problem input data. | ||
| This is used for both creating and updating user-created problems. | ||
| """ | ||
|
|
||
| id = serializers.IntegerField(required=False, allow_null=True) | ||
| premises = serializers.ListField( | ||
| child=serializers.CharField(allow_blank=False), | ||
| allow_empty=False, | ||
| help_text="List of premise sentence texts", | ||
| ) | ||
| hypothesis = serializers.CharField( | ||
| allow_blank=False, help_text="Hypothesis sentence text" | ||
| ) | ||
| kbItems = KnowledgeBaseSerializer( | ||
| many=True, allow_empty=True, help_text="List of knowledge base items" | ||
| ) | ||
|
|
||
| def validate_id(self, value): | ||
| """Validate that the Problem ID, if provided, exists and belongs to a user-created problem.""" | ||
| if value is not None: | ||
| if not Problem.objects.filter( | ||
| id=value, dataset=Problem.Dataset.USER | ||
| ).exists(): | ||
| raise serializers.ValidationError( | ||
| f"Problem with ID {value} does not exist." | ||
| ) | ||
| return value |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.