From a8cd681d655f6d900fbed34475440d3bb1d5e417 Mon Sep 17 00:00:00 2001 From: Zareian Date: Tue, 29 Sep 2026 03:34:12 +0330 Subject: [PATCH] an explicit 'draw it' request without topic words gets the whole diagram catalog (tutor-v8-asked-figure) Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 4 +++- rag/services/diagram.py | 17 +++++++++++++++++ rag/services/generation.py | 5 +++-- rag/tests_diagram.py | 12 +++++++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8393b86..a73c727 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -401,7 +401,9 @@ anyone who can read this repo can forge a token for any user.** می‌کند؛ HTML/SVGِ مدل هرگز وارد صفحه نمی‌شود. ۱۴ نوع (plane، numberline، fraction، grid، groups، clock، bar/linechart/pie، table، venn، mapping، tree، solid)؛ گالریِ آزمایشی در `?gallery` فقط در حالتِ توسعه. کاتالوگ بخش‌بخش است و کنارِ هر سوال فقط بخشِ مربوط می‌رود - (`hint_for`). پرامپت `tutor-v6-diagrams`. سنجش روی ۹۶ مسئله‌ی واقعیِ کتاب: ۴۵ از ۴۸ شکلِ + (`hint_for`)؛ سوالِ ادامه‌ای بخشِ سوالِ قبلی را می‌گیرد (`follow_up_hint_for`)، و درخواستِ صریحِ + «شکلش رو بکش» بی‌کلمه‌ی موضوعی کلِ کاتالوگ را (`asked_hint_for`، پرامپت `tutor-v8-asked-figure`؛ + یک بار با GapGPT آزموده شد: مستطیلِ باغچه). فرانت هیچ تشخیصی نمی‌دهد. پرامپت `tutor-v6-diagrams`. سنجش روی ۹۶ مسئله‌ی واقعیِ کتاب: ۴۵ از ۴۸ شکلِ معتبر (دورِ ۲)، ۰ از ۸ برای سوالِ بی‌شکل؛ وارسیِ چشمیِ ۸۳ شکل: ۶۴ درست، ۳ ضعیف، ۱۶ غلط. اصلاح‌های بعد از آن (خط از معادله، کسرِ مقایسه‌ای، محرکِ ساعت، …) روی مدل سنجیده نشده‌اند. - **فرانت آزمونِ جزیره را بازی می‌کند** (`/nodes/{id}/quiz`); خانه خودِ مسیر است با «شروع». diff --git a/rag/services/diagram.py b/rag/services/diagram.py index 522f482..c59b65d 100644 --- a/rag/services/diagram.py +++ b/rag/services/diagram.py @@ -177,6 +177,23 @@ def follow_up_hint_for(question: str, previous: str) -> str: return '\n'.join([FOLLOW_UP_HINT, _HEAD, *parts]) +# «شکلش رو بکش» بی‌هیچ کلمه‌ی موضوعی (و بی‌سوالِ شکل‌دارِ قبلی): نمی‌دانیم کدام بخش، +# پس کلِ کاتالوگ می‌رود (~۱٬۹۰۰ توکن). نادر است، چون بیشترِ درخواست‌ها کلمه‌ی موضوعی دارند. +# مرزِ پیش از کلمه لازم است: «مشکل» و «بپرسم» نباید درخواستِ شکل شمرده شوند. +_ASK_FIGURE = re.compile(r'(?… را ' + 'طبقِ این قالب بگذار؛ اگر ندارد، کوتاه بگو که این مسئله شکل ندارد.' +) + + +def asked_hint_for(question: str) -> str: + """درخواستِ صریحِ شکل وقتی هیچ بخشی از کاتالوگ با سوال (یا سوالِ قبلی) نخورد.""" + if not _ASK_FIGURE.search(question or ''): + return '' + return '\n'.join([ASKED_HINT, DIAGRAM_SPEC]) + + def hint_for(question: str) -> str: """یادآوری و فقط آن بخش‌هایی از کاتالوگ که به همین سوال می‌خورند؛ سوالِ بی‌شکل → ''.""" text = question or '' diff --git a/rag/services/generation.py b/rag/services/generation.py index d4371c5..14dcde4 100644 --- a/rag/services/generation.py +++ b/rag/services/generation.py @@ -38,7 +38,7 @@ _RAW_MARKUP = re.compile(r'\\[A-Za-z(\[]|\$|\*\*|^\s*#{1,6}\s|^\s*\|\s*:?-{3,}', # بشود گفت «کدام نسخه‌ی پرامپت جوابِ بهتری می‌داد» — بدونِ این، همه‌ی فیدبک‌ها # در یک کاسه می‌ریزند و مقایسه‌ی نسخه‌ها ممکن نیست. کشِ پاسخ هم با همین نسخه # کلید می‌خورد، پس جوابِ نسخه‌ی قبلی بعد از دیپلوی دوباره سرو نمی‌شود. -PROMPT_VERSION = 'tutor-v7-diagram-kit' +PROMPT_VERSION = 'tutor-v8-asked-figure' _PRIMARY = {'اول', 'دوم', 'سوم', 'چهارم', 'پنجم', 'ششم'} _MIDDLE = {'هفتم', 'هشتم', 'نهم'} @@ -184,7 +184,8 @@ def _user_prompt(question: str, contexts: list[str], focus: str = '', asked = (f'{asked}\n(این ادامه‌ی گفتگوست؛ سوالِ قبلیِ دانش‌آموز: «{previous[:300]}». ' 'اگر به آن مربوط است، همان مسئله را با تغییرِ خواسته‌شده حل کن.)') shape_hint = (diagram_mod.hint_for(f'{question}\n{focus}') - or diagram_mod.follow_up_hint_for(question, previous)) + or diagram_mod.follow_up_hint_for(question, previous) + or diagram_mod.asked_hint_for(question)) if shape_hint: asked = f'{asked}\n\n{shape_hint}' slash_rule = primary and '/' in question diff --git a/rag/tests_diagram.py b/rag/tests_diagram.py index 21ae97e..3e6b697 100644 --- a/rag/tests_diagram.py +++ b/rag/tests_diagram.py @@ -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-v7-diagram-kit') + self.assertEqual(message.prompt_version, 'tutor-v8-asked-figure') 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']) @@ -352,6 +352,16 @@ class FollowUpHintTests(SimpleTestCase): self.assertIn(DIAGRAM_HINT, last) self.assertNotIn(FOLLOW_UP_HINT, last) + def test_explicit_request_without_topic_words_gets_the_whole_catalog(self): + from .services.diagram import ASKED_HINT, DIAGRAM_SPEC, asked_hint_for + from .services.generation import build_messages + + last = build_messages('یه باغچه ۵ در ۸ متره، شکلش رو برام بکش', None, 'ششم')[-1]['content'] + self.assertIn(ASKED_HINT, last) + self.assertIn(DIAGRAM_SPEC, last) + for q in ('مشکل دارم با این سوال', 'می‌خوام یه سوال بپرسم', '۳۴۵ × ۱۲'): + self.assertEqual(asked_hint_for(q), '', q) + class ThirdRoundTests(SimpleTestCase): """از چتِ واقعی با gpt-4.1-mini (۲۰۲۶-۰۹-۲۹): خط، چندضلعیِ منتظم، زاویه‌ی خارجی، کسرِ کلمه‌ای."""