Skip to content

Commit 5f6f8ef

Browse files
authored
Merge pull request #2051 from wger-project/feature/exercise-submission
Exercise submission endpoint
2 parents e5fe8b2 + b8a3580 commit 5f6f8ef

File tree

14 files changed

+726
-34
lines changed

14 files changed

+726
-34
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ dependencies = [
5656
"fontawesomefree~=6.6.0",
5757
"icalendar==6.3.1",
5858
"invoke==2.2.0",
59+
"lingua-language-detector==2.1.1",
5960
"openfoodfacts==2.6.1",
6061
"packaging==25.0",
6162
"pillow==11.3.0",
@@ -128,7 +129,6 @@ exclude = [
128129
".ruff_cache",
129130
".svn",
130131
".tox",
131-
".venv",
132132
".vscode",
133133
"__pypackages__",
134134
"_build",

uv.lock

Lines changed: 53 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wger/core/api/serializers.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
from django.contrib.auth.models import User
2222
from django.contrib.auth.password_validation import validate_password
2323
from django.http import HttpRequest
24-
2524
# Third Party
25+
from lingua import LanguageDetectorBuilder
2626
from rest_framework import serializers
2727
from rest_framework.fields import empty
2828
from rest_framework.validators import UniqueValidator
@@ -36,7 +36,6 @@
3636
WeightUnit,
3737
)
3838

39-
4039
logger = logging.getLogger(__name__)
4140

4241

@@ -197,3 +196,66 @@ class RoutineWeightUnitSerializer(serializers.ModelSerializer):
197196
class Meta:
198197
model = WeightUnit
199198
fields = ['id', 'name']
199+
200+
201+
class LanguageCheckSerializer(serializers.Serializer):
202+
"""
203+
Serializer for language check
204+
"""
205+
206+
language = serializers.PrimaryKeyRelatedField(queryset=Language.objects.all(), required=False)
207+
language_code = serializers.CharField(required=False, min_length=2, max_length=2)
208+
input = serializers.CharField(min_length=10)
209+
210+
def validate(self, data):
211+
"""
212+
Check that the detected language of the description corresponds with the
213+
provided language.
214+
"""
215+
language = data.get('language')
216+
language_code = data.get('language_code')
217+
218+
if not language and not language_code:
219+
raise serializers.ValidationError(
220+
{'language': 'Either a language ID or a language code must be provided.'}
221+
)
222+
223+
if not language:
224+
try:
225+
language = Language.objects.get(short_name=language_code)
226+
except Language.DoesNotExist:
227+
raise serializers.ValidationError(
228+
{'language': f'Language with code "{language_code}" does not exist.'}
229+
)
230+
231+
# Try to detect the language
232+
detector = (
233+
LanguageDetectorBuilder.from_all_languages().with_preloaded_language_models().build()
234+
)
235+
input_str = data.get('input')
236+
237+
detected_language = detector.detect_language_of(input_str)
238+
detected_language_code = detected_language.iso_code_639_1.name.lower()
239+
confidence_values = detector.compute_language_confidence_values(input_str)
240+
logger.debug(
241+
f'Detected language: {detected_language_code}, '
242+
f'confidence values: {confidence_values}, '
243+
f'input: {input_str}'
244+
)
245+
246+
if detected_language_code != language.short_name.lower():
247+
raise serializers.ValidationError(
248+
{
249+
'check': {
250+
'result': False,
251+
'detected_language': detected_language_code,
252+
'message': f'The detected language is "{detected_language.name.capitalize()}" ({detected_language_code}), '
253+
f'which does not match your selected language "{language.full_name.capitalize()}" '
254+
f'({language.short_name}). If you believe this is incorrect, try adding more content '
255+
f'or rephrasing your text, as language detection works better with longer or more '
256+
f'complete sentences.',
257+
}
258+
}
259+
)
260+
261+
return super().validate(data)

wger/core/api/views.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from django.contrib.auth.models import User
2424
from django.utils.decorators import method_decorator
2525
from django.views.decorators.cache import cache_page
26-
2726
# Third Party
2827
from django_email_verification import send_email
2928
from drf_spectacular.types import OpenApiTypes
@@ -37,7 +36,10 @@
3736
status,
3837
viewsets,
3938
)
40-
from rest_framework.decorators import action
39+
from rest_framework.decorators import (
40+
action,
41+
api_view,
42+
)
4143
from rest_framework.fields import (
4244
BooleanField,
4345
CharField,
@@ -50,6 +52,7 @@
5052

5153
# wger
5254
from wger.core.api.serializers import (
55+
LanguageCheckSerializer,
5356
LanguageSerializer,
5457
LicenseSerializer,
5558
RepetitionUnitSerializer,
@@ -74,7 +77,6 @@
7477
get_version,
7578
)
7679

77-
7880
logger = logging.getLogger(__name__)
7981

8082

@@ -406,3 +408,14 @@ class RoutineWeightUnitViewSet(viewsets.ReadOnlyModelViewSet):
406408
serializer_class = RoutineWeightUnitSerializer
407409
ordering_fields = '__all__'
408410
filterset_fields = ('name',)
411+
412+
413+
@api_view(['POST'])
414+
def check_language(request):
415+
"""
416+
Checks the language of a string
417+
"""
418+
serializer = LanguageCheckSerializer(data=request.data)
419+
serializer.is_valid(raise_exception=True)
420+
421+
return Response({'result': True})

0 commit comments

Comments
 (0)