vishwakayireddi1234 commited on
Commit
d52747d
Β·
verified Β·
1 Parent(s): bfa49d6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -138
app.py CHANGED
@@ -1,13 +1,13 @@
1
  import gradio as gr
2
- import base64
3
  import os
4
- from io import BytesIO
5
- from huggingface_hub import InferenceClient
6
 
7
- SPACE_TOKEN = os.environ.get("HF_TOKEN", "")
 
 
8
 
9
- # Models confirmed to work with free HF inference text_generation task
10
- TEXT_MODEL = "mistralai/Mistral-7B-Instruct-v0.3"
11
 
12
  SYSTEM_PROMPT = """You are a warm, patient math tutor for students from Grade 1 through High School.
13
 
@@ -41,32 +41,20 @@ Always format your response exactly like this:
41
  πŸ’‘ [One encouraging sentence]"""
42
 
43
 
44
- def image_to_base64(pil_image):
45
- try:
46
- buffered = BytesIO()
47
- pil_image.convert("RGB").thumbnail((896, 896))
48
- pil_image.save(buffered, format="JPEG", quality=85)
49
- return base64.b64encode(buffered.getvalue()).decode("utf-8")
50
- except Exception:
51
- return None
52
-
53
-
54
- def build_mistral_prompt(system, user_msg):
55
- """Mistral instruct format: <s>[INST] ... [/INST]"""
56
- return f"<s>[INST] {system}\n\n{user_msg} [/INST]"
57
-
58
 
59
- def solve_math(image_input, text_input, grade_level, user_token):
60
- token = user_token.strip() if user_token and user_token.strip() else SPACE_TOKEN
61
-
62
- if not token:
63
  yield (
64
- "πŸ”‘ **A HuggingFace token is required.**\n\n"
65
- "It's free and takes 30 seconds:\n"
66
- "1. Go to [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)\n"
67
- "2. Click **New token** β†’ **Read** access β†’ Copy\n"
68
- "3. Paste it in the **HuggingFace Token** box\n\n"
69
- "Your token is never stored β€” session only."
 
 
 
70
  )
71
  return
72
 
@@ -82,107 +70,103 @@ def solve_math(image_input, text_input, grade_level, user_token):
82
  grade_note = f"Grade level: {grade_level}."
83
 
84
  if has_image and has_text:
85
- problem_text = text_input.strip()
 
86
  elif has_image:
87
- problem_text = (
88
- "There is a math problem in the uploaded image. "
89
- "Please solve it step by step as a math tutor. "
90
- "If you cannot determine the exact problem, explain the general method for the type of problem shown."
 
91
  )
92
  else:
93
- problem_text = text_input.strip()
94
-
95
- user_msg = f"{grade_note}\n\nProblem: {problem_text}\n\nPlease teach me how to solve this step by step."
96
- prompt = build_mistral_prompt(SYSTEM_PROMPT, user_msg)
97
 
98
  yield "⚑ Solving step by step..."
99
 
100
  try:
101
- client = InferenceClient(
102
- model=TEXT_MODEL,
103
- token=token,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  )
105
 
 
 
 
 
 
 
 
 
 
 
106
  output = ""
107
- # Use text_generation with streaming β€” works on free HF inference
108
- for chunk in client.text_generation(
109
- prompt,
110
- max_new_tokens=1000,
111
- temperature=0.3,
112
- do_sample=True,
113
- stream=True,
114
- stop_sequences=["</s>", "[INST]"],
115
- ):
116
- output += chunk
117
- yield output
 
 
 
 
118
 
119
  if not output:
120
- yield "⚠️ No response received. Please try again in a moment."
121
 
 
 
122
  except Exception as e:
123
- err = str(e)
124
- if "401" in err:
125
- yield (
126
- "❌ **Invalid token.** Please check your HuggingFace token.\n\n"
127
- "Get one free at [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)"
128
- )
129
- elif "503" in err or "loading" in err.lower():
130
- yield "⏳ **Model is warming up.** Please wait ~30 seconds and try again."
131
- elif "429" in err:
132
- yield "⚠️ HuggingFace is busy. Please wait a few seconds and try again."
133
- else:
134
- yield f"❌ Error: {err}"
135
 
136
 
137
  CSS = """
138
  @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800;900&family=JetBrains+Mono:wght@400;600&display=swap');
139
-
140
  :root {
141
- --bg: #0d1117;
142
- --surface: #161b22;
143
- --surface2: #1f2937;
144
- --accent: #58a6ff;
145
- --accent2: #bc8cff;
146
- --green: #3fb950;
147
- --text: #e6edf3;
148
- --muted: #7d8590;
149
- --border: #30363d;
150
- --radius: 14px;
151
  }
152
-
153
- body, .gradio-container { background: var(--bg) !important; font-family: 'Nunito', sans-serif !important; color: var(--text) !important; }
154
-
155
  .math-header { text-align:center; padding:32px 20px 18px; background:linear-gradient(160deg,#161b22,#0d1117); border-bottom:1px solid var(--border); border-radius:var(--radius); margin-bottom:20px; }
156
  .math-header h1 { font-size:2.2rem; font-weight:900; background:linear-gradient(90deg,var(--accent),var(--accent2),var(--green)); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; margin:0 0 6px; }
157
- .math-header p { color:var(--muted); font-size:.95rem; margin:0; }
158
-
159
  .badge-row { display:flex; gap:8px; flex-wrap:wrap; justify-content:center; margin-top:12px; }
160
  .badge { background:var(--surface2); border:1px solid var(--border); border-radius:20px; padding:3px 12px; font-size:.76rem; color:var(--muted); }
161
-
162
  .panel-label { font-size:.72rem; font-weight:800; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); margin-bottom:6px; }
163
-
164
  .token-box textarea, .token-box input { background:var(--surface2) !important; border:1px solid var(--border) !important; border-radius:10px !important; color:var(--text) !important; font-family:'JetBrains Mono',monospace !important; font-size:.85rem !important; }
165
- .token-box textarea:focus, .token-box input:focus { border-color:var(--accent) !important; box-shadow:0 0 0 3px rgba(88,166,255,.15) !important; }
166
-
167
  .gr-textbox textarea, .gr-textbox input { background:var(--surface2) !important; border:1px solid var(--border) !important; border-radius:10px !important; color:var(--text) !important; font-family:'Nunito',sans-serif !important; font-size:.95rem !important; }
168
- .gr-textbox textarea:focus { border-color:var(--accent) !important; box-shadow:0 0 0 3px rgba(88,166,255,.15) !important; }
169
-
170
  .solve-btn { background:linear-gradient(135deg,var(--accent),var(--accent2)) !important; color:#fff !important; font-family:'Nunito',sans-serif !important; font-weight:900 !important; font-size:1.05rem !important; border:none !important; border-radius:12px !important; padding:14px 0 !important; width:100% !important; cursor:pointer !important; transition:all .2s !important; }
171
  .solve-btn:hover { transform:translateY(-2px) !important; box-shadow:0 8px 24px rgba(88,166,255,.35) !important; }
172
-
173
  .clear-btn { background:var(--surface2) !important; color:var(--muted) !important; border:1px solid var(--border) !important; border-radius:12px !important; font-family:'Nunito',sans-serif !important; font-weight:700 !important; transition:all .2s !important; }
174
  .clear-btn:hover { border-color:var(--accent) !important; color:var(--text) !important; }
175
-
176
  .output-box { background:var(--surface) !important; border:1px solid var(--border) !important; border-radius:var(--radius) !important; padding:24px !important; min-height:420px !important; font-family:'Nunito',sans-serif !important; font-size:.97rem !important; line-height:1.8 !important; color:var(--text) !important; }
177
- .output-box code { font-family:'JetBrains Mono',monospace !important; background:var(--surface2) !important; border-radius:6px !important; padding:2px 8px !important; }
178
-
179
- .token-info { background:var(--surface2); border:1px solid var(--border); border-left:3px solid var(--accent); border-radius:10px; padding:12px 16px; margin-top:8px; font-size:.82rem; color:var(--muted); line-height:1.7; }
180
- .token-info a { color:var(--accent); text-decoration:none; }
181
- .token-info strong { color:var(--text); }
182
-
183
- .info-box { background:var(--surface2); border:1px solid var(--border); border-left:3px solid var(--green); border-radius:10px; padding:12px 16px; margin-top:16px; font-size:.82rem; color:var(--muted); line-height:1.6; }
184
  .info-box strong { color:var(--green); }
185
-
186
  footer { display:none !important; }
187
  """
188
 
@@ -204,21 +188,17 @@ EXAMPLES = [
204
  [None, "Differentiate f(x) = 3xΒ³ βˆ’ 2x + 7", "Grade 11–12 (Pre-Calculus, Statistics, Calculus)", ""],
205
  ]
206
 
207
- OWNER_TOKEN_SET = bool(SPACE_TOKEN)
208
 
209
  with gr.Blocks(css=CSS, title="Interactive Math Tutor") as demo:
210
-
211
  gr.HTML("""
212
  <div class="math-header">
213
  <h1>πŸ“ Interactive Math Tutor</h1>
214
- <p>Step-by-step guidance Β· Grade 1 to High School Β· Powered by open-source AI</p>
215
  <div class="badge-row">
216
- <span class="badge">✏️ Arithmetic</span>
217
- <span class="badge">Β½ Fractions</span>
218
- <span class="badge">πŸ“Š Algebra</span>
219
- <span class="badge">πŸ“ Geometry</span>
220
- <span class="badge">πŸ“ˆ Trigonometry</span>
221
- <span class="badge">∫ Calculus</span>
222
  </div>
223
  </div>
224
  """)
@@ -226,66 +206,52 @@ with gr.Blocks(css=CSS, title="Interactive Math Tutor") as demo:
226
  with gr.Row(equal_height=False):
227
  with gr.Column(scale=4, min_width=300):
228
 
229
- if not OWNER_TOKEN_SET:
230
- gr.HTML('<div class="panel-label">πŸ”‘ HuggingFace Token (free)</div>')
231
- user_token = gr.Textbox(
232
- label="", placeholder="hf_xxxxxxxxxxxxxxxxxxxx",
233
  type="password", lines=1, elem_classes=["token-box"],
234
  )
235
  gr.HTML("""
236
- <div class="token-info">
237
- <strong>Get your free token in 30 seconds:</strong><br>
238
- 1. Go to <a href="https://huggingface.co/settings/tokens" target="_blank">huggingface.co/settings/tokens</a><br>
239
- 2. Click <strong>New token</strong> β†’ <strong>Read</strong> access β†’ Copy<br>
240
  3. Paste above Β· Never stored, session-only
241
  </div>
242
  """)
243
  else:
244
- user_token = gr.Textbox(value="", visible=False)
245
  gr.HTML('<div class="info-box"><strong>βœ… Ready to use β€” no setup needed!</strong></div>')
246
 
247
  gr.HTML('<div class="panel-label" style="margin-top:16px">πŸ“Ž Upload Worksheet (optional)</div>')
248
  image_input = gr.Image(type="pil", label="", height=180)
249
 
250
  gr.HTML('<div class="panel-label" style="margin-top:14px">✏️ Or Type Your Problem</div>')
251
- text_input = gr.Textbox(
252
- label="", placeholder="e.g. Solve for x: 5x βˆ’ 3 = 22", lines=3
253
- )
254
 
255
  gr.HTML('<div class="panel-label" style="margin-top:14px">πŸŽ“ Grade Level</div>')
256
- grade_dropdown = gr.Dropdown(
257
- choices=GRADE_CHOICES, value="Auto-detect from problem", label=""
258
- )
259
 
260
  with gr.Row():
261
  solve_btn = gr.Button("πŸš€ Solve & Explain", elem_classes=["solve-btn"])
262
  clear_btn = gr.Button("πŸ—‘ Clear", elem_classes=["clear-btn"])
263
 
264
  gr.HTML('<div class="panel-label" style="margin-top:16px">πŸ’‘ Try an example</div>')
265
- gr.Examples(
266
- examples=EXAMPLES,
267
- inputs=[image_input, text_input, grade_dropdown, user_token],
268
- label=""
269
- )
270
 
271
  with gr.Column(scale=6, min_width=360):
272
  gr.HTML('<div class="panel-label">πŸŽ“ Step-by-Step Solution</div>')
273
  output_display = gr.Markdown(
274
- value="*Your solution will appear here.\nUpload a worksheet or type a problem, then click **Solve & Explain**.*",
275
  elem_classes=["output-box"],
276
  )
277
 
278
- solve_btn.click(
279
- fn=solve_math,
280
- inputs=[image_input, text_input, grade_dropdown, user_token],
281
- outputs=output_display,
282
- )
283
  clear_btn.click(
284
- fn=lambda: (None, "", "Auto-detect from problem", "",
285
- "*Your solution will appear here.*"),
286
- inputs=[],
287
- outputs=[image_input, text_input, grade_dropdown, user_token, output_display],
288
  )
289
 
290
  if __name__ == "__main__":
291
- demo.queue().launch(server_name="0.0.0.0", server_port=7860)
 
1
  import gradio as gr
 
2
  import os
3
+ import requests
4
+ import json
5
 
6
+ # Groq API - free tier, no credit card, very fast
7
+ GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
8
+ SPACE_GROQ_KEY = os.environ.get("GROQ_API_KEY", "")
9
 
10
+ MODEL = "llama-3.1-8b-instant" # free on Groq, very fast, great at math
 
11
 
12
  SYSTEM_PROMPT = """You are a warm, patient math tutor for students from Grade 1 through High School.
13
 
 
41
  πŸ’‘ [One encouraging sentence]"""
42
 
43
 
44
+ def solve_math(image_input, text_input, grade_level, user_key):
45
+ key = user_key.strip() if user_key and user_key.strip() else SPACE_GROQ_KEY
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
+ if not key:
 
 
 
48
  yield (
49
+ "πŸ”‘ **A free Groq API key is required.**\n\n"
50
+ "Get one in 60 seconds β€” no credit card needed:\n"
51
+ "1. Go to [console.groq.com/keys](https://console.groq.com/keys)\n"
52
+ "2. Sign up free β†’ click **Create API Key** β†’ copy it\n"
53
+ "3. Paste it in the **Groq API Key** box on the left\n\n"
54
+ "Your key is never stored β€” session only.\n\n"
55
+ "---\n"
56
+ "**Why Groq?** It's genuinely free (no card), extremely fast, and runs "
57
+ "Llama 3.1 which is excellent at step-by-step math explanations."
58
  )
59
  return
60
 
 
70
  grade_note = f"Grade level: {grade_level}."
71
 
72
  if has_image and has_text:
73
+ problem = text_input.strip()
74
+ user_msg = f"{grade_note}\n\nProblem (from worksheet image β€” typed by student): {problem}"
75
  elif has_image:
76
+ user_msg = (
77
+ f"{grade_note}\n\n"
78
+ "The student has uploaded a worksheet image. "
79
+ "Please ask them to type out the problem text so you can help solve it step by step, "
80
+ "then explain how you would approach that type of problem."
81
  )
82
  else:
83
+ user_msg = f"{grade_note}\n\nProblem: {text_input.strip()}"
 
 
 
84
 
85
  yield "⚑ Solving step by step..."
86
 
87
  try:
88
+ response = requests.post(
89
+ GROQ_API_URL,
90
+ headers={
91
+ "Authorization": f"Bearer {key}",
92
+ "Content-Type": "application/json",
93
+ },
94
+ json={
95
+ "model": MODEL,
96
+ "messages": [
97
+ {"role": "system", "content": SYSTEM_PROMPT},
98
+ {"role": "user", "content": user_msg},
99
+ ],
100
+ "max_tokens": 1200,
101
+ "temperature": 0.3,
102
+ "stream": True,
103
+ },
104
+ stream=True,
105
+ timeout=60,
106
  )
107
 
108
+ if response.status_code == 401:
109
+ yield "❌ **Invalid API key.** Please check your Groq key and try again."
110
+ return
111
+ if response.status_code == 429:
112
+ yield "⚠️ Rate limit hit. Please wait a few seconds and try again."
113
+ return
114
+ if response.status_code != 200:
115
+ yield f"❌ API error {response.status_code}: {response.text[:200]}"
116
+ return
117
+
118
  output = ""
119
+ for raw in response.iter_lines():
120
+ if not raw:
121
+ continue
122
+ line = raw.decode("utf-8", errors="ignore")
123
+ if line.startswith("data: "):
124
+ line = line[6:].strip()
125
+ if line == "[DONE]":
126
+ break
127
+ try:
128
+ token = json.loads(line)["choices"][0]["delta"].get("content", "")
129
+ if token:
130
+ output += token
131
+ yield output
132
+ except Exception:
133
+ continue
134
 
135
  if not output:
136
+ yield "⚠️ No response received. Please try again."
137
 
138
+ except requests.exceptions.Timeout:
139
+ yield "❌ Request timed out. Please try again."
140
  except Exception as e:
141
+ yield f"❌ Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
142
 
143
 
144
  CSS = """
145
  @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800;900&family=JetBrains+Mono:wght@400;600&display=swap');
 
146
  :root {
147
+ --bg:#0d1117; --surface:#161b22; --surface2:#1f2937;
148
+ --accent:#58a6ff; --accent2:#bc8cff; --green:#3fb950;
149
+ --text:#e6edf3; --muted:#7d8590; --border:#30363d; --radius:14px;
 
 
 
 
 
 
 
150
  }
151
+ body, .gradio-container { background:var(--bg) !important; font-family:'Nunito',sans-serif !important; color:var(--text) !important; }
 
 
152
  .math-header { text-align:center; padding:32px 20px 18px; background:linear-gradient(160deg,#161b22,#0d1117); border-bottom:1px solid var(--border); border-radius:var(--radius); margin-bottom:20px; }
153
  .math-header h1 { font-size:2.2rem; font-weight:900; background:linear-gradient(90deg,var(--accent),var(--accent2),var(--green)); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; margin:0 0 6px; }
154
+ .math-header p { color:var(--muted); font-size:.95rem; margin:0; }
 
155
  .badge-row { display:flex; gap:8px; flex-wrap:wrap; justify-content:center; margin-top:12px; }
156
  .badge { background:var(--surface2); border:1px solid var(--border); border-radius:20px; padding:3px 12px; font-size:.76rem; color:var(--muted); }
 
157
  .panel-label { font-size:.72rem; font-weight:800; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); margin-bottom:6px; }
 
158
  .token-box textarea, .token-box input { background:var(--surface2) !important; border:1px solid var(--border) !important; border-radius:10px !important; color:var(--text) !important; font-family:'JetBrains Mono',monospace !important; font-size:.85rem !important; }
 
 
159
  .gr-textbox textarea, .gr-textbox input { background:var(--surface2) !important; border:1px solid var(--border) !important; border-radius:10px !important; color:var(--text) !important; font-family:'Nunito',sans-serif !important; font-size:.95rem !important; }
 
 
160
  .solve-btn { background:linear-gradient(135deg,var(--accent),var(--accent2)) !important; color:#fff !important; font-family:'Nunito',sans-serif !important; font-weight:900 !important; font-size:1.05rem !important; border:none !important; border-radius:12px !important; padding:14px 0 !important; width:100% !important; cursor:pointer !important; transition:all .2s !important; }
161
  .solve-btn:hover { transform:translateY(-2px) !important; box-shadow:0 8px 24px rgba(88,166,255,.35) !important; }
 
162
  .clear-btn { background:var(--surface2) !important; color:var(--muted) !important; border:1px solid var(--border) !important; border-radius:12px !important; font-family:'Nunito',sans-serif !important; font-weight:700 !important; transition:all .2s !important; }
163
  .clear-btn:hover { border-color:var(--accent) !important; color:var(--text) !important; }
 
164
  .output-box { background:var(--surface) !important; border:1px solid var(--border) !important; border-radius:var(--radius) !important; padding:24px !important; min-height:420px !important; font-family:'Nunito',sans-serif !important; font-size:.97rem !important; line-height:1.8 !important; color:var(--text) !important; }
165
+ .key-info { background:var(--surface2); border:1px solid var(--border); border-left:3px solid var(--accent); border-radius:10px; padding:12px 16px; margin-top:8px; font-size:.82rem; color:var(--muted); line-height:1.7; }
166
+ .key-info a { color:var(--accent); text-decoration:none; }
167
+ .key-info strong { color:var(--text); }
168
+ .info-box { background:var(--surface2); border:1px solid var(--border); border-left:3px solid var(--green); border-radius:10px; padding:12px 16px; margin-top:8px; font-size:.82rem; color:var(--muted); line-height:1.6; }
 
 
 
169
  .info-box strong { color:var(--green); }
 
170
  footer { display:none !important; }
171
  """
172
 
 
188
  [None, "Differentiate f(x) = 3xΒ³ βˆ’ 2x + 7", "Grade 11–12 (Pre-Calculus, Statistics, Calculus)", ""],
189
  ]
190
 
191
+ OWNER_KEY_SET = bool(SPACE_GROQ_KEY)
192
 
193
  with gr.Blocks(css=CSS, title="Interactive Math Tutor") as demo:
 
194
  gr.HTML("""
195
  <div class="math-header">
196
  <h1>πŸ“ Interactive Math Tutor</h1>
197
+ <p>Step-by-step guidance Β· Grade 1 to High School Β· Powered by Llama 3.1 via Groq</p>
198
  <div class="badge-row">
199
+ <span class="badge">✏️ Arithmetic</span><span class="badge">½ Fractions</span>
200
+ <span class="badge">πŸ“Š Algebra</span><span class="badge">πŸ“ Geometry</span>
201
+ <span class="badge">πŸ“ˆ Trigonometry</span><span class="badge">∫ Calculus</span>
 
 
 
202
  </div>
203
  </div>
204
  """)
 
206
  with gr.Row(equal_height=False):
207
  with gr.Column(scale=4, min_width=300):
208
 
209
+ if not OWNER_KEY_SET:
210
+ gr.HTML('<div class="panel-label">πŸ”‘ Groq API Key (free, no card)</div>')
211
+ user_key = gr.Textbox(
212
+ label="", placeholder="gsk_xxxxxxxxxxxxxxxxxxxx",
213
  type="password", lines=1, elem_classes=["token-box"],
214
  )
215
  gr.HTML("""
216
+ <div class="key-info">
217
+ <strong>Get your free key in 60 seconds:</strong><br>
218
+ 1. Go to <a href="https://console.groq.com/keys" target="_blank">console.groq.com/keys</a><br>
219
+ 2. Sign up free (no credit card) β†’ <strong>Create API Key</strong> β†’ Copy<br>
220
  3. Paste above Β· Never stored, session-only
221
  </div>
222
  """)
223
  else:
224
+ user_key = gr.Textbox(value="", visible=False)
225
  gr.HTML('<div class="info-box"><strong>βœ… Ready to use β€” no setup needed!</strong></div>')
226
 
227
  gr.HTML('<div class="panel-label" style="margin-top:16px">πŸ“Ž Upload Worksheet (optional)</div>')
228
  image_input = gr.Image(type="pil", label="", height=180)
229
 
230
  gr.HTML('<div class="panel-label" style="margin-top:14px">✏️ Or Type Your Problem</div>')
231
+ text_input = gr.Textbox(label="", placeholder="e.g. Solve for x: 5x βˆ’ 3 = 22", lines=3)
 
 
232
 
233
  gr.HTML('<div class="panel-label" style="margin-top:14px">πŸŽ“ Grade Level</div>')
234
+ grade_dropdown = gr.Dropdown(choices=GRADE_CHOICES, value="Auto-detect from problem", label="")
 
 
235
 
236
  with gr.Row():
237
  solve_btn = gr.Button("πŸš€ Solve & Explain", elem_classes=["solve-btn"])
238
  clear_btn = gr.Button("πŸ—‘ Clear", elem_classes=["clear-btn"])
239
 
240
  gr.HTML('<div class="panel-label" style="margin-top:16px">πŸ’‘ Try an example</div>')
241
+ gr.Examples(examples=EXAMPLES, inputs=[image_input, text_input, grade_dropdown, user_key], label="")
 
 
 
 
242
 
243
  with gr.Column(scale=6, min_width=360):
244
  gr.HTML('<div class="panel-label">πŸŽ“ Step-by-Step Solution</div>')
245
  output_display = gr.Markdown(
246
+ value="*Your solution will appear here. Upload a worksheet or type a problem, then click **Solve & Explain**.*",
247
  elem_classes=["output-box"],
248
  )
249
 
250
+ solve_btn.click(fn=solve_math, inputs=[image_input, text_input, grade_dropdown, user_key], outputs=output_display)
 
 
 
 
251
  clear_btn.click(
252
+ fn=lambda: (None, "", "Auto-detect from problem", "", "*Your solution will appear here.*"),
253
+ inputs=[], outputs=[image_input, text_input, grade_dropdown, user_key, output_display],
 
 
254
  )
255
 
256
  if __name__ == "__main__":
257
+ demo.queue().launch(server_name="0.0.0.0", server_port=7860)