MasteredUltraInstinct commited on
Commit
68e99a6
ยท
verified ยท
1 Parent(s): fbda286

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -97
app.py CHANGED
@@ -4,7 +4,6 @@ from pix2tex.cli import LatexOCR
4
  import sympy as sp
5
  from sympy.parsing.latex import parse_latex
6
  import re
7
- import requests
8
 
9
  model = LatexOCR()
10
 
@@ -13,7 +12,7 @@ def preprocess_handwritten_image(pil_img):
13
 
14
  def clean_latex(latex):
15
  latex = latex.replace('\\ ', '')
16
- latex = latex.replace('\\\\', '\\')
17
  latex = re.sub(r'\\[ \t\n\r\f\v]*', '', latex)
18
  latex = re.sub(r'\\([+\-=])', r'\1', latex)
19
  replacements = {
@@ -29,48 +28,11 @@ def clean_latex(latex):
29
  }
30
  for wrong, correct in replacements.items():
31
  latex = re.sub(wrong, correct, latex)
32
- latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Xx]\s*\}?', 'x', latex)
33
- latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Yy]\s*\}?', 'y', latex)
34
- latex = re.sub(r'\\(cal|mathcal)\s*\{?\s*[Zz]\s*\}?', 'z', latex)
35
- latex = latex.replace('cal x', 'x').replace('cal X', 'x')
36
- latex = latex.replace('mathcal x', 'x').replace('mathcal X', 'x')
37
- latex = latex.replace('{', '').replace('}', '')
38
- latex = latex.strip().rstrip(',.')
39
- latex = re.sub(r'(?<![a-zA-Z0-9])e(?![a-zA-Z0-9])', 'E', latex)
40
- latex = re.sub(r'(\d)([a-zA-Z])', r'\1*\2', latex)
41
- latex = re.sub(r'(\d+)\s*i', r'\1*I', latex)
42
- latex = re.sub(r'(?<![a-zA-Z0-9])i(?![a-zA-Z0-9])', 'I', latex)
43
- latex = re.sub(r'\(([^()]+?)\)\s*([a-zA-Z](\^\d+)?)', r'(\1)*\2', latex)
44
- latex = latex.replace(r'\cdot', '*')
45
  latex = latex.replace('โˆ’', '-')
46
- latex = re.sub(r'[^\w\s^=+*\-().]', '', latex)
47
- if '=' not in latex:
48
- latex += '=0'
49
- latex = latex.replace('pi', '3.1416')
50
- latex = latex.replace('e', '2.7183')
51
- return latex
52
-
53
- # def request_llm_fallback(bad_latex, llm_url):
54
- # pre_cleaned = re.sub(r'(\\!?pm|\\not=?|\\!|\\L|\\perp|\\bar|\\Sigma|\\boldmath|G|L(?=\^))', '', bad_latex)
55
- # try:
56
- # response = requests.post(f"{llm_url}/clean", json={"prompt": pre_cleaned})
57
- # if response.status_code == 200:
58
- # return response.json().get("cleaned_latex", pre_cleaned)
59
- # except Exception as e:
60
- # print(f"LLM fallback failed: {e}")
61
- # return pre_cleaned
62
-
63
- # def request_llm_explanation(prompt, llm_url):
64
- # try:
65
- # response = requests.post(f"{llm_url}/explain", json={"prompt": prompt})
66
- # if response.status_code == 200:
67
- # return response.json().get("explanation", "โŒ No explanation returned.")
68
- # else:
69
- # return f"โŒ LLM explanation failed: {response.status_code}"
70
- # except Exception as e:
71
- # return f"โŒ LLM explanation error: {e}"
72
-
73
- def solve_polynomial(image): # removed llm_url
74
  try:
75
  img = preprocess_handwritten_image(image)
76
  latex_result = model(img)
@@ -86,9 +48,6 @@ def solve_polynomial(image): # removed llm_url
86
  if not lhs.is_polynomial():
87
  raise ValueError("Not a polynomial")
88
  except:
89
- # Commented out LLM fallback
90
- # fixed_latex = request_llm_fallback(cleaned_latex, llm_url)
91
- # cleaned_latex = clean_latex(fixed_latex)
92
  return f"โŒ Could not parse expression:\n\n```latex\n{cleaned_latex}\n```", cleaned_latex, ""
93
 
94
  output = f"## ๐Ÿ“„ Extracted LaTeX\n```latex\n{latex_result}\n```\n"
@@ -113,73 +72,75 @@ def solve_polynomial(image): # removed llm_url
113
  except Exception as e:
114
  return f"โŒ Error: {str(e)}", "", ""
115
 
116
- def wrapped_solver(img): # removed url
117
  result, cleaned, prompt = solve_polynomial(img)
118
  return result, cleaned, prompt
119
 
120
- # def solve_from_coeffs(degree, coeff_str):
121
- # try:
122
- # coeffs = [float(c.strip()) for c in coeff_str.split(",")]
123
- # if len(coeffs) != int(degree) + 1:
124
- # return f"โŒ You entered {len(coeffs)} coefficients, but degree {degree} needs {int(degree)+1}.", ""
125
-
126
- # x = sp.Symbol("x")
127
- # poly_expr = sum(coeffs[i] * x**(int(degree) - i) for i in range(len(coeffs)))
128
- # factored = sp.factor(poly_expr)
129
- # roots = sp.solve(poly_expr, x)
130
-
131
- # result = "## ๐Ÿงฎ Symbolic Roots:\n"
132
- # for i, r in enumerate(roots, 1):
133
- # result += f"- Root {i}: $${sp.latex(sp.N(r, 6))}$$\n"
134
-
135
- # terms = []
136
- # for i, c in enumerate(coeffs):
137
- # power = int(degree) - i
138
- # if power == 0:
139
- # terms.append(f"{c}")
140
- # elif power == 1:
141
- # terms.append(f"{c}x")
142
- # else:
143
- # terms.append(f"{c}x^{power}")
144
- # equation_str = " + ".join(terms).replace("+ -", "- ") + " = 0"
145
- # roots_str = f"[{', '.join(str(sp.N(r, 6)) for r in roots)}]"
146
- # factored_str = sp.pretty(factored)
147
-
148
- # llm_prompt = (
149
- # f"Equation: {equation_str}\n"
150
- # f"Factor: {factored_str} = 0\n"
151
- # f"Roots: {roots_str}\n\n"
152
- # "Explain the solution step-by-step in human language. "
153
- # "These roots are correct (up to approximation), so base your reasoning on them."
154
- # )
155
-
156
- # return result, llm_prompt
157
- # except Exception as e:
158
- # return f"โŒ Error: {str(e)}", ""
 
 
 
 
 
 
 
159
 
160
  with gr.Blocks() as demo:
161
  with gr.Tab("๐Ÿ–ผ๏ธ Parse from Image"):
162
- # llm_url = gr.Textbox(label="๐Ÿ”— Enter LLM Microservice URL (from Colab)", placeholder="https://xxxx.ngrok-free.app")
163
  image_input = gr.Image(type="pil", label="๐Ÿ“ท Upload Image of Polynomial")
164
  hidden_latex = gr.Textbox(visible=False)
165
  explanation_prompt = gr.Textbox(visible=False)
166
  output_box = gr.Markdown(label="๐Ÿ“‹ Step-by-step Solution")
167
  submit_btn = gr.Button("๐Ÿ” Solve")
168
  submit_btn.click(fn=wrapped_solver, inputs=[image_input], outputs=[output_box, hidden_latex, explanation_prompt])
 
169
  # explain_box = gr.Markdown(label="๐Ÿ—ฃ๏ธ Human-style Explanation")
170
  # explain_btn = gr.Button("๐Ÿง  Explain Human-Solution")
171
  # explain_btn.click(fn=request_llm_explanation, inputs=[explanation_prompt, llm_url], outputs=explain_box)
172
 
173
- # with gr.Tab("๐Ÿงฎ Solve by Coefficients"):
174
- # degree_input = gr.Number(label="Enter Degree of Polynomial (e.g. 3)")
175
- # coeffs_input = gr.Textbox(label="Enter Coefficients (comma-separated)", placeholder="e.g. 1, 2, 0, -4")
176
- # roots_output = gr.Markdown(label="โœ… Roots")
177
- # coeff_hidden_equation = gr.Textbox(visible=False)
178
- # coeff_btn = gr.Button("๐Ÿ“Œ Solve")
179
- # coeff_btn.click(fn=solve_from_coeffs, inputs=[degree_input, coeffs_input], outputs=[roots_output, coeff_hidden_equation])
180
- # coeff_explain_box = gr.Markdown(label="๐Ÿ—ฃ๏ธ Human-style Explanation")
181
- # coeff_explain_btn = gr.Button("๐Ÿง  Explain Human-Solution")
182
- # coeff_explain_btn.click(fn=request_llm_explanation, inputs=[coeff_hidden_equation, llm_url], outputs=coeff_explain_box)
183
 
184
  if __name__ == "__main__":
185
  demo.launch()
 
4
  import sympy as sp
5
  from sympy.parsing.latex import parse_latex
6
  import re
 
7
 
8
  model = LatexOCR()
9
 
 
12
 
13
  def clean_latex(latex):
14
  latex = latex.replace('\\ ', '')
15
+ latex = latex.replace('\\\\', '\n') # preserve newlines for multiple equations
16
  latex = re.sub(r'\\[ \t\n\r\f\v]*', '', latex)
17
  latex = re.sub(r'\\([+\-=])', r'\1', latex)
18
  replacements = {
 
28
  }
29
  for wrong, correct in replacements.items():
30
  latex = re.sub(wrong, correct, latex)
31
+ latex = re.sub(r'{|}', '', latex)
 
 
 
 
 
 
 
 
 
 
 
 
32
  latex = latex.replace('โˆ’', '-')
33
+ return latex.strip()
34
+
35
+ def solve_polynomial(image):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  try:
37
  img = preprocess_handwritten_image(image)
38
  latex_result = model(img)
 
48
  if not lhs.is_polynomial():
49
  raise ValueError("Not a polynomial")
50
  except:
 
 
 
51
  return f"โŒ Could not parse expression:\n\n```latex\n{cleaned_latex}\n```", cleaned_latex, ""
52
 
53
  output = f"## ๐Ÿ“„ Extracted LaTeX\n```latex\n{latex_result}\n```\n"
 
72
  except Exception as e:
73
  return f"โŒ Error: {str(e)}", "", ""
74
 
75
+ def wrapped_solver(img):
76
  result, cleaned, prompt = solve_polynomial(img)
77
  return result, cleaned, prompt
78
 
79
+ # ---------- Tab 2 Logic: Solve Simultaneous Linear Equations ----------
80
+
81
+ def solve_simultaneous_equations(img):
82
+ try:
83
+ img = preprocess_handwritten_image(img)
84
+ latex_result = model(img)
85
+ cleaned_latex = clean_latex(latex_result)
86
+
87
+ lines = [line.strip() for line in cleaned_latex.splitlines() if line.strip()]
88
+ if len(lines) < 2:
89
+ return f"โŒ Expected at least 2 equations but found {len(lines)}.\n\nExtracted:\n{cleaned_latex}"
90
+
91
+ equations = []
92
+ symbols = set()
93
+
94
+ for line in lines:
95
+ parsed = parse_latex(line)
96
+ if not isinstance(parsed, sp.Equality):
97
+ return f"โŒ Failed to parse line as equation: {line}"
98
+ lhs = parsed.lhs - parsed.rhs
99
+ symbols.update(lhs.free_symbols)
100
+ equations.append(lhs)
101
+
102
+ if len(symbols) < 2:
103
+ return f"โŒ Need at least 2 variables to solve system. Found: {symbols}"
104
+
105
+ sols = sp.linsolve(equations, *symbols)
106
+ if not sols:
107
+ return "โŒ No solution found."
108
+
109
+ sym_list = list(symbols)
110
+ output = "## ๐Ÿง  Extracted System:\n"
111
+ for line in lines:
112
+ output += f"$$ {line} $$\n"
113
+
114
+ output += "\n---\n## โœ… Solution:\n"
115
+ output += "$$\n\\begin{aligned}\n"
116
+ for var, val in zip(sym_list, list(sols)[0]):
117
+ output += f"{sp.latex(var)} &= {sp.latex(sp.N(val, 6))} \\\\\n"
118
+ output += "\\end{aligned}\n$$"
119
+
120
+ return output
121
+ except Exception as e:
122
+ return f"โŒ Error: {e}"
123
+
124
+ # ------------------ UI ------------------
125
 
126
  with gr.Blocks() as demo:
127
  with gr.Tab("๐Ÿ–ผ๏ธ Parse from Image"):
 
128
  image_input = gr.Image(type="pil", label="๐Ÿ“ท Upload Image of Polynomial")
129
  hidden_latex = gr.Textbox(visible=False)
130
  explanation_prompt = gr.Textbox(visible=False)
131
  output_box = gr.Markdown(label="๐Ÿ“‹ Step-by-step Solution")
132
  submit_btn = gr.Button("๐Ÿ” Solve")
133
  submit_btn.click(fn=wrapped_solver, inputs=[image_input], outputs=[output_box, hidden_latex, explanation_prompt])
134
+ # Human explanation (commented out)
135
  # explain_box = gr.Markdown(label="๐Ÿ—ฃ๏ธ Human-style Explanation")
136
  # explain_btn = gr.Button("๐Ÿง  Explain Human-Solution")
137
  # explain_btn.click(fn=request_llm_explanation, inputs=[explanation_prompt, llm_url], outputs=explain_box)
138
 
139
+ with gr.Tab("๐Ÿงฎ Simultaneous Equations"):
140
+ sim_image_input = gr.Image(type="pil", label="๐Ÿ“ท Upload Image with 2 or 3 Linear Equations")
141
+ sim_output = gr.Markdown(label="๐Ÿ“‹ Solved Result")
142
+ sim_submit = gr.Button("๐Ÿ” Solve Simultaneous Equations")
143
+ sim_submit.click(fn=solve_simultaneous_equations, inputs=[sim_image_input], outputs=[sim_output])
 
 
 
 
 
144
 
145
  if __name__ == "__main__":
146
  demo.launch()