HAMMALE commited on
Commit
07cc304
·
verified ·
1 Parent(s): f825210

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +18 -49
app.py CHANGED
@@ -9,7 +9,6 @@ import ast
9
  import operator as op
10
  import wikipedia
11
 
12
- # Tool implementations
13
  class Tool:
14
  def __init__(self, name: str, description: str, func):
15
  self.name = name
@@ -32,7 +31,6 @@ def duckduckgo_search(query: str) -> str:
32
  response = requests.get(url, params=params, timeout=10)
33
  data = response.json()
34
 
35
- # Get abstract or first related topic
36
  if data.get('Abstract'):
37
  return f"Search result: {data['Abstract']}"
38
  elif data.get('RelatedTopics') and len(data['RelatedTopics']) > 0:
@@ -50,7 +48,6 @@ def wikipedia_search(query: str) -> str:
50
  """Search Wikipedia for information."""
51
  try:
52
  wikipedia.set_lang("en")
53
- # Get summary
54
  summary = wikipedia.summary(query, sentences=3, auto_suggest=True)
55
  return f"Wikipedia: {summary}"
56
  except wikipedia.exceptions.DisambiguationError as e:
@@ -80,7 +77,6 @@ def get_weather(location: str) -> str:
80
 
81
  def calculate(expression: str) -> str:
82
  """Safely evaluate mathematical expressions."""
83
- # Supported operators
84
  operators = {
85
  ast.Add: op.add,
86
  ast.Sub: op.sub,
@@ -99,7 +95,6 @@ def calculate(expression: str) -> str:
99
  elif isinstance(node, ast.UnaryOp):
100
  return operators[type(node.op)](eval_expr(node.operand))
101
  elif isinstance(node, ast.Call):
102
- # Support basic math functions
103
  if node.func.id == 'abs':
104
  return abs(eval_expr(node.args[0]))
105
  elif node.func.id == 'round':
@@ -108,9 +103,7 @@ def calculate(expression: str) -> str:
108
  raise TypeError(node)
109
 
110
  try:
111
- # Clean the expression
112
  expression = expression.strip()
113
- # Parse and evaluate
114
  node = ast.parse(expression, mode='eval')
115
  result = eval_expr(node.body)
116
  return f"Result: {result}"
@@ -120,7 +113,6 @@ def calculate(expression: str) -> str:
120
  def python_repl(code: str) -> str:
121
  """Execute safe Python code (limited to basic operations)."""
122
  try:
123
- # Whitelist of safe builtins
124
  safe_builtins = {
125
  'abs': abs, 'round': round, 'min': min, 'max': max,
126
  'sum': sum, 'len': len, 'range': range, 'list': list,
@@ -129,23 +121,18 @@ def python_repl(code: str) -> str:
129
  'sorted': sorted, 'reversed': reversed,
130
  }
131
 
132
- # Create restricted namespace
133
  namespace = {'__builtins__': safe_builtins}
134
 
135
- # Capture output
136
  from io import StringIO
137
  import sys
138
  old_stdout = sys.stdout
139
  sys.stdout = StringIO()
140
 
141
- # Execute code
142
  exec(code, namespace)
143
 
144
- # Get output
145
  output = sys.stdout.getvalue()
146
  sys.stdout = old_stdout
147
 
148
- # Also get any variables that were set
149
  result_vars = {k: v for k, v in namespace.items() if k != '__builtins__' and not k.startswith('_')}
150
 
151
  result = output if output else str(result_vars) if result_vars else "Code executed successfully (no output)"
@@ -153,7 +140,6 @@ def python_repl(code: str) -> str:
153
  except Exception as e:
154
  return f"Python error: {str(e)}"
155
 
156
- # Define tools
157
  TOOLS = [
158
  Tool(
159
  name="duckduckgo_search",
@@ -182,14 +168,12 @@ TOOLS = [
182
  ),
183
  ]
184
 
185
- # Create tool descriptions for prompt
186
  def get_tool_descriptions() -> str:
187
  descriptions = []
188
  for tool in TOOLS:
189
  descriptions.append(f"- {tool.name}: {tool.description}")
190
  return "\n".join(descriptions)
191
 
192
- # Agent prompts
193
  THINK_ONLY_PROMPT = """You are a helpful AI assistant. You solve problems by thinking through them step-by-step.
194
 
195
  For each question:
@@ -297,11 +281,10 @@ def think_only_mode(question: str) -> Generator[str, None, None]:
297
  messages = [{"role": "user", "content": prompt}]
298
 
299
  yield "**Mode: Think-Only (Chain-of-Thought)**\n\n"
300
- yield "🤔 Generating thoughts...\n\n"
301
 
302
  response = call_llm(messages, temperature=0.7, max_tokens=800)
303
 
304
- # Parse and format the response
305
  lines = response.split('\n')
306
  for line in lines:
307
  if line.strip():
@@ -329,33 +312,29 @@ def act_only_mode(question: str, max_iterations: int = 5) -> Generator[str, None
329
 
330
  response = call_llm(messages, temperature=0.5, max_tokens=300)
331
 
332
- # Check for final answer
333
  if 'Answer:' in response:
334
  answer_match = re.search(r'Answer:\s*(.+)', response, re.IGNORECASE | re.DOTALL)
335
  if answer_match:
336
- yield f" **Answer:** {answer_match.group(1).strip()}\n\n"
337
  break
338
 
339
- # Parse action
340
  action_name, action_input = parse_action(response)
341
 
342
  if action_name and action_input:
343
- yield f" **Action:** {action_name}\n"
344
- yield f" **Action Input:** {action_input}\n\n"
345
 
346
- # Execute tool
347
  observation = call_tool(action_name, action_input)
348
- yield f" **Observation:** {observation}\n\n"
349
 
350
- # Add to conversation
351
  messages.append({"role": "assistant", "content": response})
352
  messages.append({"role": "user", "content": f"Observation: {observation}\n\nContinue with another action or provide the final answer."})
353
  else:
354
- yield f"⚠️ Could not parse action from response. Response: {response}\n\n"
355
  break
356
 
357
  if iteration >= max_iterations:
358
- yield "⚠️ **Reached maximum iterations.**\n\n"
359
 
360
  yield "\n---\n**Mode completed**\n"
361
 
@@ -374,44 +353,37 @@ def react_mode(question: str, max_iterations: int = 5) -> Generator[str, None, N
374
 
375
  response = call_llm(messages, temperature=0.7, max_tokens=400)
376
 
377
- # Parse thoughts
378
  thought_matches = re.findall(r'Thought:\s*(.+?)(?=\n(?:Action:|Answer:|$))', response, re.IGNORECASE | re.DOTALL)
379
  for thought in thought_matches:
380
  yield f"**Thought:** {thought.strip()}\n\n"
381
 
382
- # Check for final answer
383
  if 'Answer:' in response:
384
  answer_match = re.search(r'Answer:\s*(.+)', response, re.IGNORECASE | re.DOTALL)
385
  if answer_match:
386
  yield f"**Answer:** {answer_match.group(1).strip()}\n\n"
387
  break
388
 
389
- # Parse action
390
  action_name, action_input = parse_action(response)
391
 
392
  if action_name and action_input:
393
- yield f" **Action:** {action_name}\n"
394
  yield f"**Action Input:** {action_input}\n\n"
395
 
396
- # Execute tool
397
  observation = call_tool(action_name, action_input)
398
  yield f"**Observation:** {observation}\n\n"
399
 
400
- # Add to conversation
401
  messages.append({"role": "assistant", "content": response})
402
  messages.append({"role": "user", "content": f"Observation: {observation}\n\nThought:"})
403
  else:
404
- # If no action but also no answer, there might be an issue
405
  if 'Answer:' not in response:
406
- yield f"⚠️ No action found. Response: {response}\n\n"
407
  break
408
 
409
  if iteration >= max_iterations:
410
- yield "⚠️ **Reached maximum iterations.**\n\n"
411
 
412
  yield "\n---\n**Mode completed**\n"
413
 
414
- # Example questions
415
  EXAMPLES = [
416
  "What is the capital of France and what's the current weather there?",
417
  "Who wrote 'To Kill a Mockingbird' and when was it published?",
@@ -434,19 +406,17 @@ def run_comparison(question: str, mode: str):
434
  else:
435
  return "Invalid mode selected.", "", ""
436
 
437
- # Gradio Interface
438
  with gr.Blocks(title="LLM Reasoning Modes Comparison") as demo:
439
  gr.Markdown("""
440
- # 🧠 LLM Reasoning Modes Comparison
441
 
442
  Compare three reasoning approaches using **openai/gpt-oss-20b**:
443
 
444
  - **Think-Only**: Chain-of-Thought reasoning only (no tools)
445
  - **Act-Only**: Tool use only (no explicit reasoning)
446
- - **ReAct**: Interleaved Thought Action Observation
447
 
448
- ### Available Tools:
449
- 🔍 DuckDuckGo Search | 📚 Wikipedia | 🌤️ Weather API | 🧮 Calculator | 🐍 Python REPL
450
  """)
451
 
452
  with gr.Row():
@@ -461,12 +431,12 @@ with gr.Blocks(title="LLM Reasoning Modes Comparison") as demo:
461
  value="All (Compare)",
462
  label="Select Mode"
463
  )
464
- submit_btn = gr.Button(" Run", variant="primary", size="lg")
465
 
466
  with gr.Column(scale=1):
467
- gr.Markdown("### Example Questions")
468
  for idx, example in enumerate(EXAMPLES):
469
- gr.Button(f"Ex {idx+1}", size="sm").click(
470
  fn=lambda ex=example: ex,
471
  outputs=question_input
472
  )
@@ -486,7 +456,6 @@ with gr.Blocks(title="LLM Reasoning Modes Comparison") as demo:
486
  inputs=[question_input, mode_dropdown],
487
  outputs=[think_output, act_output, react_output]
488
  )
489
-
490
-
491
  if __name__ == "__main__":
492
- demo.launch()
 
9
  import operator as op
10
  import wikipedia
11
 
 
12
  class Tool:
13
  def __init__(self, name: str, description: str, func):
14
  self.name = name
 
31
  response = requests.get(url, params=params, timeout=10)
32
  data = response.json()
33
 
 
34
  if data.get('Abstract'):
35
  return f"Search result: {data['Abstract']}"
36
  elif data.get('RelatedTopics') and len(data['RelatedTopics']) > 0:
 
48
  """Search Wikipedia for information."""
49
  try:
50
  wikipedia.set_lang("en")
 
51
  summary = wikipedia.summary(query, sentences=3, auto_suggest=True)
52
  return f"Wikipedia: {summary}"
53
  except wikipedia.exceptions.DisambiguationError as e:
 
77
 
78
  def calculate(expression: str) -> str:
79
  """Safely evaluate mathematical expressions."""
 
80
  operators = {
81
  ast.Add: op.add,
82
  ast.Sub: op.sub,
 
95
  elif isinstance(node, ast.UnaryOp):
96
  return operators[type(node.op)](eval_expr(node.operand))
97
  elif isinstance(node, ast.Call):
 
98
  if node.func.id == 'abs':
99
  return abs(eval_expr(node.args[0]))
100
  elif node.func.id == 'round':
 
103
  raise TypeError(node)
104
 
105
  try:
 
106
  expression = expression.strip()
 
107
  node = ast.parse(expression, mode='eval')
108
  result = eval_expr(node.body)
109
  return f"Result: {result}"
 
113
  def python_repl(code: str) -> str:
114
  """Execute safe Python code (limited to basic operations)."""
115
  try:
 
116
  safe_builtins = {
117
  'abs': abs, 'round': round, 'min': min, 'max': max,
118
  'sum': sum, 'len': len, 'range': range, 'list': list,
 
121
  'sorted': sorted, 'reversed': reversed,
122
  }
123
 
 
124
  namespace = {'__builtins__': safe_builtins}
125
 
 
126
  from io import StringIO
127
  import sys
128
  old_stdout = sys.stdout
129
  sys.stdout = StringIO()
130
 
 
131
  exec(code, namespace)
132
 
 
133
  output = sys.stdout.getvalue()
134
  sys.stdout = old_stdout
135
 
 
136
  result_vars = {k: v for k, v in namespace.items() if k != '__builtins__' and not k.startswith('_')}
137
 
138
  result = output if output else str(result_vars) if result_vars else "Code executed successfully (no output)"
 
140
  except Exception as e:
141
  return f"Python error: {str(e)}"
142
 
 
143
  TOOLS = [
144
  Tool(
145
  name="duckduckgo_search",
 
168
  ),
169
  ]
170
 
 
171
  def get_tool_descriptions() -> str:
172
  descriptions = []
173
  for tool in TOOLS:
174
  descriptions.append(f"- {tool.name}: {tool.description}")
175
  return "\n".join(descriptions)
176
 
 
177
  THINK_ONLY_PROMPT = """You are a helpful AI assistant. You solve problems by thinking through them step-by-step.
178
 
179
  For each question:
 
281
  messages = [{"role": "user", "content": prompt}]
282
 
283
  yield "**Mode: Think-Only (Chain-of-Thought)**\n\n"
284
+ yield "Generating thoughts...\n\n"
285
 
286
  response = call_llm(messages, temperature=0.7, max_tokens=800)
287
 
 
288
  lines = response.split('\n')
289
  for line in lines:
290
  if line.strip():
 
312
 
313
  response = call_llm(messages, temperature=0.5, max_tokens=300)
314
 
 
315
  if 'Answer:' in response:
316
  answer_match = re.search(r'Answer:\s*(.+)', response, re.IGNORECASE | re.DOTALL)
317
  if answer_match:
318
+ yield f"**Answer:** {answer_match.group(1).strip()}\n\n"
319
  break
320
 
 
321
  action_name, action_input = parse_action(response)
322
 
323
  if action_name and action_input:
324
+ yield f"**Action:** {action_name}\n"
325
+ yield f"**Action Input:** {action_input}\n\n"
326
 
 
327
  observation = call_tool(action_name, action_input)
328
+ yield f"**Observation:** {observation}\n\n"
329
 
 
330
  messages.append({"role": "assistant", "content": response})
331
  messages.append({"role": "user", "content": f"Observation: {observation}\n\nContinue with another action or provide the final answer."})
332
  else:
333
+ yield f"Could not parse action from response. Response: {response}\n\n"
334
  break
335
 
336
  if iteration >= max_iterations:
337
+ yield "**Reached maximum iterations.**\n\n"
338
 
339
  yield "\n---\n**Mode completed**\n"
340
 
 
353
 
354
  response = call_llm(messages, temperature=0.7, max_tokens=400)
355
 
 
356
  thought_matches = re.findall(r'Thought:\s*(.+?)(?=\n(?:Action:|Answer:|$))', response, re.IGNORECASE | re.DOTALL)
357
  for thought in thought_matches:
358
  yield f"**Thought:** {thought.strip()}\n\n"
359
 
 
360
  if 'Answer:' in response:
361
  answer_match = re.search(r'Answer:\s*(.+)', response, re.IGNORECASE | re.DOTALL)
362
  if answer_match:
363
  yield f"**Answer:** {answer_match.group(1).strip()}\n\n"
364
  break
365
 
 
366
  action_name, action_input = parse_action(response)
367
 
368
  if action_name and action_input:
369
+ yield f"**Action:** {action_name}\n"
370
  yield f"**Action Input:** {action_input}\n\n"
371
 
 
372
  observation = call_tool(action_name, action_input)
373
  yield f"**Observation:** {observation}\n\n"
374
 
 
375
  messages.append({"role": "assistant", "content": response})
376
  messages.append({"role": "user", "content": f"Observation: {observation}\n\nThought:"})
377
  else:
 
378
  if 'Answer:' not in response:
379
+ yield f"No action found. Response: {response}\n\n"
380
  break
381
 
382
  if iteration >= max_iterations:
383
+ yield "**Reached maximum iterations.**\n\n"
384
 
385
  yield "\n---\n**Mode completed**\n"
386
 
 
387
  EXAMPLES = [
388
  "What is the capital of France and what's the current weather there?",
389
  "Who wrote 'To Kill a Mockingbird' and when was it published?",
 
406
  else:
407
  return "Invalid mode selected.", "", ""
408
 
 
409
  with gr.Blocks(title="LLM Reasoning Modes Comparison") as demo:
410
  gr.Markdown("""
411
+ # LLM Reasoning Modes Comparison
412
 
413
  Compare three reasoning approaches using **openai/gpt-oss-20b**:
414
 
415
  - **Think-Only**: Chain-of-Thought reasoning only (no tools)
416
  - **Act-Only**: Tool use only (no explicit reasoning)
417
+ - **ReAct**: Interleaved Thought, Action, Observation
418
 
419
+ Available Tools: DuckDuckGo Search | Wikipedia | Weather API | Calculator | Python REPL
 
420
  """)
421
 
422
  with gr.Row():
 
431
  value="All (Compare)",
432
  label="Select Mode"
433
  )
434
+ submit_btn = gr.Button("Run", variant="primary", size="lg")
435
 
436
  with gr.Column(scale=1):
437
+ gr.Markdown("**Example Questions**")
438
  for idx, example in enumerate(EXAMPLES):
439
+ gr.Button(f"Example {idx+1}", size="sm").click(
440
  fn=lambda ex=example: ex,
441
  outputs=question_input
442
  )
 
456
  inputs=[question_input, mode_dropdown],
457
  outputs=[think_output, act_output, react_output]
458
  )
459
+
 
460
  if __name__ == "__main__":
461
+ demo.launch()