File size: 3,570 Bytes
0531f23
5c5cb4d
2f94119
 
5c5cb4d
 
 
 
2f94119
3e7998b
2f94119
0531f23
5c5cb4d
 
0531f23
 
 
5c5cb4d
 
 
 
 
 
0531f23
 
5c5cb4d
 
0531f23
5c5cb4d
 
 
0531f23
5c5cb4d
 
 
 
 
 
 
 
 
3e7998b
 
 
0531f23
e87a45f
3e7998b
0531f23
5c5cb4d
 
 
0531f23
5c5cb4d
f09d15a
3e7998b
5c5cb4d
 
 
0531f23
3e7998b
5c5cb4d
3e7998b
 
 
0531f23
e87a45f
5c5cb4d
 
8a4e70b
0531f23
5c5cb4d
 
cf28e8a
 
8a4e70b
f09d15a
cf28e8a
 
3e7998b
5c5cb4d
 
 
cf28e8a
0531f23
e87a45f
3e7998b
 
2f94119
3e7998b
5c5cb4d
 
0531f23
5c5cb4d
3e7998b
5c5cb4d
f09d15a
2f94119
 
e87a45f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

import re
import gradio as gr
import sympy as sp
from sympy.parsing.sympy_parser import (
    parse_expr, standard_transformations,
    implicit_multiplication_application, convert_xor
)

TITLE = "LanguageBridge — Math Fast Agent (SymPy)"

# ---- 僅做安全正規化:全形→半形、^→**、√→sqrt ----
def normalize_ascii(s: str) -> str:
    table = str.maketrans({
        "(":"(", ")":")", ",":",", ";":";", ":":":",
        "=":"=", "-":"-", "+":"+", "*":"*", "/":"/", "。":".",
        "×":"*", "√":"sqrt"
    })
    return s.translate(table)

def preprocess(expr: str) -> str:
    s = (expr or "").strip()
    s = normalize_ascii(s)
    s = s.replace("^", "**")  # 2^3 -> 2**3
    # ⛔ 不再自動補 *,避免把 sin(x) 變成 sin*(x)
    return s

# SymPy 解析:啟用隱式乘法與 ^ 號處理
TRANS = standard_transformations + (implicit_multiplication_application, convert_xor)

def to_sympy_expr(s: str):
    return parse_expr(preprocess(s), transformations=TRANS)

def to_sympy_eq(s: str):
    s = preprocess(s)
    if "=" not in s:
        raise ValueError("等式缺少 '='")
    L, R = s.split("=", 1)
    return sp.Eq(parse_expr(L, transformations=TRANS),
                 parse_expr(R, transformations=TRANS))

def solve_math(q: str):
    q = (q or "").strip()
    if not q:
        return "請輸入算式或方程,例如:3x+7=1;sin(x)^2+cos(x)^2;factor(x^4-1)"

    try:
        # 多行 / 分號;分隔
        parts = [s.strip() for seg in q.split(";") for s in seg.split("\n")]
        parts = [p for p in parts if p]

        # 任何一行有 '=' → 解(可聯立)
        if any("=" in p for p in parts):
            eqs, syms = [], set()
            for s in parts:
                if "=" in s:
                    e = to_sympy_eq(s)
                    eqs.append(e)
                    syms |= e.free_symbols | getattr(e, "rhs", sp.Integer(0)).free_symbols
            if not syms:
                syms = {sp.symbols("x")}
            sol = sp.solve(eqs, list(syms), dict=True)
            if not sol:
                return "無解或需要更多條件。"
            return "\n".join(
                f"解 {i}: " + ", ".join([f"{k} = {sp.simplify(v)}" for k, v in d.items()])
                for i, d in enumerate(sol, 1)
            )

        # 否則:一般表達式(簡化/因式/微分/積分)
        expr = to_sympy_expr(q)
        out = []
        try: out.append(f"簡化:{sp.simplify(expr)}")
        except Exception: out.append(f"簡化:{expr}")
        try:
            fact = sp.factor(expr)
            if fact != expr: out.append(f"因式分解:{fact}")
        except Exception: pass
        try:
            x = next(iter(expr.free_symbols)) if expr.free_symbols else sp.symbols("x")
            out.append(f"對 {x} 微分:{sp.diff(expr, x)}")
            out.append(f"對 {x} 積分:{sp.integrate(expr, x)}")
        except Exception: pass
        return "\n".join(out) if out else f"結果:{expr}"

    except Exception as e:
        return f"解析失敗:{e}"

with gr.Blocks(title=TITLE) as demo:
    gr.Markdown(
        "## " + TITLE + "\\n"
        "貼上算式(可多行 / 分號 `;` 分隔)。支援隱式乘法(例:`3x`, `2(x+1)`, `(x+1)(x-1)`, `2sqrt(x)`)與 `^`。"
    )
    q = gr.Textbox(lines=6, label="題目 / 算式(可含聯立方程)")
    out = gr.Textbox(lines=12, label="輸出")
    gr.Button("送出 🚀").click(fn=solve_math, inputs=q, outputs=out)

if __name__ == "__main__":
    demo.launch()