Upload folder using huggingface_hub
Browse files- README.md +2 -2
- app.py +53 -79
- requirements.txt +0 -5
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title: LanguageBridge — Math
|
| 3 |
emoji: 🧮
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: blue
|
|
@@ -9,4 +9,4 @@ app_file: app.py
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
| 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
|
| 3 |
import gradio as gr
|
| 4 |
import sympy as sp
|
| 5 |
|
| 6 |
-
TITLE
|
| 7 |
-
MODEL_ID = "microsoft/phi-2"
|
| 8 |
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
def
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
)
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
tokenizer=tok,
|
| 31 |
-
device=0 if use_cuda else -1
|
| 32 |
-
)
|
| 33 |
-
return _pipe
|
| 34 |
-
except Exception:
|
| 35 |
-
return None
|
| 36 |
|
| 37 |
-
def
|
| 38 |
-
q = (q
|
| 39 |
if not q:
|
| 40 |
-
return "請輸入算式或方程,例如:2x+
|
|
|
|
| 41 |
try:
|
| 42 |
-
|
| 43 |
-
|
|
|
|
| 44 |
eqs, syms = [], set()
|
| 45 |
-
for s in
|
| 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 |
-
|
| 57 |
-
if not
|
| 58 |
-
return "
|
| 59 |
lines = []
|
| 60 |
-
for i, s in enumerate(
|
| 61 |
-
|
|
|
|
| 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 |
-
|
| 72 |
-
if
|
| 73 |
-
out.append(f"因式分解:{
|
| 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 |
-
|
| 87 |
-
|
| 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
|
| 111 |
-
|
| 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 |
-
|
| 121 |
-
|
| 122 |
|
| 123 |
-
|
|
|
|
|
|
|
|
|
| 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
|