Figure questions for grade-10 geometry (115 new), quiz prefers a figured question per lesson, tools/figures/batch.py

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 20:24:55 +03:30
parent a4e0c576bb
commit cd4f2ce0b2
4 changed files with 8495 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -260,3 +260,32 @@ class NodeQuizStabilityTests(TestCase):
UserNodeCompletion.objects.create(
user_id=self.user.id, node=self.node, correct_count=4, total_questions=4, stars=3)
self.assertEqual(first, self._ids())
class NodeQuizPrefersFigureTests(TestCase):
"""از میانِ سوال‌های یک درس، سوالِ شکل‌دار انتخاب می‌شود و آزمون برای کاربر ثابت می‌ماند."""
def setUp(self):
cache.clear()
grade = Grade.objects.create(title='پایه دهم', icon='', color='')
unit = Unit.objects.create(grade=grade, title='فصل ۱', order=1)
self.node = Node.objects.create(unit=unit, title='اول', order=1)
self.figured = []
for i in range(3):
lesson = Lesson.objects.create(node=self.node, title=f'درس {i}')
for j in range(5):
figure = {'kind': 'bar', 'title': 't', 'labels': ['a'], 'values': [1]} if j == 3 else None
q = Question.objects.create(lesson=lesson, type='multiple_choice', prompt=f'س {i}-{j}', figure=figure)
Choice.objects.create(question=q, value='الف', is_correct=True)
Choice.objects.create(question=q, value='ب', is_correct=False)
if figure:
self.figured.append(q.id)
self.user = User.objects.create(phone='09120000020', grade_id=grade.id)
self.auth = {'HTTP_AUTHORIZATION': f'Bearer {issue_access_token(self.user.id)}'}
def test_figured_question_wins_in_every_lesson_and_is_stable(self):
ids = lambda: [q['id'] for q in self.client.get(
f'/api/nodes/{self.node.pk}/quiz?size=3', **self.auth).json()['questions']]
first = ids()
self.assertCountEqual(first, [str(i) for i in self.figured])
self.assertEqual(first, ids())

View File

@@ -1117,10 +1117,17 @@ class NodeQuizView(APIView):
# حداکثر یک سوال از هر درس تا آزمون روی یک مهارت گیر نکند؛ اگر با این
# شرط به اندازه‌ی لازم نرسیدیم، بقیه از همان استخر پر می‌شوند.
# از میانِ سوال‌های یک درس، سوالِ شکل‌دار مقدم است (تصمیمِ مالک ۲۰۲۶-۱۰-۱۴: هندسه و آمار
# بدونِ شکل کم‌اثر است). ترتیبِ درهم‌ریخته‌ی پایدار حفظ می‌شود، پس برای هر کاربر ثابت می‌ماند.
best = {}
for question in questions:
if question.lesson_id not in best or (best[question.lesson_id].figure is None and question.figure is not None):
best[question.lesson_id] = question
picked, seen_lessons = [], set()
for question in questions:
if question.lesson_id in seen_lessons:
continue
question = best[question.lesson_id]
seen_lessons.add(question.lesson_id)
picked.append(question)
if len(picked) >= size: