aciang commited on
Commit
cb4a7d6
·
verified ·
1 Parent(s): 4344237

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. README.md +2 -2
  2. app.py +53 -79
  3. requirements.txt +0 -5
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: LanguageBridge — Math Hybrid (Phi + SymPy)
3
  emoji: 🧮
4
  colorFrom: yellow
5
  colorTo: blue
@@ -9,4 +9,4 @@ app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- 混合路線:先用 SymPy 精準解(代數 / 化簡 / 微積分),必要時用 Phi LLM 補步驟與敘述。
 
1
  ---
2
+ title: LanguageBridge — Math Fast Agent (SymPy, Robust)
3
  emoji: 🧮
4
  colorFrom: yellow
5
  colorTo: blue
 
9
  pinned: false
10
  ---
11
 
12
+ SymPy 的數學推理小助手:支援一次貼上長式、因式分解、微分/積分,並能從多行敘述中自動擷取真正的方程行。**不依賴 torch**,可在 CPU Basic 上穩定運作。
app.py CHANGED
@@ -1,49 +1,47 @@
1
 
2
- import os, re
3
  import gradio as gr
4
  import sympy as sp
5
 
6
- TITLE = "LanguageBridge — Math Hybrid (Phi + SymPy)"
7
- MODEL_ID = "microsoft/phi-2"
8
 
9
- _pipe = None
 
 
 
10
 
11
- def lazy_load_llm():
12
- global _pipe
13
- if _pipe is not None:
14
- return _pipe
15
- try:
16
- import torch
17
- from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
18
- use_cuda = torch.cuda.is_available()
19
- tok = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
20
- if tok.pad_token_id is None and tok.eos_token_id is not None:
21
- tok.pad_token = tok.eos_token
22
- model = AutoModelForCausalLM.from_pretrained(
23
- MODEL_ID,
24
- torch_dtype=torch.float32,
25
- device_map="cuda" if use_cuda else "cpu"
26
- )
27
- _pipe = pipeline(
28
- "text-generation",
29
- model=model,
30
- tokenizer=tok,
31
- device=0 if use_cuda else -1
32
- )
33
- return _pipe
34
- except Exception:
35
- return None
36
 
37
- def solve_with_sympy(q: str) -> str:
38
- q = (q or "").strip()
39
  if not q:
40
- return "請輸入算式或方程,例如:2x+5=11;或:sin(x)**2 + cos(x)**2;或:factor(x**2-9)"
 
41
  try:
42
- if "=" in q:
43
- parts = [s.strip() for seg in q.split(";") for s in seg.split("\n")]
 
44
  eqs, syms = [], set()
45
- for s in parts:
46
- if not s:
47
  continue
48
  left, right = s.split("=", 1)
49
  eq = sp.Eq(sp.sympify(left), sp.sympify(right))
@@ -53,14 +51,16 @@ def solve_with_sympy(q: str) -> str:
53
  syms |= eq.rhs.free_symbols
54
  if not syms:
55
  syms = {sp.symbols("x")}
56
- sols = sp.solve(eqs, list(syms), dict=True)
57
- if not sols:
58
- return "(SymPy)無解或需要更多條件。"
59
  lines = []
60
- for i, s in enumerate(sols, 1):
61
- lines.append(f"解 {i}: " + ", ".join([f"{k} = {sp.simplify(v)}" for k, v in s.items()]))
 
62
  return "\n".join(lines)
63
 
 
64
  expr = sp.sympify(q)
65
  out = []
66
  try:
@@ -68,9 +68,9 @@ def solve_with_sympy(q: str) -> str:
68
  except Exception:
69
  pass
70
  try:
71
- fctr = sp.factor(expr)
72
- if fctr != expr:
73
- out.append(f"因式分解:{fctr}")
74
  except Exception:
75
  pass
76
  try:
@@ -80,44 +80,18 @@ def solve_with_sympy(q: str) -> str:
80
  except Exception:
81
  pass
82
  return "\n".join(out) if out else f"結果:{expr}"
83
- except Exception as e:
84
- return f"(SymPy 解析失敗) {e}"
85
 
86
- def hybrid_solve(q: str, max_new_tokens: int, temperature: float, top_p: float):
87
- q = (q or "").strip()
88
- sym = solve_with_sympy(q)
89
- if sym and not sym.startswith("(SymPy 解析失敗)"):
90
- return sym
91
-
92
- pipe = lazy_load_llm()
93
- if pipe is None:
94
- return sym + "\n\n(提示) LLM 尚未就緒或未安裝 torch/transformers,僅回傳 SymPy 嘗試結果。"
95
-
96
- prompt = f"請閱讀題目並用中文說明步驟,最後給出答案。\n題目:{q}\n"
97
- outs = pipe(
98
- prompt,
99
- max_new_tokens=max_new_tokens,
100
- do_sample=True if temperature>0 else False,
101
- top_p=top_p,
102
- temperature=temperature,
103
- repetition_penalty=1.05,
104
- pad_token_id=pipe.tokenizer.eos_token_id,
105
- )
106
- txt = outs[0]["generated_text"]
107
- return txt[len(prompt):].strip()
108
 
109
  with gr.Blocks(title=TITLE) as demo:
110
- gr.Markdown(f"## {TITLE}\n貼上文字題或算式:LLM 解析 → SymPy 精算(可聯立)")
111
- with gr.Row():
112
- q = gr.Textbox(lines=7, label="題目 / 算式(可含聯立方程)",
113
- placeholder="例如:一個數加 5 等於 11,求此數;\n或:2x+5=11;或:sin(x)**2+cos(x)**2")
114
- with gr.Accordion("進階(LLM 生成)", open=False):
115
- mx_tok = gr.Slider(32, 256, value=128, step=8, label="max_new_tokens")
116
- temp = gr.Slider(0.0, 1.2, value=0.3, step=0.05, label="temperature")
117
- top_p = gr.Slider(0.1, 1.0, value=0.9, step=0.05, label="top_p")
118
  out = gr.Textbox(lines=12, label="輸出")
119
  btn = gr.Button("送出 🚀")
120
- btn.click(hybrid_solve, inputs=[q, mx_tok, temp, top_p], outputs=out, concurrency_limit=1)
121
- gr.Markdown("**小技巧**:先輸入方程/算式讓 SymPy 直接求;純文字題會呼叫 LLM 先轉譯再解。")
122
 
123
- demo.launch(max_threads=8)
 
 
 
1
 
2
+ import re
3
  import gradio as gr
4
  import sympy as sp
5
 
6
+ TITLE = "LanguageBridge — Math Fast Agent (SymPy, Robust)"
 
7
 
8
+ # ---- 全形轉半形表 ----
9
+ FULL2HALF = str.maketrans({
10
+ "+":"+","-":"-","*":"*","/":"/","^":"^","=":"=",",":",","(":"(",")":")",":":":",";":";","×":"*"
11
+ })
12
 
13
+ def _normalize(text: str) -> str:
14
+ t = (text or "").translate(FULL2HALF)
15
+ t = t.replace("\u3000"," ").strip()
16
+ return t
17
+
18
+ def _pick_equation_lines(text: str):
19
+ # 挑出真正像方程式的行(含 '='),過濾純敘述行。
20
+ eq_lines = []
21
+ for ln in text.splitlines():
22
+ s = ln.strip()
23
+ if not s:
24
+ continue
25
+ if "=" in s and re.search(r"[A-Za-z0-9πe]|[+\-*/^()]", s):
26
+ eq_lines.append(s)
27
+ if not eq_lines:
28
+ m = re.search(r"([^\n=]+=[^\n=]+)", text)
29
+ if m:
30
+ eq_lines.append(m.group(1).strip())
31
+ return eq_lines
 
 
 
 
 
 
32
 
33
+ def solve_math(q: str):
34
+ q = _normalize(q)
35
  if not q:
36
+ return "請輸入算式或方程,例如:2x+3=11;或:sin(x)**2 + cos(x)**2;或:factor(x**2-9)"
37
+
38
  try:
39
+ # 先嘗試方程/聯立模式
40
+ eq_lines = _pick_equation_lines(q)
41
+ if eq_lines:
42
  eqs, syms = [], set()
43
+ for s in eq_lines:
44
+ if "=" not in s:
45
  continue
46
  left, right = s.split("=", 1)
47
  eq = sp.Eq(sp.sympify(left), sp.sympify(right))
 
51
  syms |= eq.rhs.free_symbols
52
  if not syms:
53
  syms = {sp.symbols("x")}
54
+ sol = sp.solve(eqs, list(syms), dict=True)
55
+ if not sol:
56
+ return "無解或需要更多條件。"
57
  lines = []
58
+ for i, s in enumerate(sol, 1):
59
+ items = [f"{k} = {sp.simplify(v)}" for k, v in s.items()]
60
+ lines.append(f"解 {i}: " + ", ".join(items))
61
  return "\n".join(lines)
62
 
63
+ # 無等號:表達式模式 → 給常見操作
64
  expr = sp.sympify(q)
65
  out = []
66
  try:
 
68
  except Exception:
69
  pass
70
  try:
71
+ fac = sp.factor(expr)
72
+ if fac != expr:
73
+ out.append(f"因式分解:{fac}")
74
  except Exception:
75
  pass
76
  try:
 
80
  except Exception:
81
  pass
82
  return "\n".join(out) if out else f"結果:{expr}"
 
 
83
 
84
+ except Exception as e:
85
+ return f"(SymPy 解析失敗) {e}\n(提示)若要讓 LLM 協助長敘述理解,請改用混合版或安裝 torch/transformers。"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  with gr.Blocks(title=TITLE) as demo:
88
+ gr.Markdown(f"## {TITLE}\n貼上算式(可多行;含敘述亦可,系統會自動擷取方程式):")
89
+ q = gr.Textbox(lines=6, label="題目 / 算式(可含聯立方程或敘述)")
 
 
 
 
 
 
90
  out = gr.Textbox(lines=12, label="輸出")
91
  btn = gr.Button("送出 🚀")
92
+ # 使用 concurrency_limit 代替舊的 concurrency_count,避免 Spaces 日誌警告/報錯
93
+ btn.click(fn=solve_math, inputs=q, outputs=out, concurrency_limit=2)
94
 
95
+ # 在本地執行才 launch;Spaces 會自動匯入 app.py
96
+ if __name__ == "__main__":
97
+ demo.launch(share=True, max_threads=2)
requirements.txt CHANGED
@@ -1,8 +1,3 @@
1
  gradio==4.44.1
2
  sympy>=1.12
3
- torch==2.1.2
4
- transformers==4.41.2
5
- accelerate==0.31.0
6
- safetensors>=0.4.3
7
- sentencepiece>=0.1.99
8
  huggingface_hub>=0.24.0
 
1
  gradio==4.44.1
2
  sympy>=1.12
 
 
 
 
 
3
  huggingface_hub>=0.24.0