import gradio as gr import sympy as sp def default_symbols(): names = ["x","y","z","t","theta","a","b","c","n","m"] d = {name: sp.symbols(name, real=True) for name in names} d["pi"] = sp.pi d["e"] = sp.E d["sqrt"] = sp.sqrt return d def parse_constraints(parts, syms): cons = [] for p in parts: s = p.strip() if not s: continue try: rel = sp.sympify(s, locals=syms) cons.append(rel) except Exception: pass return cons def solve_line(txt): syms = default_symbols() # constraints after comma: "eq, 0 <= theta < 2*pi" if "," in txt: main = txt.split(",", 1)[0].strip() cons = parse_constraints(txt.split(",")[1:].copy(), syms) else: main = txt.strip() cons = [] if not main: return "Empty input." if "=" in main: left, right = main.split("=", 1) try: eq = sp.Eq(sp.sympify(left, locals=syms), sp.sympify(right, locals=syms)) except Exception as e: return f"Parse equation failed: {e}" vars_set = set(eq.free_symbols) if not vars_set: vars_set = {sp.symbols("x", real=True)} vars_list = list(vars_set) # try solveset on first var with simple real-domain extraction if cons: v = vars_list[0] domain = sp.S.Reals try: # If constraints form an And of relationals, keep as boolean condition. cond = cons[0] for c in cons[1:]: cond = sp.And(cond, c) # best-effort: do not over-process; pass domain=Reals sol = sp.solveset(eq, v, domain=domain) return f"solveset({v} in Reals): {sp.simplify(sol)}" except Exception: pass try: sols = sp.solve([eq], vars_list, dict=True) if not sols: return "No solution or need more conditions." lines = [] for i, s in enumerate(sols, 1): parts = [] for k, v in s.items(): parts.append(f"{k} = {sp.simplify(v)}") lines.append("Solution " + str(i) + ": " + ", ".join(parts)) return "\n".join(lines) except Exception as e: return f"Solve failed: {e}" # pure expression branch try: expr = sp.sympify(main, locals=syms) except Exception as e: return f"Parse failed: {e}" out = [] try: out.append("Simplify: " + str(sp.simplify(expr))) except Exception: pass try: fact = sp.factor(expr) if fact != expr: out.append("Factor: " + str(fact)) except Exception: pass try: v = list(expr.free_symbols)[0] if expr.free_symbols else sp.symbols("x", real=True) out.append("d/d" + str(v) + ": " + str(sp.diff(expr, v))) out.append("Integral d" + str(v) + ": " + str(sp.integrate(expr, v))) except Exception: pass if out: return "\n".join(out) return "Result: " + str(expr) def solve_math(q): q = (q or "").strip() if not q: return "Enter expression(s) or equation(s). Use semicolons or newlines to separate.\nExamples:\n 2*x + 5 = 11\n sin(theta) = sqrt(3)/2, 0 <= theta < 2*pi\n factor(x**4 - 1)" segs = [] for line in q.splitlines(): segs.extend([p for p in line.split(";")]) segs = [s.strip() for s in segs if s.strip()] outputs = [] for s in segs: outputs.append(">>> " + s + "\n" + solve_line(s)) return "\n\n".join(outputs) with gr.Blocks(title="LanguageBridge — Math Fast Agent (SymPy)") as demo: gr.Markdown("# LanguageBridge — Math Fast Agent (SymPy)") gr.Markdown("Paste expressions or equations. Add constraints after a comma. Examples:\n- 2*x + 5 = 11\n- sin(theta) = sqrt(3)/2, 0 <= theta < 2*pi\n- factor(x**4 - 1)") q = gr.Textbox(lines=6, label="Problem / Expression (semicolon or newline for systems)") out = gr.Textbox(lines=12, label="Output") btn = gr.Button("Solve") btn.click(fn=solve_math, inputs=q, outputs=out) if __name__ == "__main__": demo.launch(share=True)