Subjects per grade (math, calculus, geometry, stats, discrete), 5 new textbooks, 202 new islands, long islands split, hand-written figures and lesson texts for the new books

- content.Subject + Unit.subject, /api/home?subject=, tutor grounded in the chosen book
- 5 new books ingested; ~1150 hand-written questions, islands named by hand
- node_split: islands over 7 lessons split into parts of <=6 (lesson ids and progress kept)
- Lesson.figures hand-authored and visually checked for 653 lessons of the new books;
  gen_lesson_figures got --subject and survives network errors
- seed files re-exported

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 05:35:18 +03:30
parent 3d51b3b83a
commit 8cb1ecb85e
32 changed files with 81218 additions and 4486 deletions

View File

@@ -84,3 +84,48 @@ class AskWithoutLessonUsesTheStudentsBookTests(TestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(retrieve_mock.call_args.kwargs['subject'], '')
class AskFollowsTheBookTheStudentPickedTests(TestCase):
"""۲۰۲۶-۱۰-۱۱: یک پایه چند کتاب دارد؛ دستیار از کتابی جواب می‌دهد که دانش‌آموز انتخاب کرده یا درس به آن تعلق دارد."""
def setUp(self):
cache.clear()
self.grade = Grade.objects.create(title='پایه دوازدهم', icon='', color='')
self.user = User.objects.create(phone='09120000021', grade_id=self.grade.id)
def _ask(self, **extra):
retrieve = mock.patch('rag.services.retrieval.retrieve_context',
return_value=([], {'gradeTitle': 'دوازدهم'}))
generate = mock.patch('rag.services.generation.generate_answer', return_value=('جواب', [], {}))
configured = mock.patch('rag.services.config.rag_is_configured', return_value=True)
with retrieve as retrieve_mock, generate, configured:
response = self.client.post(
'/api/ai/ask', {'userQuestion': 'ماتریس چیست؟', **extra}, content_type='application/json',
HTTP_AUTHORIZATION=f'Bearer {issue_access_token(self.user.id)}',
)
self.assertEqual(response.status_code, 200)
return retrieve_mock.call_args.kwargs
def test_explicit_subject_without_lesson_gets_the_grade_title(self):
kwargs = self._ask(subject='هندسه')
self.assertEqual((kwargs['subject'], kwargs['grade_title']), ('هندسه', 'دوازدهم'))
def test_lesson_beats_the_subject_stored_on_the_conversation(self):
from content.models import Lesson, Node, Subject, Unit
geo = Unit.objects.create(grade=self.grade, subject=Subject.objects.get(key='geometry'),
title='فصل ۱: ماتریس و کاربردها', order=1)
calc = Unit.objects.create(grade=self.grade, subject=Subject.objects.get(key='calculus'),
title='فصل ۴: مشتق', order=4)
geo_lesson = Lesson.objects.create(node=Node.objects.create(unit=geo, title='n'), title='l')
calc_lesson = Lesson.objects.create(node=Node.objects.create(unit=calc, title='n'), title='l')
first = self.client.post(
'/api/ai/ask', {'userQuestion': 'سلام', 'lessonId': str(geo_lesson.id)},
content_type='application/json', HTTP_AUTHORIZATION=f'Bearer {issue_access_token(self.user.id)}',
)
self.assertEqual(first.status_code, 200)
conversation_id = first.json()['conversationId']
kwargs = self._ask(conversationId=conversation_id, lessonId=str(calc_lesson.id))
self.assertEqual((kwargs['subject'], kwargs['lesson_number']), ('حسابان', 4))