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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -34
app.py CHANGED
@@ -15,15 +15,14 @@ model = LatexOCR()
15
 
16
  # Clean LaTeX output
17
  def clean_latex(latex):
18
- # πŸ”§ Remove bad spacing escapes and redundant slashes
19
  latex = latex.replace('\\ ', '')
20
  latex = latex.replace('\\\\', '\\')
21
  latex = re.sub(r'\\[ \t\n\r\f\v]*', '', latex)
22
 
23
- # βœ… Fix invalid LaTeX escapes like \+ \- \=
24
  latex = re.sub(r'\\([+\-=])', r'\1', latex)
25
 
26
- # πŸ” Replace common misrecognized symbols
27
  replacements = {
28
  r'\\chi': 'x', r'chi': 'x',
29
  r'\\xi': 'x', r'xi': 'x',
@@ -32,42 +31,32 @@ def clean_latex(latex):
32
  r'\\gamma': 'y', r'gamma': 'y',
33
  r'\\vartheta': '3', r'vartheta': '3',
34
  r'\\mathcalW': 'x', r'mathcalW': 'x',
 
 
35
  }
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)
58
  latex = re.sub(r'\(([^()]+?)\)\s*([a-zA-Z](\^\d+)?)', r'(\1)*\2', latex)
59
 
60
- # βœ… Fix symbols
61
  latex = latex.replace(r'\cdot', '*')
62
  latex = latex.replace('βˆ’', '-') # Unicode minus
63
-
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
 
@@ -75,7 +64,9 @@ def clean_latex(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,7 +75,7 @@ def request_llm_fallback(bad_latex, llm_url):
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})
@@ -110,12 +101,15 @@ def solve_polynomial(image, llm_url):
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)
@@ -125,19 +119,24 @@ def solve_polynomial(image, llm_url):
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):
@@ -151,9 +150,10 @@ def solve_polynomial(image, llm_url):
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"
@@ -173,8 +173,8 @@ def solve_polynomial(image, llm_url):
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,7 +190,7 @@ with gr.Blocks() as demo:
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()
 
15
 
16
  # Clean LaTeX output
17
  def clean_latex(latex):
 
18
  latex = latex.replace('\\ ', '')
19
  latex = latex.replace('\\\\', '\\')
20
  latex = re.sub(r'\\[ \t\n\r\f\v]*', '', latex)
21
 
22
+ # Fix invalid LaTeX escapes like \+ \- \=
23
  latex = re.sub(r'\\([+\-=])', r'\1', latex)
24
 
25
+ # Replace common misrecognized symbols
26
  replacements = {
27
  r'\\chi': 'x', r'chi': 'x',
28
  r'\\xi': 'x', r'xi': 'x',
 
31
  r'\\gamma': 'y', r'gamma': 'y',
32
  r'\\vartheta': '3', r'vartheta': '3',
33
  r'\\mathcalW': 'x', r'mathcalW': 'x',
34
+ r'\\pi': 'pi', r'pi': 'pi', # βœ… prevent pi β†’ ip
35
+ r'\\mathrm': '', r'mathrm': '',
36
  }
37
  for wrong, correct in replacements.items():
38
  latex = re.sub(wrong, correct, latex)
39
 
 
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
  latex = latex.replace('cal x', 'x').replace('cal X', 'x')
45
  latex = latex.replace('mathcal x', 'x').replace('mathcal X', 'x')
46
 
 
47
  latex = latex.replace('{', '').replace('}', '')
48
+ latex = latex.strip().rstrip(',.')
 
 
 
49
  latex = re.sub(r'(?<![a-zA-Z0-9])e(?![a-zA-Z0-9])', 'E', latex)
50
 
51
+ latex = re.sub(r'(\d)([a-zA-Z])', r'\1*\2', latex)
 
52
  latex = re.sub(r'(\d+)\s*i', r'\1*I', latex)
53
  latex = re.sub(r'(?<![a-zA-Z0-9])i(?![a-zA-Z0-9])', 'I', latex)
54
  latex = re.sub(r'\(([^()]+?)\)\s*([a-zA-Z](\^\d+)?)', r'(\1)*\2', latex)
55
 
 
56
  latex = latex.replace(r'\cdot', '*')
57
  latex = latex.replace('βˆ’', '-') # Unicode minus
 
 
58
  latex = re.sub(r'[^\w\s^=+*\-().]', '', latex)
59
 
 
 
 
 
60
  if '=' not in latex:
61
  latex += '=0'
62
 
 
64
 
65
  # Fallback to external LLM microservice
66
  def request_llm_fallback(bad_latex, llm_url):
67
+ pre_cleaned = re.sub(
68
+ r'(\\!?pm|\\not=?|\\!|\\L|\\perp|\\bar|\\Sigma|\\boldmath|G|L(?=\^))', '', bad_latex
69
+ )
70
  try:
71
  response = requests.post(f"{llm_url}/clean", json={"prompt": pre_cleaned})
72
  if response.status_code == 200:
 
75
  print(f"LLM fallback failed: {e}")
76
  return pre_cleaned
77
 
78
+ # Request human-style explanation
79
  def request_llm_explanation(latex, llm_url):
80
  try:
81
  response = requests.post(f"{llm_url}/explain", json={"prompt": latex})
 
101
  expr = parse_latex(cleaned_latex)
102
  if not isinstance(expr, sp.Equality):
103
  raise ValueError("Expression is not an equation.")
104
+
105
  lhs_minus_rhs = expr.lhs - expr.rhs
106
  if not lhs_minus_rhs.is_polynomial():
107
+ raise ValueError("Expression is not a polynomial.")
108
+
109
  junk_symbols = {"pm", "cdot", "mathrm", "boldmath", "bar", "L"}
110
+ symbols = {str(s) for s in expr.free_symbols}
111
+ if symbols & junk_symbols:
112
+ raise ValueError("Expression contains junk symbols.")
113
  except Exception:
114
  fixed_latex = request_llm_fallback(cleaned_latex, llm_url)
115
  cleaned_latex = clean_latex(fixed_latex)
 
119
  raise ValueError("Expression is not an equation.")
120
  lhs_minus_rhs = expr.lhs - expr.rhs
121
  if not lhs_minus_rhs.is_polynomial():
122
+ raise ValueError("Expression is not a polynomial.")
123
+ symbols = {str(s) for s in expr.free_symbols}
124
+ if symbols & junk_symbols:
125
+ raise ValueError("Expression contains junk symbols.")
126
  except Exception:
127
  expr = None
128
 
129
  if expr is None:
130
+ return (
131
+ f"❌ Could not parse expression even after fallback:\n\n```latex\n{cleaned_latex}\n```",
132
+ cleaned_latex,
133
+ ""
134
+ )
135
 
136
  output = (
137
+ f"## πŸ“„ Extracted LaTeX\n\n```latex\n{latex_result}\n```\n"
138
+ f"\n---\n## 🧹 Cleaned LaTeX Used\n\n```latex\n{cleaned_latex}\n```\n"
139
+ f"\n---\n## 🧠 Parsed Expression\n\n$$ {sp.latex(expr)} $$\n\n---\n"
140
  )
141
 
142
  if isinstance(expr, sp.Equality):
 
150
  x_sym = sym
151
  break
152
  if x_sym is None:
153
+ raise ValueError("❌ Could not find variable 'x' in the equation.")
154
 
155
  roots = sp.solve(sp.Eq(lhs, 0), x_sym, dict=True)
156
+
157
  output += "## βœ… Step 3: Solve Roots\n"
158
  if roots:
159
  output += "$$\n\\begin{aligned}\n"
 
173
 
174
  # Gradio UI
175
  with gr.Blocks() as demo:
176
+ llm_url = gr.Textbox(label="πŸ”— Enter LLM Microservice URL (from Colab)", placeholder="https://xxxx.ngrok-free.app")
177
+ image_input = gr.Image(type="pil", label="πŸ“· Upload Image of Polynomial")
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 polynomial image (typed or handwritten). View symbolic steps and human-style explanation."
194
 
195
  if __name__ == "__main__":
196
  demo.launch()