Khoi1234210 commited on
Commit
76dba01
·
verified ·
1 Parent(s): 7b5fbc0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +194 -222
app.py CHANGED
@@ -4,310 +4,282 @@ from huggingface_hub import InferenceClient
4
  from datasets import load_dataset
5
  import random
6
  import re
7
- import sympy as sp # Added SymPy for symbolic computation and better rendering/verification
 
8
 
9
- # Global datasets - load lazily
10
- math_samples = None
 
11
 
12
  def load_sample_problems():
13
- """Load sample problems from ALL datasets - FIXED VERSION"""
14
- global math_samples
15
- if math_samples is not None:
16
- return math_samples
17
-
18
  samples = []
 
19
  try:
20
- print("🔄 Loading GSM8K...")
21
- # GSM8K (math problems)
22
- gsm8k = load_dataset("openai/gsm8k", "main", streaming=True)
23
- gsm_count = 0
24
- for i, item in enumerate(gsm8k["train"]):
25
- samples.append(item["question"])
26
- gsm_count += 1
27
- if gsm_count >= 50:
28
  break
 
29
 
30
- print("🔄 Loading Fineweb-edu...")
31
- # Fineweb-edu (educational text - extract math-like questions)
32
  fw = load_dataset("HuggingFaceFW/fineweb-edu", name="sample-10BT", split="train", streaming=True)
33
  fw_count = 0
34
  for item in fw:
35
- # Filter for math-related content
 
36
  text_lower = item['text'].lower()
37
- if any(word in text_lower for word in ['math', 'calculate', 'solve', 'derivative', 'integral', 'triangle', 'equation', 'area', 'volume', 'probability']):
38
- # Truncate and format as question
39
- question = item['text'][:150].strip()
40
- if len(question) > 20: # Ensure it's substantial
41
- samples.append(question + " (Solve this math problem.)")
42
  fw_count += 1
43
- if fw_count >= 20:
44
- break
45
 
46
- print("🔄 Loading Ultrachat...")
47
- # Ultrachat_200k (chat-like math queries)
48
- ds = load_dataset("HuggingFaceH4/ultrachat_200k", streaming=True)
49
  ds_count = 0
50
  for item in ds:
 
 
51
  if len(item['messages']) > 0:
52
  content = item['messages'][0]['content'].lower()
53
- if any(word in content for word in ['math', 'calculate', 'solve', 'problem', 'equation', 'derivative', 'integral']):
54
- user_msg = item['messages'][0]['content']
55
- if len(user_msg) > 10: # Valid length
56
- samples.append(user_msg)
57
- ds_count += 1
58
- if ds_count >= 20:
59
- break
60
 
61
- print(f"✅ Loaded {len(samples)} samples: GSM8K ({gsm_count}), Fineweb-edu ({fw_count}), Ultrachat ({ds_count})")
62
- math_samples = samples
63
- return samples
64
 
65
  except Exception as e:
66
- print(f"⚠️ Dataset error: {e}, using fallback")
67
- math_samples = [
68
- "What is the derivative of f(x) = 3x² + 2x - 1?",
69
- "A triangle has sides of length 5, 12, and 13. What is its area?",
70
- "If log₂(x) + log₂(x+6) = 4, find the value of x.",
71
- "Find the limit: lim(x->0) (sin(x)/x)",
72
- "Solve the system: x + 2y = 7, 3x - y = 4",
73
- "Calculate the integral of sin(x) from 0 to pi.",
74
- "What is the probability of rolling a 6 on a die 3 times in a row?"
75
- ]
76
- return math_samples
77
 
78
- def create_math_system_message():
79
- """Specialized system prompt for mathematics with LaTeX"""
80
- return r"""You are Mathetics AI, an advanced mathematics tutor and problem solver.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- 🧮 **Your Expertise:**
83
- - Step-by-step problem solving with clear explanations
84
- - Multiple solution approaches when applicable
85
- - Proper mathematical notation and terminology using LaTeX
86
- - Verification of answers through different methods
87
 
88
- 📐 **Problem Domains:**
89
- - Arithmetic, Algebra, and Number Theory
90
- - Geometry, Trigonometry, and Coordinate Geometry
91
- - Calculus (Limits, Derivatives, Integrals)
92
- - Statistics, Probability, and Data Analysis
93
- - Competition Mathematics (AMC, AIME level)
94
 
95
- 💡 **Teaching Style:**
96
- 1. **Understand the Problem** - Identify what's being asked
97
- 2. **Plan the Solution** - Choose the appropriate method
98
- 3. **Execute Step-by-Step** - Show all work clearly with LaTeX formatting
99
- 4. **Verify the Answer** - Check if the result makes sense
100
- 5. **Alternative Methods** - Mention other possible approaches
101
 
102
- **LaTeX Guidelines:**
103
- - Use $...$ for inline math: $x^2 + y^2 = z^2$
104
- - Use $$...$$ for display math
105
- - Box final answers: \boxed{answer}
106
- - Fractions: \frac{numerator}{denominator}
107
- - Limits: \lim_{x \to 0}
108
- - Derivatives: \frac{d}{dx} or f'(x)
109
 
110
- Always be precise, educational, and encourage mathematical thinking."""
111
 
112
  def render_latex(text):
113
- """Enhanced LaTeX cleanup with support for advanced SymPy outputs"""
114
  if not text:
115
  return text
116
 
117
- try:
118
- # Convert LaTeX bracket notation to dollar signs
119
- text = re.sub(r'\\\[(.*?)\\\]', r'$$\1$$', text, flags=re.DOTALL)
120
- text = re.sub(r'\\\((.*?)\\\)', r'$\1$', text, flags=re.DOTALL)
121
-
122
- # Fix boxed answers if not in math mode
123
- if '\\boxed' in text and not re.search(r'\$.*\\boxed.*\$', text):
124
- text = re.sub(r'\\boxed\{([^}]+)\}', r'$$\boxed{\1}$$', text)
125
-
126
- # Handle equation environments for display in Gradio (convert to $$...$$)
127
- text = re.sub(r'\\begin\{equation\*\}(.*?)\\end\{equation\*\}', r'$$\1$$', text, flags=re.DOTALL)
128
-
129
- # Clean up any escaped % or special chars for Markdown compatibility
130
- text = re.sub(r'\\%', '%', text)
131
-
132
- except Exception as e:
133
- print(f"⚠️ LaTeX error: {e}")
134
 
135
  return text
136
 
137
  def try_sympy_compute(message):
138
- """Attempt to compute the result using SymPy for verification and better rendering, with advanced LaTeX options."""
139
- message_lower = message.lower()
140
 
 
141
  x = sp.Symbol('x')
 
142
 
143
- # Handle definite integrals
144
- if 'integral' in message_lower or '∫' in message:
145
- match = re.search(r'(?:integral of|∫) (.+?) from (.+?) to (.+)', message_lower)
146
  if match:
147
  expr_str, lower, upper = match.groups()
148
- try:
149
- expr = sp.sympify(expr_str.replace('^', '**')) # Handle ^ for power
150
- result = sp.integrate(expr, (x, sp.sympify(lower), sp.sympify(upper)))
151
- # Advanced LaTeX: fold fractions, plain mode, manual box
152
- return r'\boxed{' + sp.latex(result, mode='plain', fold_frac_powers=True) + r'}'
153
- except Exception as e:
154
- print(f"⚠️ SymPy integral error: {e}")
155
- return None
156
-
157
- # Handle derivatives with inv_trig_style
158
- elif 'derivative' in message_lower:
159
- match = re.search(r'derivative of (.+)', message_lower)
160
- if match:
161
- expr_str = match.group(1)
162
- try:
163
- expr = sp.sympify(expr_str.replace('^', '**'))
164
- result = sp.diff(expr, x)
165
- # Advanced LaTeX: power style for inv trig, fold short frac
166
- return r'\boxed{' + sp.latex(result, inv_trig_style='power', fold_short_frac=True) + r'}'
167
- except Exception as e:
168
- print(f"⚠️ SymPy derivative error: {e}")
169
- return None
170
-
171
- # Handle limits
172
- elif 'limit' in message_lower or 'lim' in message_lower:
173
- match = re.search(r'(?:limit|lim) (.+?) as (.+?) to (.+)', message_lower)
174
  if match:
175
- expr_str, var, to_val = match.groups()
176
- try:
177
- expr = sp.sympify(expr_str.replace('^', '**'))
178
- result = sp.limit(expr, sp.Symbol(var), sp.sympify(to_val))
179
- # Advanced LaTeX: equation* mode for display
180
- return sp.latex(result, mode='equation*')
181
- except Exception as e:
182
- print(f"⚠️ SymPy limit error: {e}")
183
- return None
184
-
185
- # Handle triangle area (Heron's formula)
186
- elif 'area of triangle' in message_lower:
187
- match = re.search(r'(\d+)[ -](\d+)[ -](\d+)', message_lower) # Matches 5-12-13 or 5 12 13
188
  if match:
 
 
 
 
 
 
 
 
189
  a, b, c = map(float, match.groups())
190
- try:
191
- s = (a + b + c) / 2
192
- area = sp.sqrt(s * (s - a) * (s - b) * (s - c))
193
- # Advanced LaTeX: inline mode with folding
194
- return r'\boxed{' + sp.latex(area, mode='inline', fold_frac_powers=True) + r'}'
195
- except Exception as e:
196
- print(f"⚠️ SymPy area error: {e}")
197
- return None
198
-
199
- # Handle simple matrices (e.g., "matrix [[1,2],[3,4]]")
200
- elif 'matrix' in message_lower:
201
- match = re.search(r'matrix \[\[(.+?)\]\]', message_lower) # Basic parsing; extend as needed
202
- if match:
203
- try:
204
- elements = [list(map(sp.sympify, row.split(','))) for row in match.group(1).split('],[')]
205
- m = sp.Matrix(elements)
206
- # Advanced LaTeX: custom delimiters and matrix style
207
- return sp.latex(m, mat_delim='[', mat_str='bmatrix')
208
- except Exception as e:
209
- print(f"⚠️ SymPy matrix error: {e}")
210
- return None
211
 
212
  return None
213
 
214
  def respond(message, history, system_message, max_tokens, temperature, top_p):
215
- """Non-streaming response for stability, with SymPy verification for supported queries."""
216
  client = InferenceClient(model="Qwen/Qwen2.5-Math-7B-Instruct")
217
 
218
  messages = [{"role": "system", "content": system_message}]
219
- # Iterate over history dicts and add user/assistant pairs
220
  for msg in history:
221
- if msg["role"] == "user":
222
- messages.append({"role": "user", "content": msg["content"]})
223
- elif msg["role"] == "assistant":
224
- messages.append({"role": "assistant", "content": msg["content"]})
225
  messages.append({"role": "user", "content": message})
226
 
227
  try:
228
- completion = client.chat_completion(
 
229
  messages,
230
  max_tokens=max_tokens,
231
  temperature=temperature,
232
  top_p=top_p,
233
- )
234
- response = completion.choices[0].message.content
 
 
 
235
 
236
- # Add SymPy verification if applicable (now with advanced LaTeX)
237
  sympy_result = try_sympy_compute(message)
238
  if sympy_result:
239
- response += "\n\n**Verified with SymPy (for exact symbolic computation):** $$" + sympy_result + "$$"
240
-
241
- return render_latex(response)
242
  except Exception as e:
243
- return f"❌ Error: {str(e)[:100]}... Try a simpler problem."
 
244
 
245
  def get_random_sample():
246
- """Get a random sample problem - loads datasets if needed"""
247
- global math_samples
248
- if math_samples is None:
249
- math_samples = load_sample_problems()
 
250
  return random.choice(math_samples)
251
 
252
- def insert_sample_to_chat(difficulty):
253
- """Insert random sample into chat input"""
254
- return get_random_sample()
255
-
256
- def show_help():
257
- return """**🧮 Math Help Tips:**
258
-
259
- 1. Be Specific: "Find the derivative of x² + 3x" instead of "help with calculus"
260
- 2. Request Steps: "Show me step-by-step how to solve..."
261
- 3. Ask for Verification: "Check if my answer x=5 is correct"
262
- 4. Alternative Methods: "What's another way to solve this integral?"
263
- 5. Use Clear Notation: "lim(x->0)" for limits
264
-
265
- Pro Tip: Crank tokens to 1500+ for competition problems!"""
266
-
267
- # Simple Chatbot interface
268
- with gr.Blocks(title="🧮 Mathetics AI") as demo:
269
- gr.Markdown("# 🧮 **Mathetics AI** - Math Tutor\nPowered by Qwen 2.5-Math")
270
 
271
- chatbot = gr.Chatbot(height=500, label="Conversation", type='messages')
272
- help_text = gr.Markdown(visible=False)
273
-
274
- msg = gr.Textbox(placeholder="Ask a math problem...", show_label=False)
275
 
276
  with gr.Row():
277
- submit = gr.Button("Solve", variant="primary")
278
- clear = gr.Button("Clear", variant="secondary")
279
- sample = gr.Button("Random Problem", variant="secondary")
280
- help_btn = gr.Button("Help", variant="secondary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
 
282
  gr.Examples(
283
  examples=[
284
- ["derivative of x^2 sin(x)"],
285
- ["area of triangle 5-12-13"],
286
- ["x^2 dx from 0 to 2"],
287
- ["limit sin(x)/x as x to 0"],
288
- ["matrix [[1,2],[3,4]]"]
289
  ],
290
  inputs=msg
291
  )
292
 
293
- def chat_response(message, history):
294
- """Updated to use dict-based history for type='messages'."""
295
- bot_response = respond(message, history, create_math_system_message(), 1024, 0.3, 0.85)
296
- # Append as dicts, not tuples
 
297
  history.append({"role": "user", "content": message})
298
- history.append({"role": "assistant", "content": bot_response})
 
 
 
 
 
 
 
 
299
  return history, ""
300
 
301
  def clear_chat():
302
- """Clear the chat history and textbox."""
303
  return [], ""
304
 
305
- msg.submit(chat_response, [msg, chatbot], [chatbot, msg])
306
- submit.click(chat_response, [msg, chatbot], [chatbot, msg])
307
- clear.click(clear_chat, outputs=[chatbot, msg])
308
- sample.click(insert_sample_to_chat, outputs=msg)
309
- help_btn.click(lambda: (show_help(), gr.update(visible=True)), outputs=[help_text, help_text]).then(
310
- lambda: gr.update(visible=False), outputs=help_text
311
  )
 
 
 
 
 
 
 
312
 
313
  demo.launch()
 
4
  from datasets import load_dataset
5
  import random
6
  import re
7
+ import sympy as sp
8
+ import threading
9
 
10
+ # Global datasets
11
+ math_samples = []
12
+ loading_status = {"loaded": False, "error": None}
13
 
14
  def load_sample_problems():
15
+ """Load sample problems asynchronously"""
16
+ global math_samples, loading_status
 
 
 
17
  samples = []
18
+
19
  try:
20
+ # GSM8K
21
+ gsm8k = load_dataset("openai/gsm8k", "main", streaming=True, split="train")
22
+ for i, item in enumerate(gsm8k):
23
+ if i >= 30:
 
 
 
 
24
  break
25
+ samples.append(item["question"])
26
 
27
+ # Fineweb-edu
 
28
  fw = load_dataset("HuggingFaceFW/fineweb-edu", name="sample-10BT", split="train", streaming=True)
29
  fw_count = 0
30
  for item in fw:
31
+ if fw_count >= 15:
32
+ break
33
  text_lower = item['text'].lower()
34
+ if any(w in text_lower for w in ['math', 'calculate', 'solve', 'equation']):
35
+ q = item['text'][:120].strip()
36
+ if len(q) > 20:
37
+ samples.append(q + "...")
 
38
  fw_count += 1
 
 
39
 
40
+ # Ultrachat
41
+ ds = load_dataset("HuggingFaceH4/ultrachat_200k", streaming=True, split="train_sft")
 
42
  ds_count = 0
43
  for item in ds:
44
+ if ds_count >= 15:
45
+ break
46
  if len(item['messages']) > 0:
47
  content = item['messages'][0]['content'].lower()
48
+ if any(w in content for w in ['math', 'solve', 'equation', 'calculate']):
49
+ samples.append(item['messages'][0]['content'])
50
+ ds_count += 1
 
 
 
 
51
 
52
+ math_samples = samples if samples else get_fallback_samples()
53
+ loading_status["loaded"] = True
54
+ print(f"✅ Loaded {len(math_samples)} samples")
55
 
56
  except Exception as e:
57
+ print(f"⚠️ Dataset error: {e}")
58
+ math_samples = get_fallback_samples()
59
+ loading_status["error"] = str(e)
60
+ loading_status["loaded"] = True
 
 
 
 
 
 
 
61
 
62
+ def get_fallback_samples():
63
+ """Extended fallback problems"""
64
+ return [
65
+ "Find the derivative of f(x) = 3x² + 2x - 1",
66
+ "A triangle has sides 5, 12, and 13. What is its area?",
67
+ "If log₂(x) + log₂(x+6) = 4, find x",
68
+ "Calculate lim(x→0) sin(x)/x",
69
+ "Solve: x + 2y = 7, 3x - y = 4",
70
+ "Integrate sin(x) from 0 to π",
71
+ "What is P(rolling three 6s in a row)?",
72
+ "Simplify: (x² - 4)/(x - 2)",
73
+ "Find the sum of 1 + 2 + 3 + ... + 100",
74
+ "What is the 10th Fibonacci number?",
75
+ "Calculate the area of a circle with radius 5",
76
+ "Factor x² + 5x + 6",
77
+ "Solve x² - 4x + 4 = 0",
78
+ "Find tan(π/4)",
79
+ "What is 15% of 240?",
80
+ ]
81
 
82
+ # Start background loading
83
+ threading.Thread(target=load_sample_problems, daemon=True).start()
 
 
 
84
 
85
+ def create_math_system_message():
86
+ """System prompt for math tutoring"""
87
+ return r"""You are Mathetics AI, an expert mathematics tutor.
 
 
 
88
 
89
+ **Teaching Approach:**
90
+ 1. Understand the problem clearly
91
+ 2. Show step-by-step solutions with LaTeX
92
+ 3. Verify answers when possible
93
+ 4. Suggest alternative methods
 
94
 
95
+ **LaTeX Formatting:**
96
+ - Inline: $x^2 + y^2 = r^2$
97
+ - Display: $$\int_0^\pi \sin(x)\,dx = 2$$
98
+ - Box answers: $\boxed{42}$
99
+ - Fractions: $\frac{a}{b}$
100
+ - Limits: $\lim_{x \to 0}$
 
101
 
102
+ Be clear, precise, and educational."""
103
 
104
  def render_latex(text):
105
+ """Clean and normalize LaTeX"""
106
  if not text:
107
  return text
108
 
109
+ # Convert LaTeX brackets to dollars
110
+ text = re.sub(r'\\\[(.*?)\\\]', r'$$\1$$', text, flags=re.DOTALL)
111
+ text = re.sub(r'\\\((.*?)\\\)', r'$\1$', text, flags=re.DOTALL)
112
+
113
+ # Fix boxed answers outside math mode
114
+ text = re.sub(r'(?<!\$)\\boxed\{([^}]+)\}(?!\$)', r'$\\boxed{\1}$', text)
115
+
116
+ # Convert equation environments
117
+ text = re.sub(r'\\begin\{equation\*?\}(.*?)\\end\{equation\*?\}', r'$$\1$$', text, flags=re.DOTALL)
118
+
119
+ # Remove duplicate $$
120
+ text = re.sub(r'\$\$+', '$$', text)
 
 
 
 
 
121
 
122
  return text
123
 
124
  def try_sympy_compute(message):
125
+ """Enhanced SymPy computation with better parsing"""
126
+ from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application
127
 
128
+ msg_lower = message.lower()
129
  x = sp.Symbol('x')
130
+ transforms = standard_transformations + (implicit_multiplication_application,)
131
 
132
+ try:
133
+ # Definite integrals
134
+ match = re.search(r'int(?:egral)?(?:\s+of)?\s+(.+?)\s+from\s+(.+?)\s+to\s+(.+?)(?:\s|$)', msg_lower)
135
  if match:
136
  expr_str, lower, upper = match.groups()
137
+ expr = parse_expr(expr_str.replace('^', '**'), transformations=transforms)
138
+ result = sp.integrate(expr, (x, sp.sympify(lower.strip()), sp.sympify(upper.strip())))
139
+ return sp.latex(result, mode='plain')
140
+
141
+ # Derivatives
142
+ match = re.search(r'deriv(?:ative)?(?:\s+of)?\s+(.+?)(?:\s|$)', msg_lower)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  if match:
144
+ expr_str = match.group(1).strip()
145
+ expr = parse_expr(expr_str.replace('^', '**'), transformations=transforms)
146
+ result = sp.diff(expr, x)
147
+ return sp.latex(result, inv_trig_style='power')
148
+
149
+ # Limits
150
+ match = re.search(r'lim(?:it)?.*?(?:\()?(.+?)\s+(?:as\s+)?(?:x\s*)?(?:→|->|to)\s*(.+?)(?:\)|$)', msg_lower)
 
 
 
 
 
 
151
  if match:
152
+ expr_str, to_val = match.groups()
153
+ expr = parse_expr(expr_str.replace('^', '**'), transformations=transforms)
154
+ result = sp.limit(expr, x, sp.sympify(to_val.strip()))
155
+ return sp.latex(result)
156
+
157
+ # Triangle area (Heron's formula)
158
+ match = re.search(r'(\d+)[,\s-]+(\d+)[,\s-]+(\d+)', message)
159
+ if match and 'triangle' in msg_lower:
160
  a, b, c = map(float, match.groups())
161
+ s = (a + b + c) / 2
162
+ area = sp.sqrt(s * (s-a) * (s-b) * (s-c))
163
+ return sp.latex(area.evalf())
164
+
165
+ except Exception as e:
166
+ print(f"⚠️ SymPy error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
  return None
169
 
170
  def respond(message, history, system_message, max_tokens, temperature, top_p):
171
+ """Streaming response with error handling"""
172
  client = InferenceClient(model="Qwen/Qwen2.5-Math-7B-Instruct")
173
 
174
  messages = [{"role": "system", "content": system_message}]
 
175
  for msg in history:
176
+ messages.append({"role": msg["role"], "content": msg["content"]})
 
 
 
177
  messages.append({"role": "user", "content": message})
178
 
179
  try:
180
+ response_text = ""
181
+ for chunk in client.chat_completion(
182
  messages,
183
  max_tokens=max_tokens,
184
  temperature=temperature,
185
  top_p=top_p,
186
+ stream=True
187
+ ):
188
+ if chunk.choices[0].delta.content:
189
+ response_text += chunk.choices[0].delta.content
190
+ yield render_latex(response_text)
191
 
192
+ # Add SymPy verification
193
  sympy_result = try_sympy_compute(message)
194
  if sympy_result:
195
+ response_text += f"\n\n**✓ Verified with SymPy:** $${sympy_result}$$"
196
+ yield render_latex(response_text)
197
+
198
  except Exception as e:
199
+ error_msg = f"❌ **Error:** {str(e)}\n\nTry:\n- Simpler wording\n- Breaking into steps\n- Checking notation"
200
+ yield error_msg
201
 
202
  def get_random_sample():
203
+ """Get random sample with loading status"""
204
+ if not loading_status["loaded"]:
205
+ return "⏳ Loading samples..."
206
+ if not math_samples:
207
+ return get_fallback_samples()[0]
208
  return random.choice(math_samples)
209
 
210
+ # Gradio Interface
211
+ with gr.Blocks(title="🧮 Mathetics AI", theme=gr.themes.Soft()) as demo:
212
+ gr.Markdown("# 🧮 **Mathetics AI**\n*Advanced Math Tutor powered by Qwen2.5-Math*")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
+ chatbot = gr.Chatbot(height=500, type='messages', label="💬 Conversation")
215
+ msg = gr.Textbox(placeholder="Ask any math problem...", show_label=False, scale=4)
 
 
216
 
217
  with gr.Row():
218
+ submit = gr.Button("🚀 Solve", variant="primary", scale=1)
219
+ clear = gr.Button("🗑️ Clear", variant="secondary", scale=1)
220
+ sample = gr.Button("🎲 Random", variant="secondary", scale=1)
221
+
222
+ with gr.Accordion("⚙️ Advanced Settings", open=False):
223
+ temp_slider = gr.Slider(0.1, 1.0, value=0.3, step=0.1, label="Temperature (creativity)")
224
+ tokens_slider = gr.Slider(256, 2048, value=1024, step=128, label="Max Tokens")
225
+ top_p_slider = gr.Slider(0.1, 1.0, value=0.85, step=0.05, label="Top-p (nucleus sampling)")
226
+
227
+ with gr.Accordion("💡 Help & Examples", open=False):
228
+ gr.Markdown("""
229
+ **Tips:**
230
+ - Be specific: "derivative of sin(2x)" not "help with calculus"
231
+ - Request steps: "show step-by-step"
232
+ - Use clear notation: `x^2` for powers, `lim x->0` for limits
233
+
234
+ **Examples:**
235
+ - Calculus: "Find ∫x² dx from 0 to 5"
236
+ - Algebra: "Solve x² + 5x + 6 = 0"
237
+ - Geometry: "Area of triangle with sides 3, 4, 5"
238
+ - Limits: "Calculate lim(x→0) sin(x)/x"
239
+ """)
240
 
241
  gr.Examples(
242
  examples=[
243
+ ["Find the derivative of x² sin(x)"],
244
+ ["Calculate the area of a triangle with sides 5, 12, 13"],
245
+ ["Integrate x² from 0 to 2"],
246
+ ["What is lim(x→0) sin(x)/x?"],
247
+ ["Solve the equation x² - 5x + 6 = 0"],
248
  ],
249
  inputs=msg
250
  )
251
 
252
+ # Hidden system message (passed to respond)
253
+ system_msg = gr.State(create_math_system_message())
254
+
255
+ def chat_response(message, history, sys_msg, max_tok, temp, top_p):
256
+ """Handle chat with streaming"""
257
  history.append({"role": "user", "content": message})
258
+
259
+ # Create assistant message slot
260
+ history.append({"role": "assistant", "content": ""})
261
+
262
+ # Stream responses
263
+ for response in respond(message, history[:-1], sys_msg, max_tok, temp, top_p):
264
+ history[-1]["content"] = response
265
+ yield history, ""
266
+
267
  return history, ""
268
 
269
  def clear_chat():
 
270
  return [], ""
271
 
272
+ msg.submit(
273
+ chat_response,
274
+ [msg, chatbot, system_msg, tokens_slider, temp_slider, top_p_slider],
275
+ [chatbot, msg]
 
 
276
  )
277
+ submit.click(
278
+ chat_response,
279
+ [msg, chatbot, system_msg, tokens_slider, temp_slider, top_p_slider],
280
+ [chatbot, msg]
281
+ )
282
+ clear.click(clear_chat, outputs=[chatbot, msg])
283
+ sample.click(get_random_sample, outputs=msg)
284
 
285
  demo.launch()