Leonardo commited on
Commit
7ab7a72
·
verified ·
1 Parent(s): fbec7e7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -58
app.py CHANGED
@@ -11,6 +11,7 @@ import os
11
  import re
12
  import shutil
13
  import datetime
 
14
 
15
  from dotenv import load_dotenv
16
  from huggingface_hub import login
@@ -38,9 +39,9 @@ from smolagents import (
38
  TransformersModel,
39
  GoogleSearchTool,
40
  Tool,
 
41
  )
42
- from smolagents.agent_types import AgentText, AgentImage, AgentAudio
43
- from smolagents.gradio_ui import pull_messages_from_step, handle_agent_output_types
44
 
45
  # ------------------------ Configuration and Setup ------------------------
46
  # Constants and configurations
@@ -247,6 +248,9 @@ def create_agent():
247
  # Create tool instances with proper error handling
248
  web_tools = ToolRegistry.load_web_tools(model, browser, text_limit)
249
 
 
 
 
250
  try:
251
  doc_tools = ToolRegistry.load_document_tools()
252
  except AssertionError as e:
@@ -265,6 +269,7 @@ def create_agent():
265
  tool
266
  for tool in (
267
  [visualizer]
 
268
  + web_tools
269
  + doc_tools
270
  + ([image_generator] if image_generator else [])
@@ -280,61 +285,44 @@ def create_agent():
280
  return CodeAgent(
281
  model=model,
282
  tools=all_tools,
283
- max_steps=12,
284
  verbosity_level=2,
285
  additional_authorized_imports=AUTHORIZED_IMPORTS,
286
  planning_interval=4,
 
 
 
 
 
 
 
 
 
 
 
 
287
  )
288
  except Exception as e:
289
  print(f"Failed to create agent: {e}")
290
  raise RuntimeError(f"Agent creation failed: {e}") from e
291
 
292
 
293
- def stream_to_gradio(agent, task, reset_agent_memory=False, additional_args=None):
294
- """Runs an agent with the given task and streams messages as Gradio ChatMessages."""
295
- try:
296
- for step_log in agent.run(
297
- task, stream=True, reset=reset_agent_memory, additional_args=additional_args
298
- ):
299
- yield from pull_messages_from_step(step_log)
300
 
301
- # Get the last step log from the agent's memory for final answer
302
- last_step_log = agent.memory.steps[-1] if agent.memory.steps else None
303
 
304
- if last_step_log:
305
- # Process final answer with comprehensive media output
306
- final_answer = handle_agent_output_types(last_step_log)
 
307
 
308
- # Output handling based on type
309
- if isinstance(final_answer, AgentText):
310
- yield gr.ChatMessage(
311
- role="assistant",
312
- content=f"**Final answer:**\n{final_answer.to_string()}\n",
313
- )
314
- elif isinstance(final_answer, AgentImage):
315
- yield gr.ChatMessage(
316
- role="assistant",
317
- content={"image": final_answer.to_string(), "type": "file"},
318
- )
319
- elif isinstance(final_answer, AgentAudio):
320
- yield gr.ChatMessage(
321
- role="assistant",
322
- content={"audio": final_answer.to_string(), "type": "file"},
323
- )
324
- else:
325
- yield gr.ChatMessage(
326
- role="assistant", content=f"**Final answer:** {str(final_answer)}"
327
- )
328
- else:
329
- yield gr.ChatMessage(
330
- role="assistant",
331
- content="No final answer was generated. Please try again.",
332
- )
333
- except Exception as e:
334
- yield gr.ChatMessage(
335
- role="assistant",
336
- content=f"**Error occurred during processing**: {str(e)}\n\nPlease try again with a different query or check your inputs.",
337
- )
338
 
339
 
340
  # ------------------------ Gradio UI Components ------------------------
@@ -376,7 +364,19 @@ class GradioUI:
376
 
377
  try:
378
  # Check if agent should be reset (e.g., if too many requests)
379
- reset_needed = session_state["request_count"] > 15
 
 
 
 
 
 
 
 
 
 
 
 
380
 
381
  for msg in stream_to_gradio(
382
  session_state["agent"], task=prompt, reset_agent_memory=reset_needed
@@ -418,6 +418,11 @@ class GradioUI:
418
 
419
  # Check MIME type
420
  mime_type, _ = mimetypes.guess_type(file.name)
 
 
 
 
 
421
  if mime_type not in ALLOWED_FILE_TYPES:
422
  allowed_extensions = [
423
  t.rsplit("/", maxsplit=1)[-1] for t in ALLOWED_FILE_TYPES
@@ -462,20 +467,34 @@ class GradioUI:
462
  category = "images"
463
  elif ext in [".mp3", ".wav", ".ogg"]:
464
  category = "audio"
 
 
 
 
465
  else:
466
  category = "documents"
467
 
468
  if category not in file_info:
469
  file_info[category] = []
470
- file_info[category].append(os.path.basename(file_path))
 
 
471
 
472
  # Format file information for the agent
473
  file_message = "\nYou have been provided with these files:\n"
474
  for category, files in file_info.items():
475
- file_message += f"- {category.capitalize()}: {', '.join(files)}\n"
 
 
 
 
476
 
477
  message += file_message
478
- message += "\nUse inspect_file_as_text for documents, visualizer for images, and the appropriate tools for audio files."
 
 
 
 
479
 
480
  return (
481
  message,
@@ -533,7 +552,7 @@ class GradioUI:
533
  with gr.Blocks(fill_height=True) as sidebar_demo:
534
  with gr.Sidebar():
535
  gr.Markdown(
536
- """#
537
  ### Smolagents + Document Tools
538
  """
539
  )
@@ -554,7 +573,7 @@ class GradioUI:
554
  # File upload section with better labeling
555
  if self.file_upload_folder is not None:
556
  with gr.Group():
557
- gr.Markdown("** Upload Documents**")
558
  upload_file = gr.File(
559
  label="Upload files for analysis",
560
  file_types=[
@@ -592,6 +611,23 @@ class GradioUI:
592
  [uploaded_files_display],
593
  )
594
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
595
  gr.HTML("<br><hr><h4><center>Powered by:</center></h4>")
596
  with gr.Row():
597
  gr.HTML(
@@ -648,14 +684,14 @@ class GradioUI:
648
  def _create_mobile_layout(self):
649
  """Create the mobile layout (simpler without sidebar)."""
650
  with gr.Blocks(fill_height=True) as simple_demo:
651
- gr.Markdown("""#OpenDeepResearch - free the AI agents!""")
652
  # Add session state to store session-specific data
653
  session_state = gr.State({})
654
  stored_messages = gr.State([])
655
  file_uploads_log = gr.State([])
656
 
657
  chatbot = gr.Chatbot(
658
- label="open-Deep-Research",
659
  type="messages",
660
  avatar_images=(
661
  None,
@@ -667,7 +703,10 @@ class GradioUI:
667
 
668
  # If an upload folder is provided, enable the upload feature
669
  if self.file_upload_folder is not None:
670
- upload_file = gr.File(label="Upload a file")
 
 
 
671
  upload_status = gr.Textbox(
672
  label="Upload Status", interactive=False, visible=False
673
  )
@@ -678,11 +717,21 @@ class GradioUI:
678
  )
679
 
680
  text_input = gr.Textbox(
681
- lines=1,
682
- label="What's on your mind mate?",
683
- placeholder="Chuck in a question and we'll take care of the rest",
 
 
 
 
 
 
 
 
 
 
 
684
  )
685
- launch_research_btn = gr.Button("Run", variant="primary")
686
 
687
  self._connect_event_handlers(
688
  text_input,
@@ -757,6 +806,9 @@ def main():
757
  # Ensure downloads folder exists
758
  os.makedirs(f"./{BROWSER_CONFIG['downloads_folder']}", exist_ok=True)
759
 
 
 
 
760
  # Launch UI
761
  GradioUI(file_upload_folder="uploaded_files").launch()
762
 
 
11
  import re
12
  import shutil
13
  import datetime
14
+ from typing import Optional, List, Dict, Any
15
 
16
  from dotenv import load_dotenv
17
  from huggingface_hub import login
 
39
  TransformersModel,
40
  GoogleSearchTool,
41
  Tool,
42
+ FinalAnswerTool,
43
  )
44
+ from smolagents.gradio_ui import pull_messages_from_step, stream_to_gradio
 
45
 
46
  # ------------------------ Configuration and Setup ------------------------
47
  # Constants and configurations
 
248
  # Create tool instances with proper error handling
249
  web_tools = ToolRegistry.load_web_tools(model, browser, text_limit)
250
 
251
+ # Add FinalAnswerTool explicitly to ensure it's available
252
+ final_answer_tool = FinalAnswerTool()
253
+
254
  try:
255
  doc_tools = ToolRegistry.load_document_tools()
256
  except AssertionError as e:
 
269
  tool
270
  for tool in (
271
  [visualizer]
272
+ + [final_answer_tool] # Added explicitly
273
  + web_tools
274
  + doc_tools
275
  + ([image_generator] if image_generator else [])
 
285
  return CodeAgent(
286
  model=model,
287
  tools=all_tools,
288
+ max_steps=15, # Increased from 12 to give more room for complex tasks
289
  verbosity_level=2,
290
  additional_authorized_imports=AUTHORIZED_IMPORTS,
291
  planning_interval=4,
292
+ prompt_templates={
293
+ "system_prompt": """You are a helpful AI assistant with access to various tools.
294
+ Always think step by step, carefully planning your approach to the task.
295
+ When using Python code:
296
+ - Keep your code simple and readable
297
+ - Use the final_answer tool to provide your final response
298
+ Example of how to provide a final answer:
299
+ ```python
300
+ final_answer("This is my final answer based on my analysis.")
301
+ ```
302
+ """
303
+ },
304
  )
305
  except Exception as e:
306
  print(f"Failed to create agent: {e}")
307
  raise RuntimeError(f"Agent creation failed: {e}") from e
308
 
309
 
310
+ def detect_agent_loop(agent):
311
+ """Check if agent is stuck in a loop of similar errors"""
312
+ if not hasattr(agent, "memory") or not hasattr(agent.memory, "steps"):
313
+ return False
 
 
 
314
 
315
+ if len(agent.memory.steps) < 4:
316
+ return False
317
 
318
+ recent_steps = agent.memory.steps[-4:]
319
+ error_count = sum(
320
+ 1 for step in recent_steps if hasattr(step, "error") and step.error is not None
321
+ )
322
 
323
+ if error_count >= 3:
324
+ return True
325
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
 
328
  # ------------------------ Gradio UI Components ------------------------
 
364
 
365
  try:
366
  # Check if agent should be reset (e.g., if too many requests)
367
+ reset_needed = session_state["request_count"] > 15 or detect_agent_loop(
368
+ session_state["agent"]
369
+ )
370
+
371
+ # If agent is in a loop, provide a hint
372
+ if detect_agent_loop(session_state["agent"]):
373
+ messages.append(
374
+ gr.ChatMessage(
375
+ role="assistant",
376
+ content="I notice I'm having trouble executing some commands. Let me try a different approach...",
377
+ )
378
+ )
379
+ yield messages
380
 
381
  for msg in stream_to_gradio(
382
  session_state["agent"], task=prompt, reset_agent_memory=reset_needed
 
418
 
419
  # Check MIME type
420
  mime_type, _ = mimetypes.guess_type(file.name)
421
+
422
+ # Ensure Markdown files are recognized properly
423
+ if file.name.lower().endswith(".md"):
424
+ mime_type = "text/markdown"
425
+
426
  if mime_type not in ALLOWED_FILE_TYPES:
427
  allowed_extensions = [
428
  t.rsplit("/", maxsplit=1)[-1] for t in ALLOWED_FILE_TYPES
 
467
  category = "images"
468
  elif ext in [".mp3", ".wav", ".ogg"]:
469
  category = "audio"
470
+ elif ext in [".md"]:
471
+ category = "markdown"
472
+ elif ext in [".pdf"]:
473
+ category = "pdf"
474
  else:
475
  category = "documents"
476
 
477
  if category not in file_info:
478
  file_info[category] = []
479
+ file_info[category].append(
480
+ file_path
481
+ ) # Store full path for easier access
482
 
483
  # Format file information for the agent
484
  file_message = "\nYou have been provided with these files:\n"
485
  for category, files in file_info.items():
486
+ # Convert to filename-only for display
487
+ file_names = [os.path.basename(f) for f in files]
488
+ file_message += f"- {category.capitalize()}: {', '.join(file_names)}\n"
489
+ # Add full paths after names
490
+ file_message += f" Paths: {', '.join(files)}\n"
491
 
492
  message += file_message
493
+ message += (
494
+ "\nUse inspect_file_as_text for documents/markdown/pdf, "
495
+ "visualizer for images, and the appropriate tools for audio files. "
496
+ "Remember to use the full file path when accessing the files."
497
+ )
498
 
499
  return (
500
  message,
 
552
  with gr.Blocks(fill_height=True) as sidebar_demo:
553
  with gr.Sidebar():
554
  gr.Markdown(
555
+ """# 🔍 OpenDeepResearch
556
  ### Smolagents + Document Tools
557
  """
558
  )
 
573
  # File upload section with better labeling
574
  if self.file_upload_folder is not None:
575
  with gr.Group():
576
+ gr.Markdown("**📎 Upload Documents**")
577
  upload_file = gr.File(
578
  label="Upload files for analysis",
579
  file_types=[
 
611
  [uploaded_files_display],
612
  )
613
 
614
+ # Add helpful tool usage examples
615
+ with gr.Accordion("Tool Usage Examples", open=False):
616
+ gr.Markdown(
617
+ """
618
+ ### Document Tools
619
+ - "Extract metadata from this document" - Uses frontmatter generator
620
+ - "Clean and format this text" - Uses text cleaner
621
+
622
+ ### File Analysis
623
+ - "Analyze this PDF and summarize the key points" - Uses inspect_file_as_text
624
+ - "What's in this image?" - Uses visualizer
625
+
626
+ ### Web Search
627
+ - "Find information about XYZ" - Uses search tools
628
+ """
629
+ )
630
+
631
  gr.HTML("<br><hr><h4><center>Powered by:</center></h4>")
632
  with gr.Row():
633
  gr.HTML(
 
684
  def _create_mobile_layout(self):
685
  """Create the mobile layout (simpler without sidebar)."""
686
  with gr.Blocks(fill_height=True) as simple_demo:
687
+ gr.Markdown("""# 🔍 OpenDeepResearch""")
688
  # Add session state to store session-specific data
689
  session_state = gr.State({})
690
  stored_messages = gr.State([])
691
  file_uploads_log = gr.State([])
692
 
693
  chatbot = gr.Chatbot(
694
+ label="OpenDeepResearch Assistant",
695
  type="messages",
696
  avatar_images=(
697
  None,
 
703
 
704
  # If an upload folder is provided, enable the upload feature
705
  if self.file_upload_folder is not None:
706
+ upload_file = gr.File(
707
+ label="Upload a file",
708
+ file_types=["pdf", "docx", "txt", "md", "jpg", "png"],
709
+ )
710
  upload_status = gr.Textbox(
711
  label="Upload Status", interactive=False, visible=False
712
  )
 
717
  )
718
 
719
  text_input = gr.Textbox(
720
+ lines=2,
721
+ label="Your question",
722
+ placeholder="Enter your question here",
723
+ )
724
+
725
+ with gr.Row():
726
+ clear_btn = gr.Button("Clear", variant="secondary")
727
+ launch_research_btn = gr.Button("Run", variant="primary")
728
+
729
+ # Connect clear button
730
+ clear_btn.click(
731
+ lambda: ([], [], {"agent": session_state.get("agent")}),
732
+ None,
733
+ [chatbot, stored_messages, session_state],
734
  )
 
735
 
736
  self._connect_event_handlers(
737
  text_input,
 
806
  # Ensure downloads folder exists
807
  os.makedirs(f"./{BROWSER_CONFIG['downloads_folder']}", exist_ok=True)
808
 
809
+ # Ensure uploads folder exists
810
+ os.makedirs("uploaded_files", exist_ok=True)
811
+
812
  # Launch UI
813
  GradioUI(file_upload_folder="uploaded_files").launch()
814