Charles Azam commited on
Commit
fe6be00
·
1 Parent(s): bd41508

feat: add support for images

Browse files
gradio_app.py CHANGED
@@ -4,7 +4,9 @@ from deepengineer.backend.gradio_tools import run_agent_stream
4
  with gr.Blocks() as demo:
5
  gr.Markdown("# Agent Interface with Real‑Time Tool Logging")
6
  user_input = gr.Textbox(label="User Message")
7
- agent_output = gr.Markdown(label="Agent Response")
 
 
8
  log_output = gr.Textbox(label="Tool Invocation Log", interactive=False)
9
 
10
  send = gr.Button("Send")
 
4
  with gr.Blocks() as demo:
5
  gr.Markdown("# Agent Interface with Real‑Time Tool Logging")
6
  user_input = gr.Textbox(label="User Message")
7
+ agent_output = gr.Markdown(
8
+ label="Agent Response",
9
+ )
10
  log_output = gr.Textbox(label="Tool Invocation Log", interactive=False)
11
 
12
  send = gr.Button("Send")
src/deepengineer/backend/gradio_tools.py CHANGED
@@ -1,8 +1,55 @@
1
  import threading
2
  import time
3
  import queue
 
 
4
 
5
  from deepengineer.deepsearch.main_agent import main_search
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
 
8
  def run_agent_stream(user_input: str):
@@ -11,7 +58,7 @@ def run_agent_stream(user_input: str):
11
  – starts the agent in a background thread
12
  – while the agent runs, flushes anything that tools
13
  have pushed into `log_queue`
14
- – finally yields the agents answer
15
  Yields tuples: (agent_output, log_output)
16
  """
17
  log_queue = queue.Queue()
@@ -21,11 +68,11 @@ def run_agent_stream(user_input: str):
21
  print("Emptying log queue")
22
  log_queue.get_nowait()
23
 
24
- answer_container = {"text": None}
25
  done = threading.Event()
26
 
27
  def _worker():
28
- answer_container["text"], output_image_path = main_search(user_input, log_queue)
29
  done.set()
30
 
31
  threading.Thread(target=_worker, daemon=True).start()
@@ -45,5 +92,12 @@ def run_agent_stream(user_input: str):
45
  log_line = log_queue.get()
46
  log_buffer += log_line + "\n"
47
 
48
- # final yield: agent_output filled, log_output frozen
49
- yield (answer_container["text"], log_buffer.rstrip())
 
 
 
 
 
 
 
 
1
  import threading
2
  import time
3
  import queue
4
+ import re
5
+ from pathlib import Path
6
 
7
  from deepengineer.deepsearch.main_agent import main_search
8
+ from deepengineer.common_path import DATA_DIR
9
+
10
+
11
+ def parse_markdown_images(markdown_text: str, image_dir: Path) -> str:
12
+ """
13
+ Parse markdown text and convert image references to absolute file paths
14
+ that Gradio can display.
15
+
16
+ Args:
17
+ markdown_text: The markdown text containing image references
18
+ image_dir: The directory containing the generated images
19
+
20
+ Returns:
21
+ Modified markdown text with absolute file paths for images
22
+ """
23
+ if not markdown_text or not image_dir:
24
+ return markdown_text
25
+
26
+ # Pattern to match markdown image syntax: ![alt text](image_path)
27
+ image_pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
28
+
29
+ def replace_image_path(match):
30
+ alt_text = match.group(1)
31
+ image_path = match.group(2)
32
+
33
+ # If the path is already absolute, return as is
34
+ if Path(image_path).is_absolute():
35
+ return f'![{alt_text}]({image_path})'
36
+
37
+ # If it's a relative path, try to find it in the image directory
38
+ if image_dir.exists():
39
+ # Look for the image file in the image directory
40
+ for img_file in image_dir.glob('*'):
41
+ if img_file.name == Path(image_path).name:
42
+ return f'![{alt_text}]({img_file.absolute()})'
43
+
44
+ # If not found by name, try to find any image file
45
+ image_files = list(image_dir.glob('*.png')) + list(image_dir.glob('*.jpg')) + list(image_dir.glob('*.jpeg'))
46
+ if image_files:
47
+ return f'![{alt_text}]({image_files[0].absolute()})'
48
+
49
+ # If no image found, return the original reference
50
+ return match.group(0)
51
+
52
+ return re.sub(image_pattern, replace_image_path, markdown_text)
53
 
54
 
55
  def run_agent_stream(user_input: str):
 
58
  – starts the agent in a background thread
59
  – while the agent runs, flushes anything that tools
60
  have pushed into `log_queue`
61
+ – finally yields the agent's answer with embedded images
62
  Yields tuples: (agent_output, log_output)
63
  """
64
  log_queue = queue.Queue()
 
68
  print("Emptying log queue")
69
  log_queue.get_nowait()
70
 
71
+ answer_container = {"text": None, "image_dir": None}
72
  done = threading.Event()
73
 
74
  def _worker():
75
+ answer_container["text"], answer_container["image_dir"] = main_search(user_input, log_queue)
76
  done.set()
77
 
78
  threading.Thread(target=_worker, daemon=True).start()
 
92
  log_line = log_queue.get()
93
  log_buffer += log_line + "\n"
94
 
95
+ # Process the final answer to include images
96
+ final_answer = answer_container["text"]
97
+ image_dir = answer_container["image_dir"]
98
+
99
+ if final_answer and image_dir:
100
+ final_answer = parse_markdown_images(final_answer, image_dir)
101
+
102
+ # final yield: agent_output filled with processed markdown, log_output frozen
103
+ yield (final_answer, log_buffer.rstrip())
src/deepengineer/deepsearch/main_agent.py CHANGED
@@ -69,7 +69,7 @@ def create_main_search_agent(
69
  return search_agent
70
 
71
 
72
- def main_search(task: str, log_queue: queue.Queue | None = None):
73
  output_image_path = create_output_image_path()
74
  MAIN_PROMPT = """
75
  You are DeepDraft, an advanced research and analysis agent specialized in deep technical research, data visualization, and comprehensive information synthesis. You have access to powerful tools for web search, document analysis, and data visualization.
@@ -90,6 +90,10 @@ You have the tools to search the web using Linkup API for comprehensive research
90
  ### **Data Visualization Tools**
91
  - You can always use the tool `SaveMatplotlibFigTool` to save a figure at the end of a matplotlib code block. You can then include the figure in your final answer.
92
 
 
 
 
 
93
  You have one question to answer. It is paramount that you provide a correct answer.
94
  Give it all you can: I know for a fact that you have access to all the relevant tools to solve it and find the correct answer (the answer does exist).
95
  Failure or 'I cannot answer' or 'None found' will not be tolerated, success will be rewarded.
 
69
  return search_agent
70
 
71
 
72
+ def main_search(task: str, log_queue: queue.Queue | None = None) -> tuple[str, Path]:
73
  output_image_path = create_output_image_path()
74
  MAIN_PROMPT = """
75
  You are DeepDraft, an advanced research and analysis agent specialized in deep technical research, data visualization, and comprehensive information synthesis. You have access to powerful tools for web search, document analysis, and data visualization.
 
90
  ### **Data Visualization Tools**
91
  - You can always use the tool `SaveMatplotlibFigTool` to save a figure at the end of a matplotlib code block. You can then include the figure in your final answer.
92
 
93
+ ## Answer format
94
+ You must answer the question in markdown format. Remember, you are a coding agent and you can pass the answer only by using the `final_answer("your markdown answer")` tool.
95
+ Also, if you want to include images in your answer, you MUST include the image in the markdown like this: ![title](image_name.png).
96
+
97
  You have one question to answer. It is paramount that you provide a correct answer.
98
  Give it all you can: I know for a fact that you have access to all the relevant tools to solve it and find the correct answer (the answer does exist).
99
  Failure or 'I cannot answer' or 'None found' will not be tolerated, success will be rewarded.