Lesson figures: 1-based step index, smaller graph ranges, no tick marks; regenerated 4 calculus-12 lessons

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 16:47:35 +03:30
parent 25b3d24eb4
commit b93f43ef02
2 changed files with 261 additions and 33 deletions

View File

@@ -20,15 +20,17 @@ from rag.services.generation import chat_model_for, completion_kwargs
PROMPT = ( PROMPT = (
'تو برای یک درسِ ریاضی (اپِ آموزشی) شکل‌های آموزشی می‌سازی. متنِ درس: «توضیح»، «مثال» و ' 'تو برای یک درسِ ریاضی (اپِ آموزشی) شکل‌های آموزشی می‌سازی. متنِ درس: «توضیح»، «مثال» و '
'«قدم‌ها» (شماره از صفر). فقط جاهایی شکل بگذار که دیدنش مفهوم را روشن می‌کند (نمودار، ' '«قدم‌ها» (شماره‌ی قدم‌ها از ۱، همان شماره‌ای که کاربر می‌بیند). فقط جاهایی شکل بگذار که دیدنش مفهوم را روشن می‌کند (نمودار، '
'انتقال، تقارن، محور، جدول، هندسه)؛ هر شکل باید دقیقاً همان چیزی را نشان دهد که آن بخش ' 'انتقال، تقارن، محور، جدول، هندسه)؛ هر شکل باید دقیقاً همان چیزی را نشان دهد که آن بخش '
'می‌گوید، با همان اعداد. بخشِ بی‌نیاز شکل نمی‌گیرد؛ اگر هیچ‌جا لازم نبود []. حداکثر ۵ شکل.\n' 'می‌گوید، با همان اعداد. بخشِ بی‌نیاز شکل نمی‌گیرد؛ اگر هیچ‌جا لازم نبود []. حداکثر ۵ شکل.\n'
'خروجی فقط یک آرایه‌ی JSON: [{"where":"intro"|"example"|"step","index":0,"diagram":{...}}] ' 'خروجی فقط یک آرایه‌ی JSON: [{"where":"intro"|"example"|"step","index":0,"diagram":{...}}] '
'(index فقط برای step). بدونِ توضیح و بدونِ ```.\n' '(index فقط برای step و همان شماره‌ی ۱‌به‌بعدِ قدم). بدونِ توضیح و بدونِ ```.\n'
'مثال‌های کاتالوگ فقط قالب‌اند: نقطه، تابع یا آیتمی را که این درس لازم ندارد کپی نکن؛ فقط ' 'مثال‌های کاتالوگ فقط قالب‌اند: نقطه، تابع یا آیتمی را که این درس لازم ندارد کپی نکن؛ فقط '
'چیزهایی بگذار که همین شکل نشان می‌دهد (برای نمودارِ تابع معمولاً فقط items با type=function). نمودارِ خط‌شکسته یا تکه‌ای از نقطه‌ها را ' 'چیزهایی بگذار که همین شکل نشان می‌دهد (برای نمودارِ تابع معمولاً فقط items با type=function). نمودارِ خط‌شکسته یا تکه‌ای از نقطه‌ها را '
'با type=segment بین نقطه‌های متوالی بکش، نه type=line (آن خطِ بی‌پایان است). نقطه‌هایی که ' 'با type=segment بین نقطه‌های متوالی بکش، نه type=line (آن خطِ بی‌پایان است). نقطه‌هایی که '
'در items نمی‌آیند تعریف نکن.\n\n' 'در items نمی‌آیند تعریف نکن. شکلِ هر قدم باید همان چیزی را نشان دهد که متنِ همان قدم می‌گوید '
'(نه قدمِ قبل یا بعد). بازه‌ی x نمودارِ تابع را کوچک بگیر (مثلاً دو واحد دور از رأس/نقطه‌های مهم) تا '
'مقدارِ y از حدود ۹ بیشتر نشود و منحنی له نشود؛ marks فقط برای یک منحنی بگذار تا برچسب‌ها روی هم نیفتند.\n\n'
) )
@@ -57,7 +59,7 @@ class Command(BaseCommand):
spent = prompt_t = out_t = 0 spent = prompt_t = out_t = 0
for lesson in lessons: for lesson in lessons:
body = (f'عنوان: {lesson.title}\nتوضیح: {lesson.intro_text}\nمثال: {lesson.example}\n' body = (f'عنوان: {lesson.title}\nتوضیح: {lesson.intro_text}\nمثال: {lesson.example}\n'
+ '\n'.join(f'قدم {i}: {s}' for i, s in enumerate(lesson.steps or []))) + '\n'.join(f'قدم {i}: {s}' for i, s in enumerate(lesson.steps or [], 1)))
r = client.chat.completions.create( r = client.chat.completions.create(
model=model, **completion_kwargs(model), model=model, **completion_kwargs(model),
messages=[{'role': 'system', 'content': PROMPT + diagram_mod.DIAGRAM_SPEC}, messages=[{'role': 'system', 'content': PROMPT + diagram_mod.DIAGRAM_SPEC},
@@ -80,11 +82,16 @@ class Command(BaseCommand):
where = it.get('where') if isinstance(it, dict) else None where = it.get('where') if isinstance(it, dict) else None
spec = diagram_mod.validate(it.get('diagram')) if where else None spec = diagram_mod.validate(it.get('diagram')) if where else None
idx = it.get('index') idx = it.get('index')
if where == 'step' and isinstance(idx, int):
idx -= 1 # مدل ۱‌به‌بعد می‌نویسد؛ ذخیره از صفر
if (spec is None or where not in ('intro', 'example', 'step') if (spec is None or where not in ('intro', 'example', 'step')
or (where == 'step' and not (isinstance(idx, int) and 0 <= idx < len(lesson.steps or []))) or (where == 'step' and not (isinstance(idx, int) and 0 <= idx < len(lesson.steps or [])))
or (where == 'example' and not lesson.example)): or (where == 'example' and not lesson.example)):
dropped += 1 dropped += 1
continue continue
for item in spec.get('items', []):
if item.get('type') == 'segment':
item.pop('ticks', None) # علامتِ «ضلع مساوی» روی نمودارِ تابع فقط شلوغی است
figures.append({'where': where, **({'index': idx} if where == 'step' else {}), 'diagram': spec}) figures.append({'where': where, **({'index': idx} if where == 'step' else {}), 'diagram': spec})
self.stdout.write(f'درس {lesson.id} «{lesson.title}»: {len(figures)} شکل، {dropped} ردشده') self.stdout.write(f'درس {lesson.id} «{lesson.title}»: {len(figures)} شکل، {dropped} ردشده')
for f in figures: for f in figures:

View File

@@ -20735,18 +20735,34 @@
"axes": true, "axes": true,
"points": { "points": {
"A": [ "A": [
-5.0, -4.0,
0.0 0.0
], ],
"B": [ "B": [
-3.0, -2.0,
1.0 1.0
], ],
"C": [ "C": [
-1.0, 0.0,
1.0 1.0
], ],
"D": [ "D": [
3.0,
0.0
],
"A1": [
-5.0,
0.0
],
"B1": [
-3.0,
1.0
],
"C1": [
-1.0,
1.0
],
"D1": [
2.0, 2.0,
0.0 0.0
] ]
@@ -20769,19 +20785,42 @@
"point": "D" "point": "D"
}, },
{ {
"type": "segment", "type": "point",
"from": "A", "point": "A1",
"to": "B" "color": "red"
},
{
"type": "point",
"point": "B1",
"color": "red"
},
{
"type": "point",
"point": "C1",
"color": "red"
},
{
"type": "point",
"point": "D1",
"color": "red"
}, },
{ {
"type": "segment", "type": "segment",
"from": "B", "from": "A1",
"to": "C" "to": "B1",
"color": "red"
}, },
{ {
"type": "segment", "type": "segment",
"from": "C", "from": "B1",
"to": "D" "to": "C1",
"color": "red"
},
{
"type": "segment",
"from": "C1",
"to": "D1",
"color": "red"
} }
], ],
"grid": true "grid": true
@@ -20789,25 +20828,41 @@
}, },
{ {
"where": "step", "where": "step",
"index": 1, "index": 2,
"diagram": { "diagram": {
"kind": "plane", "kind": "plane",
"title": "انتقال نمودار به سمت پایین", "title": "انتقال نمودار به سمت پایین",
"axes": true, "axes": true,
"points": { "points": {
"A": [ "A1": [
-5.0,
0.0
],
"B1": [
-3.0,
1.0
],
"C1": [
-1.0,
1.0
],
"D1": [
2.0,
0.0
],
"A2": [
-5.0, -5.0,
-3.0 -3.0
], ],
"B": [ "B2": [
-3.0, -3.0,
-2.0 -2.0
], ],
"C": [ "C2": [
-1.0, -1.0,
-2.0 -2.0
], ],
"D": [ "D2": [
2.0, 2.0,
-3.0 -3.0
] ]
@@ -20815,34 +20870,61 @@
"items": [ "items": [
{ {
"type": "point", "type": "point",
"point": "A" "point": "A1",
"color": "red"
}, },
{ {
"type": "point", "type": "point",
"point": "B" "point": "B1",
"color": "red"
}, },
{ {
"type": "point", "type": "point",
"point": "C" "point": "C1",
"color": "red"
}, },
{ {
"type": "point", "type": "point",
"point": "D" "point": "D1",
"color": "red"
},
{
"type": "point",
"point": "A2",
"color": "blue"
},
{
"type": "point",
"point": "B2",
"color": "blue"
},
{
"type": "point",
"point": "C2",
"color": "blue"
},
{
"type": "point",
"point": "D2",
"color": "blue"
}, },
{ {
"type": "segment", "type": "segment",
"from": "A", "from": "A2",
"to": "B" "to": "B2",
"color": "blue"
}, },
{ {
"type": "segment", "type": "segment",
"from": "B", "from": "B2",
"to": "C" "to": "C2",
"color": "blue"
}, },
{ {
"type": "segment", "type": "segment",
"from": "C", "from": "C2",
"to": "D" "to": "D2",
"color": "blue"
} }
], ],
"grid": true "grid": true
@@ -20861,6 +20943,145 @@
"به طور مثال، نقطه (-4,0) ابتدا به (-5,0) منتقل می‌شود و سپس به (-5,-3) می‌رسد.", "به طور مثال، نقطه (-4,0) ابتدا به (-5,0) منتقل می‌شود و سپس به (-5,-3) می‌رسد.",
"همین کار برای سایر نقاط انجام می‌شود و نمودار نهایی به دست می‌آید.", "همین کار برای سایر نقاط انجام می‌شود و نمودار نهایی به دست می‌آید.",
"✅ جواب: نقاط جدید: (-5,-3), (-3,-2), (-1,-2), (2,-3)" "✅ جواب: نقاط جدید: (-5,-3), (-3,-2), (-1,-2), (2,-3)"
],
"figures": [
{
"where": "example",
"diagram": {
"kind": "plane",
"title": "نمودار تابع f",
"axes": true,
"points": {},
"items": [
{
"type": "segment",
"from": [
-4.0,
0.0
],
"to": [
-2.0,
1.0
]
},
{
"type": "segment",
"from": [
-2.0,
1.0
],
"to": [
0.0,
1.0
]
},
{
"type": "segment",
"from": [
0.0,
1.0
],
"to": [
3.0,
0.0
]
}
],
"grid": true
}
},
{
"where": "step",
"index": 0,
"diagram": {
"kind": "plane",
"title": "انتقال نمودار f به سمت چپ",
"axes": true,
"points": {},
"items": [
{
"type": "segment",
"from": [
-5.0,
0.0
],
"to": [
-3.0,
1.0
]
},
{
"type": "segment",
"from": [
-3.0,
1.0
],
"to": [
-1.0,
1.0
]
},
{
"type": "segment",
"from": [
-1.0,
1.0
],
"to": [
2.0,
0.0
]
}
],
"grid": true
}
},
{
"where": "step",
"index": 2,
"diagram": {
"kind": "plane",
"title": "انتقال نمودار به سمت پایین",
"axes": true,
"points": {},
"items": [
{
"type": "segment",
"from": [
-5.0,
-3.0
],
"to": [
-3.0,
-2.0
]
},
{
"type": "segment",
"from": [
-3.0,
-2.0
],
"to": [
-1.0,
-2.0
]
},
{
"type": "segment",
"from": [
-1.0,
-2.0
],
"to": [
2.0,
-3.0
]
}
],
"grid": true
}
}
] ]
}, },
{ {
@@ -20871,7 +21092,7 @@
"where": "intro", "where": "intro",
"diagram": { "diagram": {
"kind": "plane", "kind": "plane",
"title": "انتقال عمودی نمودار تابع", "title": "انتقال عمودی تابع",
"axes": true, "axes": true,
"points": {}, "points": {},
"items": [ "items": [
@@ -20926,15 +21147,15 @@
{ {
"type": "function", "type": "function",
"expr": "(x-2)^2", "expr": "(x-2)^2",
"from": -3.0, "from": -1.0,
"to": 3.0, "to": 5.0,
"marks": [ "marks": [
"vertex" "vertex"
], ],
"label": "y = g(x)" "label": "y = g(x)"
} }
], ],
"grid": true "grid": false
} }
} }
] ]