HAMMALE commited on
Commit
286a919
·
verified ·
1 Parent(s): bde8061

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -104
app.py CHANGED
@@ -8,7 +8,7 @@ from datetime import datetime
8
  import ast
9
  import operator as op
10
  import wikipedia
11
- from transformers import pipeline
12
  import torch
13
 
14
  class Tool:
@@ -41,6 +41,10 @@ def wikipedia_search(query: str) -> str:
41
  wikipedia.set_lang("en")
42
  summary = wikipedia.summary(query, sentences=3, auto_suggest=True)
43
  return f"Wikipedia: {summary}"
 
 
 
 
44
  except Exception as e:
45
  return f"Wikipedia error: {str(e)}"
46
 
@@ -99,36 +103,80 @@ TOOLS = [
99
  ]
100
 
101
  MODEL_NAME = "openai/gpt-oss-20b"
102
- pipe = None
 
103
  model_loaded = False
104
 
105
  def download_and_load_model(progress=gr.Progress()):
106
- global pipe, model_loaded
107
 
108
  try:
109
- progress(0, desc="Downloading model...")
110
- progress(0.5, desc="Loading model...")
111
 
112
- pipe = pipeline(
113
- "text-generation",
114
- model=MODEL_NAME,
115
- torch_dtype=torch.bfloat16,
 
116
  device_map="auto",
 
117
  )
118
 
119
  progress(0.95, desc="Finalizing...")
120
  model_loaded = True
121
  progress(1.0, desc="Model loaded!")
122
- return "Model loaded successfully!"
123
  except Exception as e:
124
  return f"Error: {str(e)}"
125
 
126
  def get_tool_descriptions() -> str:
127
  return "\n".join([f"- {tool.name}: {tool.description}" for tool in TOOLS])
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  def parse_action(text: str) -> tuple:
130
  action_match = re.search(r'Action:\s*(\w+)', text, re.IGNORECASE)
131
- input_match = re.search(r'Action Input:\s*(.+?)(?=\n|$)', text, re.IGNORECASE | re.DOTALL)
132
  return (action_match.group(1).strip(), input_match.group(1).strip()) if action_match and input_match else (None, None)
133
 
134
  def call_tool(tool_name: str, tool_input: str) -> str:
@@ -137,129 +185,161 @@ def call_tool(tool_name: str, tool_input: str) -> str:
137
  return tool(tool_input)
138
  return f"Error: Tool '{tool_name}' not found."
139
 
140
- def call_llm(messages: List[Dict], max_tokens: int = 500) -> str:
141
  if not model_loaded:
142
- return "Error: Model not loaded. Please click 'Load Model' button first."
143
 
144
  try:
145
- outputs = pipe(messages, max_new_tokens=max_tokens, do_sample=True, temperature=0.7)
146
- return outputs[0]["generated_text"][-1]["content"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  except Exception as e:
148
- return f"Error: {str(e)}"
149
 
150
- def chat_function(message, history, mode):
151
- """Main chat function"""
152
-
153
  if not model_loaded:
154
- return history + [[message, "Error: Model not loaded. Please click 'Load Model' button first."]]
155
 
156
- if mode == "Think-Only":
157
- system_prompt = "You are a helpful AI assistant. Think step-by-step and provide clear answers."
158
-
159
- elif mode == "Act-Only":
160
- system_prompt = f"""You are a helpful AI assistant with tools.
161
-
162
- Available tools:
163
- {get_tool_descriptions()}
164
-
165
- Use tools when needed. Format:
166
- Action: tool_name
167
- Action Input: input"""
168
-
169
- else:
170
- system_prompt = f"""You are a helpful AI assistant with tools.
171
-
172
- Available tools:
173
- {get_tool_descriptions()}
174
-
175
- Think step-by-step and use tools when needed. Format:
176
- Thought: [reasoning]
177
- Action: tool_name
178
- Action Input: input"""
179
 
180
- messages = [{"role": "system", "content": system_prompt}]
 
181
 
182
- for user_msg, assistant_msg in history:
183
- messages.append({"role": "user", "content": user_msg})
184
- messages.append({"role": "assistant", "content": assistant_msg})
185
 
186
- messages.append({"role": "user", "content": message})
 
 
 
 
187
 
188
- response_parts = []
189
- max_iterations = 3
190
 
191
  for iteration in range(max_iterations):
192
- response = call_llm(messages, max_tokens=400)
193
 
194
- if mode == "ReAct":
195
- thoughts = re.findall(r'Thought:\s*(.+?)(?=\nAction:|$)', response, re.IGNORECASE | re.DOTALL)
196
- for thought in thoughts:
197
- response_parts.append(f"💭 {thought.strip()}")
198
 
199
- action_name, action_input = parse_action(response)
200
 
201
- if action_name and action_input and mode in ["Act-Only", "ReAct"]:
202
- response_parts.append(f"🔧 Using: {action_name}")
 
 
 
 
 
 
 
203
  observation = call_tool(action_name, action_input)
204
- response_parts.append(f"📊 {observation}")
205
-
206
- messages.append({"role": "assistant", "content": response})
207
- messages.append({"role": "user", "content": f"Result: {observation}\n\nProvide final answer."})
208
  else:
209
- response_parts.append(response)
210
  break
211
 
212
- final_response = "\n\n".join(response_parts)
213
- return history + [[message, final_response]]
214
 
215
- with gr.Blocks(title="LLM Reasoning Chat") as demo:
216
- gr.Markdown("""
217
- # LLM Reasoning Chat
218
-
219
- **Model:** openai/gpt-oss-20b
220
-
221
- **Modes:**
222
- - **Think-Only**: Pure reasoning
223
- - **Act-Only**: Uses tools
224
- - **ReAct**: Thinks and uses tools
225
- """)
226
 
227
- with gr.Row():
228
- load_btn = gr.Button("Load Model", variant="primary", size="lg")
229
- status = gr.Textbox(label="Status", value="Click 'Load Model'", interactive=False)
230
 
231
- mode_selector = gr.Radio(
232
- choices=["Think-Only", "Act-Only", "ReAct"],
233
- value="ReAct",
234
- label="Reasoning Mode"
235
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
- chatbot = gr.Chatbot(label="Chat", height=400)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
 
239
  with gr.Row():
240
- msg = gr.Textbox(label="Message", placeholder="Ask anything...", scale=4)
241
- submit = gr.Button("Send", variant="primary", scale=1)
242
 
243
- clear = gr.Button("Clear Chat")
244
-
245
- gr.Examples(
246
- examples=[
247
- "What is the capital of France and its weather?",
248
- "Calculate: 1000 * (1.05 ** 3)",
249
- "Who wrote To Kill a Mockingbird?",
250
- ],
251
- inputs=msg
252
- )
253
-
254
- load_btn.click(fn=download_and_load_model, outputs=status)
255
 
256
- submit.click(fn=chat_function, inputs=[msg, chatbot, mode_selector], outputs=chatbot)
257
- msg.submit(fn=chat_function, inputs=[msg, chatbot, mode_selector], outputs=chatbot)
258
 
259
- submit.click(lambda: "", outputs=msg)
260
- msg.submit(lambda: "", outputs=msg)
 
 
261
 
262
- clear.click(lambda: [], outputs=chatbot)
 
263
 
264
  if __name__ == "__main__":
265
  demo.launch(share=True)
 
8
  import ast
9
  import operator as op
10
  import wikipedia
11
+ from transformers import AutoTokenizer, AutoModelForCausalLM
12
  import torch
13
 
14
  class Tool:
 
41
  wikipedia.set_lang("en")
42
  summary = wikipedia.summary(query, sentences=3, auto_suggest=True)
43
  return f"Wikipedia: {summary}"
44
+ except wikipedia.exceptions.DisambiguationError as e:
45
+ return f"Wikipedia: Multiple results found. Options: {', '.join(e.options[:5])}"
46
+ except wikipedia.exceptions.PageError:
47
+ return f"Wikipedia: No page found for '{query}'."
48
  except Exception as e:
49
  return f"Wikipedia error: {str(e)}"
50
 
 
103
  ]
104
 
105
  MODEL_NAME = "openai/gpt-oss-20b"
106
+ model = None
107
+ tokenizer = None
108
  model_loaded = False
109
 
110
  def download_and_load_model(progress=gr.Progress()):
111
+ global model, tokenizer, model_loaded
112
 
113
  try:
114
+ progress(0, desc="Downloading tokenizer...")
115
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
116
 
117
+ progress(0.4, desc="Downloading model (this may take several minutes)...")
118
+ model = AutoModelForCausalLM.from_pretrained(
119
+ MODEL_NAME,
120
+ trust_remote_code=True,
121
+ torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32,
122
  device_map="auto",
123
+ low_cpu_mem_usage=True,
124
  )
125
 
126
  progress(0.95, desc="Finalizing...")
127
  model_loaded = True
128
  progress(1.0, desc="Model loaded!")
129
+ return f"Model '{MODEL_NAME}' loaded successfully!"
130
  except Exception as e:
131
  return f"Error: {str(e)}"
132
 
133
  def get_tool_descriptions() -> str:
134
  return "\n".join([f"- {tool.name}: {tool.description}" for tool in TOOLS])
135
 
136
+ THINK_ONLY_PROMPT = """You are a helpful AI assistant. Solve problems step-by-step.
137
+
138
+ Format:
139
+ Thought: your reasoning
140
+ Answer: your final answer
141
+
142
+ Question: {question}
143
+
144
+ Think step by step:"""
145
+
146
+ ACT_ONLY_PROMPT = """You are a helpful AI assistant with tools.
147
+
148
+ Available tools:
149
+ {tools}
150
+
151
+ Format:
152
+ Action: tool_name
153
+ Action Input: input
154
+
155
+ Question: {question}
156
+
157
+ Action:"""
158
+
159
+ REACT_PROMPT = """You are a helpful AI assistant with tools.
160
+
161
+ Available tools:
162
+ {tools}
163
+
164
+ Pattern:
165
+ Thought: what to do next
166
+ Action: tool_name
167
+ Action Input: input
168
+ Observation: [result]
169
+ ... repeat as needed
170
+ Thought: I know the answer
171
+ Answer: final answer
172
+
173
+ Question: {question}
174
+
175
+ Thought:"""
176
+
177
  def parse_action(text: str) -> tuple:
178
  action_match = re.search(r'Action:\s*(\w+)', text, re.IGNORECASE)
179
+ input_match = re.search(r'Action Input:\s*(.+?)(?=\n(?:Thought:|Action:|Answer:|$))', text, re.IGNORECASE | re.DOTALL)
180
  return (action_match.group(1).strip(), input_match.group(1).strip()) if action_match and input_match else (None, None)
181
 
182
  def call_tool(tool_name: str, tool_input: str) -> str:
 
185
  return tool(tool_input)
186
  return f"Error: Tool '{tool_name}' not found."
187
 
188
+ def call_llm(prompt: str, max_tokens: int = 500) -> str:
189
  if not model_loaded:
190
+ return "Error: Model not loaded."
191
 
192
  try:
193
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=2048)
194
+
195
+ if torch.cuda.is_available():
196
+ inputs = {k: v.to(model.device) for k, v in inputs.items()}
197
+
198
+ with torch.no_grad():
199
+ outputs = model.generate(
200
+ **inputs,
201
+ max_new_tokens=max_tokens,
202
+ temperature=0.7,
203
+ do_sample=True,
204
+ top_p=0.9,
205
+ pad_token_id=tokenizer.eos_token_id,
206
+ eos_token_id=tokenizer.eos_token_id,
207
+ )
208
+
209
+ response = tokenizer.decode(outputs[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True)
210
+ return response.strip()
211
  except Exception as e:
212
+ return f"Error during generation: {str(e)}"
213
 
214
+ def think_only_mode(question: str) -> str:
 
 
215
  if not model_loaded:
216
+ return "Error: Model not loaded."
217
 
218
+ output = "**Mode: Think-Only**\n\n"
219
+ response = call_llm(THINK_ONLY_PROMPT.format(question=question), max_tokens=800)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
+ if response.startswith("Error"):
222
+ return output + response
223
 
224
+ for line in response.split('\n'):
225
+ if line.strip():
226
+ output += f"**{line.strip()}**\n\n" if line.strip().startswith(('Thought:', 'Answer:')) else f"{line}\n\n"
227
 
228
+ return output + "\n---\n"
229
+
230
+ def act_only_mode(question: str, max_iterations: int = 5) -> str:
231
+ if not model_loaded:
232
+ return "Error: Model not loaded."
233
 
234
+ output = "**Mode: Act-Only**\n\n"
235
+ conversation = ACT_ONLY_PROMPT.format(question=question, tools=get_tool_descriptions())
236
 
237
  for iteration in range(max_iterations):
238
+ response = call_llm(conversation, max_tokens=300)
239
 
240
+ if response.startswith("Error"):
241
+ return output + response
 
 
242
 
243
+ output += f"**Iteration {iteration + 1}:**\n{response}\n\n"
244
 
245
+ if 'Answer:' in response:
246
+ match = re.search(r'Answer:\s*(.+)', response, re.IGNORECASE | re.DOTALL)
247
+ if match:
248
+ output += f"**Final Answer:** {match.group(1).strip()}\n\n"
249
+ break
250
+
251
+ action_name, action_input = parse_action(response)
252
+ if action_name and action_input:
253
+ output += f"**Action:** {action_name}\n**Input:** {action_input}\n\n"
254
  observation = call_tool(action_name, action_input)
255
+ output += f"**Observation:** {observation}\n\n"
256
+ conversation += f"\n{response}\nObservation: {observation}\n\n"
 
 
257
  else:
258
+ output += f"No valid action found in iteration {iteration + 1}.\n\n"
259
  break
260
 
261
+ return output + "\n---\n"
 
262
 
263
+ def react_mode(question: str, max_iterations: int = 5) -> str:
264
+ if not model_loaded:
265
+ return "Error: Model not loaded."
 
 
 
 
 
 
 
 
266
 
267
+ output = "**Mode: ReAct**\n\n"
268
+ conversation = REACT_PROMPT.format(question=question, tools=get_tool_descriptions())
 
269
 
270
+ for iteration in range(max_iterations):
271
+ response = call_llm(conversation, max_tokens=400)
272
+
273
+ if response.startswith("Error"):
274
+ return output + response
275
+
276
+ output += f"**Iteration {iteration + 1}:**\n"
277
+
278
+ for thought in re.findall(r'Thought:\s*(.+?)(?=\n(?:Action:|Answer:|$))', response, re.IGNORECASE | re.DOTALL):
279
+ output += f"**Thought:** {thought.strip()}\n\n"
280
+
281
+ if 'Answer:' in response:
282
+ match = re.search(r'Answer:\s*(.+)', response, re.IGNORECASE | re.DOTALL)
283
+ if match:
284
+ output += f"**Answer:** {match.group(1).strip()}\n\n"
285
+ break
286
+
287
+ action_name, action_input = parse_action(response)
288
+ if action_name and action_input:
289
+ output += f"**Action:** {action_name}\n**Input:** {action_input}\n\n"
290
+ observation = call_tool(action_name, action_input)
291
+ output += f"**Observation:** {observation}\n\n"
292
+ conversation += f"\n{response}\nObservation: {observation}\n\nThought:"
293
+ else:
294
+ output += f"No action found in iteration {iteration + 1}.\n{response}\n\n"
295
+ break
296
 
297
+ return output + "\n---\n"
298
+
299
+ EXAMPLES = [
300
+ "What is 25 * 47?",
301
+ "What is the weather in Paris?",
302
+ "Who wrote 1984?",
303
+ "Calculate: 100 + 200",
304
+ ]
305
+
306
+ def run_comparison(question: str, mode: str):
307
+ if mode == "Think-Only":
308
+ return think_only_mode(question), "", ""
309
+ elif mode == "Act-Only":
310
+ return "", act_only_mode(question), ""
311
+ elif mode == "ReAct":
312
+ return "", "", react_mode(question)
313
+ elif mode == "All (Compare)":
314
+ return think_only_mode(question), act_only_mode(question), react_mode(question)
315
+ return "Invalid mode.", "", ""
316
+
317
+ with gr.Blocks(title="LLM Reasoning Modes") as demo:
318
+ gr.Markdown("# LLM Reasoning Modes Comparison\n\n**Model:** openai/gpt-oss-20b\n\n**Tools:** DuckDuckGo | Wikipedia | Weather | Calculator | Python")
319
 
320
  with gr.Row():
321
+ download_btn = gr.Button("Download & Load Model", variant="primary", size="lg")
322
+ model_status = gr.Textbox(label="Status", value="Click to download", interactive=False)
323
 
324
+ with gr.Row():
325
+ with gr.Column(scale=3):
326
+ question_input = gr.Textbox(label="Question", lines=3)
327
+ mode_dropdown = gr.Dropdown(choices=["Think-Only", "Act-Only", "ReAct", "All (Compare)"], value="Think-Only", label="Mode")
328
+ submit_btn = gr.Button("Run", variant="primary", size="lg")
329
+ with gr.Column(scale=1):
330
+ gr.Markdown("**Examples**")
331
+ for idx, ex in enumerate(EXAMPLES):
332
+ gr.Button(f"Ex {idx+1}", size="sm").click(fn=lambda e=ex: e, outputs=question_input)
 
 
 
333
 
334
+ gr.Markdown("---")
 
335
 
336
+ with gr.Row():
337
+ think_output = gr.Markdown(label="Think-Only")
338
+ act_output = gr.Markdown(label="Act-Only")
339
+ react_output = gr.Markdown(label="ReAct")
340
 
341
+ download_btn.click(fn=download_and_load_model, outputs=model_status)
342
+ submit_btn.click(fn=run_comparison, inputs=[question_input, mode_dropdown], outputs=[think_output, act_output, react_output])
343
 
344
  if __name__ == "__main__":
345
  demo.launch(share=True)