mohammedelfeky-ai commited on
Commit
cb4e5b3
·
verified ·
1 Parent(s): 3e2ff2f

Update Gradio_UI.py

Browse files
Files changed (1) hide show
  1. Gradio_UI.py +36 -67
Gradio_UI.py CHANGED
@@ -18,14 +18,14 @@ import os
18
  import re
19
  import shutil
20
  from typing import Optional
21
- import tempfile # Added for PIL image saving
22
- from PIL import Image as PILImage # Added for PIL image handling
23
 
24
  from smolagents.agent_types import AgentAudio, AgentImage, AgentText, handle_agent_output_types
25
  from smolagents.agents import ActionStep, MultiStepAgent
26
  from smolagents.memory import MemoryStep
27
  from smolagents.utils import _is_package_available
28
- import gradio as gr # Ensure gradio is imported at the top level
29
 
30
 
31
  def pull_messages_from_step_dict(step_log: MemoryStep):
@@ -66,7 +66,7 @@ def pull_messages_from_step_dict(step_log: MemoryStep):
66
  obs_content = step_log.observations.strip()
67
  obs_content = re.sub(r"^Execution logs:\s*", "", obs_content).strip()
68
  if obs_content:
69
- tool_info_md += f"📝 **Tool Output/Logs:**\n```text\n{obs_content}\n```\n" # Use text for generic logs
70
 
71
  if hasattr(step_log, "error") and step_log.error:
72
  tool_info_md += f"💥 **Error:** {str(step_log.error)}\n"
@@ -105,10 +105,9 @@ def stream_to_gradio(
105
  agent.interaction_logs.clear()
106
  print("DEBUG Gradio: Cleared agent interaction_logs for new run.")
107
 
108
- # This will collect all step_log objects from the agent run
109
  all_step_logs = []
110
  for step_log in agent.run(task, stream=True, reset=reset_agent_memory, additional_args=additional_args):
111
- all_step_logs.append(step_log) # Store the log
112
  if hasattr(agent.model, "last_input_token_count") and agent.model.last_input_token_count is not None:
113
  if isinstance(step_log, ActionStep):
114
  step_log.input_token_count = agent.model.last_input_token_count
@@ -117,79 +116,58 @@ def stream_to_gradio(
117
  for msg_dict in pull_messages_from_step_dict(step_log):
118
  yield msg_dict
119
 
120
- # After the loop, the last item in all_step_logs is the final output/state from agent.run
121
- if not all_step_logs: # Should not happen if agent.run yields at least one thing
122
  yield {"role": "assistant", "content": "Agent did not produce any output."}
123
  return
124
 
125
- final_answer_content = all_step_logs[-1] # This is what final_answer tool returns or the last ActionStep.final_answer
126
 
127
- # --- Handle final answer for type="messages" ---
128
- if isinstance(final_answer_content, PILImage.Image):
129
- print("DEBUG Gradio (stream_to_gradio): Final answer content IS a raw PIL Image.")
130
- try:
131
- # delete=False is crucial for Gradio to access the file before it's cleaned up
132
- with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp_file:
133
- final_answer_content.save(tmp_file, format="PNG")
134
- image_path_for_gradio = tmp_file.name
135
- print(f"DEBUG Gradio: Saved PIL image to temp path for display: {image_path_for_gradio}")
136
- yield {"role": "assistant", "content": image_path_for_gradio}
137
- return
138
- except Exception as e:
139
- print(f"DEBUG Gradio: Error saving PIL image from final_answer_content: {e}")
140
- yield {"role": "assistant", "content": f"**Final Answer (Error displaying image):** {e}"}
141
- return
142
-
143
- # If not a raw PIL Image, then try smolagents processing from handle_agent_output_types
144
- # The 'final_answer_content' here could be a FinalAnswerStep object or similar
145
- # We need to extract the actual content from it if it's a wrapper.
146
  actual_content_for_handling = final_answer_content
147
  if hasattr(final_answer_content, 'final_answer') and not isinstance(final_answer_content, (str, PILImage.Image)):
148
  actual_content_for_handling = final_answer_content.final_answer
149
  print(f"DEBUG Gradio: Extracted actual_content_for_handling from FinalAnswerStep: {type(actual_content_for_handling)}")
150
 
151
-
152
- # Re-check if the extracted content is a PIL Image
153
  if isinstance(actual_content_for_handling, PILImage.Image):
154
- print("DEBUG Gradio (stream_to_gradio): Extracted content IS a raw PIL Image.")
155
  try:
156
  with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp_file:
157
  actual_content_for_handling.save(tmp_file, format="PNG")
158
  image_path_for_gradio = tmp_file.name
159
- print(f"DEBUG Gradio: Saved extracted PIL image to temp path: {image_path_for_gradio}")
160
- yield {"role": "assistant", "content": image_path_for_gradio}
 
161
  return
162
  except Exception as e:
163
  print(f"DEBUG Gradio: Error saving extracted PIL image: {e}")
164
- yield {"role": "assistant", "content": f"**Final Answer (Error displaying image from extracted content):** {e}"}
165
  return
166
 
167
  final_answer_processed = handle_agent_output_types(actual_content_for_handling)
168
  print(f"DEBUG Gradio: final_answer_processed type after handle_agent_output_types: {type(final_answer_processed)}")
169
 
170
-
171
  if isinstance(final_answer_processed, AgentText):
172
  yield {"role": "assistant", "content": f"**Final Answer:**\n{final_answer_processed.to_string()}"}
173
  elif isinstance(final_answer_processed, AgentImage):
174
  image_path = final_answer_processed.to_string()
175
  print(f"DEBUG Gradio (stream_to_gradio): final_answer_processed is AgentImage. Path: {image_path}")
176
  if image_path and os.path.exists(image_path):
177
- yield {"role": "assistant", "content": image_path}
 
178
  else:
179
- err_msg = f"Error: Image path from AgentImage ('{image_path}') not found or invalid after smolagents processing."
180
  print(f"DEBUG Gradio: {err_msg}")
181
  yield {"role": "assistant", "content": f"**Final Answer ({err_msg})**"}
182
  elif isinstance(final_answer_processed, AgentAudio):
183
  audio_path = final_answer_processed.to_string()
184
  print(f"DEBUG Gradio (stream_to_gradio): AgentAudio path: {audio_path}")
185
  if audio_path and os.path.exists(audio_path):
186
- yield {"role": "assistant", "content": audio_path}
 
187
  else:
188
  err_msg = f"Error: Audio path from AgentAudio ('{audio_path}') not found"
189
  print(f"DEBUG Gradio: {err_msg}")
190
  yield {"role": "assistant", "content": f"**Final Answer ({err_msg})**"}
191
  else:
192
- # This will display the string representation of FinalAnswerStep if not handled above
193
  yield {"role": "assistant", "content": f"**Final Answer:**\n{str(final_answer_processed)}"}
194
 
195
 
@@ -211,12 +189,8 @@ class GradioUI:
211
  for log_entry in reversed(self.agent.interaction_logs):
212
  if isinstance(log_entry, ActionStep):
213
  observations = getattr(log_entry, 'observations', None)
214
- tool_calls = getattr(log_entry, 'tool_calls', [])
215
-
216
- # Check if python_interpreter was used AND its code involved create_document
217
- # For simplicity, we'll primarily rely on parsing observations for the path pattern
218
  if observations and isinstance(observations, str):
219
- # This regex should match paths printed by your create_document tool
220
  path_match = re.search(r"(/tmp/[a-zA-Z0-9_]+/generated_document\.(?:docx|pdf|txt))", observations)
221
  if path_match:
222
  extracted_path = path_match.group(1)
@@ -234,7 +208,6 @@ class GradioUI:
234
  print(f"DEBUG Gradio: interact_with_agent called with prompt: '{prompt_text}'")
235
  print(f"DEBUG Gradio: Current chat history (input type {type(current_chat_history)}): {current_chat_history}")
236
 
237
- # current_chat_history from gr.Chatbot(type="messages") is already a list of dicts
238
  updated_chat_history = current_chat_history + [{"role": "user", "content": prompt_text}]
239
 
240
  yield updated_chat_history, gr.update(visible=False), gr.update(value=None, visible=False)
@@ -275,7 +248,6 @@ class GradioUI:
275
  sanitized_name = re.sub(r"[^\w\-.]", "_", original_name)
276
  base_name, current_ext = os.path.splitext(sanitized_name)
277
 
278
- # Updated mimetypes to extension mapping
279
  common_mime_to_ext = {
280
  "application/pdf": ".pdf",
281
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx",
@@ -302,7 +274,7 @@ class GradioUI:
302
  if current_file_uploads:
303
  files_str = ", ".join([os.path.basename(f) for f in current_file_uploads])
304
  full_prompt += f"\n\n[Uploaded files for context: {files_str}]"
305
- print(f"DEBUG Gradio: Prepared prompt for agent: {full_prompt[:300]}...") # Log snippet
306
  return full_prompt, ""
307
 
308
  def prepare_and_show_download_file(self):
@@ -313,46 +285,44 @@ class GradioUI:
313
  visible=True)
314
  else:
315
  print("DEBUG Gradio UI: No valid file path to prepare for download component.")
316
- # gr.Warning("No file available for download or path is invalid.") # Causes JS error if used as return
317
- return gr.File.update(visible=False, value=None) # Ensure value is None if not visible
318
 
319
  def launch(self, **kwargs):
320
  with gr.Blocks(fill_height=True, theme=gr.themes.Soft(primary_hue=gr.themes.colors.blue)) as demo:
321
  file_uploads_log_state = gr.State([])
322
  prepared_prompt_for_agent = gr.State("")
323
 
324
- gr.Markdown("## Smol Talk with your Agent") # Changed title slightly
325
 
326
- with gr.Row(equal_height=False): # Allow columns to size independently
327
  with gr.Column(scale=3):
328
  chatbot_display = gr.Chatbot(
329
  label="Agent Interaction",
330
  type="messages",
331
  avatar_images=(None, "https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo-round.png"),
332
- height=700, # Increased height
333
  show_copy_button=True,
334
  bubble_full_width=False,
335
- show_label=False # Hide the "Agent Interaction" label above chatbot
336
  )
337
  text_message_input = gr.Textbox(
338
  lines=1,
339
  label="Your Message to the Agent",
340
  placeholder="Type your message and press Enter, or Shift+Enter for new line...",
341
- show_label=False # Hide label for text input
342
  )
343
 
344
  with gr.Column(scale=1):
345
- if self.file_upload_folder is not None:
346
- with gr.Accordion("File Upload", open=False): # Collapsible section
347
- file_uploader = gr.File(label="Upload a supporting file (PDF, DOCX, TXT, JPG, PNG)")
348
- upload_status_text = gr.Textbox(label="Upload Status", interactive=False, lines=1) # single line
349
- file_uploader.upload( # Changed from .change to .upload for gr.File
350
- self.upload_file,
351
- [file_uploader, file_uploads_log_state],
352
- [upload_status_text, file_uploads_log_state],
353
- )
354
 
355
- with gr.Accordion("Generated File", open=True): # Collapsible, open by default
356
  download_action_button = gr.Button("Download Generated File", visible=False)
357
  file_download_display_component = gr.File(label="Downloadable Document", visible=False, interactive=False)
358
 
@@ -362,8 +332,8 @@ class GradioUI:
362
  [prepared_prompt_for_agent, text_message_input]
363
  ).then(
364
  self.interact_with_agent,
365
- [prepared_prompt_for_agent, chatbot_display], # chatbot_display is input here
366
- [chatbot_display, download_action_button, file_download_display_component] # chatbot_display is output here
367
  )
368
 
369
  download_action_button.click(
@@ -371,7 +341,6 @@ class GradioUI:
371
  [],
372
  [file_download_display_component]
373
  )
374
- # Default share=False, can be overridden by kwargs
375
  demo.launch(debug=True, share=kwargs.get("share", False), **kwargs)
376
 
377
  __all__ = ["stream_to_gradio", "GradioUI"]
 
18
  import re
19
  import shutil
20
  from typing import Optional
21
+ import tempfile
22
+ from PIL import Image as PILImage
23
 
24
  from smolagents.agent_types import AgentAudio, AgentImage, AgentText, handle_agent_output_types
25
  from smolagents.agents import ActionStep, MultiStepAgent
26
  from smolagents.memory import MemoryStep
27
  from smolagents.utils import _is_package_available
28
+ import gradio as gr
29
 
30
 
31
  def pull_messages_from_step_dict(step_log: MemoryStep):
 
66
  obs_content = step_log.observations.strip()
67
  obs_content = re.sub(r"^Execution logs:\s*", "", obs_content).strip()
68
  if obs_content:
69
+ tool_info_md += f"📝 **Tool Output/Logs:**\n```text\n{obs_content}\n```\n"
70
 
71
  if hasattr(step_log, "error") and step_log.error:
72
  tool_info_md += f"💥 **Error:** {str(step_log.error)}\n"
 
105
  agent.interaction_logs.clear()
106
  print("DEBUG Gradio: Cleared agent interaction_logs for new run.")
107
 
 
108
  all_step_logs = []
109
  for step_log in agent.run(task, stream=True, reset=reset_agent_memory, additional_args=additional_args):
110
+ all_step_logs.append(step_log)
111
  if hasattr(agent.model, "last_input_token_count") and agent.model.last_input_token_count is not None:
112
  if isinstance(step_log, ActionStep):
113
  step_log.input_token_count = agent.model.last_input_token_count
 
116
  for msg_dict in pull_messages_from_step_dict(step_log):
117
  yield msg_dict
118
 
119
+ if not all_step_logs:
 
120
  yield {"role": "assistant", "content": "Agent did not produce any output."}
121
  return
122
 
123
+ final_answer_content = all_step_logs[-1]
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  actual_content_for_handling = final_answer_content
126
  if hasattr(final_answer_content, 'final_answer') and not isinstance(final_answer_content, (str, PILImage.Image)):
127
  actual_content_for_handling = final_answer_content.final_answer
128
  print(f"DEBUG Gradio: Extracted actual_content_for_handling from FinalAnswerStep: {type(actual_content_for_handling)}")
129
 
 
 
130
  if isinstance(actual_content_for_handling, PILImage.Image):
131
+ print("DEBUG Gradio (stream_to_gradio): Actual content IS a raw PIL Image.")
132
  try:
133
  with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp_file:
134
  actual_content_for_handling.save(tmp_file, format="PNG")
135
  image_path_for_gradio = tmp_file.name
136
+ print(f"DEBUG Gradio: Saved PIL image to temp path: {image_path_for_gradio}")
137
+ # MODIFIED: Yield tuple (filepath, alt_text)
138
+ yield {"role": "assistant", "content": (image_path_for_gradio, "Generated Image")}
139
  return
140
  except Exception as e:
141
  print(f"DEBUG Gradio: Error saving extracted PIL image: {e}")
142
+ yield {"role": "assistant", "content": f"**Final Answer (Error displaying image):** {e}"}
143
  return
144
 
145
  final_answer_processed = handle_agent_output_types(actual_content_for_handling)
146
  print(f"DEBUG Gradio: final_answer_processed type after handle_agent_output_types: {type(final_answer_processed)}")
147
 
 
148
  if isinstance(final_answer_processed, AgentText):
149
  yield {"role": "assistant", "content": f"**Final Answer:**\n{final_answer_processed.to_string()}"}
150
  elif isinstance(final_answer_processed, AgentImage):
151
  image_path = final_answer_processed.to_string()
152
  print(f"DEBUG Gradio (stream_to_gradio): final_answer_processed is AgentImage. Path: {image_path}")
153
  if image_path and os.path.exists(image_path):
154
+ # MODIFIED: Yield tuple (filepath, alt_text)
155
+ yield {"role": "assistant", "content": (image_path, "Generated Image (from AgentImage)")}
156
  else:
157
+ err_msg = f"Error: Image path from AgentImage ('{image_path}') not found or invalid."
158
  print(f"DEBUG Gradio: {err_msg}")
159
  yield {"role": "assistant", "content": f"**Final Answer ({err_msg})**"}
160
  elif isinstance(final_answer_processed, AgentAudio):
161
  audio_path = final_answer_processed.to_string()
162
  print(f"DEBUG Gradio (stream_to_gradio): AgentAudio path: {audio_path}")
163
  if audio_path and os.path.exists(audio_path):
164
+ # MODIFIED: Yield tuple (filepath, alt_text) for consistency, though Gradio might just use path for audio
165
+ yield {"role": "assistant", "content": (audio_path, "Generated Audio")}
166
  else:
167
  err_msg = f"Error: Audio path from AgentAudio ('{audio_path}') not found"
168
  print(f"DEBUG Gradio: {err_msg}")
169
  yield {"role": "assistant", "content": f"**Final Answer ({err_msg})**"}
170
  else:
 
171
  yield {"role": "assistant", "content": f"**Final Answer:**\n{str(final_answer_processed)}"}
172
 
173
 
 
189
  for log_entry in reversed(self.agent.interaction_logs):
190
  if isinstance(log_entry, ActionStep):
191
  observations = getattr(log_entry, 'observations', None)
 
 
 
 
192
  if observations and isinstance(observations, str):
193
+ print(f"DEBUG Gradio UI: Checking observations: {observations[:200]}")
194
  path_match = re.search(r"(/tmp/[a-zA-Z0-9_]+/generated_document\.(?:docx|pdf|txt))", observations)
195
  if path_match:
196
  extracted_path = path_match.group(1)
 
208
  print(f"DEBUG Gradio: interact_with_agent called with prompt: '{prompt_text}'")
209
  print(f"DEBUG Gradio: Current chat history (input type {type(current_chat_history)}): {current_chat_history}")
210
 
 
211
  updated_chat_history = current_chat_history + [{"role": "user", "content": prompt_text}]
212
 
213
  yield updated_chat_history, gr.update(visible=False), gr.update(value=None, visible=False)
 
248
  sanitized_name = re.sub(r"[^\w\-.]", "_", original_name)
249
  base_name, current_ext = os.path.splitext(sanitized_name)
250
 
 
251
  common_mime_to_ext = {
252
  "application/pdf": ".pdf",
253
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx",
 
274
  if current_file_uploads:
275
  files_str = ", ".join([os.path.basename(f) for f in current_file_uploads])
276
  full_prompt += f"\n\n[Uploaded files for context: {files_str}]"
277
+ print(f"DEBUG Gradio: Prepared prompt for agent: {full_prompt[:300]}...")
278
  return full_prompt, ""
279
 
280
  def prepare_and_show_download_file(self):
 
285
  visible=True)
286
  else:
287
  print("DEBUG Gradio UI: No valid file path to prepare for download component.")
288
+ return gr.File.update(visible=False, value=None)
 
289
 
290
  def launch(self, **kwargs):
291
  with gr.Blocks(fill_height=True, theme=gr.themes.Soft(primary_hue=gr.themes.colors.blue)) as demo:
292
  file_uploads_log_state = gr.State([])
293
  prepared_prompt_for_agent = gr.State("")
294
 
295
+ gr.Markdown("## Smol Talk with your Agent")
296
 
297
+ with gr.Row(equal_height=False):
298
  with gr.Column(scale=3):
299
  chatbot_display = gr.Chatbot(
300
  label="Agent Interaction",
301
  type="messages",
302
  avatar_images=(None, "https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo-round.png"),
303
+ height=700,
304
  show_copy_button=True,
305
  bubble_full_width=False,
306
+ show_label=False
307
  )
308
  text_message_input = gr.Textbox(
309
  lines=1,
310
  label="Your Message to the Agent",
311
  placeholder="Type your message and press Enter, or Shift+Enter for new line...",
312
+ show_label=False
313
  )
314
 
315
  with gr.Column(scale=1):
316
+ with gr.Accordion("File Upload", open=False):
317
+ file_uploader = gr.File(label="Upload a supporting file (PDF, DOCX, TXT, JPG, PNG)")
318
+ upload_status_text = gr.Textbox(label="Upload Status", interactive=False, lines=1)
319
+ file_uploader.upload(
320
+ self.upload_file,
321
+ [file_uploader, file_uploads_log_state],
322
+ [upload_status_text, file_uploads_log_state],
323
+ )
 
324
 
325
+ with gr.Accordion("Generated File", open=True):
326
  download_action_button = gr.Button("Download Generated File", visible=False)
327
  file_download_display_component = gr.File(label="Downloadable Document", visible=False, interactive=False)
328
 
 
332
  [prepared_prompt_for_agent, text_message_input]
333
  ).then(
334
  self.interact_with_agent,
335
+ [prepared_prompt_for_agent, chatbot_display],
336
+ [chatbot_display, download_action_button, file_download_display_component]
337
  )
338
 
339
  download_action_button.click(
 
341
  [],
342
  [file_download_display_component]
343
  )
 
344
  demo.launch(debug=True, share=kwargs.get("share", False), **kwargs)
345
 
346
  __all__ = ["stream_to_gradio", "GradioUI"]