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:
@@ -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))
|
||||
|
||||
@@ -406,10 +406,14 @@ class AskAIView(APIView):
|
||||
# فقط conversationId میفرستد و دیگر lessonId/gradeId نمیآید.
|
||||
grade_id = v.get('gradeId') or conversation.grade_id
|
||||
lesson_id = v.get('lessonId') or conversation.lesson_id
|
||||
subject = (v.get('subject') or conversation.subject or '').strip()
|
||||
# ⚠️ درسِ تازهی همین درخواست از کتابِ ذخیرهشدهی مکالمه جلو میافتد: از وقتی یک پایه چند
|
||||
# کتاب دارد، مکالمهای که با درسِ هندسه شروع شده میتواند با درسِ حسابان ادامه پیدا کند و
|
||||
# `conversation.subject`/`lesson_number`ِ قدیمی جواب را از کتابِ غلط میگرفت.
|
||||
explicit_lesson = bool(v.get('lessonId'))
|
||||
subject = (v.get('subject') or ('' if explicit_lesson else conversation.subject) or '').strip()
|
||||
grade_title = (v.get('grade') or '').strip()
|
||||
lesson_number = v.get('lessonNumber')
|
||||
if lesson_number is None:
|
||||
if lesson_number is None and not explicit_lesson:
|
||||
lesson_number = conversation.lesson_number
|
||||
|
||||
# اگر اپ فقط lessonId (یا فقط conversationId) داده — حالتِ طبیعی، چون
|
||||
@@ -436,6 +440,14 @@ class AskAIView(APIView):
|
||||
conversation.lesson_number = lesson_number
|
||||
conversation.save(update_fields=['subject', 'lesson_number'])
|
||||
|
||||
# کتاب صریح آمده (فرانت کتابِ انتخابیِ دانشآموز را میفرستد) ولی درس و عنوانِ پایه نه:
|
||||
# عنوانِ پایه از پایهی خودِ کاربر درمیآید، وگرنه resolve_target هیچ collectionی نمیسازد
|
||||
# و جواب بیصدا عمومی میشد.
|
||||
if subject and not grade_title:
|
||||
from rag.services.config import resolve_grade_title
|
||||
|
||||
grade_title = resolve_grade_title(grade_id or getattr(user, 'grade_id', None)) or ''
|
||||
|
||||
# نه درسی آمده نه subject — حالتِ عادیِ صفحهی «از پی بپرس» که از نوارِ
|
||||
# پایین باز میشود. پایهی ذخیرهشدهی خودِ کاربر کتاب را معلوم میکند؛
|
||||
# بدونِ این، جوابهای آن صفحه هیچوقت به کتاب مستند نمیشدند.
|
||||
|
||||
Reference in New Issue
Block a user