MasteredUltraInstinct commited on
Commit
6884711
Β·
verified Β·
1 Parent(s): f6f4cb0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -46
app.py CHANGED
@@ -36,24 +36,22 @@ def clean_latex(latex):
36
  for wrong, correct in replacements.items():
37
  latex = re.sub(wrong, correct, latex)
38
 
39
- # βœ… Fix mathcal and cal variables in all formats
40
  latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Xx]\s*\}?', 'x', latex)
41
  latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Yy]\s*\}?', 'y', latex)
42
  latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Zz]\s*\}?', 'z', latex)
43
-
44
- # βœ… Clean OCR artifacts like "cal X"
45
  latex = latex.replace('cal x', 'x').replace('cal X', 'x')
46
  latex = latex.replace('mathcal x', 'x').replace('mathcal X', 'x')
47
 
48
- # 🧹 Remove curly braces and punctuation
49
  latex = latex.replace('{', '').replace('}', '')
50
- latex = latex.strip().rstrip(',.') # remove trailing punctuation
51
 
52
- # βœ… Symbolic constants: keep pi and E as symbols
53
- latex = latex.replace(r'\pi', 'pi')
54
  latex = re.sub(r'(?<![a-zA-Z0-9])e(?![a-zA-Z0-9])', 'E', latex)
55
 
56
- # βœ… Add multiplication
57
  latex = re.sub(r'(\d)([a-zA-Z])', r'\1*\2', latex) # 4x β†’ 4*x
58
  latex = re.sub(r'(\d+)\s*i', r'\1*I', latex)
59
  latex = re.sub(r'(?<![a-zA-Z0-9])i(?![a-zA-Z0-9])', 'I', latex)
@@ -66,18 +64,18 @@ def clean_latex(latex):
66
  # βœ… Final cleanup
67
  latex = re.sub(r'[^\w\s^=+*\-().]', '', latex)
68
 
69
- # βœ… Ensure it's an equation
 
 
 
70
  if '=' not in latex:
71
  latex += '=0'
72
 
73
  return latex
74
 
75
-
76
  # Fallback to external LLM microservice
77
  def request_llm_fallback(bad_latex, llm_url):
78
- pre_cleaned = re.sub(
79
- r'(\\!?pm|\\not=?|\\!|\\L|\\perp|\\bar|\\Sigma|\\boldmath|G|L(?=\^))', '', bad_latex
80
- )
81
  try:
82
  response = requests.post(f"{llm_url}/clean", json={"prompt": pre_cleaned})
83
  if response.status_code == 200:
@@ -86,7 +84,7 @@ def request_llm_fallback(bad_latex, llm_url):
86
  print(f"LLM fallback failed: {e}")
87
  return pre_cleaned
88
 
89
- # NEW: Request human-style explanation
90
  def request_llm_explanation(latex, llm_url):
91
  try:
92
  response = requests.post(f"{llm_url}/explain", json={"prompt": latex})
@@ -97,7 +95,7 @@ def request_llm_explanation(latex, llm_url):
97
  except Exception as e:
98
  return f"❌ LLM explanation error: {e}"
99
 
100
- # Main function
101
  def solve_polynomial(image, llm_url):
102
  try:
103
  img = preprocess_handwritten_image(image)
@@ -110,19 +108,14 @@ def solve_polynomial(image, llm_url):
110
 
111
  try:
112
  expr = parse_latex(cleaned_latex)
113
-
114
  if not isinstance(expr, sp.Equality):
115
  raise ValueError("Expression is not an equation.")
116
-
117
  lhs_minus_rhs = expr.lhs - expr.rhs
118
  if not lhs_minus_rhs.is_polynomial():
119
- raise ValueError("Expression is not a polynomial.")
120
-
121
  junk_symbols = {"pm", "cdot", "mathrm", "boldmath", "bar", "L"}
122
- symbols = {str(s) for s in expr.free_symbols}
123
- if symbols & junk_symbols:
124
- raise ValueError("Expression contains junk symbols.")
125
-
126
  except Exception:
127
  fixed_latex = request_llm_fallback(cleaned_latex, llm_url)
128
  cleaned_latex = clean_latex(fixed_latex)
@@ -130,29 +123,21 @@ def solve_polynomial(image, llm_url):
130
  expr = parse_latex(cleaned_latex)
131
  if not isinstance(expr, sp.Equality):
132
  raise ValueError("Expression is not an equation.")
133
-
134
  lhs_minus_rhs = expr.lhs - expr.rhs
135
  if not lhs_minus_rhs.is_polynomial():
136
- raise ValueError("Expression is not a polynomial.")
137
-
138
- symbols = {str(s) for s in expr.free_symbols}
139
- if symbols & junk_symbols:
140
- raise ValueError("Expression contains junk symbols.")
141
-
142
  except Exception:
143
  expr = None
144
 
145
  if expr is None:
146
- return (
147
- f"❌ Could not parse expression even after fallback:\n\n```latex\n{cleaned_latex}\n```",
148
- cleaned_latex,
149
- ""
150
- )
151
 
152
  output = (
153
- f"## πŸ“„ Extracted LaTeX\n\n```latex\n{latex_result}\n```\n"
154
- f"\n---\n## 🧹 Cleaned LaTeX Used\n\n```latex\n{cleaned_latex}\n```\n"
155
- f"\n---\n## 🧠 Parsed Expression\n\n$$ {sp.latex(expr)} $$\n\n---\n"
156
  )
157
 
158
  if isinstance(expr, sp.Equality):
@@ -160,17 +145,15 @@ def solve_polynomial(image, llm_url):
160
  output += f"## ✏️ Step 1: Standard Form\n$$ {sp.latex(lhs)} = 0 $$\n---\n"
161
  output += f"## 🧩 Step 2: Factor\n$$ {sp.latex(sp.factor(lhs))} = 0 $$\n---\n"
162
 
163
- # βœ… SOLVE FOR x BY NAME ONLY
164
  x_sym = None
165
  for sym in lhs.free_symbols:
166
  if str(sym) == "x":
167
  x_sym = sym
168
  break
169
  if x_sym is None:
170
- raise ValueError("❌ Could not find variable 'x' in the equation.")
171
 
172
  roots = sp.solve(sp.Eq(lhs, 0), x_sym, dict=True)
173
-
174
  output += "## βœ… Step 3: Solve Roots\n"
175
  if roots:
176
  output += "$$\n\\begin{aligned}\n"
@@ -187,11 +170,11 @@ def solve_polynomial(image, llm_url):
187
 
188
  except Exception as e:
189
  return f"❌ **Error**: {str(e)}", "", ""
190
-
191
- # UI
192
  with gr.Blocks() as demo:
193
- llm_url = gr.Textbox(label="πŸ”— Enter LLM Microservice URL (from Colab)", placeholder="https://xxxx.ngrok-free.app")
194
- image_input = gr.Image(type="pil", label="πŸ“· Upload Image of Polynomial")
195
  output_box = gr.Markdown(label="πŸ“‹ Step-by-step Solution")
196
  explain_box = gr.Markdown(label="πŸ—£οΈ Human-style Explanation")
197
  hidden_latex = gr.Textbox(visible=False)
@@ -207,7 +190,7 @@ with gr.Blocks() as demo:
207
  explain_btn.click(fn=request_llm_explanation, inputs=[hidden_latex, llm_url], outputs=explain_box)
208
 
209
  demo.title = "🧠 Polynomial Solver from Image"
210
- demo.description = "Upload a polynomial image (typed or handwritten). View symbolic steps and human-style explanation."
211
 
212
  if __name__ == "__main__":
213
  demo.launch()
 
36
  for wrong, correct in replacements.items():
37
  latex = re.sub(wrong, correct, latex)
38
 
39
+ # βœ… Fix mathcal and cal variables
40
  latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Xx]\s*\}?', 'x', latex)
41
  latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Yy]\s*\}?', 'y', latex)
42
  latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Zz]\s*\}?', 'z', latex)
 
 
43
  latex = latex.replace('cal x', 'x').replace('cal X', 'x')
44
  latex = latex.replace('mathcal x', 'x').replace('mathcal X', 'x')
45
 
46
+ # 🧹 Remove curly braces and trailing punctuation
47
  latex = latex.replace('{', '').replace('}', '')
48
+ latex = latex.strip().rstrip(',.')
49
 
50
+ # βœ… Replace symbolic constants and protect them
51
+ latex = latex.replace(r'\pi', 'SYMPY_PI') # protect pi
52
  latex = re.sub(r'(?<![a-zA-Z0-9])e(?![a-zA-Z0-9])', 'E', latex)
53
 
54
+ # βœ… Add multiplication without breaking pi
55
  latex = re.sub(r'(\d)([a-zA-Z])', r'\1*\2', latex) # 4x β†’ 4*x
56
  latex = re.sub(r'(\d+)\s*i', r'\1*I', latex)
57
  latex = re.sub(r'(?<![a-zA-Z0-9])i(?![a-zA-Z0-9])', 'I', latex)
 
64
  # βœ… Final cleanup
65
  latex = re.sub(r'[^\w\s^=+*\-().]', '', latex)
66
 
67
+ # βœ… Restore pi
68
+ latex = latex.replace('SYMPY_PI', 'pi')
69
+
70
+ # βœ… Ensure equation
71
  if '=' not in latex:
72
  latex += '=0'
73
 
74
  return latex
75
 
 
76
  # Fallback to external LLM microservice
77
  def request_llm_fallback(bad_latex, llm_url):
78
+ pre_cleaned = re.sub(r'(\\!?pm|\\not=?|\\!|\\L|\\perp|\\bar|\\Sigma|\\boldmath|G|L(?=\^))', '', bad_latex)
 
 
79
  try:
80
  response = requests.post(f"{llm_url}/clean", json={"prompt": pre_cleaned})
81
  if response.status_code == 200:
 
84
  print(f"LLM fallback failed: {e}")
85
  return pre_cleaned
86
 
87
+ # Explanation
88
  def request_llm_explanation(latex, llm_url):
89
  try:
90
  response = requests.post(f"{llm_url}/explain", json={"prompt": latex})
 
95
  except Exception as e:
96
  return f"❌ LLM explanation error: {e}"
97
 
98
+ # Main solver
99
  def solve_polynomial(image, llm_url):
100
  try:
101
  img = preprocess_handwritten_image(image)
 
108
 
109
  try:
110
  expr = parse_latex(cleaned_latex)
 
111
  if not isinstance(expr, sp.Equality):
112
  raise ValueError("Expression is not an equation.")
 
113
  lhs_minus_rhs = expr.lhs - expr.rhs
114
  if not lhs_minus_rhs.is_polynomial():
115
+ raise ValueError("Not a polynomial.")
 
116
  junk_symbols = {"pm", "cdot", "mathrm", "boldmath", "bar", "L"}
117
+ if {str(s) for s in expr.free_symbols} & junk_symbols:
118
+ raise ValueError("Contains junk.")
 
 
119
  except Exception:
120
  fixed_latex = request_llm_fallback(cleaned_latex, llm_url)
121
  cleaned_latex = clean_latex(fixed_latex)
 
123
  expr = parse_latex(cleaned_latex)
124
  if not isinstance(expr, sp.Equality):
125
  raise ValueError("Expression is not an equation.")
 
126
  lhs_minus_rhs = expr.lhs - expr.rhs
127
  if not lhs_minus_rhs.is_polynomial():
128
+ raise ValueError("Not a polynomial.")
129
+ if {str(s) for s in expr.free_symbols} & junk_symbols:
130
+ raise ValueError("Contains junk.")
 
 
 
131
  except Exception:
132
  expr = None
133
 
134
  if expr is None:
135
+ return f"❌ Could not parse even after fallback:\n\n```latex\n{cleaned_latex}\n```", cleaned_latex, ""
 
 
 
 
136
 
137
  output = (
138
+ f"## πŸ“„ Extracted LaTeX\n```latex\n{latex_result}\n```\n"
139
+ f"\n---\n## 🧹 Cleaned LaTeX Used\n```latex\n{cleaned_latex}\n```\n"
140
+ f"\n---\n## 🧠 Parsed Expression\n$$ {sp.latex(expr)} $$\n---\n"
141
  )
142
 
143
  if isinstance(expr, sp.Equality):
 
145
  output += f"## ✏️ Step 1: Standard Form\n$$ {sp.latex(lhs)} = 0 $$\n---\n"
146
  output += f"## 🧩 Step 2: Factor\n$$ {sp.latex(sp.factor(lhs))} = 0 $$\n---\n"
147
 
 
148
  x_sym = None
149
  for sym in lhs.free_symbols:
150
  if str(sym) == "x":
151
  x_sym = sym
152
  break
153
  if x_sym is None:
154
+ raise ValueError("❌ Could not find variable 'x'.")
155
 
156
  roots = sp.solve(sp.Eq(lhs, 0), x_sym, dict=True)
 
157
  output += "## βœ… Step 3: Solve Roots\n"
158
  if roots:
159
  output += "$$\n\\begin{aligned}\n"
 
170
 
171
  except Exception as e:
172
  return f"❌ **Error**: {str(e)}", "", ""
173
+
174
+ # Gradio UI
175
  with gr.Blocks() as demo:
176
+ llm_url = gr.Textbox(label="πŸ”— Enter LLM Microservice URL", placeholder="https://xxxx.ngrok-free.app")
177
+ image_input = gr.Image(type="pil", label="πŸ“· Upload Polynomial Image")
178
  output_box = gr.Markdown(label="πŸ“‹ Step-by-step Solution")
179
  explain_box = gr.Markdown(label="πŸ—£οΈ Human-style Explanation")
180
  hidden_latex = gr.Textbox(visible=False)
 
190
  explain_btn.click(fn=request_llm_explanation, inputs=[hidden_latex, llm_url], outputs=explain_box)
191
 
192
  demo.title = "🧠 Polynomial Solver from Image"
193
+ demo.description = "Upload a typed or handwritten polynomial image. View symbolic steps and approximate root solutions."
194
 
195
  if __name__ == "__main__":
196
  demo.launch()