Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 71689a1

Browse files
Improved application
- Debugged progress calculation - Added ML model for classification
1 parent dac91ed commit 71689a1

File tree

19 files changed

+190
-96
lines changed

19 files changed

+190
-96
lines changed

‎requirements.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ iniconfig==1.1.1
5656
itypes==1.2.0
5757
Jinja2==3.0.1
5858
jiter==0.7.1
59+
joblib==1.4.2
5960
MarkupSafe==2.0.1
6061
mccabe==0.7.0
6162
mindsdb-sql==0.21.0
@@ -101,6 +102,8 @@ requests-oauthlib==1.3.1
101102
rsa==4.9
102103
ruamel.yaml==0.18.6
103104
ruamel.yaml.clib==0.2.12
105+
scikit-learn==1.5.2
106+
scipy==1.14.1
104107
simplejson==3.19.3
105108
six==1.16.0
106109
sly==0.5
@@ -109,6 +112,7 @@ SQLAlchemy==2.0.36
109112
sqlparse==0.5.2
110113
sseclient-py==1.8.0
111114
tenacity==9.0.0
115+
threadpoolctl==3.5.0
112116
tomli==2.1.0
113117
tqdm==4.67.0
114118
tweepy==4.14.0

‎src/Curriculum/api/base/serializers.py‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from rest_framework import serializers
22

3-
from Curriculum.models import (Curriculum, CurriculumEnrollment,CurriculumReview,
4-
CurriculumSyllabi, SyllabiProgress,
5-
SyllabiTopic)
3+
from Curriculum.models import (Curriculum, CurriculumEnrollment,
4+
CurriculumReview, CurriculumSyllabi,
5+
SyllabiProgress, SyllabiTopic)
66
from Quiz.models import QOption, Quiz
77
from Resource.models import Resource
88

@@ -71,12 +71,12 @@ class EnrolledSingleCurriculumSerializer(CurriculumSerializer):
7171
syllabus = serializers.SerializerMethodField()
7272

7373
def get_syllabus(self, obj: Curriculum):
74-
enrollment = self.context.get("enrolloment")
74+
enrollment = self.context.get("enrollment")
7575
syllabus = []
7676

7777
for syllabi in obj.get_syllabus():
78-
completed = SyllabiProgress.objects.syllabi_completed(
79-
enrollment, syllabi)
78+
completed = SyllabiProgress.objects.filter(
79+
enrollment=enrollment, syllabi=syllabi).syllabi_completed()
8080
data = CurriculumSyllabiSerializer(instance=syllabi).data
8181
data['completed'] = completed
8282
syllabus.append(data)
@@ -232,3 +232,8 @@ class EventSerializer(serializers.Serializer):
232232
reading_time = serializers.CharField()
233233
image = serializers.URLField()
234234
projectSummary = serializers.CharField()
235+
upvotes = serializers.IntegerField()
236+
views = serializers.IntegerField()
237+
reading_time = serializers.CharField()
238+
image = serializers.URLField()
239+
projectSummary = serializers.CharField()

‎src/Curriculum/api/base/views.py‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
from rest_framework.response import Response
1010

1111
from Curriculum.models import Curriculum, SyllabiProgress, SyllabiTopic
12+
from Feedback.models import UserFeedback
1213
from Quiz.models import QOption, Quiz
1314
from utils.base.date import dt_now
14-
from utils.base.mindsdb import classify_text, sentiment_text
15+
from utils.base.ml_loader import ModelLoader
16+
from utils.base.sentiment import analyze_sentiment
1517
from utils.base.showwcase import show_get
1618

1719
from . import serializers
@@ -50,7 +52,7 @@ def get_serializer_context(self):
5052
data = super().get_serializer_context()
5153
return {
5254
**data,
53-
"enrolloment": self.request.user
55+
"enrollment": self.request.user
5456
.get_curriculum_enrollment(self.get_object())
5557
}
5658

@@ -256,7 +258,7 @@ def get_serializer_context(self):
256258
data = super().get_serializer_context()
257259
return {
258260
**data,
259-
"enrolloment": self.request.user
261+
"enrollment": self.request.user
260262
.get_curriculum_enrollment(self.get_object())
261263
}
262264

@@ -296,9 +298,13 @@ def get(self, request, *args, **kwargs):
296298
instance=syllabi_progress).data
297299
responses.append(data)
298300

301+
cur_serializer = serializers.EnrolledSingleCurriculumSerializer(
302+
instance=cur, context={ "enrollment": enrollment })
303+
# cur_serializer.context = {
304+
# "enrollment": enrollment
305+
# }
299306
data = {
300-
"curriculum": serializers.EnrolledSingleCurriculumSerializer(
301-
instance=cur).data,
307+
"curriculum": cur_serializer.data,
302308
"progress": responses
303309
}
304310
return Response(data)
@@ -333,8 +339,10 @@ def perform_create(self, serializer):
333339
review = serializer.save(enrollment=enrollment)
334340

335341
# Classify review here, in live app use cron job
336-
review.sentiment = sentiment_text(review.review)
337-
review.label = classify_text(review.review)
342+
review.sentiment = UserFeedback.SENTIMENT_REV_LOOKUP[analyze_sentiment(review.review)]
343+
review.label = UserFeedback.LABEL_REV_LOOKUP[ModelLoader().predict(review.review)]
344+
345+
print(review.sentiment, review.label)
338346
review.save()
339347

340348
@swagger_auto_schema(

‎src/Curriculum/apps.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@
44
class CurriculumConfig(AppConfig):
55
default_auto_field = 'django.db.models.BigAutoField'
66
name = 'Curriculum'
7+
8+
def ready(self):
9+
# Preload the model when the app starts
10+
from utils.base.ml_loader import ModelLoader
11+
ModelLoader()

‎src/Curriculum/managers.py‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33

44
class SyllabiProgressQuery(QuerySet):
55

6-
def syllabi_completed(self, enrollment, syllabi):
7-
qset = self.filter(syllabi=syllabi, enrollment=enrollment)
8-
print(qset, qset.filter(completed=True))
9-
completed = qset.filter(completed=True).count()
10-
return completed == qset.count()
6+
def syllabi_completed(self):
7+
print(self, self.filter(completed=True))
8+
completed = self.filter(completed=True).count()
9+
return completed == self.count()
1110

1211
def get_by_enrollment_topic(self, enrollment, topic):
1312
return self.get(topic=topic, enrollment=enrollment)
@@ -17,8 +16,8 @@ class SyllabiProgressManager(Manager):
1716
def get_queryset(self):
1817
return SyllabiProgressQuery(model=self.model, using=self._db)
1918

20-
def syllabi_completed(self, enrollment, syllabi):
21-
return self.get_queryset().syllabi_completed(enrollment, syllabi)
19+
def syllabi_completed(self):
20+
return self.get_queryset().syllabi_completed()
2221

2322
def get_by_enrollment_topic(self, enrollment, topic):
2423
return self.get_queryset().get_by_enrollment_topic(enrollment, topic)

‎src/Curriculum/models.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,13 @@ class CurriculumEnrollment(models.Model):
132132
@property
133133
def completed_weeks(self):
134134
syllabus = self.curriculum.get_syllabus()
135+
progress = SyllabiProgress.objects.filter(enrollment=self)
135136

136137
def count(prev: int, syllabi: CurriculumSyllabi):
137138
"""
138139
Count completed syllabus
139140
"""
140-
is_completed = SyllabiProgress.objects.syllabi_completed(self, syllabi)
141+
is_completed = progress.filter(self, syllabi).syllabi_completed()
141142
return prev + 1 if is_completed else prev
142143

143144
return reduce(count, syllabus, 0)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.1.3 on 2024年11月24日 09:57
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('Feedback', '0001_initial'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='userfeedback',
15+
name='label',
16+
field=models.CharField(blank=True, choices=[('A', 'Course Content'), ('B', 'Exercises'), ('C', 'Course Structure'), ('D', 'Learning Experience'), ('E', 'Feature Request'), ('F', 'Improvement')], max_length=1, null=True),
17+
),
18+
]

‎src/Feedback/models.py‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from django.db import models
21
from django.conf import settings
2+
from django.db import models
33

44

55
class UserFeedback(models.Model):
@@ -10,13 +10,17 @@ class UserFeedback(models.Model):
1010
('N', 'Negative'),
1111
('N', 'Neutral'),
1212
)
13+
SENTIMENT_REV_LOOKUP = {v: k for k, v in dict(SENTIMENT).items()}
14+
1315
LABEL = (
14-
('A', 'Overall User Experience'),
15-
('B', 'Customer Support'),
16-
('C', 'Content Quality'),
16+
('A', 'Course Content'),
17+
('B', 'Exercises'),
18+
('C', 'Course Structure'),
1719
('D', 'Learning Experience'),
18-
('E', 'Community and Collaboration'),
20+
('E', 'Feature Request'),
21+
('F', 'Improvement'),
1922
)
23+
LABEL_REV_LOOKUP = {v: k for k, v in dict(LABEL).items()}
2024

2125
user = models.ForeignKey(
2226
settings.AUTH_USER_MODEL,

‎src/account/api/base/serializers.py‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,12 @@ def save(self) -> User:
163163
user.profile.save()
164164
return user
165165

166+
166167
class LoginTwitterSerializer(LoginGoogleSerializer):
167168
def save(self) -> User:
168169
with atomic():
169170
data = self.validated_data["id_token"]
170-
email = data['email']
171+
email = data["email"]
171172

172173
try:
173174
user = User.objects.get(email=email)
@@ -211,6 +212,16 @@ def create(self, validated_data):
211212
return user
212213

213214

215+
class ResendOTPSerializer(serializers.Serializer):
216+
email = serializers.EmailField(required=True)
217+
218+
def validate_email(self, value):
219+
try:
220+
return User.objects.get(email=value)
221+
except User.DoesNotExist:
222+
return None
223+
224+
214225
class ValidateOtpSerializer(serializers.Serializer):
215226
email = serializers.EmailField(required=True)
216227
otp = serializers.CharField(required=True)
@@ -225,7 +236,7 @@ def validate_email(self, value):
225236
def validate(self, attrs):
226237
otp = attrs["otp"]
227238
user: User = attrs["email"]
228-
239+
229240
if not user.validate_otp(otp):
230241
raise serializers.ValidationError({"otp": "Invalid otp"})
231242

@@ -237,11 +248,16 @@ class ForgetPasswordTokenSerializer(serializers.Serializer):
237248
uidb64 = serializers.CharField(required=True)
238249

239250

251+
class MessageSerializer(serializers.Serializer):
252+
message = serializers.CharField()
253+
254+
240255
class ValidateRegistrationOtpSerializer(ValidateOtpSerializer):
241256
def save(self, **kwargs):
242257
user: User = self.validated_data["email"]
243258
user.verified_email = True
244259
user.save()
260+
return user
245261

246262

247263
class LoginSerializer(serializers.Serializer):

‎src/account/api/base/urls.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
path('twitter/', views.LoginWithTwitterView.as_view(), name='twitter'),
1010
path('github/', views.LoginWithGithubView.as_view(), name='github'),
1111
path('register/', views.RegisterAPIView.as_view(), name='register'),
12+
path('resend-otp/', views.ResendOTPView.as_view(), name='resend-otp'),
1213
path(
1314
'validate-otp/',
1415
views.ValidateRegistrationOtpView.as_view(), name='validate_otp'),

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /