aciang commited on
Commit
374899e
·
verified ·
1 Parent(s): ac21aca

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. README.md +3 -8
  2. _rebuild_ping.txt +1 -0
  3. app.py +48 -161
  4. requirements.txt +1 -8
README.md CHANGED
@@ -1,17 +1,12 @@
1
  ---
2
- title: LanguageBridge — Math Hybrid (Phi + SymPy)
3
  emoji: 🧮
4
  colorFrom: yellow
5
- colorTo: blue
6
  sdk: gradio
7
  sdk_version: "4.44.1"
8
  app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- 一個**小型 LLM(Phi-2 / Phi-3-mini)+ SymPy** 的數學混合推理 Space:
13
- - LLM:把**文字題**解析為可計算的數學式或步驟
14
- - SymPy:遇到**可符號計算**的部分(方程、微積分、因式分解…)直接算出精準解
15
- - 自動偵測:若輸入就是算式/方程 → 直接 SymPy;否則走 LLM→SymPy 流程
16
-
17
- > 預設模型:`microsoft/phi-2`(可在 app.py 換成你喜歡的小型模型)
 
1
  ---
2
+ title: LanguageBridge — Math Fast Agent (SymPy)
3
  emoji: 🧮
4
  colorFrom: yellow
5
+ colorTo: gray
6
  sdk: gradio
7
  sdk_version: "4.44.1"
8
  app_file: app.py
9
  pinned: false
10
  ---
11
 
12
+ SymPy 的數學推理代理(不依賴 LLM),支援一次貼上長式、簡化、解一元/聯立方程。
 
 
 
 
 
_rebuild_ping.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 1762069998.8309631
app.py CHANGED
@@ -1,181 +1,68 @@
1
- import os, sys, re, json
2
  import gradio as gr
3
  import sympy as sp
4
 
5
- from transformers import (
6
- AutoTokenizer, AutoModelForCausalLM, pipeline
7
- )
8
 
9
- TITLE = "LanguageBridge — Math Hybrid (Phi + SymPy)"
10
- MODEL_ID = "microsoft/phi-2"
11
- MAX_NEW_TOKENS = 512
12
-
13
- def try_sympy_direct(q: str):
14
- """若使用者輸入就是算式/方程,走 SymPy 精準計算。支援多行 / 分號分隔 / 聯立。"""
15
  q = (q or "").strip()
16
  if not q:
17
- return None
18
-
19
- # 粗略偵測:若含 = 或 明顯算式符號
20
- if any(s in q for s in ["=", "+", "-", "*", "/", "^", "sin", "cos", "tan", "log", "sqrt", "∫", "d/dx"]):
21
- try:
22
- # 支援多式/聯立:以分號或換行切
23
  parts = [s.strip() for seg in q.split(";") for s in seg.split("\n")]
24
  eqs, syms = [], set()
25
  for s in parts:
26
  if not s:
27
  continue
28
- if "=" in s:
29
- left, right = s.split("=", 1)
30
- eq = sp.Eq(sp.sympify(left), sp.sympify(right))
31
- eqs.append(eq)
32
- syms |= eq.free_symbols
33
- syms |= eq.rhs.free_symbols if hasattr(eq, "rhs") else set()
34
- else:
35
- # 非方程,當作一般表達式,做一輪常見操作
36
- expr = sp.sympify(s)
37
- tips = []
38
- try:
39
- tips.append(f"簡化:{sp.simplify(expr)}")
40
- except Exception:
41
- pass
42
- try:
43
- x = list(expr.free_symbols)[0] if expr.free_symbols else sp.symbols("x")
44
- tips.append(f" {x} 微分:{sp.diff(expr, x)}")
45
- tips.append(f"對 {x} 積分:{sp.integrate(expr, x)}")
46
- except Exception:
47
- pass
48
- if tips:
49
- return "\n".join(tips) # 只要有一行就回傳
50
- else:
51
- return f"結果:{expr}"
52
-
53
- if eqs:
54
- if not syms:
55
- x = sp.symbols("x")
56
- syms = {x}
57
- sol = sp.solve(eqs, list(syms), dict=True)
58
- if not sol:
59
- return "SymPy:無解或需要更多條件。"
60
- lines = []
61
- for i, sdict in enumerate(sol, 1):
62
- lines.append("解 {}: ".format(i) + ", ".join([f"{k} = {sp.simplify(v)}" for k, v in sdict.items()]))
63
- return "\n".join(lines)
64
-
65
- except Exception as e:
66
- # 交給 LLM 流程
67
- return None
68
-
69
- return None
70
-
71
-
72
- def build_llm():
73
- """嘗試以 4-bit 啟動(有 CUDA 時),否則退回 CPU。"""
74
- import torch
75
- has_cuda = torch.cuda.is_available()
76
- load_kwargs = {"device_map":"auto"}
77
-
78
- if has_cuda:
79
  try:
80
- import bitsandbytes as bnb # 檢查有無 bnb
81
- load_kwargs.update({"load_in_4bit": True})
82
  except Exception:
83
- # 沒有 bnb 就用 fp16
84
- load_kwargs.update({"torch_dtype": torch.float16})
85
- else:
86
- # CPU:讓 transformers 自行決定 dtype
87
- pass
88
-
89
- tok = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
90
- if tok.pad_token_id is None and tok.eos_token_id is not None:
91
- tok.pad_token = tok.eos_token
92
-
93
- mdl = AutoModelForCausalLM.from_pretrained(
94
- MODEL_ID,
95
- trust_remote_code=True,
96
- **load_kwargs
97
- )
98
-
99
- pipe = pipeline(
100
- "text-generation",
101
- model=mdl,
102
- tokenizer=tok,
103
- do_sample=False,
104
- max_new_tokens=MAX_NEW_TOKENS,
105
- temperature=0.2,
106
- top_p=0.9
107
- )
108
- return pipe
109
-
110
- LLM = None
111
-
112
- SYSTEM_PROMPT = (
113
- "You are a math teacher. When the user asks a word problem,\n"
114
- "1) parse it into a clean mathematical expression or a system of equations;\n"
115
- "2) if it is solvable by SymPy, output a single line starting with 'SymPy:' followed by a Python/SymPy expression;\n"
116
- "3) then give a concise final answer on the next line starting with 'Answer:'."
117
- )
118
-
119
- def llm_to_sympy_and_answer(pipe, q: str):
120
- prompt = (
121
- f"<s>System:\n{SYSTEM_PROMPT}\n</s>\n"
122
- f"User: {q}\n"
123
- f"Assistant:"
124
- )
125
- out = pipe(prompt, pad_token_id=pipe.tokenizer.eos_token_id)[0]["generated_text"]
126
- # 嘗試抓 SymPy: 行
127
- sym_line = None
128
- ans_line = None
129
- for line in out.splitlines():
130
- if line.strip().startswith("SymPy:"):
131
- sym_line = line.split("SymPy:",1)[-1].strip()
132
- if line.strip().startswith("Answer:"):
133
- ans_line = line.split("Answer:",1)[-1].strip()
134
-
135
- checked = ""
136
- if sym_line:
137
  try:
138
- val = eval(sym_line, {"sp": sp, "sympy": sp})
139
- # 若是可列印的結果(非方程),試著數值化或簡化
140
- if isinstance(val, (int, float, sp.Basic)):
141
- checked = f"SymPy 檢算:{sp.simplify(val)}"
142
- except Exception as e:
143
- checked = f"SymPy 檢算失敗:{e}"
144
-
145
- merge = []
146
- if sym_line: merge.append(f"SymPy: {sym_line}")
147
- if ans_line: merge.append(f"Answer: {ans_line}")
148
- if checked: merge.append(checked)
149
- return "\n".join(merge) if merge else out
150
-
151
-
152
- def solve(q: str):
153
- global LLM
154
- q = (q or "").strip()
155
- if not q:
156
- return "請輸入題目或算式。"
157
-
158
- # 1) 先嘗試 SymPy 直接處理
159
- direct = try_sympy_direct(q)
160
- if direct:
161
- return direct
162
-
163
- # 2) 走 LLM → SymPy
164
- if LLM is None:
165
- LLM = build_llm()
166
- try:
167
- return llm_to_sympy_and_answer(LLM, q)
168
  except Exception as e:
169
- return f"[LLM流程失敗] {e}"
170
 
171
  with gr.Blocks(title=TITLE) as demo:
172
- gr.Markdown(f"## {TITLE}\n貼上文字題或算式:LLM 解析 SymPy 精算(可聯立)")
173
- with gr.Row():
174
- q = gr.Textbox(label="題目 / 算式", lines=8, placeholder="例如:一個數加上 5 等於 11,求這個數。\n或:2*x + 5 = 11;或:sin(x)**2 + cos(x)**2")
175
- with gr.Row():
176
- out = gr.Textbox(label="輸出", lines=12)
177
- btn = gr.Button("送出 🚀")
178
- btn.click(fn=solve, inputs=q, outputs=out)
179
 
180
  if __name__ == "__main__":
181
  demo.launch()
 
1
+ \
2
  import gradio as gr
3
  import sympy as sp
4
 
5
+ TITLE = "LanguageBridge — Math Fast Agent (SymPy)"
 
 
6
 
7
+ def solve_math(q: str):
 
 
 
 
 
8
  q = (q or "").strip()
9
  if not q:
10
+ return "請輸入算式或方程,例如:2x+3=11;或:sin(x)**2 + cos(x)**2;或:factor(x**2-9)"
11
+ try:
12
+ # 支援方程/聯立:可用分號或換行分隔
13
+ if "=" in q:
 
 
14
  parts = [s.strip() for seg in q.split(";") for s in seg.split("\n")]
15
  eqs, syms = [], set()
16
  for s in parts:
17
  if not s:
18
  continue
19
+ if "=" not in s:
20
+ continue
21
+ left, right = s.split("=", 1)
22
+ eq = sp.Eq(sp.sympify(left), sp.sympify(right))
23
+ eqs.append(eq)
24
+ syms |= eq.free_symbols
25
+ if hasattr(eq, "rhs"):
26
+ syms |= eq.rhs.free_symbols
27
+ if not syms:
28
+ x = sp.symbols("x")
29
+ syms = {x}
30
+ sol = sp.solve(eqs, list(syms), dict=True)
31
+ if not sol:
32
+ return "無解或需要更多條件。"
33
+ lines = []
34
+ for i, s in enumerate(sol, 1):
35
+ lines.append(f" {i}: " + ", ".join([f"{k} = {sp.simplify(v)}" for k, v in s.items()]))
36
+ return "\n".join(lines)
37
+
38
+ # 非方程:做一輪常見操作
39
+ expr = sp.sympify(q)
40
+ tips = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  try:
42
+ tips.append(f"簡化:{sp.simplify(expr)}")
 
43
  except Exception:
44
+ tips.append(f"簡化:{expr}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  try:
46
+ fact = sp.factor(expr)
47
+ if fact != expr:
48
+ tips.append(f"因式分解:{fact}")
49
+ except Exception:
50
+ pass
51
+ try:
52
+ x = list(expr.free_symbols)[0] if expr.free_symbols else sp.symbols("x")
53
+ tips.append(f"對 {x} 微分:{sp.diff(expr, x)}")
54
+ tips.append(f" {x} 積分:{sp.integrate(expr, x)}")
55
+ except Exception:
56
+ pass
57
+ return "\n".join(tips) if tips else f"結果:{expr}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  except Exception as e:
59
+ return f"解析失敗:{e}"
60
 
61
  with gr.Blocks(title=TITLE) as demo:
62
+ gr.Markdown(f"## {TITLE}\n貼上算式(可多行 / 用分號 `;` 分隔):")
63
+ q = gr.Textbox(lines=6, label="題目 / 算式(可含聯立方程)")
64
+ out = gr.Textbox(lines=10, label="輸出")
65
+ gr.Button("送出 🚀").click(fn=solve_math, inputs=q, outputs=out)
 
 
 
66
 
67
  if __name__ == "__main__":
68
  demo.launch()
requirements.txt CHANGED
@@ -1,10 +1,3 @@
1
  gradio==4.44.1
2
- transformers==4.44.2
3
- accelerate>=0.31.0
4
- bitsandbytes==0.43.3
5
- sentencepiece
6
  sympy>=1.12
7
- huggingface_hub>=0.24.0
8
- safetensors
9
- einops
10
- numpy<2
 
1
  gradio==4.44.1
 
 
 
 
2
  sympy>=1.12
3
+ huggingface_hub==0.23.4