diagram kit: triangles and quadrilaterals from problem data, shape patterns, translate points, arithmetic/quote/duplicate-key repairs, clock guard (tutor-v10-shape-anchor)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -130,7 +130,7 @@ class DiagramThroughTheApiTests(TestCase):
|
||||
|
||||
message = Message.objects.get(role='assistant', conversation__user_id=self.user.id)
|
||||
self.assertEqual(message.diagram, done['diagram'])
|
||||
self.assertEqual(message.prompt_version, 'tutor-v8-asked-figure')
|
||||
self.assertEqual(message.prompt_version, 'tutor-v10-shape-anchor')
|
||||
history = self.client.get(f'/api/ai/conversations/{done["conversationId"]}/messages').json()
|
||||
self.assertEqual(history['messages'][-1]['diagram']['kind'], 'plane')
|
||||
self.assertIsNone(history['messages'][0]['diagram'])
|
||||
@@ -356,7 +356,7 @@ class FollowUpHintTests(SimpleTestCase):
|
||||
from .services.diagram import ASKED_HINT, DIAGRAM_SPEC, asked_hint_for
|
||||
from .services.generation import build_messages
|
||||
|
||||
last = build_messages('یه باغچه ۵ در ۸ متره، شکلش رو برام بکش', None, 'ششم')[-1]['content']
|
||||
last = build_messages('یه جعبهی کادو دارم، شکلش رو برام بکش', None, 'ششم')[-1]['content']
|
||||
self.assertIn(ASKED_HINT, last)
|
||||
self.assertIn(DIAGRAM_SPEC, last)
|
||||
for q in ('مشکل دارم با این سوال', 'میخوام یه سوال بپرسم', '۳۴۵ × ۱۲'):
|
||||
@@ -390,3 +390,73 @@ class ThirdRoundTests(SimpleTestCase):
|
||||
|
||||
self.assertIn(_PARTS, hint_for('یکپنجم و نُهدهم رو با هم مقایسه کن، کدوم بزرگتره؟'))
|
||||
self.assertNotIn(_PARTS, hint_for('رتبهی پنجمین نفر در مسابقه چند است؟'))
|
||||
|
||||
|
||||
class FourthRoundTests(SimpleTestCase):
|
||||
"""سنجشِ ۲۰۲۶-۰۹-۲۹ (۶۴ مسئلهی تازه): مثلث و چهارضلعی از روی داده، الگوی شکلی، و لغزشهای JSON."""
|
||||
|
||||
def test_triangle_and_quad_from_problem_data(self):
|
||||
from .services.diagram import parse
|
||||
tri = parse('{"kind":"plane","items":[{"type":"triangle","names":["A","B","C"],"sides":{"AB":6,"AC":8},'
|
||||
'"angles":{"A":90},"labels":{"BC":"x","Z":"?"},"altitude":"C"}]}')['items'][0]
|
||||
self.assertEqual(tri['sides'], {'AB': 6.0, 'AC': 8.0})
|
||||
self.assertEqual(tri['labels'], {'BC': 'x'})
|
||||
self.assertEqual(tri['altitude'], 'C')
|
||||
# زاویههایی که جمعشان ۱۸۰ یا بیشتر است مثلث نمیسازند
|
||||
self.assertIsNone(parse('{"kind":"plane","items":[{"type":"triangle","angles":{"A":100,"B":90}}]}'))
|
||||
quad = parse('{"kind":"plane","items":[{"type":"quad","shape":"rhombus","d1":8,"d2":6}]}')['items'][0]
|
||||
self.assertEqual((quad['names'], quad['d1'], quad['d2']), (['A', 'B', 'C', 'D'], 8.0, 6.0))
|
||||
self.assertIsNone(parse('{"kind":"plane","items":[{"type":"quad","shape":"kite","w":3}]}'))
|
||||
|
||||
def test_pattern_kind(self):
|
||||
from .services.diagram import _PATTERN, hint_for, parse
|
||||
spec = parse('{"kind":"pattern","layout":"triangle","unit":"dot","stages":[1,2,3,40],"next":true}')
|
||||
self.assertEqual(spec['stages'], [1, 2, 3, 12])
|
||||
self.assertIn(_PATTERN, hint_for('در الگوی زیر شکلِ ۵ چند چوب کبریت دارد؟'))
|
||||
|
||||
def test_json_slips_seen_in_the_benchmark(self):
|
||||
from .services.diagram import parse
|
||||
# رشتهی بستهنشده پیش از }
|
||||
self.assertEqual(parse('{"kind":"plane","items":[{"type":"segment","from":"A","to":"B","color":"orange}]}')
|
||||
['items'][0]['color'], 'orange')
|
||||
# کلیدِ تکراریِ points: هر دو نگه داشته میشوند
|
||||
spec = parse('{"kind":"plane","points":{"A":[0,0]},"items":[{"type":"point","point":"A"}],"points":{"B":[1,1]}}')
|
||||
self.assertEqual(set(spec['points']), {'A', 'B'})
|
||||
# عددِ کسری بیگیومه؛ برچسبِ «۱۲/۱۸» دست نمیخورد
|
||||
spec = parse('{"kind":"plane","items":[{"type":"function","expr":"x^2","from":-5/3,"to":5/3,"label":"12/18"}]}')
|
||||
self.assertAlmostEqual(spec['items'][0]['from'], -5 / 3, places=4)
|
||||
self.assertEqual(spec['items'][0]['label'], '12/18')
|
||||
self.assertEqual(parse('{"kind":"compare","compare":[{"parts":5,"shaded":1},{"parts":10,"shaded":9}]}')['kind'],
|
||||
'fraction')
|
||||
|
||||
def test_real_world_geometry_words_get_the_plane_section(self):
|
||||
from .services.diagram import _PLANE, hint_for
|
||||
for q in ('نردبانی به طولِ ۵ متر به دیوار تکیه داده شده', 'زمینی به طولِ ۲۰ و عرضِ ۱۲ متر'):
|
||||
self.assertIn(_PLANE, hint_for(q), q)
|
||||
|
||||
|
||||
class FifthRoundTests(SimpleTestCase):
|
||||
"""نگهبانِ ساعت، نقطهی انتقال، جای شکل."""
|
||||
|
||||
def test_clock_only_for_telling_time(self):
|
||||
from .services.diagram import _CLOCK, fits, hint_for
|
||||
clock = {'kind': 'clock', 'title': '', 'hour': 0, 'minute': 12}
|
||||
self.assertIsNone(fits('۲۰ درصد یک ساعت چند دقیقه است؟', clock))
|
||||
self.assertEqual(fits('ساعت ۳ و ۲۵ دقیقه را روی ساعت نشان بده', clock), clock)
|
||||
self.assertNotIn(_CLOCK, hint_for('۲۰ درصد یک ساعت چند دقیقه است؟'))
|
||||
self.assertEqual(fits('حالا ۱۰ دقیقه بعد؟\n\nساعت ۳ و ۲۵ دقیقه', clock), clock)
|
||||
self.assertIsNone(fits('x', None))
|
||||
|
||||
def test_translate_point_and_shape_anchor(self):
|
||||
from .services.diagram import parse
|
||||
spec = parse('{"kind":"plane","points":{"A":[0,0],"B":{"translate":[2,3],"from":"A"}},'
|
||||
'"items":[{"type":"quad","shape":"square","side":2,"at":[5,0]}]}')
|
||||
self.assertEqual(spec['points']['B'], {'translate': [2.0, 3.0], 'from': 'A'})
|
||||
self.assertEqual(spec['items'][0]['at'], [5.0, 0.0])
|
||||
|
||||
def test_shape_name_as_kind_with_aliases(self):
|
||||
from .services.diagram import parse
|
||||
item = parse('{"kind":"trapezoid","title":"ذوزنقه","bases":[10,6],"height":4,"color":"blue"}')['items'][0]
|
||||
self.assertEqual((item['type'], item['shape'], item['w'], item['top'], item['h']), ('quad', 'trapezoid', 10.0, 6.0, 4.0))
|
||||
item = parse('{"kind":"rectangle","length":8,"width":5}')['items'][0]
|
||||
self.assertEqual((item['w'], item['h']), (8.0, 5.0))
|
||||
|
||||
Reference in New Issue
Block a user