redraw the figure on follow-ups that only change the numbers; add a local fake OpenAI server
"What if 6 were 4?" has no shape word, so the diagram hint never went next to it and the tutor would answer without a new figure. When the previous user question in the conversation had one, a soft hint (redraw only if this continues that problem) and the same catalog sections now go along. tools/fake_openai.py stands in for GapGPT locally so the whole tutor path can be exercised without credit: 12 scripted answers across grades 6-12 went through streaming, block splitting, repair, storage, history and rendering in the real chat screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -148,6 +148,27 @@ DIAGRAM_HINT = (
|
||||
)
|
||||
|
||||
|
||||
FOLLOW_UP_HINT = (
|
||||
'اگر این سوال ادامهی همان مسئلهی شکلدارِ قبلی است (عدد یا اندازه عوض شده، یا توضیحِ بیشتر '
|
||||
'خواسته)، در پایانِ پاسخ شکلِ تازه را با عددهای تازه در بلوکِ <diagram>…</diagram> بکش؛ '
|
||||
'اگر نیست، شکل نگذار.'
|
||||
)
|
||||
|
||||
|
||||
def follow_up_hint_for(question: str, previous: str) -> str:
|
||||
"""
|
||||
سوالِ ادامهای بیکلمهی شکلدار («اگه بهجای ۶ بذاریم ۴ چی؟») بعد از یک سوالِ شکلدار:
|
||||
یادآوریِ نرم (نه «این سوال شکل دارد») و بخشهای کاتالوگِ همان سوالِ قبلی. نرم است چون
|
||||
«مرسی» بعد از یک سوالِ هندسه نباید شکل بگیرد.
|
||||
"""
|
||||
if not previous or not (question or '').strip():
|
||||
return ''
|
||||
parts = [section for pattern, section in SECTIONS if pattern.search(previous)]
|
||||
if not parts:
|
||||
return ''
|
||||
return '\n'.join([FOLLOW_UP_HINT, _HEAD, *parts])
|
||||
|
||||
|
||||
def hint_for(question: str) -> str:
|
||||
"""یادآوری و فقط آن بخشهایی از کاتالوگ که به همین سوال میخورند؛ سوالِ بیشکل → ''."""
|
||||
text = question or ''
|
||||
|
||||
@@ -176,9 +176,10 @@ _SLASH_READING = (
|
||||
|
||||
|
||||
def _user_prompt(question: str, contexts: list[str], focus: str = '',
|
||||
primary: bool = False) -> str:
|
||||
primary: bool = False, previous: str = '') -> str:
|
||||
asked = f'سوالِ دانشآموز: {question}'
|
||||
shape_hint = diagram_mod.hint_for(f'{question}\n{focus}')
|
||||
shape_hint = (diagram_mod.hint_for(f'{question}\n{focus}')
|
||||
or diagram_mod.follow_up_hint_for(question, previous))
|
||||
if shape_hint:
|
||||
asked = f'{asked}\n\n{shape_hint}'
|
||||
slash_rule = primary and '/' in question
|
||||
@@ -250,8 +251,11 @@ def build_messages(question: str, context_chunks: list[dict] | None,
|
||||
text = (turn.get('text') or '').strip()
|
||||
if text:
|
||||
messages.append({'role': role, 'content': text[:_HISTORY_CHARS]})
|
||||
# سوالِ قبلیِ کاربر: «اگه بهجای ۶ بذاریم ۴ چی؟» کلمهی شکلدار ندارد، ولی ادامهی
|
||||
# همان مسئلهی شکلدار است و شکلش باید با عددِ تازه دوباره کشیده شود.
|
||||
previous = next((t.get('text') or '' for t in reversed(history or []) if t.get('role') == 'user'), '')
|
||||
messages.append({'role': 'user', 'content': _user_prompt(
|
||||
question, contexts, focus, primary=grade_tier(grade_title) == 'primary')})
|
||||
question, contexts, focus, primary=grade_tier(grade_title) == 'primary', previous=previous)})
|
||||
return messages
|
||||
|
||||
|
||||
|
||||
@@ -320,3 +320,34 @@ class SecondRoundKindsTests(SimpleTestCase):
|
||||
self.assertNotIn(_CLOCK, hint_for('فاطمه ۶ ساعت کتاب خواند. چند صفحه ماند؟'))
|
||||
self.assertIn(_CLOCK, hint_for('عقربهی ساعتشمار روی ۳ است. ساعت چند است؟'))
|
||||
self.assertIn(_CLOCK, hint_for('ساعت ۳ و ۲۵ دقیقه را روی ساعت نشان بده'))
|
||||
|
||||
|
||||
class FollowUpHintTests(SimpleTestCase):
|
||||
"""«اگه بهجای ۶ بذاریم ۴ چی؟» بعد از یک سوالِ شکلدار هم شکلِ تازه میخواهد."""
|
||||
|
||||
def test_follow_up_without_shape_words_gets_the_soft_hint(self):
|
||||
from .services.diagram import FOLLOW_UP_HINT, _GRAPH
|
||||
from .services.generation import build_messages
|
||||
|
||||
history = [{'role': 'user', 'text': 'ریشهها و رأسِ سهمیِ y = x² − 5x + 6 را پیدا کن'},
|
||||
{'role': 'assistant', 'text': '…'}]
|
||||
last = build_messages('اگه بهجای ۶ بذاریم ۴ چی میشه؟', None, 'یازدهم', history=history)[-1]['content']
|
||||
self.assertIn(FOLLOW_UP_HINT, last)
|
||||
self.assertIn(_GRAPH, last)
|
||||
|
||||
def test_no_hint_without_a_shape_question_before(self):
|
||||
from .services.diagram import FOLLOW_UP_HINT
|
||||
from .services.generation import build_messages
|
||||
|
||||
history = [{'role': 'user', 'text': 'حاصلِ ۲۳ × ۴۵ چند است؟'}, {'role': 'assistant', 'text': '۱۰۳۵'}]
|
||||
last = build_messages('اگه ۲۴ باشه چی؟', None, 'هشتم', history=history)[-1]['content']
|
||||
self.assertNotIn(FOLLOW_UP_HINT, last)
|
||||
|
||||
def test_a_shape_question_keeps_the_strong_hint(self):
|
||||
from .services.diagram import DIAGRAM_HINT, FOLLOW_UP_HINT
|
||||
from .services.generation import build_messages
|
||||
|
||||
history = [{'role': 'user', 'text': 'مثلثی با ضلعهای ۳ و ۴'}]
|
||||
last = build_messages('حالا دایرهای به شعاعِ ۲', None, 'نهم', history=history)[-1]['content']
|
||||
self.assertIn(DIAGRAM_HINT, last)
|
||||
self.assertNotIn(FOLLOW_UP_HINT, last)
|
||||
|
||||
Reference in New Issue
Block a user