| """tutor/model_loader.py โ generates child-facing feedback (templates + optional LLM).""" |
| from __future__ import annotations |
| import os, random |
| from typing import Optional |
|
|
| _CORRECT = { |
| "en": ["Amazing work! ๐ You got it!","Superstar! โญ That's exactly right!", |
| "Brilliant! ๐ You're on fire!","Perfect! Keep it up! ๐","You nailed it! ๐"], |
| "fr": ["Bravo ! ๐ C'est exactement รงa !","Super ! โญ Tu es fantastique !", |
| "Excellent ! ๐ Continue comme รงa !","Parfait ! ๐ฅณ Tu es une รฉtoile !"], |
| "kin": ["Byiza cyane! ๐ Wabitsinze!","Ntangaza! โญ Uravuga ukuri!", |
| "Komeza! ๐ Uri inzobere!","Superbe! ๐ฅณ Urashoboye!"], |
| "sw": ["Vizuri sana! ๐ Umeshinda!","Hongera! โญ Jibu sahihi!", |
| "Endelea hivyo! ๐ Umefaulu!","Bora sana! ๐ฅณ Ushindi!"], |
| } |
| _WRONG = { |
| "en": ["Almost! Give it another try ๐ช","Not quite โ you can do it! ๐", |
| "Good try! Think again ๐ค","Keep going โ try once more! ๐ซ"], |
| "fr": ["Presque ! Essaie encore ๐ช","Pas tout ร fait โ tu peux le faire ! ๐", |
| "Bon essai ! Rรฉflรฉchis encore ๐ค"], |
| "kin": ["Hafi! Gerageza nanone ๐ช","Ntabwo ari byo โ gerageza! ๐","Gerageza nanone! ๐ค"], |
| "sw": ["Karibu! Jaribu tena ๐ช","Si sahihi โ unaweza! ๐","Jaribu tena! ๐ค"], |
| } |
|
|
| _sdk_checked = False |
| _sdk_ok = False |
|
|
| def _check_sdk(): |
| global _sdk_checked, _sdk_ok |
| if _sdk_checked: |
| return _sdk_ok |
| _sdk_checked = True |
| try: |
| import anthropic |
| _sdk_ok = bool(os.environ.get("ANTHROPIC_API_KEY")) |
| except ImportError: |
| pass |
| return _sdk_ok |
|
|
| def _llm_feedback(is_correct, answer, lang, child_text) -> Optional[str]: |
| if not _check_sdk(): |
| return None |
| try: |
| import anthropic |
| client = anthropic.Anthropic() |
| outcome = "correct" if is_correct else "incorrect" |
| msg = client.messages.create( |
| model="claude-haiku-4-5-20251001", max_tokens=60, |
| messages=[{"role":"user","content": |
| f"You are a warm math tutor for a child aged 5-9. " |
| f"Child answered '{child_text}', correct answer is {answer}, " |
| f"their answer was {outcome}. Reply in language '{lang}' " |
| f"with ONE short encouraging sentence (max 12 words)."}]) |
| return msg.content[0].text.strip() |
| except Exception: |
| return None |
|
|
| def generate_feedback(is_correct: bool, answer: int, |
| lang: str = "en", child_text: str = "") -> str: |
| llm = _llm_feedback(is_correct, answer, lang, child_text) |
| if llm: |
| return llm |
| bank = _CORRECT if is_correct else _WRONG |
| return random.choice(bank.get(lang, bank["en"])) |
|
|