realArceus commited on
Commit
5a96cd2
Β·
verified Β·
1 Parent(s): 7cf695b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -145
app.py CHANGED
@@ -4,7 +4,7 @@ import random
4
  from huggingface_hub import InferenceClient
5
 
6
  # ── Model config ──────────────────────────────────────────────────────────────
7
- REASONER_MODEL = "Qwen/Qwen2.5-7B-Instruct" # swap later for local
8
  client = InferenceClient(REASONER_MODEL)
9
 
10
  SYSTEM_PROMPT = """You are a careful step-by-step reasoner.
@@ -17,24 +17,20 @@ Final Answer: <answer>
17
 
18
  Be deliberate. Show your full working. Each step should be one clear thought."""
19
 
20
- # ── Sentinel (placeholder β€” will be replaced with fine-tuned model) ───────────
21
- def sentinel_score(problem: str, steps_so_far: list[str]) -> tuple[str, float]:
22
  """
23
- Placeholder sentinel. Returns (label, confidence).
24
  Real version: fine-tuned classifier on PRM800K step-level annotations.
25
  """
26
  context = " ".join(steps_so_far).lower()
27
- red_flags = [
28
- "therefore", "obviously", "clearly", "must be", "so",
29
- "=", "thus", "hence"
30
- ]
31
- # Heuristic: suspiciously fast conclusions or leaps get flagged
32
  leap_score = sum(1 for f in red_flags if f in context) / max(len(steps_so_far), 1)
33
  confidence = round(min(0.95, max(0.4, 0.85 - leap_score * 0.15 + random.uniform(-0.05, 0.05))), 2)
34
  label = "OK" if confidence >= 0.6 else "FAIL"
35
  return label, confidence
36
 
37
- # ── Core reasoning pipeline ───────────────────────────────────────────────────
38
  def run_twt(problem: str):
39
  if not problem.strip():
40
  yield (
@@ -44,11 +40,8 @@ def run_twt(problem: str):
44
  )
45
  return
46
 
47
- steps_so_far = []
48
  cot_html = ""
49
- trace_html = ""
50
 
51
- # Stream CoT from reasoner
52
  messages = [
53
  {"role": "system", "content": SYSTEM_PROMPT},
54
  {"role": "user", "content": problem.strip()}
@@ -72,15 +65,9 @@ def run_twt(problem: str):
72
  )
73
  return
74
 
75
- # Parse into steps
76
  lines = full_response.strip().split("\n")
77
- parsed_steps = []
78
- for line in lines:
79
- line = line.strip()
80
- if line:
81
- parsed_steps.append(line)
82
 
83
- # Animate step by step with sentinel scoring
84
  displayed_steps = []
85
  first_fail_seen = False
86
 
@@ -89,11 +76,10 @@ def run_twt(problem: str):
89
  is_final = step.lower().startswith("final answer")
90
 
91
  if not is_final:
92
- label, conf = sentinel_score(problem, displayed_steps)
93
  else:
94
  label, conf = "FINAL", 1.0
95
 
96
- # Build step card
97
  if is_final:
98
  icon = "🏁"
99
  badge_class = "badge-final"
@@ -110,42 +96,36 @@ def run_twt(problem: str):
110
  first_fail_seen = True
111
 
112
  step_card = f"""
113
- <div class='step-card {"step-fault" if label == "FAIL" else ""}' style='animation-delay:{i*0.05}s'>
114
  <span class='step-icon'>{icon}</span>
115
  <span class='step-text'>{step}</span>
116
  <span class='badge {badge_class}'>{badge_text}</span>
117
  </div>"""
118
  cot_html += step_card
119
 
120
- # Build trace panel
121
- trace_html = build_trace(parsed_steps[:i+1], displayed_steps, first_fail_seen)
122
-
123
  yield (full_response, cot_html, trace_html)
124
  time.sleep(0.15)
125
 
126
- # Final trace summary
127
- fault_count = sum(1 for s in displayed_steps
128
- if sentinel_score(problem, displayed_steps[:displayed_steps.index(s)+1])[0] == "FAIL")
129
- yield (full_response, cot_html, build_trace(parsed_steps, displayed_steps, first_fail_seen, done=True))
130
 
131
 
132
- def build_trace(all_steps, displayed, first_fail, done=False):
133
- total = len(all_steps)
134
  faults = 0
135
  rows = ""
136
  for i, s in enumerate(displayed):
137
  is_final = s.lower().startswith("final answer")
138
  if not is_final:
139
- lbl, conf = sentinel_score("", displayed[:i+1])
140
  if lbl == "FAIL":
141
  faults += 1
142
  dot = f"<span class='dot dot-{'ok' if lbl == 'OK' else 'fail'}'></span>"
143
- rows += f"<div class='trace-row'>{dot} Step {i+1} β€” {int(conf*100)}% confidence</div>"
144
  else:
145
- rows += f"<div class='trace-row'><span class='dot dot-final'></span> {s}</div>"
146
 
147
  health = max(0, 100 - faults * 20)
148
- bar_color = "#4ade80" if health > 60 else "#f87171"
149
  summary = f"""
150
  <div class='trace-summary'>
151
  <div class='trace-label'>Reasoning Health</div>
@@ -159,171 +139,215 @@ def build_trace(all_steps, displayed, first_fail, done=False):
159
  return f"{rows}{summary}"
160
 
161
 
162
- # ── CSS ───────────────────────────────────────────────────────────────────────
163
  CSS = """
164
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
165
 
166
- * { box-sizing: border-box; margin: 0; padding: 0; }
167
 
168
- body, .gradio-container {
169
- background: #1e1e2e !important;
170
- color: #cdd6f4 !important;
171
  font-family: 'Inter', sans-serif !important;
172
  }
173
 
174
- /* Header */
 
 
 
 
 
175
  .twt-header {
176
  text-align: center;
177
- padding: 2.5rem 1rem 1.5rem;
178
- border-bottom: 1px solid #313244;
179
  margin-bottom: 1.5rem;
 
 
180
  }
181
  .twt-title {
182
  font-size: 2rem;
183
- font-weight: 600;
184
- letter-spacing: -0.03em;
185
- color: #cdd6f4;
186
- font-family: 'JetBrains Mono', monospace;
187
  }
188
- .twt-title span { color: #cba6f7; }
189
  .twt-sub {
190
- font-size: 0.8rem;
191
- color: #6c7086;
192
- margin-top: 0.4rem;
193
- letter-spacing: 0.08em;
194
  text-transform: uppercase;
 
195
  }
196
 
197
- /* Input area */
198
  .input-label {
199
- font-size: 0.75rem;
200
- font-weight: 500;
201
- color: #a6adc8;
202
- letter-spacing: 0.06em;
203
  text-transform: uppercase;
204
- margin-bottom: 0.5rem;
205
  }
 
206
  textarea {
207
- background: #181825 !important;
208
- border: 1px solid #45475a !important;
209
  border-radius: 8px !important;
210
- color: #cdd6f4 !important;
211
- font-family: 'Inter', sans-serif !important;
212
  font-size: 0.95rem !important;
213
- transition: border-color 0.2s !important;
 
 
214
  }
215
  textarea:focus {
216
- border-color: #cba6f7 !important;
 
217
  outline: none !important;
218
  }
 
219
 
220
- /* Button */
221
  button.primary {
222
- background: #cba6f7 !important;
223
- color: #1e1e2e !important;
224
  font-weight: 600 !important;
225
  font-family: 'Inter', sans-serif !important;
226
  border: none !important;
227
  border-radius: 8px !important;
228
  padding: 0.65rem 1.5rem !important;
229
  font-size: 0.9rem !important;
230
- letter-spacing: 0.02em !important;
231
- transition: background 0.2s !important;
232
  cursor: pointer !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  }
234
- button.primary:hover { background: #b4befe !important; }
235
 
236
- /* Step cards */
237
  .step-card {
238
  display: flex;
239
  align-items: flex-start;
240
  gap: 0.75rem;
241
  padding: 0.75rem 1rem;
242
  margin-bottom: 0.5rem;
243
- background: #181825;
244
- border: 1px solid #313244;
245
  border-radius: 8px;
246
- font-size: 0.88rem;
247
- line-height: 1.6;
248
- animation: fadeSlide 0.25s ease both;
 
249
  }
250
  .step-card.step-fault {
251
- border-color: #f38ba8;
252
- background: #2a1520;
253
  }
254
- @keyframes fadeSlide {
255
- from { opacity: 0; transform: translateY(6px); }
256
  to { opacity: 1; transform: translateY(0); }
257
  }
258
- .step-icon { font-size: 1rem; flex-shrink: 0; margin-top: 1px; }
259
- .step-text { flex: 1; color: #cdd6f4; font-family: 'Inter', sans-serif; }
 
 
 
 
 
260
  .badge {
261
  flex-shrink: 0;
262
- font-size: 0.65rem;
263
- font-weight: 600;
264
- font-family: 'JetBrains Mono', monospace;
265
- letter-spacing: 0.05em;
266
- padding: 0.2rem 0.5rem;
267
  border-radius: 4px;
268
  align-self: flex-start;
269
- margin-top: 2px;
270
  }
271
- .badge-ok { background: #1e3a2a; color: #a6e3a1; border: 1px solid #a6e3a1; }
272
- .badge-fail { background: #3a1e22; color: #f38ba8; border: 1px solid #f38ba8; }
273
- .badge-final { background: #2a1e3a; color: #cba6f7; border: 1px solid #cba6f7; }
274
 
275
- /* Trace panel */
276
  .trace-row {
277
  display: flex;
278
  align-items: center;
279
  gap: 0.6rem;
280
- font-size: 0.8rem;
281
- color: #a6adc8;
282
- font-family: 'JetBrains Mono', monospace;
283
  padding: 0.35rem 0;
284
- border-bottom: 1px solid #313244;
285
  }
286
  .dot {
287
  width: 8px; height: 8px;
288
  border-radius: 50%;
289
  flex-shrink: 0;
290
  }
291
- .dot-ok { background: #a6e3a1; }
292
- .dot-fail { background: #f38ba8; box-shadow: 0 0 6px #f38ba8; }
293
- .dot-final { background: #cba6f7; }
294
-
295
- .trace-summary { margin-top: 1rem; }
296
- .trace-label { font-size: 0.7rem; color: #a6adc8; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 0.4rem; }
297
- .trace-bar-bg { background: #313244; border-radius: 4px; height: 6px; overflow: hidden; }
298
- .trace-bar { height: 100%; border-radius: 4px; transition: width 0.5s ease; }
299
- .trace-pct { font-size: 0.75rem; color: #a6adc8; margin-top: 0.3rem; font-family: 'JetBrains Mono', monospace; }
300
 
301
- /* Panel labels */
302
- .panel-label {
303
- font-size: 0.7rem;
304
- font-weight: 600;
305
- color: #a6adc8;
306
  text-transform: uppercase;
307
  letter-spacing: 0.1em;
308
- margin-bottom: 0.75rem;
309
- padding-bottom: 0.5rem;
310
- border-bottom: 1px solid #313244;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  }
312
 
313
- /* Messages */
314
  .msg { padding: 0.75rem 1rem; border-radius: 8px; font-size: 0.85rem; }
315
- .msg.warn { background: #2a2010; color: #f9e2af; border: 1px solid #f9e2af; }
316
- .msg.error { background: #2a1520; color: #f38ba8; border: 1px solid #f38ba8; }
317
- .msg.empty { color: #6c7086; font-size: 0.8rem; font-family: 'JetBrains Mono', monospace; }
318
-
319
- /* Output panels */
320
- .output-panel {
321
- background: #181825;
322
- border: 1px solid #313244;
323
- border-radius: 10px;
324
  padding: 1rem;
325
- min-height: 200px;
326
  }
 
 
 
 
 
327
  """
328
 
329
  # ── Layout ────────────────────────────────────────────────────────────────────
@@ -334,7 +358,7 @@ HEADER = """
334
  </div>
335
  """
336
 
337
- EXAMPLE_PROBLEMS = [
338
  "If a bat and a ball cost $1.10 in total, and the bat costs $1 more than the ball, how much does the ball cost?",
339
  "A farmer has 17 sheep. All but 9 die. How many sheep are left?",
340
  "What is 15% of 80? Then add that to 25% of 60.",
@@ -349,20 +373,16 @@ with gr.Blocks(css=CSS, title="ThinkWhileThinking") as demo:
349
  gr.HTML("<div class='input-label'>Problem</div>")
350
  problem_input = gr.Textbox(
351
  placeholder="Enter a math, logic, or reasoning problem...",
352
- lines=4,
353
  show_label=False,
354
  )
355
- run_btn = gr.Button("β–Ά Analyze Reasoning", variant="primary")
356
- gr.Examples(
357
- examples=EXAMPLE_PROBLEMS,
358
- inputs=problem_input,
359
- label="Try an example",
360
- )
361
 
362
  with gr.Column(scale=3):
363
  with gr.Row():
364
  with gr.Column(scale=3):
365
- gr.HTML("<div class='panel-label'>Chain of Thought Β· Sentinel Scores</div>")
366
  cot_output = gr.HTML(
367
  value="<div class='msg empty'>// awaiting problem input</div>"
368
  )
@@ -374,15 +394,7 @@ with gr.Blocks(css=CSS, title="ThinkWhileThinking") as demo:
374
 
375
  raw_output = gr.Textbox(visible=False)
376
 
377
- run_btn.click(
378
- fn=run_twt,
379
- inputs=[problem_input],
380
- outputs=[raw_output, cot_output, trace_output],
381
- )
382
- problem_input.submit(
383
- fn=run_twt,
384
- inputs=[problem_input],
385
- outputs=[raw_output, cot_output, trace_output],
386
- )
387
 
388
  demo.launch()
 
4
  from huggingface_hub import InferenceClient
5
 
6
  # ── Model config ──────────────────────────────────────────────────────────────
7
+ REASONER_MODEL = "Qwen/Qwen2.5-7B-Instruct"
8
  client = InferenceClient(REASONER_MODEL)
9
 
10
  SYSTEM_PROMPT = """You are a careful step-by-step reasoner.
 
17
 
18
  Be deliberate. Show your full working. Each step should be one clear thought."""
19
 
20
+ # ── Step Probe (placeholder β€” will be replaced with fine-tuned model) ─────────
21
+ def probe_step(problem: str, steps_so_far: list[str]) -> tuple[str, float]:
22
  """
23
+ Step-level reasoning probe. Returns (label, confidence).
24
  Real version: fine-tuned classifier on PRM800K step-level annotations.
25
  """
26
  context = " ".join(steps_so_far).lower()
27
+ red_flags = ["therefore", "obviously", "clearly", "must be", "so", "=", "thus", "hence"]
 
 
 
 
28
  leap_score = sum(1 for f in red_flags if f in context) / max(len(steps_so_far), 1)
29
  confidence = round(min(0.95, max(0.4, 0.85 - leap_score * 0.15 + random.uniform(-0.05, 0.05))), 2)
30
  label = "OK" if confidence >= 0.6 else "FAIL"
31
  return label, confidence
32
 
33
+ # ── Core pipeline ─────────────────────────────────────────────────────────────
34
  def run_twt(problem: str):
35
  if not problem.strip():
36
  yield (
 
40
  )
41
  return
42
 
 
43
  cot_html = ""
 
44
 
 
45
  messages = [
46
  {"role": "system", "content": SYSTEM_PROMPT},
47
  {"role": "user", "content": problem.strip()}
 
65
  )
66
  return
67
 
 
68
  lines = full_response.strip().split("\n")
69
+ parsed_steps = [l.strip() for l in lines if l.strip()]
 
 
 
 
70
 
 
71
  displayed_steps = []
72
  first_fail_seen = False
73
 
 
76
  is_final = step.lower().startswith("final answer")
77
 
78
  if not is_final:
79
+ label, conf = probe_step(problem, displayed_steps)
80
  else:
81
  label, conf = "FINAL", 1.0
82
 
 
83
  if is_final:
84
  icon = "🏁"
85
  badge_class = "badge-final"
 
96
  first_fail_seen = True
97
 
98
  step_card = f"""
99
+ <div class='step-card {"step-fault" if label == "FAIL" else ""}'>
100
  <span class='step-icon'>{icon}</span>
101
  <span class='step-text'>{step}</span>
102
  <span class='badge {badge_class}'>{badge_text}</span>
103
  </div>"""
104
  cot_html += step_card
105
 
106
+ trace_html = build_trace(displayed_steps, first_fail_seen)
 
 
107
  yield (full_response, cot_html, trace_html)
108
  time.sleep(0.15)
109
 
110
+ yield (full_response, cot_html, build_trace(displayed_steps, first_fail_seen, done=True))
 
 
 
111
 
112
 
113
+ def build_trace(displayed, first_fail, done=False):
 
114
  faults = 0
115
  rows = ""
116
  for i, s in enumerate(displayed):
117
  is_final = s.lower().startswith("final answer")
118
  if not is_final:
119
+ lbl, conf = probe_step("", displayed[:i+1])
120
  if lbl == "FAIL":
121
  faults += 1
122
  dot = f"<span class='dot dot-{'ok' if lbl == 'OK' else 'fail'}'></span>"
123
+ rows += f"<div class='trace-row'>{dot} Step {i+1} &mdash; {int(conf*100)}%</div>"
124
  else:
125
+ rows += f"<div class='trace-row'><span class='dot dot-final'></span> Final Answer</div>"
126
 
127
  health = max(0, 100 - faults * 20)
128
+ bar_color = "#16a34a" if health > 60 else "#dc2626"
129
  summary = f"""
130
  <div class='trace-summary'>
131
  <div class='trace-label'>Reasoning Health</div>
 
139
  return f"{rows}{summary}"
140
 
141
 
142
+ # ── CSS β€” clean light theme, high contrast ────────────────────────────────────
143
  CSS = """
144
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
145
 
146
+ *, *::before, *::after { box-sizing: border-box; }
147
 
148
+ body, .gradio-container, .gradio-container * {
 
 
149
  font-family: 'Inter', sans-serif !important;
150
  }
151
 
152
+ .gradio-container {
153
+ background: #f8fafc !important;
154
+ max-width: 1200px !important;
155
+ }
156
+
157
+ /* ── Header ── */
158
  .twt-header {
159
  text-align: center;
160
+ padding: 2rem 1rem 1.25rem;
161
+ border-bottom: 2px solid #e2e8f0;
162
  margin-bottom: 1.5rem;
163
+ background: #ffffff;
164
+ border-radius: 12px 12px 0 0;
165
  }
166
  .twt-title {
167
  font-size: 2rem;
168
+ font-weight: 700;
169
+ letter-spacing: -0.04em;
170
+ color: #0f172a;
171
+ font-family: 'JetBrains Mono', monospace !important;
172
  }
173
+ .twt-title span { color: #7c3aed; }
174
  .twt-sub {
175
+ font-size: 0.75rem;
176
+ color: #94a3b8;
177
+ margin-top: 0.35rem;
178
+ letter-spacing: 0.1em;
179
  text-transform: uppercase;
180
+ font-weight: 500;
181
  }
182
 
183
+ /* ── Input ── */
184
  .input-label {
185
+ font-size: 0.7rem;
186
+ font-weight: 700;
187
+ color: #64748b;
188
+ letter-spacing: 0.1em;
189
  text-transform: uppercase;
190
+ margin-bottom: 0.4rem;
191
  }
192
+
193
  textarea {
194
+ background: #ffffff !important;
195
+ border: 1.5px solid #cbd5e1 !important;
196
  border-radius: 8px !important;
197
+ color: #0f172a !important;
 
198
  font-size: 0.95rem !important;
199
+ line-height: 1.6 !important;
200
+ transition: border-color 0.15s !important;
201
+ padding: 0.75rem !important;
202
  }
203
  textarea:focus {
204
+ border-color: #7c3aed !important;
205
+ box-shadow: 0 0 0 3px rgba(124,58,237,0.1) !important;
206
  outline: none !important;
207
  }
208
+ textarea::placeholder { color: #94a3b8 !important; }
209
 
210
+ /* ── Button ── */
211
  button.primary {
212
+ background: #7c3aed !important;
213
+ color: #ffffff !important;
214
  font-weight: 600 !important;
215
  font-family: 'Inter', sans-serif !important;
216
  border: none !important;
217
  border-radius: 8px !important;
218
  padding: 0.65rem 1.5rem !important;
219
  font-size: 0.9rem !important;
220
+ letter-spacing: 0.01em !important;
221
+ transition: background 0.15s, transform 0.1s !important;
222
  cursor: pointer !important;
223
+ width: 100% !important;
224
+ }
225
+ button.primary:hover {
226
+ background: #6d28d9 !important;
227
+ transform: translateY(-1px) !important;
228
+ }
229
+ button.primary:active { transform: translateY(0) !important; }
230
+
231
+ /* ── Panel labels ── */
232
+ .panel-label {
233
+ font-size: 0.68rem;
234
+ font-weight: 700;
235
+ color: #64748b;
236
+ text-transform: uppercase;
237
+ letter-spacing: 0.12em;
238
+ margin-bottom: 0.75rem;
239
+ padding-bottom: 0.5rem;
240
+ border-bottom: 2px solid #e2e8f0;
241
  }
 
242
 
243
+ /* ── Step cards ── */
244
  .step-card {
245
  display: flex;
246
  align-items: flex-start;
247
  gap: 0.75rem;
248
  padding: 0.75rem 1rem;
249
  margin-bottom: 0.5rem;
250
+ background: #ffffff;
251
+ border: 1.5px solid #e2e8f0;
252
  border-radius: 8px;
253
+ font-size: 0.875rem;
254
+ line-height: 1.65;
255
+ animation: fadeUp 0.2s ease both;
256
+ box-shadow: 0 1px 3px rgba(0,0,0,0.04);
257
  }
258
  .step-card.step-fault {
259
+ border-color: #fca5a5;
260
+ background: #fff5f5;
261
  }
262
+ @keyframes fadeUp {
263
+ from { opacity: 0; transform: translateY(8px); }
264
  to { opacity: 1; transform: translateY(0); }
265
  }
266
+ .step-icon { font-size: 1rem; flex-shrink: 0; margin-top: 2px; }
267
+ .step-text {
268
+ flex: 1;
269
+ color: #1e293b;
270
+ font-family: 'Inter', sans-serif !important;
271
+ font-size: 0.875rem;
272
+ }
273
  .badge {
274
  flex-shrink: 0;
275
+ font-size: 0.62rem;
276
+ font-weight: 700;
277
+ font-family: 'JetBrains Mono', monospace !important;
278
+ letter-spacing: 0.04em;
279
+ padding: 0.18rem 0.5rem;
280
  border-radius: 4px;
281
  align-self: flex-start;
282
+ margin-top: 3px;
283
  }
284
+ .badge-ok { background: #dcfce7; color: #15803d; border: 1px solid #86efac; }
285
+ .badge-fail { background: #fee2e2; color: #b91c1c; border: 1px solid #fca5a5; }
286
+ .badge-final { background: #ede9fe; color: #6d28d9; border: 1px solid #c4b5fd; }
287
 
288
+ /* ── Trace panel ── */
289
  .trace-row {
290
  display: flex;
291
  align-items: center;
292
  gap: 0.6rem;
293
+ font-size: 0.78rem;
294
+ color: #475569;
295
+ font-family: 'JetBrains Mono', monospace !important;
296
  padding: 0.35rem 0;
297
+ border-bottom: 1px solid #f1f5f9;
298
  }
299
  .dot {
300
  width: 8px; height: 8px;
301
  border-radius: 50%;
302
  flex-shrink: 0;
303
  }
304
+ .dot-ok { background: #22c55e; }
305
+ .dot-fail { background: #ef4444; box-shadow: 0 0 5px rgba(239,68,68,0.4); }
306
+ .dot-final { background: #7c3aed; }
 
 
 
 
 
 
307
 
308
+ .trace-summary { margin-top: 1rem; padding-top: 0.75rem; border-top: 1px solid #e2e8f0; }
309
+ .trace-label {
310
+ font-size: 0.65rem;
311
+ font-weight: 700;
312
+ color: #64748b;
313
  text-transform: uppercase;
314
  letter-spacing: 0.1em;
315
+ margin-bottom: 0.5rem;
316
+ }
317
+ .trace-bar-bg {
318
+ background: #e2e8f0;
319
+ border-radius: 999px;
320
+ height: 6px;
321
+ overflow: hidden;
322
+ }
323
+ .trace-bar {
324
+ height: 100%;
325
+ border-radius: 999px;
326
+ transition: width 0.6s ease;
327
+ }
328
+ .trace-pct {
329
+ font-size: 0.72rem;
330
+ color: #475569;
331
+ margin-top: 0.3rem;
332
+ font-family: 'JetBrains Mono', monospace !important;
333
+ font-weight: 500;
334
  }
335
 
336
+ /* ── Messages ── */
337
  .msg { padding: 0.75rem 1rem; border-radius: 8px; font-size: 0.85rem; }
338
+ .msg.warn { background: #fffbeb; color: #92400e; border: 1px solid #fcd34d; }
339
+ .msg.error { background: #fff5f5; color: #b91c1c; border: 1px solid #fca5a5; }
340
+ .msg.empty {
341
+ color: #94a3b8;
342
+ font-size: 0.8rem;
343
+ font-family: 'JetBrains Mono', monospace !important;
 
 
 
344
  padding: 1rem;
 
345
  }
346
+
347
+ /* ── Gradio overrides ── */
348
+ .gradio-container .prose { color: #1e293b !important; }
349
+ .gr-box, .gr-form { background: #ffffff !important; border-color: #e2e8f0 !important; }
350
+ label span { color: #374151 !important; font-size: 0.85rem !important; }
351
  """
352
 
353
  # ── Layout ────────────────────────────────────────────────────────────────────
 
358
  </div>
359
  """
360
 
361
+ EXAMPLES = [
362
  "If a bat and a ball cost $1.10 in total, and the bat costs $1 more than the ball, how much does the ball cost?",
363
  "A farmer has 17 sheep. All but 9 die. How many sheep are left?",
364
  "What is 15% of 80? Then add that to 25% of 60.",
 
373
  gr.HTML("<div class='input-label'>Problem</div>")
374
  problem_input = gr.Textbox(
375
  placeholder="Enter a math, logic, or reasoning problem...",
376
+ lines=5,
377
  show_label=False,
378
  )
379
+ run_btn = gr.Button("β–Ά Analyze Reasoning", variant="primary")
380
+ gr.Examples(examples=EXAMPLES, inputs=problem_input, label="Try an example")
 
 
 
 
381
 
382
  with gr.Column(scale=3):
383
  with gr.Row():
384
  with gr.Column(scale=3):
385
+ gr.HTML("<div class='panel-label'>Chain of Thought Β· Step Scores</div>")
386
  cot_output = gr.HTML(
387
  value="<div class='msg empty'>// awaiting problem input</div>"
388
  )
 
394
 
395
  raw_output = gr.Textbox(visible=False)
396
 
397
+ run_btn.click(fn=run_twt, inputs=[problem_input], outputs=[raw_output, cot_output, trace_output])
398
+ problem_input.submit(fn=run_twt, inputs=[problem_input], outputs=[raw_output, cot_output, trace_output])
 
 
 
 
 
 
 
 
399
 
400
  demo.launch()