| import sympy as sp |
|
|
| class MathContext: |
| """ |
| A sandbox for the LLM to execute mathematics. |
| Each operation is recorded with Hebrew context and exact LaTeX representation. |
| """ |
| def __init__(self): |
| self.steps = [] |
| |
| |
| self.sp = sp |
| self.Eq = sp.Eq |
| self.solve = sp.solve |
| self.expand = sp.expand |
| self.simplify = sp.simplify |
| self.sqrt = sp.sqrt |
| self.diff = sp.diff |
|
|
| def _format_latex(self, expr) -> str: |
| """Converts SymPy to precise LaTeX, without $$ so it renders correctly in Flutter.""" |
| if isinstance(expr, str): |
| |
| try: |
| expr = sp.sympify(expr) |
| except: |
| pass |
|
|
| latex_str = sp.latex(expr) |
| return latex_str |
|
|
| def explain(self, text: str): |
| """Adds a pure Hebrew explanation step without math.""" |
| self.steps.append({ |
| "content_mixed": text, |
| "block_math": "" |
| }) |
|
|
| def declare_equation(self, text: str, eq: sp.Eq): |
| """Prints a known equation with its explanation.""" |
| self.steps.append({ |
| "content_mixed": text, |
| "block_math": self._format_latex(eq) |
| }) |
| return eq |
|
|
| def expand_expr(self, text: str, expr): |
| """Expands an expression completely (e.g. squaring a root).""" |
| expanded = sp.expand(expr) |
| self.steps.append({ |
| "content_mixed": text, |
| "block_math": self._format_latex(expanded) |
| }) |
| return expanded |
|
|
| def solve_equation(self, text: str, eq: sp.Eq, var): |
| """Solves an equation for a specific variable.""" |
| solutions = sp.solve(eq, var) |
| |
| |
| if isinstance(solutions, list): |
| if len(solutions) == 1: |
| math_result = sp.Eq(var, solutions[0]) |
| else: |
| |
| parts = [f"{sp.latex(var)}_{{{i+1}}} = {sp.latex(sol)}" for i, sol in enumerate(solutions)] |
| math_result = " \\text{ 讜讗讜 } ".join(parts) |
| else: |
| math_result = sp.Eq(var, solutions) |
|
|
| self.steps.append({ |
| "content_mixed": text, |
| "block_math": math_result if isinstance(math_result, str) else self._format_latex(math_result) |
| }) |
| return solutions |
|
|
| def finish(self, final_answer: str, teacher_summary: str = ""): |
| """Sets the final human-readable answer for the UI.""" |
| self.final_answer = final_answer |
| self.teacher_summary = teacher_summary |
|
|
| def run_llm_code(python_code: str) -> dict: |
| """ |
| Executes the LLM-generated Python code in our secure MathContext. |
| Returns the step-by-step UI format required by BuddyMath. |
| """ |
| ctx = MathContext() |
| |
| |
| safe_globals = { |
| "ctx": ctx, |
| "x": sp.Symbol('x'), |
| "y": sp.Symbol('y'), |
| "a": sp.Symbol('a'), |
| "b": sp.Symbol('b'), |
| "c": sp.Symbol('c'), |
| "m": sp.Symbol('m'), |
| "R": sp.Symbol('R'), |
| "sp": sp, |
| } |
|
|
| try: |
| |
| exec(python_code, safe_globals) |
| |
| return { |
| "success": True, |
| "steps": ctx.steps, |
| "final_answer": getattr(ctx, 'final_answer', "讛讙注谞讜 诇驻转专讜谉."), |
| "teacher_summary": getattr(ctx, 'teacher_summary', "") |
| } |
| except Exception as e: |
| return { |
| "success": False, |
| "error": str(e) |
| } |
|
|
| if __name__ == "__main__": |
| |
| |
| |
| llm_code = """ |
| ctx.explain("谞住诪谉 讗转 讛谞拽讜讚讛 讛讻诇诇讬转 注诇 讛诪拽讜诐 讛讙讬讗讜诪讟专讬 讻- (x,y). 诇驻讬 讛谞转讜谉, 讛诪专讞拽 诪讛诪讜拽讚 砖讜讜讛 诇诪专讞拽 诪讛诪讚专讬讱.") |
| d1 = sp.sqrt((x - 2)**2 + (y - 0)**2) # 诪讜拽讚 |
| d2 = sp.sqrt((x - (-2))**2) # 诪讚专讬讱 |
| |
| eq1 = ctx.declare_equation("讛诪砖讜讜讗讛 讛诪砖讜讜讛 讘讬谉 讛诪专讞拽讬诐 讛讬讗:", ctx.Eq(d1, d2)) |
| |
| ctx.explain("谞注诇讛 讗转 砖谞讬 讛讗讙驻讬诐 讘专讬讘讜注 讻讚讬 诇讛讬驻讟专 诪讛砖讜专砖:") |
| # SymPy understands squaring both sides! We square them and declare equality. |
| squared_eq = ctx.Eq(d1**2, d2**2) |
| ctx.steps[-1]["block_math"] = ctx._format_latex(squared_eq) # Override previous block math |
| |
| # Now expand and simplify it beautifully |
| expanded_eq = ctx.declare_equation("谞专讞讬讘 讗转 讛讘讬讟讜讬讬诐 (驻转讬讞转 住讜讙专讬讬诐 诪诇讗讛):", ctx.Eq(ctx.expand(squared_eq.lhs), ctx.expand(squared_eq.rhs))) |
| |
| # SymPy's powerful simplify equation solver (subtract RHS from LHS) |
| simplified_expr = ctx.simplify(expanded_eq.lhs - expanded_eq.rhs) |
| final_eq = ctx.declare_equation("诇讗讞专 讻讬谞讜住 讗讬讘专讬诐 讜讛注讘专转 讗讙驻讬诐, 谞拽讘诇 讗转 爪讜专转 讛驻专讘讜诇讛 讛驻砖讜讟讛:", ctx.Eq(simplified_expr, 0)) |
| |
| # Also isolate y^2 if needed |
| y_sq_isolated = ctx.solve(final_eq, y**2) |
| if y_sq_isolated: |
| ctx.declare_equation("谞讘讜讚讚 讗转 y^2 讘诪砖讜讜讗讛:", ctx.Eq(y**2, y_sq_isolated[0])) |
| |
| ctx.finish("$$ y^2 = 8x $$") |
| """ |
| |
| print("馃殌 Running LLM Mathematics Script:") |
| result = run_llm_code(llm_code) |
| |
| import json |
| |
| print(json.dumps(result, indent=2, ensure_ascii=False)) |
|
|