rating when ai is steaming

This commit is contained in:
2026-06-11 19:53:13 -06:00
parent cd6d67ac97
commit 6938133775
3 changed files with 134 additions and 1 deletions

View File

@@ -20,6 +20,7 @@ from django.db.models import (
Q, Q,
Subquery, Subquery,
) )
from django.utils import timezone
from account.decorators import admin_required from account.decorators import admin_required
from prompt.models import Conversation, Message from prompt.models import Conversation, Message
from .classifier import classify_conversation_messages from .classifier import classify_conversation_messages
@@ -44,6 +45,7 @@ from .schemas import (
SubmissionIn, SubmissionIn,
SubmissionOut, SubmissionOut,
RatingScoreIn, RatingScoreIn,
RandomRatingOut,
TaskStatsOut, TaskStatsOut,
TopViewedItem, TopViewedItem,
UserTag, UserTag,
@@ -288,6 +290,37 @@ def list_by_user_task(request, user_id: int, task_id: int):
) )
@router.get("/random-for-rating/", response=Optional[RandomRatingOut])
@login_required
def get_random_for_rating(request, exclude_id: Optional[UUID] = None):
"""
随机返回一个待打分的其他同学的提交用于AI生成期间的随手打分弹窗
"""
if request.user.role == RoleChoices.NORMAL:
today_start = timezone.now().replace(
hour=0, minute=0, second=0, microsecond=0
)
today_end = today_start + timezone.timedelta(days=1)
rating_count = Rating.objects.filter(
user=request.user, created__range=(today_start, today_end)
).count()
if rating_count >= 30:
return None
candidates = (
Submission.objects.select_related("task", "user")
.exclude(user=request.user)
.exclude(ratings__user=request.user)
)
if exclude_id:
candidates = candidates.exclude(pk=exclude_id)
pending = candidates.annotate(rating_count=Count("ratings")).filter(
rating_count__lt=5
)
return pending.order_by("?").first() or candidates.order_by("?").first()
@router.delete("/flags") @router.delete("/flags")
@login_required @login_required
def clear_all_flags(request): def clear_all_flags(request):

View File

@@ -296,3 +296,34 @@ class PromptRoundOut(Schema):
html: Optional[str] = None html: Optional[str] = None
css: Optional[str] = None css: Optional[str] = None
js: Optional[str] = None js: Optional[str] = None
class RandomRatingOut(Schema):
submission_id: UUID
username: str
task_title: str
task_display: int
task_type: Literal["tutorial", "challenge"]
html: Optional[str] = None
css: Optional[str] = None
js: Optional[str] = None
@staticmethod
def resolve_submission_id(obj):
return obj.id
@staticmethod
def resolve_username(obj):
return obj.user.username
@staticmethod
def resolve_task_title(obj):
return obj.task.title
@staticmethod
def resolve_task_display(obj):
return obj.task.display
@staticmethod
def resolve_task_type(obj):
return obj.task.task_type

View File

@@ -10,7 +10,7 @@ from account.models import RoleChoices
from prompt.models import Conversation, Message from prompt.models import Conversation, Message
from task.models import Task from task.models import Task
from .models import Award, Submission, SubmissionAward from .models import Award, Rating, Submission, SubmissionAward
User = get_user_model() User = get_user_model()
@@ -533,3 +533,72 @@ class GradebookApiTest(TestCase):
self.assertEqual(rows[1][2], "alice") self.assertEqual(rows[1][2], "alice")
self.assertEqual(rows[1][4], "4") self.assertEqual(rows[1][4], "4")
self.assertEqual(rows[1][7], "4") self.assertEqual(rows[1][7], "4")
class RandomForRatingApiTest(TestCase):
def setUp(self):
self.viewer = _make_user("viewer")
self.author = _make_user("author")
self.task = _make_task()
def _submission(self, user, html="<div>work</div>"):
return Submission.objects.create(
user=user, task=self.task, html=html, css="", js=""
)
def test_excludes_own_and_already_rated_submissions(self):
self._submission(self.viewer) # 自己的提交,应排除
rated = self._submission(self.author)
Rating.objects.create(user=self.viewer, submission=rated, score=4)
eligible = self._submission(self.author)
self.client.force_login(self.viewer)
resp = self.client.get("/api/submission/random-for-rating/")
self.assertEqual(resp.status_code, 200)
data = resp.json()
self.assertIsNotNone(data)
self.assertEqual(data["submission_id"], str(eligible.id))
self.assertEqual(data["username"], "author")
self.assertEqual(data["task_title"], self.task.title)
self.assertEqual(data["task_display"], self.task.display)
self.assertEqual(data["task_type"], "challenge")
def test_prefers_submission_with_fewer_than_five_ratings(self):
raters = [_make_user(f"rater{i}") for i in range(5)]
many_ratings = self._submission(self.author, html="<div>many</div>")
for rater in raters:
Rating.objects.create(user=rater, submission=many_ratings, score=3)
few_ratings = self._submission(self.author, html="<div>few</div>")
for rater in raters[:2]:
Rating.objects.create(user=rater, submission=few_ratings, score=3)
self.client.force_login(self.viewer)
resp = self.client.get("/api/submission/random-for-rating/")
self.assertEqual(resp.status_code, 200)
data = resp.json()
self.assertEqual(data["submission_id"], str(few_ratings.id))
def test_exclude_id_param_excludes_given_submission(self):
only = self._submission(self.author)
self.client.force_login(self.viewer)
resp = self.client.get(
f"/api/submission/random-for-rating/?exclude_id={only.id}"
)
self.assertEqual(resp.status_code, 200)
self.assertIsNone(resp.json())
def test_normal_user_reaching_daily_cap_returns_none(self):
self._submission(self.author, html="<div>extra</div>")
for i in range(30):
target = self._submission(self.author, html=f"<div>{i}</div>")
Rating.objects.create(user=self.viewer, submission=target, score=3)
self.client.force_login(self.viewer)
resp = self.client.get("/api/submission/random-for-rating/")
self.assertEqual(resp.status_code, 200)
self.assertIsNone(resp.json())