# domain/curriculum_classifier.py import sympy as sp import logging logger = logging.getLogger(__name__) class CurriculumClassifier: """ V6.1 Hybrid Architecture - Phase 1: Router Layer Evaluates math complexity and injects grade-specific pedagogical prompts. """ @staticmethod def estimate_complexity(math_string: str) -> int: """ Calculates a complexity score (1-10) based on AST features. """ score = 1 try: # Parse multiple equations if necessary expressions = [] # Helper to quickly strip common LaTeX that crashes sympify import re cleaned_str = re.sub(r'\\[a-zA-Z]+', '', str(math_string)) cleaned_str = cleaned_str.replace('{', '(').replace('}', ')').replace('$', '') for part in cleaned_str.split(','): expressions.append(sp.sympify(part.replace('=', '-'), evaluate=False)) for expr in expressions: # Number of variables vars_count = len(expr.free_symbols) if vars_count > 1: score += vars_count # Number of operations / tree depth mapping (approx) ops_count = expr.count_ops() score += ops_count // 3 # Advanced functions (Trigonometry, Logarithms) if expr.has(sp.sin, sp.cos, sp.tan, sp.log, sp.exp): score += 3 # High degree polynomials if expr.is_polynomial(): degrees = sp.degree_list(expr) max_deg = max(degrees) if degrees else 0 if max_deg > 2: score += 2 except Exception as e: # Fallback heuristic if SymPy parse fails entirely raw_len = len(str(math_string)) fallback_score = 3 + (raw_len // 15) logger.warning(f"Complexity estimation failed, falling back to len heuristic ({fallback_score}): {e}") score = fallback_score final_score = min(max(int(score), 1), 10) logger.info(f"[ROUTER] Intended Math Complexity Score: {final_score}/10") return final_score @staticmethod def get_prompt_specialization(grade: str, intent_category: str) -> str: """ Returns pedagogical prompt constraints based on the student's grade. """ grade_num = 0 import re match = re.search(r'\d+', str(grade)) if match: grade_num = int(match.group()) constraints = [] # Base setup constraints.append("אתה מורה פרטי למתמטיקה.") # Grade specific logic if grade_num <= 7: constraints.append("הסבר במונחים פשוטים מאוד. אל תשתמש במילים כמו 'נבודד' או 'נפשט', אלא 'נשאיר את הנעלם לבד' או 'נחשב את המספרים'.") elif grade_num <= 9: constraints.append("השתמש במונחי אלגברה תקניים כמו 'העברת אגפים', 'כינוס איברים דומים', ו'בידוד משתנה'. שמור על שפה מעודדת.") elif grade_num <= 12: constraints.append("הנח כי התלמיד מכיר מושגי יסוד באלגברה. התמקד בהיגיון העמוק של התרגיל ובחוקים המתמטיים (למשל חוקי חזקות, זהויות). הייה רשמי ומדויק.") if "TRIGONOMETRY" in intent_category.upper(): constraints.append("במשוואות טריגונומטריות, הבהר תמיד את שיקולי המחזוריות או מעגל היחידה.") else: constraints.append("הסבר בבהירות ובצורה ישירה.") specialization = " ".join(constraints) logger.info(f"[ROUTER] Prompt specialization applied for Grade {grade} ({intent_category})") return specialization