Spaces:
Running
Running
harshalmore31
commited on
Synced repo using 'sync_with_huggingface' Github Action
Browse files
app.py
CHANGED
@@ -1,1807 +1,5 @@
|
|
1 |
-
import
|
2 |
-
from dotenv import load_dotenv
|
3 |
-
from typing import AsyncGenerator, List, Dict, Any, Tuple, Optional
|
4 |
-
import json
|
5 |
-
import time
|
6 |
-
import asyncio
|
7 |
-
import gradio as gr
|
8 |
-
from swarms.structs.agent import Agent
|
9 |
-
from swarms.structs.swarm_router import SwarmRouter
|
10 |
-
from swarms.utils.loguru_logger import initialize_logger
|
11 |
-
import re
|
12 |
-
import csv # Import the csv module for csv parsing
|
13 |
-
from swarms.utils.litellm_wrapper import LiteLLM
|
14 |
-
from litellm import models_by_provider
|
15 |
-
from dotenv import set_key, find_dotenv
|
16 |
-
import logging # Import the logging module
|
17 |
-
|
18 |
-
# Initialize logger
|
19 |
-
load_dotenv()
|
20 |
-
|
21 |
-
# Initialize logger
|
22 |
-
logger = initialize_logger(log_folder="swarm_ui")
|
23 |
-
|
24 |
-
|
25 |
-
# Define the path to agent_prompts.json
|
26 |
-
PROMPT_JSON_PATH = os.path.join(
|
27 |
-
os.path.dirname(os.path.abspath(__file__)), "agent_prompts.json"
|
28 |
-
)
|
29 |
-
logger.info(f"Loading prompts from: {PROMPT_JSON_PATH}")
|
30 |
-
|
31 |
-
# Load prompts first so its available for create_app
|
32 |
-
def load_prompts_from_json() -> Dict[str, str]:
|
33 |
-
try:
|
34 |
-
if not os.path.exists(PROMPT_JSON_PATH):
|
35 |
-
# Load default prompts
|
36 |
-
return {
|
37 |
-
"Agent-Data_Extractor": "You are a data extraction agent...",
|
38 |
-
"Agent-Summarizer": "You are a summarization agent...",
|
39 |
-
"Agent-Onboarding_Agent": "You are an onboarding agent...",
|
40 |
-
}
|
41 |
-
|
42 |
-
with open(PROMPT_JSON_PATH, "r", encoding="utf-8") as f:
|
43 |
-
try:
|
44 |
-
data = json.load(f)
|
45 |
-
except json.JSONDecodeError:
|
46 |
-
# Load default prompts
|
47 |
-
return {
|
48 |
-
"Agent-Data_Extractor": "You are a data extraction agent...",
|
49 |
-
"Agent-Summarizer": "You are a summarization agent...",
|
50 |
-
"Agent-Onboarding_Agent": "You are an onboarding agent...",
|
51 |
-
}
|
52 |
-
|
53 |
-
if not isinstance(data, dict):
|
54 |
-
# Load default prompts
|
55 |
-
return {
|
56 |
-
"Agent-Data_Extractor": "You are a data extraction agent...",
|
57 |
-
"Agent-Summarizer": "You are a summarization agent...",
|
58 |
-
"Agent-Onboarding_Agent": "You are an onboarding agent...",
|
59 |
-
}
|
60 |
-
|
61 |
-
prompts = {}
|
62 |
-
for agent_name, details in data.items():
|
63 |
-
if (
|
64 |
-
not isinstance(details, dict)
|
65 |
-
or "system_prompt" not in details
|
66 |
-
):
|
67 |
-
continue
|
68 |
-
|
69 |
-
prompts[agent_name] = details["system_prompt"]
|
70 |
-
|
71 |
-
if not prompts:
|
72 |
-
# Load default prompts
|
73 |
-
return {
|
74 |
-
"Agent-Data_Extractor": "You are a data extraction agent...",
|
75 |
-
"Agent-Summarizer": "You are a summarization agent...",
|
76 |
-
"Agent-Onboarding_Agent": "You are an onboarding agent...",
|
77 |
-
}
|
78 |
-
|
79 |
-
return prompts
|
80 |
-
|
81 |
-
except Exception:
|
82 |
-
# Load default prompts
|
83 |
-
return {
|
84 |
-
"Agent-Data_Extractor": "You are a data extraction agent...",
|
85 |
-
"Agent-Summarizer": "You are a summarization agent...",
|
86 |
-
"Agent-Onboarding_Agent": "You are an onboarding agent...",
|
87 |
-
}
|
88 |
-
|
89 |
-
|
90 |
-
AGENT_PROMPTS = load_prompts_from_json()
|
91 |
-
|
92 |
-
|
93 |
-
def initialize_agents(
|
94 |
-
dynamic_temp: float,
|
95 |
-
agent_keys: List[str],
|
96 |
-
model_name: str,
|
97 |
-
provider: str,
|
98 |
-
api_key: str,
|
99 |
-
temperature: float,
|
100 |
-
max_tokens: int,
|
101 |
-
) -> List[Agent]:
|
102 |
-
logger.info("Initializing agents...")
|
103 |
-
agents = []
|
104 |
-
seen_names = set()
|
105 |
-
try:
|
106 |
-
for agent_key in agent_keys:
|
107 |
-
if agent_key not in AGENT_PROMPTS:
|
108 |
-
raise ValueError(f"Invalid agent key: {agent_key}")
|
109 |
-
|
110 |
-
agent_prompt = AGENT_PROMPTS[agent_key]
|
111 |
-
agent_name = agent_key
|
112 |
-
|
113 |
-
# Ensure unique agent names
|
114 |
-
base_name = agent_name
|
115 |
-
counter = 1
|
116 |
-
while agent_name in seen_names:
|
117 |
-
agent_name = f"{base_name}_{counter}"
|
118 |
-
counter += 1
|
119 |
-
seen_names.add(agent_name)
|
120 |
-
|
121 |
-
llm = LiteLLM(
|
122 |
-
model_name=model_name,
|
123 |
-
system_prompt=agent_prompt,
|
124 |
-
temperature=temperature,
|
125 |
-
max_tokens=max_tokens,
|
126 |
-
)
|
127 |
-
|
128 |
-
agent = Agent(
|
129 |
-
agent_name=agent_name,
|
130 |
-
system_prompt=agent_prompt,
|
131 |
-
llm=llm,
|
132 |
-
max_loops=1,
|
133 |
-
autosave=True,
|
134 |
-
verbose=True,
|
135 |
-
dynamic_temperature_enabled=True,
|
136 |
-
saved_state_path=f"agent_{agent_name}.json",
|
137 |
-
user_name="pe_firm",
|
138 |
-
retry_attempts=1,
|
139 |
-
context_length=200000,
|
140 |
-
output_type="string", # here is the output type which is string
|
141 |
-
temperature=dynamic_temp,
|
142 |
-
)
|
143 |
-
print(
|
144 |
-
f"Agent created: {agent.agent_name}"
|
145 |
-
) # Debug: Print agent name
|
146 |
-
agents.append(agent)
|
147 |
-
logger.info(f"Agents initialized successfully: {[agent.agent_name for agent in agents]}")
|
148 |
-
return agents
|
149 |
-
except Exception as e:
|
150 |
-
logger.error(f"Error initializing agents: {e}", exc_info=True)
|
151 |
-
raise
|
152 |
-
|
153 |
-
def validate_flow(flow, agents_dict):
|
154 |
-
logger.info(f"Validating flow: {flow}")
|
155 |
-
agent_names = flow.split("->")
|
156 |
-
for agent in agent_names:
|
157 |
-
agent = agent.strip()
|
158 |
-
if agent not in agents_dict:
|
159 |
-
logger.error(f"Agent '{agent}' specified in the flow does not exist.")
|
160 |
-
raise ValueError(
|
161 |
-
f"Agent '{agent}' specified in the flow does not exist."
|
162 |
-
)
|
163 |
-
logger.info(f"Flow validated successfully: {flow}")
|
164 |
-
|
165 |
-
class TaskExecutionError(Exception):
|
166 |
-
"""Custom exception for task execution errors."""
|
167 |
-
def __init__(self, message: str):
|
168 |
-
self.message = message
|
169 |
-
super().__init__(self.message)
|
170 |
-
|
171 |
-
def __str__(self):
|
172 |
-
return f"TaskExecutionError: {self.message}"
|
173 |
-
|
174 |
-
async def execute_task(
|
175 |
-
task: str,
|
176 |
-
max_loops: int,
|
177 |
-
dynamic_temp: float,
|
178 |
-
swarm_type: str,
|
179 |
-
agent_keys: List[str],
|
180 |
-
flow: str = None,
|
181 |
-
model_name: str = "gpt-4o",
|
182 |
-
provider: str = "openai",
|
183 |
-
api_key: str = None,
|
184 |
-
temperature: float = 0.5,
|
185 |
-
max_tokens: int = 4000,
|
186 |
-
agents: dict = None,
|
187 |
-
log_display=None,
|
188 |
-
error_display=None
|
189 |
-
) -> AsyncGenerator[Tuple[Any, Optional["SwarmRouter"], str], None]: # Changed the return type here
|
190 |
-
logger.info(f"Executing task: {task} with swarm type: {swarm_type}")
|
191 |
-
try:
|
192 |
-
if not task:
|
193 |
-
logger.error("Task description is missing.")
|
194 |
-
yield "Please provide a task description.", gr.update(visible=True), ""
|
195 |
-
return
|
196 |
-
if not agent_keys:
|
197 |
-
logger.error("No agents selected.")
|
198 |
-
yield "Please select at least one agent.", gr.update(visible=True), ""
|
199 |
-
return
|
200 |
-
if not provider:
|
201 |
-
logger.error("Provider is missing.")
|
202 |
-
yield "Please select a provider.", gr.update(visible=True), ""
|
203 |
-
return
|
204 |
-
if not model_name:
|
205 |
-
logger.error("Model is missing.")
|
206 |
-
yield "Please select a model.", gr.update(visible=True), ""
|
207 |
-
return
|
208 |
-
if not api_key:
|
209 |
-
logger.error("API Key is missing.")
|
210 |
-
yield "Please enter an API Key.", gr.update(visible=True), ""
|
211 |
-
return
|
212 |
-
|
213 |
-
# Initialize agents
|
214 |
-
try:
|
215 |
-
if not agents:
|
216 |
-
agents = initialize_agents(
|
217 |
-
dynamic_temp,
|
218 |
-
agent_keys,
|
219 |
-
model_name,
|
220 |
-
provider,
|
221 |
-
api_key,
|
222 |
-
temperature,
|
223 |
-
max_tokens,
|
224 |
-
)
|
225 |
-
except Exception as e:
|
226 |
-
logger.error(f"Error initializing agents: {e}", exc_info=True)
|
227 |
-
yield f"Error initializing agents: {e}", gr.update(visible=True), ""
|
228 |
-
return
|
229 |
-
|
230 |
-
# Swarm-specific configurations
|
231 |
-
router_kwargs = {
|
232 |
-
"name": "multi-agent-workflow",
|
233 |
-
"description": f"Executing {swarm_type} workflow",
|
234 |
-
"max_loops": max_loops,
|
235 |
-
"agents": list(agents.values()),
|
236 |
-
"autosave": True,
|
237 |
-
"return_json": True,
|
238 |
-
"output_type": "string", # Default output type
|
239 |
-
"swarm_type": swarm_type, # Pass swarm_type here
|
240 |
-
}
|
241 |
-
|
242 |
-
if swarm_type == "AgentRearrange":
|
243 |
-
if not flow:
|
244 |
-
logger.error("Flow configuration is missing for AgentRearrange.")
|
245 |
-
yield "Flow configuration is required for AgentRearrange", gr.update(visible=True), ""
|
246 |
-
return
|
247 |
-
|
248 |
-
|
249 |
-
# Generate unique agent names in the flow
|
250 |
-
flow_agents = []
|
251 |
-
used_agent_names = set()
|
252 |
-
for agent_key in flow.split("->"):
|
253 |
-
agent_key = agent_key.strip()
|
254 |
-
base_agent_name = agent_key
|
255 |
-
count = 1
|
256 |
-
while agent_key in used_agent_names:
|
257 |
-
agent_key = f"{base_agent_name}_{count}"
|
258 |
-
count += 1
|
259 |
-
used_agent_names.add(agent_key)
|
260 |
-
flow_agents.append(agent_key)
|
261 |
-
|
262 |
-
# Update the flow string with unique names
|
263 |
-
flow = " -> ".join(flow_agents)
|
264 |
-
logger.info(f"Updated Flow string: {flow}")
|
265 |
-
router_kwargs["flow"] = flow
|
266 |
-
router_kwargs["output_type"] = "string" # Changed output type here
|
267 |
-
|
268 |
-
|
269 |
-
if swarm_type == "MixtureOfAgents":
|
270 |
-
if len(agents) < 2:
|
271 |
-
logger.error("MixtureOfAgents requires at least 2 agents.")
|
272 |
-
yield "MixtureOfAgents requires at least 2 agents", gr.update(visible=True), ""
|
273 |
-
return
|
274 |
-
|
275 |
-
if swarm_type == "SequentialWorkflow":
|
276 |
-
if len(agents) < 2:
|
277 |
-
logger.error("SequentialWorkflow requires at least 2 agents.")
|
278 |
-
yield "SequentialWorkflow requires at least 2 agents", gr.update(visible=True), ""
|
279 |
-
return
|
280 |
-
|
281 |
-
if swarm_type == "ConcurrentWorkflow":
|
282 |
-
pass
|
283 |
-
|
284 |
-
if swarm_type == "SpreadSheetSwarm":
|
285 |
-
pass
|
286 |
-
|
287 |
-
if swarm_type == "auto":
|
288 |
-
pass
|
289 |
-
|
290 |
-
# Create and execute SwarmRouter
|
291 |
-
try:
|
292 |
-
timeout = (
|
293 |
-
450 if swarm_type != "SpreadSheetSwarm" else 900
|
294 |
-
) # SpreadSheetSwarm will have different timeout.
|
295 |
-
|
296 |
-
if swarm_type == "AgentRearrange":
|
297 |
-
from swarms.structs.rearrange import AgentRearrange
|
298 |
-
router = AgentRearrange(
|
299 |
-
agents=list(agents.values()),
|
300 |
-
flow=flow,
|
301 |
-
max_loops=max_loops,
|
302 |
-
name="multi-agent-workflow",
|
303 |
-
description=f"Executing {swarm_type} workflow",
|
304 |
-
# autosave=True,
|
305 |
-
return_json=True,
|
306 |
-
output_type="string", # Changed output type according to agent rearrange
|
307 |
-
)
|
308 |
-
result = router(task) # Changed run method
|
309 |
-
logger.info(f"AgentRearrange task executed successfully.")
|
310 |
-
yield result, None, ""
|
311 |
-
return
|
312 |
-
|
313 |
-
# For other swarm types use the SwarmRouter and its run method
|
314 |
-
router = SwarmRouter(**router_kwargs) # Initialize SwarmRouter
|
315 |
-
if swarm_type == "ConcurrentWorkflow":
|
316 |
-
async def run_agent_task(agent, task_):
|
317 |
-
return agent.run(task_)
|
318 |
-
|
319 |
-
tasks = [
|
320 |
-
run_agent_task(agent, task)
|
321 |
-
for agent in list(agents.values())
|
322 |
-
]
|
323 |
-
responses = await asyncio.gather(*tasks)
|
324 |
-
result = {}
|
325 |
-
for agent, response in zip(list(agents.values()), responses):
|
326 |
-
result[agent.agent_name] = response
|
327 |
-
|
328 |
-
# Convert the result to JSON string for parsing
|
329 |
-
result = json.dumps(
|
330 |
-
{
|
331 |
-
"input" : {
|
332 |
-
"swarm_id" : "concurrent_workflow_swarm_id",
|
333 |
-
"name" : "ConcurrentWorkflow",
|
334 |
-
"flow" : "->".join([agent.agent_name for agent in list(agents.values())])
|
335 |
-
},
|
336 |
-
"time" : time.time(),
|
337 |
-
"outputs" : [
|
338 |
-
{
|
339 |
-
"agent_name": agent_name,
|
340 |
-
"steps" : [{"role":"assistant", "content":response}]
|
341 |
-
} for agent_name, response in result.items()
|
342 |
-
]
|
343 |
-
}
|
344 |
-
)
|
345 |
-
logger.info(f"ConcurrentWorkflow task executed successfully.")
|
346 |
-
yield result, None, ""
|
347 |
-
return
|
348 |
-
elif swarm_type == "auto":
|
349 |
-
result = await asyncio.wait_for(
|
350 |
-
asyncio.to_thread(router.run, task),
|
351 |
-
timeout=timeout
|
352 |
-
)
|
353 |
-
if isinstance(result,dict):
|
354 |
-
result = json.dumps(
|
355 |
-
{
|
356 |
-
"input" : {
|
357 |
-
"swarm_id" : "auto_swarm_id",
|
358 |
-
"name" : "AutoSwarm",
|
359 |
-
"flow" : "->".join([agent.agent_name for agent in list(agents.values())])
|
360 |
-
},
|
361 |
-
"time" : time.time(),
|
362 |
-
"outputs" : [
|
363 |
-
{
|
364 |
-
"agent_name": agent.agent_name,
|
365 |
-
"steps" : [{"role":"assistant", "content":response}]
|
366 |
-
} for agent, response in result.items()
|
367 |
-
]
|
368 |
-
}
|
369 |
-
)
|
370 |
-
elif isinstance(result, str):
|
371 |
-
result = json.dumps(
|
372 |
-
{
|
373 |
-
"input" : {
|
374 |
-
"swarm_id" : "auto_swarm_id",
|
375 |
-
"name" : "AutoSwarm",
|
376 |
-
"flow" : "->".join([agent.agent_name for agent in list(agents.values())])
|
377 |
-
},
|
378 |
-
"time" : time.time(),
|
379 |
-
"outputs" : [
|
380 |
-
{
|
381 |
-
"agent_name": "auto",
|
382 |
-
"steps" : [{"role":"assistant", "content":result}]
|
383 |
-
}
|
384 |
-
]
|
385 |
-
}
|
386 |
-
)
|
387 |
-
else :
|
388 |
-
logger.error("Auto Swarm returned an unexpected type")
|
389 |
-
yield "Error : Auto Swarm returned an unexpected type", gr.update(visible=True), ""
|
390 |
-
return
|
391 |
-
logger.info(f"Auto task executed successfully.")
|
392 |
-
yield result, None, ""
|
393 |
-
return
|
394 |
-
else:
|
395 |
-
result = await asyncio.wait_for(
|
396 |
-
asyncio.to_thread(router.run, task),
|
397 |
-
timeout=timeout
|
398 |
-
)
|
399 |
-
logger.info(f"{swarm_type} task executed successfully.")
|
400 |
-
yield result, None, ""
|
401 |
-
return
|
402 |
-
except asyncio.TimeoutError as e:
|
403 |
-
logger.error(f"Task execution timed out after {timeout} seconds", exc_info=True)
|
404 |
-
yield f"Task execution timed out after {timeout} seconds", gr.update(visible=True), ""
|
405 |
-
return
|
406 |
-
except Exception as e:
|
407 |
-
logger.error(f"Error executing task: {e}", exc_info=True)
|
408 |
-
yield f"Error executing task: {e}", gr.update(visible=True), ""
|
409 |
-
return
|
410 |
-
|
411 |
-
except TaskExecutionError as e:
|
412 |
-
logger.error(f"Task execution error: {e}")
|
413 |
-
yield str(e), gr.update(visible=True), ""
|
414 |
-
return
|
415 |
-
except Exception as e:
|
416 |
-
logger.error(f"An unexpected error occurred: {e}", exc_info=True)
|
417 |
-
yield f"An unexpected error occurred: {e}", gr.update(visible=True), ""
|
418 |
-
return
|
419 |
-
finally:
|
420 |
-
logger.info(f"Task execution finished for: {task} with swarm type: {swarm_type}")
|
421 |
-
|
422 |
-
|
423 |
-
def format_output(data:Optional[str], swarm_type:str, error_display=None) -> str:
|
424 |
-
if data is None:
|
425 |
-
return "Error : No output from the swarm."
|
426 |
-
if swarm_type == "AgentRearrange":
|
427 |
-
return parse_agent_rearrange_output(data, error_display)
|
428 |
-
elif swarm_type == "MixtureOfAgents":
|
429 |
-
return parse_mixture_of_agents_output(data, error_display)
|
430 |
-
elif swarm_type in ["SequentialWorkflow", "ConcurrentWorkflow"]:
|
431 |
-
return parse_sequential_workflow_output(data, error_display)
|
432 |
-
elif swarm_type == "SpreadSheetSwarm":
|
433 |
-
if os.path.exists(data):
|
434 |
-
return parse_spreadsheet_swarm_output(data, error_display)
|
435 |
-
else:
|
436 |
-
return parse_json_output(data, error_display)
|
437 |
-
elif swarm_type == "auto":
|
438 |
-
return parse_auto_swarm_output(data, error_display)
|
439 |
-
else:
|
440 |
-
return "Unsupported swarm type."
|
441 |
-
|
442 |
-
def parse_mixture_of_agents_data(data: dict, error_display=None) -> str:
|
443 |
-
"""Parses the MixtureOfAgents output data and formats it for display."""
|
444 |
-
logger.info("Parsing MixtureOfAgents data within Auto Swarm output...")
|
445 |
-
|
446 |
-
try:
|
447 |
-
output = ""
|
448 |
-
if "InputConfig" in data and isinstance(data["InputConfig"], dict):
|
449 |
-
input_config = data["InputConfig"]
|
450 |
-
output += f"Mixture of Agents Workflow Details\n\n"
|
451 |
-
output += f"Name: `{input_config.get('name', 'N/A')}`\n"
|
452 |
-
output += (
|
453 |
-
f"Description:"
|
454 |
-
f" `{input_config.get('description', 'N/A')}`\n\n---\n"
|
455 |
-
)
|
456 |
-
output += f"Agent Task Execution\n\n"
|
457 |
-
|
458 |
-
for agent in input_config.get("agents", []):
|
459 |
-
output += (
|
460 |
-
f"Agent: `{agent.get('agent_name', 'N/A')}`\n"
|
461 |
-
)
|
462 |
-
|
463 |
-
if "normal_agent_outputs" in data and isinstance(
|
464 |
-
data["normal_agent_outputs"], list
|
465 |
-
):
|
466 |
-
for i, agent_output in enumerate(
|
467 |
-
data["normal_agent_outputs"], start=3
|
468 |
-
):
|
469 |
-
agent_name = agent_output.get("agent_name", "N/A")
|
470 |
-
output += f"Run {(3 - i)} (Agent: `{agent_name}`)\n\n"
|
471 |
-
for j, step in enumerate(
|
472 |
-
agent_output.get("steps", []), start=3
|
473 |
-
):
|
474 |
-
if (
|
475 |
-
isinstance(step, dict)
|
476 |
-
and "role" in step
|
477 |
-
and "content" in step
|
478 |
-
and step["role"].strip() != "System:"
|
479 |
-
):
|
480 |
-
content = step["content"]
|
481 |
-
output += f"Step {(3 - j)}: \n"
|
482 |
-
output += f"Response:\n {content}\n\n"
|
483 |
-
|
484 |
-
if "aggregator_agent_summary" in data:
|
485 |
-
output += (
|
486 |
-
f"\nAggregated Summary :\n"
|
487 |
-
f"{data['aggregator_agent_summary']}\n{'=' * 50}\n"
|
488 |
-
)
|
489 |
-
|
490 |
-
logger.info("MixtureOfAgents data parsed successfully within Auto Swarm.")
|
491 |
-
return output
|
492 |
-
|
493 |
-
except Exception as e:
|
494 |
-
logger.error(
|
495 |
-
f"Error during parsing MixtureOfAgents data within Auto Swarm: {e}",
|
496 |
-
exc_info=True,
|
497 |
-
)
|
498 |
-
return f"Error during parsing: {str(e)}"
|
499 |
-
|
500 |
-
def parse_auto_swarm_output(data: Optional[str], error_display=None) -> str:
|
501 |
-
"""Parses the auto swarm output string and formats it for display."""
|
502 |
-
logger.info("Parsing Auto Swarm output...")
|
503 |
-
if data is None:
|
504 |
-
logger.error("No data provided for parsing Auto Swarm output.")
|
505 |
-
return "Error: No data provided for parsing."
|
506 |
-
|
507 |
-
print(f"Raw data received for parsing:\n{data}") # Debug: Print raw data
|
508 |
-
|
509 |
-
try:
|
510 |
-
parsed_data = json.loads(data)
|
511 |
-
errors = []
|
512 |
-
|
513 |
-
# Basic structure validation
|
514 |
-
if (
|
515 |
-
"input" not in parsed_data
|
516 |
-
or not isinstance(parsed_data.get("input"), dict)
|
517 |
-
):
|
518 |
-
errors.append(
|
519 |
-
"Error: 'input' data is missing or not a dictionary."
|
520 |
-
)
|
521 |
-
else:
|
522 |
-
if "swarm_id" not in parsed_data["input"]:
|
523 |
-
errors.append(
|
524 |
-
"Error: 'swarm_id' key is missing in the 'input'."
|
525 |
-
)
|
526 |
-
if "name" not in parsed_data["input"]:
|
527 |
-
errors.append(
|
528 |
-
"Error: 'name' key is missing in the 'input'."
|
529 |
-
)
|
530 |
-
if "flow" not in parsed_data["input"]:
|
531 |
-
errors.append(
|
532 |
-
"Error: 'flow' key is missing in the 'input'."
|
533 |
-
)
|
534 |
-
|
535 |
-
if "time" not in parsed_data:
|
536 |
-
errors.append("Error: 'time' key is missing.")
|
537 |
-
|
538 |
-
if errors:
|
539 |
-
logger.error(
|
540 |
-
f"Errors found while parsing Auto Swarm output: {errors}"
|
541 |
-
)
|
542 |
-
return "\n".join(errors)
|
543 |
-
|
544 |
-
swarm_id = parsed_data["input"]["swarm_id"]
|
545 |
-
swarm_name = parsed_data["input"]["name"]
|
546 |
-
agent_flow = parsed_data["input"]["flow"]
|
547 |
-
overall_time = parsed_data["time"]
|
548 |
-
|
549 |
-
output = f"Workflow Execution Details\n\n"
|
550 |
-
output += f"Swarm ID: `{swarm_id}`\n"
|
551 |
-
output += f"Swarm Name: `{swarm_name}`\n"
|
552 |
-
output += f"Agent Flow: `{agent_flow}`\n\n---\n"
|
553 |
-
output += f"Agent Task Execution\n\n"
|
554 |
-
|
555 |
-
# Handle nested MixtureOfAgents data
|
556 |
-
if (
|
557 |
-
"outputs" in parsed_data
|
558 |
-
and isinstance(parsed_data["outputs"], list)
|
559 |
-
and parsed_data["outputs"]
|
560 |
-
and isinstance(parsed_data["outputs"][0], dict)
|
561 |
-
and parsed_data["outputs"][0].get("agent_name") == "auto"
|
562 |
-
):
|
563 |
-
mixture_data = parsed_data["outputs"][0].get("steps", [])
|
564 |
-
if mixture_data and isinstance(mixture_data[0], dict) and "content" in mixture_data[0]:
|
565 |
-
try:
|
566 |
-
mixture_content = json.loads(mixture_data[0]["content"])
|
567 |
-
output += parse_mixture_of_agents_data(mixture_content)
|
568 |
-
except json.JSONDecodeError as e:
|
569 |
-
logger.error(f"Error decoding nested MixtureOfAgents data: {e}", exc_info=True)
|
570 |
-
return f"Error decoding nested MixtureOfAgents data: {e}"
|
571 |
-
else :
|
572 |
-
for i, agent_output in enumerate(parsed_data["outputs"], start=3):
|
573 |
-
if not isinstance(agent_output, dict):
|
574 |
-
errors.append(f"Error: Agent output at index {i} is not a dictionary")
|
575 |
-
continue
|
576 |
-
if "agent_name" not in agent_output:
|
577 |
-
errors.append(f"Error: 'agent_name' key is missing at index {i}")
|
578 |
-
continue
|
579 |
-
if "steps" not in agent_output:
|
580 |
-
errors.append(f"Error: 'steps' key is missing at index {i}")
|
581 |
-
continue
|
582 |
-
if agent_output["steps"] is None:
|
583 |
-
errors.append(f"Error: 'steps' data is None at index {i}")
|
584 |
-
continue
|
585 |
-
if not isinstance(agent_output["steps"], list):
|
586 |
-
errors.append(f"Error: 'steps' data is not a list at index {i}")
|
587 |
-
continue
|
588 |
-
|
589 |
-
|
590 |
-
agent_name = agent_output["agent_name"]
|
591 |
-
output += f"Run {(3-i)} (Agent: `{agent_name}`)\n\n"
|
592 |
-
|
593 |
-
# Iterate over steps
|
594 |
-
for j, step in enumerate(agent_output["steps"], start=3):
|
595 |
-
if not isinstance(step, dict):
|
596 |
-
errors.append(f"Error: step at index {j} is not a dictionary at {i} agent output.")
|
597 |
-
continue
|
598 |
-
if step is None:
|
599 |
-
errors.append(f"Error: step at index {j} is None at {i} agent output")
|
600 |
-
continue
|
601 |
-
|
602 |
-
if "role" not in step:
|
603 |
-
errors.append(f"Error: 'role' key missing at step {j} at {i} agent output.")
|
604 |
-
continue
|
605 |
-
|
606 |
-
if "content" not in step:
|
607 |
-
errors.append(f"Error: 'content' key missing at step {j} at {i} agent output.")
|
608 |
-
continue
|
609 |
-
|
610 |
-
if step["role"].strip() != "System:": # Filter out system prompts
|
611 |
-
content = step["content"]
|
612 |
-
output += f"Step {(3-j)}:\n"
|
613 |
-
output += f"Response : {content}\n\n"
|
614 |
-
|
615 |
-
output += f"Overall Completion Time: `{overall_time}`"
|
616 |
-
|
617 |
-
if errors:
|
618 |
-
logger.error(
|
619 |
-
f"Errors found while parsing Auto Swarm output: {errors}"
|
620 |
-
)
|
621 |
-
return "\n".join(errors)
|
622 |
-
|
623 |
-
logger.info("Auto Swarm output parsed successfully.")
|
624 |
-
return output
|
625 |
-
|
626 |
-
except json.JSONDecodeError as e:
|
627 |
-
logger.error(
|
628 |
-
f"Error during parsing Auto Swarm output: {e}", exc_info=True
|
629 |
-
)
|
630 |
-
return f"Error during parsing json.JSONDecodeError: {e}"
|
631 |
-
|
632 |
-
except Exception as e:
|
633 |
-
logger.error(
|
634 |
-
f"Error during parsing Auto Swarm output: {e}", exc_info=True
|
635 |
-
)
|
636 |
-
return f"Error during parsing: {str(e)}"
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
def parse_agent_rearrange_output(data: Optional[str], error_display=None) -> str:
|
641 |
-
"""
|
642 |
-
Parses the AgentRearrange output string and formats it for display.
|
643 |
-
"""
|
644 |
-
logger.info("Parsing AgentRearrange output...")
|
645 |
-
if data is None:
|
646 |
-
logger.error("No data provided for parsing AgentRearrange output.")
|
647 |
-
return "Error: No data provided for parsing."
|
648 |
-
|
649 |
-
print(
|
650 |
-
f"Raw data received for parsing:\n{data}"
|
651 |
-
) # Debug: Print raw data
|
652 |
-
|
653 |
-
try:
|
654 |
-
parsed_data = json.loads(data)
|
655 |
-
errors = []
|
656 |
-
|
657 |
-
if (
|
658 |
-
"input" not in parsed_data
|
659 |
-
or not isinstance(parsed_data.get("input"), dict)
|
660 |
-
):
|
661 |
-
errors.append(
|
662 |
-
"Error: 'input' data is missing or not a dictionary."
|
663 |
-
)
|
664 |
-
else:
|
665 |
-
if "swarm_id" not in parsed_data["input"]:
|
666 |
-
errors.append(
|
667 |
-
"Error: 'swarm_id' key is missing in the 'input'."
|
668 |
-
)
|
669 |
-
|
670 |
-
if "name" not in parsed_data["input"]:
|
671 |
-
errors.append(
|
672 |
-
"Error: 'name' key is missing in the 'input'."
|
673 |
-
)
|
674 |
-
|
675 |
-
if "flow" not in parsed_data["input"]:
|
676 |
-
errors.append(
|
677 |
-
"Error: 'flow' key is missing in the 'input'."
|
678 |
-
)
|
679 |
-
|
680 |
-
if "time" not in parsed_data:
|
681 |
-
errors.append("Error: 'time' key is missing.")
|
682 |
-
|
683 |
-
if errors:
|
684 |
-
logger.error(f"Errors found while parsing AgentRearrange output: {errors}")
|
685 |
-
return "\n".join(errors)
|
686 |
-
|
687 |
-
swarm_id = parsed_data["input"]["swarm_id"]
|
688 |
-
swarm_name = parsed_data["input"]["name"]
|
689 |
-
agent_flow = parsed_data["input"]["flow"]
|
690 |
-
overall_time = parsed_data["time"]
|
691 |
-
|
692 |
-
output = f"Workflow Execution Details\n\n"
|
693 |
-
output += f"Swarm ID: `{swarm_id}`\n"
|
694 |
-
output += f"Swarm Name: `{swarm_name}`\n"
|
695 |
-
output += f"Agent Flow: `{agent_flow}`\n\n---\n"
|
696 |
-
output += f"Agent Task Execution\n\n"
|
697 |
-
|
698 |
-
if "outputs" not in parsed_data:
|
699 |
-
errors.append("Error: 'outputs' key is missing")
|
700 |
-
elif parsed_data["outputs"] is None:
|
701 |
-
errors.append("Error: 'outputs' data is None")
|
702 |
-
elif not isinstance(parsed_data["outputs"], list):
|
703 |
-
errors.append("Error: 'outputs' data is not a list.")
|
704 |
-
elif not parsed_data["outputs"]:
|
705 |
-
errors.append("Error: 'outputs' list is empty.")
|
706 |
-
|
707 |
-
if errors:
|
708 |
-
logger.error(f"Errors found while parsing AgentRearrange output: {errors}")
|
709 |
-
return "\n".join(errors)
|
710 |
-
|
711 |
-
for i, agent_output in enumerate(
|
712 |
-
parsed_data["outputs"], start=3
|
713 |
-
):
|
714 |
-
if not isinstance(agent_output, dict):
|
715 |
-
errors.append(
|
716 |
-
f"Error: Agent output at index {i} is not a"
|
717 |
-
" dictionary"
|
718 |
-
)
|
719 |
-
continue
|
720 |
-
|
721 |
-
if "agent_name" not in agent_output:
|
722 |
-
errors.append(
|
723 |
-
f"Error: 'agent_name' key is missing at index {i}"
|
724 |
-
)
|
725 |
-
continue
|
726 |
-
|
727 |
-
if "steps" not in agent_output:
|
728 |
-
errors.append(
|
729 |
-
f"Error: 'steps' key is missing at index {i}"
|
730 |
-
)
|
731 |
-
continue
|
732 |
-
|
733 |
-
if agent_output["steps"] is None:
|
734 |
-
errors.append(
|
735 |
-
f"Error: 'steps' data is None at index {i}"
|
736 |
-
)
|
737 |
-
continue
|
738 |
-
|
739 |
-
if not isinstance(agent_output["steps"], list):
|
740 |
-
errors.append(
|
741 |
-
f"Error: 'steps' data is not a list at index {i}"
|
742 |
-
)
|
743 |
-
continue
|
744 |
-
|
745 |
-
if not agent_output["steps"]:
|
746 |
-
errors.append(
|
747 |
-
f"Error: 'steps' list is empty at index {i}"
|
748 |
-
)
|
749 |
-
continue
|
750 |
-
|
751 |
-
agent_name = agent_output["agent_name"]
|
752 |
-
output += f"Run {(3-i)} (Agent: `{agent_name}`)**\n\n"
|
753 |
-
# output += "<details>\n<summary>Show/Hide Agent Steps</summary>\n\n"
|
754 |
-
|
755 |
-
# Iterate over steps
|
756 |
-
for j, step in enumerate(agent_output["steps"], start=3):
|
757 |
-
if not isinstance(step, dict):
|
758 |
-
errors.append(
|
759 |
-
f"Error: step at index {j} is not a dictionary"
|
760 |
-
f" at {i} agent output."
|
761 |
-
)
|
762 |
-
continue
|
763 |
-
|
764 |
-
if step is None:
|
765 |
-
errors.append(
|
766 |
-
f"Error: step at index {j} is None at {i} agent"
|
767 |
-
" output"
|
768 |
-
)
|
769 |
-
continue
|
770 |
-
|
771 |
-
if "role" not in step:
|
772 |
-
errors.append(
|
773 |
-
f"Error: 'role' key missing at step {j} at {i}"
|
774 |
-
" agent output."
|
775 |
-
)
|
776 |
-
continue
|
777 |
-
|
778 |
-
if "content" not in step:
|
779 |
-
errors.append(
|
780 |
-
f"Error: 'content' key missing at step {j} at"
|
781 |
-
f" {i} agent output."
|
782 |
-
)
|
783 |
-
continue
|
784 |
-
|
785 |
-
if step["role"].strip() != "System:": # Filter out system prompts
|
786 |
-
# role = step["role"]
|
787 |
-
content = step["content"]
|
788 |
-
output += f"Step {(3-j)}: \n"
|
789 |
-
output += f"Response :\n {content}\n\n"
|
790 |
-
|
791 |
-
# output += "</details>\n\n---\n"
|
792 |
-
|
793 |
-
output += f"Overall Completion Time: `{overall_time}`"
|
794 |
-
if errors:
|
795 |
-
logger.error(f"Errors found while parsing AgentRearrange output: {errors}")
|
796 |
-
return "\n".join(errors)
|
797 |
-
else:
|
798 |
-
logger.info("AgentRearrange output parsed successfully.")
|
799 |
-
return output
|
800 |
-
except json.JSONDecodeError as e:
|
801 |
-
logger.error(f"Error during parsing AgentRearrange output: {e}", exc_info=True)
|
802 |
-
return f"Error during parsing: json.JSONDecodeError {e}"
|
803 |
-
|
804 |
-
except Exception as e:
|
805 |
-
logger.error(f"Error during parsing AgentRearrange output: {e}", exc_info=True)
|
806 |
-
return f"Error during parsing: {str(e)}"
|
807 |
-
|
808 |
-
|
809 |
-
def parse_mixture_of_agents_output(data: Optional[str], error_display=None) -> str:
|
810 |
-
"""Parses the MixtureOfAgents output string and formats it for display."""
|
811 |
-
logger.info("Parsing MixtureOfAgents output...")
|
812 |
-
if data is None:
|
813 |
-
logger.error("No data provided for parsing MixtureOfAgents output.")
|
814 |
-
return "Error: No data provided for parsing."
|
815 |
-
|
816 |
-
print(f"Raw data received for parsing:\n{data}") # Debug: Print raw data
|
817 |
-
|
818 |
-
try:
|
819 |
-
parsed_data = json.loads(data)
|
820 |
-
|
821 |
-
if "InputConfig" not in parsed_data or not isinstance(parsed_data["InputConfig"], dict):
|
822 |
-
logger.error("Error: 'InputConfig' data is missing or not a dictionary.")
|
823 |
-
return "Error: 'InputConfig' data is missing or not a dictionary."
|
824 |
-
|
825 |
-
if "name" not in parsed_data["InputConfig"]:
|
826 |
-
logger.error("Error: 'name' key is missing in 'InputConfig'.")
|
827 |
-
return "Error: 'name' key is missing in 'InputConfig'."
|
828 |
-
if "description" not in parsed_data["InputConfig"]:
|
829 |
-
logger.error("Error: 'description' key is missing in 'InputConfig'.")
|
830 |
-
return "Error: 'description' key is missing in 'InputConfig'."
|
831 |
-
|
832 |
-
if "agents" not in parsed_data["InputConfig"] or not isinstance(parsed_data["InputConfig"]["agents"], list) :
|
833 |
-
logger.error("Error: 'agents' key is missing in 'InputConfig' or not a list.")
|
834 |
-
return "Error: 'agents' key is missing in 'InputConfig' or not a list."
|
835 |
-
|
836 |
-
|
837 |
-
name = parsed_data["InputConfig"]["name"]
|
838 |
-
description = parsed_data["InputConfig"]["description"]
|
839 |
-
|
840 |
-
output = f"Mixture of Agents Workflow Details\n\n"
|
841 |
-
output += f"Name: `{name}`\n"
|
842 |
-
output += f"Description: `{description}`\n\n---\n"
|
843 |
-
output += f"Agent Task Execution\n\n"
|
844 |
-
|
845 |
-
for agent in parsed_data["InputConfig"]["agents"]:
|
846 |
-
if not isinstance(agent, dict):
|
847 |
-
logger.error("Error: agent is not a dict in InputConfig agents")
|
848 |
-
return "Error: agent is not a dict in InputConfig agents"
|
849 |
-
if "agent_name" not in agent:
|
850 |
-
logger.error("Error: 'agent_name' key is missing in agents.")
|
851 |
-
return "Error: 'agent_name' key is missing in agents."
|
852 |
-
|
853 |
-
if "system_prompt" not in agent:
|
854 |
-
logger.error("Error: 'system_prompt' key is missing in agents.")
|
855 |
-
return f"Error: 'system_prompt' key is missing in agents."
|
856 |
-
|
857 |
-
agent_name = agent["agent_name"]
|
858 |
-
# system_prompt = agent["system_prompt"]
|
859 |
-
output += f"Agent: `{agent_name}`\n"
|
860 |
-
# output += f"* **System Prompt:** `{system_prompt}`\n\n"
|
861 |
-
|
862 |
-
if "normal_agent_outputs" not in parsed_data or not isinstance(parsed_data["normal_agent_outputs"], list) :
|
863 |
-
logger.error("Error: 'normal_agent_outputs' key is missing or not a list.")
|
864 |
-
return "Error: 'normal_agent_outputs' key is missing or not a list."
|
865 |
-
|
866 |
-
for i, agent_output in enumerate(parsed_data["normal_agent_outputs"], start=3):
|
867 |
-
if not isinstance(agent_output, dict):
|
868 |
-
logger.error(f"Error: agent output at index {i} is not a dictionary.")
|
869 |
-
return f"Error: agent output at index {i} is not a dictionary."
|
870 |
-
if "agent_name" not in agent_output:
|
871 |
-
logger.error(f"Error: 'agent_name' key is missing at index {i}")
|
872 |
-
return f"Error: 'agent_name' key is missing at index {i}"
|
873 |
-
if "steps" not in agent_output:
|
874 |
-
logger.error(f"Error: 'steps' key is missing at index {i}")
|
875 |
-
return f"Error: 'steps' key is missing at index {i}"
|
876 |
-
|
877 |
-
if agent_output["steps"] is None:
|
878 |
-
logger.error(f"Error: 'steps' is None at index {i}")
|
879 |
-
return f"Error: 'steps' is None at index {i}"
|
880 |
-
if not isinstance(agent_output["steps"], list):
|
881 |
-
logger.error(f"Error: 'steps' data is not a list at index {i}.")
|
882 |
-
return f"Error: 'steps' data is not a list at index {i}."
|
883 |
-
|
884 |
-
agent_name = agent_output["agent_name"]
|
885 |
-
output += f"Run {(3-i)} (Agent: `{agent_name}`)\n\n"
|
886 |
-
# output += "<details>\n<summary>Show/Hide Agent Steps</summary>\n\n"
|
887 |
-
for j, step in enumerate(agent_output["steps"], start=3):
|
888 |
-
if not isinstance(step, dict):
|
889 |
-
logger.error(f"Error: step at index {j} is not a dictionary at {i} agent output.")
|
890 |
-
return f"Error: step at index {j} is not a dictionary at {i} agent output."
|
891 |
-
|
892 |
-
if step is None:
|
893 |
-
logger.error(f"Error: step at index {j} is None at {i} agent output.")
|
894 |
-
return f"Error: step at index {j} is None at {i} agent output."
|
895 |
-
|
896 |
-
if "role" not in step:
|
897 |
-
logger.error(f"Error: 'role' key missing at step {j} at {i} agent output.")
|
898 |
-
return f"Error: 'role' key missing at step {j} at {i} agent output."
|
899 |
-
|
900 |
-
if "content" not in step:
|
901 |
-
logger.error(f"Error: 'content' key missing at step {j} at {i} agent output.")
|
902 |
-
return f"Error: 'content' key missing at step {j} at {i} agent output."
|
903 |
-
|
904 |
-
if step["role"].strip() != "System:": # Filter out system prompts
|
905 |
-
# role = step["role"]
|
906 |
-
content = step["content"]
|
907 |
-
output += f"Step {(3-j)}: \n"
|
908 |
-
output += f"Response:\n {content}\n\n"
|
909 |
-
|
910 |
-
# output += "</details>\n\n---\n"
|
911 |
-
|
912 |
-
if "aggregator_agent_summary" in parsed_data:
|
913 |
-
output += f"\nAggregated Summary :\n{parsed_data['aggregator_agent_summary']}\n{'=' * 50}\n"
|
914 |
-
logger.info("MixtureOfAgents output parsed successfully.")
|
915 |
-
return output
|
916 |
-
|
917 |
-
except json.JSONDecodeError as e:
|
918 |
-
logger.error(f"Error during parsing MixtureOfAgents output: {e}", exc_info=True)
|
919 |
-
return f"Error during parsing json.JSONDecodeError : {e}"
|
920 |
-
|
921 |
-
except Exception as e:
|
922 |
-
logger.error(f"Error during parsing MixtureOfAgents output: {e}", exc_info=True)
|
923 |
-
return f"Error during parsing: {str(e)}"
|
924 |
-
|
925 |
-
|
926 |
-
def parse_sequential_workflow_output(data: Optional[str], error_display=None) -> str:
|
927 |
-
"""Parses the SequentialWorkflow output string and formats it for display."""
|
928 |
-
logger.info("Parsing SequentialWorkflow output...")
|
929 |
-
if data is None:
|
930 |
-
logger.error("No data provided for parsing SequentialWorkflow output.")
|
931 |
-
return "Error: No data provided for parsing."
|
932 |
-
|
933 |
-
print(f"Raw data received for parsing:\n{data}") # Debug: Print raw data
|
934 |
-
|
935 |
-
try:
|
936 |
-
parsed_data = json.loads(data)
|
937 |
-
|
938 |
-
if "input" not in parsed_data or not isinstance(parsed_data.get("input"), dict):
|
939 |
-
logger.error("Error: 'input' data is missing or not a dictionary.")
|
940 |
-
return "Error: 'input' data is missing or not a dictionary."
|
941 |
-
|
942 |
-
if "swarm_id" not in parsed_data["input"] :
|
943 |
-
logger.error("Error: 'swarm_id' key is missing in the 'input'.")
|
944 |
-
return "Error: 'swarm_id' key is missing in the 'input'."
|
945 |
-
|
946 |
-
if "name" not in parsed_data["input"]:
|
947 |
-
logger.error("Error: 'name' key is missing in the 'input'.")
|
948 |
-
return "Error: 'name' key is missing in the 'input'."
|
949 |
-
|
950 |
-
if "flow" not in parsed_data["input"]:
|
951 |
-
logger.error("Error: 'flow' key is missing in the 'input'.")
|
952 |
-
return "Error: 'flow' key is missing in the 'input'."
|
953 |
-
|
954 |
-
if "time" not in parsed_data :
|
955 |
-
logger.error("Error: 'time' key is missing.")
|
956 |
-
return "Error: 'time' key is missing."
|
957 |
-
|
958 |
-
swarm_id = parsed_data["input"]["swarm_id"]
|
959 |
-
swarm_name = parsed_data["input"]["name"]
|
960 |
-
agent_flow = parsed_data["input"]["flow"]
|
961 |
-
overall_time = parsed_data["time"]
|
962 |
-
|
963 |
-
output = f"Workflow Execution Details\n\n"
|
964 |
-
output += f"Swarm ID: `{swarm_id}`\n"
|
965 |
-
output += f"Swarm Name: `{swarm_name}`\n"
|
966 |
-
output += f"Agent Flow: `{agent_flow}`\n\n---\n"
|
967 |
-
output += f"Agent Task Execution\n\n"
|
968 |
-
|
969 |
-
if "outputs" not in parsed_data:
|
970 |
-
logger.error("Error: 'outputs' key is missing")
|
971 |
-
return "Error: 'outputs' key is missing"
|
972 |
-
|
973 |
-
if parsed_data["outputs"] is None:
|
974 |
-
logger.error("Error: 'outputs' data is None")
|
975 |
-
return "Error: 'outputs' data is None"
|
976 |
-
|
977 |
-
if not isinstance(parsed_data["outputs"], list):
|
978 |
-
logger.error("Error: 'outputs' data is not a list.")
|
979 |
-
return "Error: 'outputs' data is not a list."
|
980 |
-
|
981 |
-
for i, agent_output in enumerate(parsed_data["outputs"], start=3):
|
982 |
-
if not isinstance(agent_output, dict):
|
983 |
-
logger.error(f"Error: Agent output at index {i} is not a dictionary")
|
984 |
-
return f"Error: Agent output at index {i} is not a dictionary"
|
985 |
-
|
986 |
-
if "agent_name" not in agent_output:
|
987 |
-
logger.error(f"Error: 'agent_name' key is missing at index {i}")
|
988 |
-
return f"Error: 'agent_name' key is missing at index {i}"
|
989 |
-
|
990 |
-
if "steps" not in agent_output:
|
991 |
-
logger.error(f"Error: 'steps' key is missing at index {i}")
|
992 |
-
return f"Error: 'steps' key is missing at index {i}"
|
993 |
-
|
994 |
-
if agent_output["steps"] is None:
|
995 |
-
logger.error(f"Error: 'steps' data is None at index {i}")
|
996 |
-
return f"Error: 'steps' data is None at index {i}"
|
997 |
-
|
998 |
-
if not isinstance(agent_output["steps"], list):
|
999 |
-
logger.error(f"Error: 'steps' data is not a list at index {i}")
|
1000 |
-
return f"Error: 'steps' data is not a list at index {i}"
|
1001 |
-
|
1002 |
-
agent_name = agent_output["agent_name"]
|
1003 |
-
output += f"Run {(3-i)} (Agent: `{agent_name}`)\n\n"
|
1004 |
-
# output += "<details>\n<summary>Show/Hide Agent Steps</summary>\n\n"
|
1005 |
-
|
1006 |
-
# Iterate over steps
|
1007 |
-
for j, step in enumerate(agent_output["steps"], start=3):
|
1008 |
-
if not isinstance(step, dict):
|
1009 |
-
logger.error(f"Error: step at index {j} is not a dictionary at {i} agent output.")
|
1010 |
-
return f"Error: step at index {j} is not a dictionary at {i} agent output."
|
1011 |
-
|
1012 |
-
if step is None:
|
1013 |
-
logger.error(f"Error: step at index {j} is None at {i} agent output")
|
1014 |
-
return f"Error: step at index {j} is None at {i} agent output"
|
1015 |
-
|
1016 |
-
if "role" not in step:
|
1017 |
-
logger.error(f"Error: 'role' key missing at step {j} at {i} agent output.")
|
1018 |
-
return f"Error: 'role' key missing at step {j} at {i} agent output."
|
1019 |
-
|
1020 |
-
if "content" not in step:
|
1021 |
-
logger.error(f"Error: 'content' key missing at step {j} at {i} agent output.")
|
1022 |
-
return f"Error: 'content' key missing at step {j} at {i} agent output."
|
1023 |
-
|
1024 |
-
if step["role"].strip() != "System:": # Filter out system prompts
|
1025 |
-
# role = step["role"]
|
1026 |
-
content = step["content"]
|
1027 |
-
output += f"Step {(3-j)}:\n"
|
1028 |
-
output += f"Response : {content}\n\n"
|
1029 |
-
|
1030 |
-
# output += "</details>\n\n---\n"
|
1031 |
-
|
1032 |
-
output += f"Overall Completion Time: `{overall_time}`"
|
1033 |
-
logger.info("SequentialWorkflow output parsed successfully.")
|
1034 |
-
return output
|
1035 |
-
|
1036 |
-
except json.JSONDecodeError as e :
|
1037 |
-
logger.error(f"Error during parsing SequentialWorkflow output: {e}", exc_info=True)
|
1038 |
-
return f"Error during parsing json.JSONDecodeError : {e}"
|
1039 |
-
|
1040 |
-
except Exception as e:
|
1041 |
-
logger.error(f"Error during parsing SequentialWorkflow output: {e}", exc_info=True)
|
1042 |
-
return f"Error during parsing: {str(e)}"
|
1043 |
-
|
1044 |
-
def parse_spreadsheet_swarm_output(file_path: str, error_display=None) -> str:
|
1045 |
-
"""Parses the SpreadSheetSwarm output CSV file and formats it for display."""
|
1046 |
-
logger.info("Parsing SpreadSheetSwarm output...")
|
1047 |
-
if not file_path:
|
1048 |
-
logger.error("No file path provided for parsing SpreadSheetSwarm output.")
|
1049 |
-
return "Error: No file path provided for parsing."
|
1050 |
-
|
1051 |
-
print(f"Parsing spreadsheet output from: {file_path}")
|
1052 |
-
|
1053 |
-
try:
|
1054 |
-
with open(file_path, 'r', encoding='utf-8') as file:
|
1055 |
-
csv_reader = csv.reader(file)
|
1056 |
-
header = next(csv_reader, None) # Read the header row
|
1057 |
-
if not header:
|
1058 |
-
logger.error("CSV file is empty or has no header.")
|
1059 |
-
return "Error: CSV file is empty or has no header"
|
1060 |
-
|
1061 |
-
output = "### Spreadsheet Swarm Output ###\n\n"
|
1062 |
-
output += "| " + " | ".join(header) + " |\n" # Adding header
|
1063 |
-
output += "| " + " | ".join(["---"] * len(header)) + " |\n" # Adding header seperator
|
1064 |
-
|
1065 |
-
for row in csv_reader:
|
1066 |
-
output += "| " + " | ".join(row) + " |\n" # Adding row
|
1067 |
-
|
1068 |
-
output += "\n"
|
1069 |
-
logger.info("SpreadSheetSwarm output parsed successfully.")
|
1070 |
-
return output
|
1071 |
-
|
1072 |
-
except FileNotFoundError as e:
|
1073 |
-
logger.error(f"Error during parsing SpreadSheetSwarm output: {e}", exc_info=True)
|
1074 |
-
return "Error: CSV file not found."
|
1075 |
-
except Exception as e:
|
1076 |
-
logger.error(f"Error during parsing SpreadSheetSwarm output: {e}", exc_info=True)
|
1077 |
-
return f"Error during parsing CSV file: {str(e)}"
|
1078 |
-
def parse_json_output(data:str, error_display=None) -> str:
|
1079 |
-
"""Parses a JSON string and formats it for display."""
|
1080 |
-
logger.info("Parsing JSON output...")
|
1081 |
-
if not data:
|
1082 |
-
logger.error("No data provided for parsing JSON output.")
|
1083 |
-
return "Error: No data provided for parsing."
|
1084 |
-
|
1085 |
-
print(f"Parsing json output from: {data}")
|
1086 |
-
try:
|
1087 |
-
parsed_data = json.loads(data)
|
1088 |
-
|
1089 |
-
output = "### Swarm Metadata ###\n\n"
|
1090 |
-
|
1091 |
-
for key,value in parsed_data.items():
|
1092 |
-
if key == "outputs":
|
1093 |
-
output += f"**{key}**:\n"
|
1094 |
-
if isinstance(value, list):
|
1095 |
-
for item in value:
|
1096 |
-
output += f" - Agent Name : {item.get('agent_name', 'N/A')}\n"
|
1097 |
-
output += f" Task : {item.get('task', 'N/A')}\n"
|
1098 |
-
output += f" Result : {item.get('result', 'N/A')}\n"
|
1099 |
-
output += f" Timestamp : {item.get('timestamp', 'N/A')}\n\n"
|
1100 |
-
|
1101 |
-
else :
|
1102 |
-
output += f" {value}\n"
|
1103 |
-
|
1104 |
-
else :
|
1105 |
-
output += f"**{key}**: {value}\n"
|
1106 |
-
logger.info("JSON output parsed successfully.")
|
1107 |
-
return output
|
1108 |
-
|
1109 |
-
except json.JSONDecodeError as e:
|
1110 |
-
logger.error(f"Error during parsing JSON output: {e}", exc_info=True)
|
1111 |
-
return f"Error: Invalid JSON format - {e}"
|
1112 |
-
|
1113 |
-
except Exception as e:
|
1114 |
-
logger.error(f"Error during parsing JSON output: {e}", exc_info=True)
|
1115 |
-
return f"Error during JSON parsing: {str(e)}"
|
1116 |
-
|
1117 |
-
class UI:
|
1118 |
-
def __init__(self, theme):
|
1119 |
-
self.theme = theme
|
1120 |
-
self.blocks = gr.Blocks(theme=self.theme)
|
1121 |
-
self.components = {} # Dictionary to store UI components
|
1122 |
-
|
1123 |
-
def create_markdown(self, text, is_header=False):
|
1124 |
-
if is_header:
|
1125 |
-
markdown = gr.Markdown(
|
1126 |
-
f"<h1 style='color: #ffffff; text-align:"
|
1127 |
-
f" center;'>{text}</h1>"
|
1128 |
-
)
|
1129 |
-
else:
|
1130 |
-
markdown = gr.Markdown(
|
1131 |
-
f"<p style='color: #cccccc; text-align:"
|
1132 |
-
f" center;'>{text}</p>"
|
1133 |
-
)
|
1134 |
-
self.components[f"markdown_{text}"] = markdown
|
1135 |
-
return markdown
|
1136 |
-
|
1137 |
-
def create_text_input(self, label, lines=3, placeholder=""):
|
1138 |
-
text_input = gr.Textbox(
|
1139 |
-
label=label,
|
1140 |
-
lines=lines,
|
1141 |
-
placeholder=placeholder,
|
1142 |
-
elem_classes=["custom-input"],
|
1143 |
-
)
|
1144 |
-
self.components[f"text_input_{label}"] = text_input
|
1145 |
-
return text_input
|
1146 |
-
|
1147 |
-
def create_slider(
|
1148 |
-
self, label, minimum=0, maximum=1, value=0.5, step=0.1
|
1149 |
-
):
|
1150 |
-
slider = gr.Slider(
|
1151 |
-
minimum=minimum,
|
1152 |
-
maximum=maximum,
|
1153 |
-
value=value,
|
1154 |
-
step=step,
|
1155 |
-
label=label,
|
1156 |
-
interactive=True,
|
1157 |
-
)
|
1158 |
-
self.components[f"slider_{label}"] = slider
|
1159 |
-
return slider
|
1160 |
-
|
1161 |
-
def create_dropdown(
|
1162 |
-
self, label, choices, value=None, multiselect=False
|
1163 |
-
):
|
1164 |
-
if not choices:
|
1165 |
-
choices = ["No options available"]
|
1166 |
-
if value is None and choices:
|
1167 |
-
value = choices[0] if not multiselect else [choices[0]]
|
1168 |
-
|
1169 |
-
dropdown = gr.Dropdown(
|
1170 |
-
label=label,
|
1171 |
-
choices=choices,
|
1172 |
-
value=value,
|
1173 |
-
interactive=True,
|
1174 |
-
multiselect=multiselect,
|
1175 |
-
)
|
1176 |
-
self.components[f"dropdown_{label}"] = dropdown
|
1177 |
-
return dropdown
|
1178 |
-
|
1179 |
-
def create_button(self, text, variant="primary"):
|
1180 |
-
button = gr.Button(text, variant=variant)
|
1181 |
-
self.components[f"button_{text}"] = button
|
1182 |
-
return button
|
1183 |
-
|
1184 |
-
def create_text_output(self, label, lines=10, placeholder=""):
|
1185 |
-
text_output = gr.Textbox(
|
1186 |
-
label=label,
|
1187 |
-
interactive=False,
|
1188 |
-
placeholder=placeholder,
|
1189 |
-
lines=lines,
|
1190 |
-
elem_classes=["custom-output"],
|
1191 |
-
)
|
1192 |
-
self.components[f"text_output_{label}"] = text_output
|
1193 |
-
return text_output
|
1194 |
-
|
1195 |
-
def create_tab(self, label, content_function):
|
1196 |
-
with gr.Tab(label):
|
1197 |
-
content_function(self)
|
1198 |
-
|
1199 |
-
def set_event_listener(self, button, function, inputs, outputs):
|
1200 |
-
button.click(function, inputs=inputs, outputs=outputs)
|
1201 |
-
|
1202 |
-
def get_components(self, *keys):
|
1203 |
-
if not keys:
|
1204 |
-
return self.components # return all components
|
1205 |
-
return [self.components[key] for key in keys]
|
1206 |
-
|
1207 |
-
def create_json_output(self, label, placeholder=""):
|
1208 |
-
json_output = gr.JSON(
|
1209 |
-
label=label,
|
1210 |
-
value={},
|
1211 |
-
elem_classes=["custom-output"],
|
1212 |
-
)
|
1213 |
-
self.components[f"json_output_{label}"] = json_output
|
1214 |
-
return json_output
|
1215 |
-
|
1216 |
-
def build(self):
|
1217 |
-
return self.blocks
|
1218 |
-
|
1219 |
-
def create_conditional_input(
|
1220 |
-
self, component, visible_when, watch_component
|
1221 |
-
):
|
1222 |
-
"""Create an input that's only visible under certain conditions"""
|
1223 |
-
watch_component.change(
|
1224 |
-
fn=lambda x: gr.update(visible=visible_when(x)),
|
1225 |
-
inputs=[watch_component],
|
1226 |
-
outputs=[component],
|
1227 |
-
)
|
1228 |
-
|
1229 |
-
@staticmethod
|
1230 |
-
def create_ui_theme(primary_color="red"):
|
1231 |
-
return gr.themes.Ocean(
|
1232 |
-
primary_hue=primary_color,
|
1233 |
-
secondary_hue=primary_color,
|
1234 |
-
neutral_hue="gray",
|
1235 |
-
).set(
|
1236 |
-
body_background_fill="#20252c",
|
1237 |
-
body_text_color="#f0f0f0",
|
1238 |
-
button_primary_background_fill=primary_color,
|
1239 |
-
button_primary_text_color="#ffffff",
|
1240 |
-
button_secondary_background_fill=primary_color,
|
1241 |
-
button_secondary_text_color="#ffffff",
|
1242 |
-
shadow_drop="0px 2px 4px rgba(0, 0, 0, 0.3)",
|
1243 |
-
)
|
1244 |
-
|
1245 |
-
def create_agent_details_tab(self):
|
1246 |
-
"""Create the agent details tab content."""
|
1247 |
-
with gr.Column():
|
1248 |
-
gr.Markdown("### Agent Details")
|
1249 |
-
gr.Markdown(
|
1250 |
-
"""
|
1251 |
-
**Available Agent Types:**
|
1252 |
-
- Data Extraction Agent: Specialized in extracting relevant information
|
1253 |
-
- Summary Agent - Analysis Agent: Performs detailed analysis of data
|
1254 |
-
|
1255 |
-
**Swarm Types:**
|
1256 |
-
- ConcurrentWorkflow: Agents work in parallel
|
1257 |
-
- SequentialWorkflow: Agents work in sequence
|
1258 |
-
- AgentRearrange: Custom agent execution flow
|
1259 |
-
- MixtureOfAgents: Combines multiple agents with an aggregator
|
1260 |
-
- SpreadSheetSwarm: Specialized for spreadsheet operations
|
1261 |
-
- Auto: Automatically determines optimal workflow
|
1262 |
-
"""
|
1263 |
-
)
|
1264 |
-
return gr.Column()
|
1265 |
-
|
1266 |
-
def create_logs_tab(self):
|
1267 |
-
"""Create the logs tab content."""
|
1268 |
-
with gr.Column():
|
1269 |
-
gr.Markdown("### Execution Logs")
|
1270 |
-
logs_display = gr.Textbox(
|
1271 |
-
label="System Logs",
|
1272 |
-
placeholder="Execution logs will appear here...",
|
1273 |
-
interactive=False,
|
1274 |
-
lines=10,
|
1275 |
-
)
|
1276 |
-
return logs_display
|
1277 |
-
def update_flow_agents(agent_keys):
|
1278 |
-
"""Update flow agents based on selected agent prompts."""
|
1279 |
-
if not agent_keys:
|
1280 |
-
return [], "No agents selected"
|
1281 |
-
agent_names = [key for key in agent_keys]
|
1282 |
-
print(f"Flow agents: {agent_names}") # Debug: Print flow agents
|
1283 |
-
return agent_names, "Select agents in execution order"
|
1284 |
-
|
1285 |
-
def update_flow_preview(selected_flow_agents):
|
1286 |
-
"""Update flow preview based on selected agents."""
|
1287 |
-
if not selected_flow_agents:
|
1288 |
-
return "Flow will be shown here..."
|
1289 |
-
flow = " -> ".join(selected_flow_agents)
|
1290 |
-
return flow
|
1291 |
-
|
1292 |
-
def create_app():
|
1293 |
-
# Initialize UI
|
1294 |
-
theme = UI.create_ui_theme(primary_color="red")
|
1295 |
-
ui = UI(theme=theme)
|
1296 |
-
global AGENT_PROMPTS
|
1297 |
-
# Available providers and models
|
1298 |
-
providers = [
|
1299 |
-
"openai",
|
1300 |
-
"anthropic",
|
1301 |
-
"cohere",
|
1302 |
-
"gemini",
|
1303 |
-
"mistral",
|
1304 |
-
"groq",
|
1305 |
-
"perplexity",
|
1306 |
-
]
|
1307 |
-
|
1308 |
-
filtered_models = {}
|
1309 |
-
|
1310 |
-
for provider in providers:
|
1311 |
-
filtered_models[provider] = models_by_provider.get(provider, [])
|
1312 |
-
|
1313 |
-
with ui.blocks:
|
1314 |
-
with gr.Row():
|
1315 |
-
with gr.Column(scale=4): # Left column (80% width)
|
1316 |
-
ui.create_markdown("Swarms", is_header=True)
|
1317 |
-
ui.create_markdown(
|
1318 |
-
"<b>The Enterprise-Grade Production-Ready Multi-Agent"
|
1319 |
-
" Orchestration Framework</b>"
|
1320 |
-
)
|
1321 |
-
with gr.Row():
|
1322 |
-
with gr.Column(scale=4):
|
1323 |
-
with gr.Row():
|
1324 |
-
task_input = gr.Textbox(
|
1325 |
-
label="Task Description",
|
1326 |
-
placeholder="Describe your task here...",
|
1327 |
-
lines=3,
|
1328 |
-
)
|
1329 |
-
with gr.Row():
|
1330 |
-
with gr.Column(scale=1):
|
1331 |
-
with gr.Row():
|
1332 |
-
# Provider selection dropdown
|
1333 |
-
provider_dropdown = gr.Dropdown(
|
1334 |
-
label="Select Provider",
|
1335 |
-
choices=providers,
|
1336 |
-
value=providers[0]
|
1337 |
-
if providers
|
1338 |
-
else None,
|
1339 |
-
interactive=True,
|
1340 |
-
)
|
1341 |
-
# with gr.Row():
|
1342 |
-
# # Model selection dropdown (initially empty)
|
1343 |
-
model_dropdown = gr.Dropdown(
|
1344 |
-
label="Select Model",
|
1345 |
-
choices=[],
|
1346 |
-
interactive=True,
|
1347 |
-
)
|
1348 |
-
with gr.Row():
|
1349 |
-
# API key input
|
1350 |
-
api_key_input = gr.Textbox(
|
1351 |
-
label="API Key",
|
1352 |
-
placeholder="Enter your API key",
|
1353 |
-
type="password",
|
1354 |
-
)
|
1355 |
-
with gr.Column(scale=1):
|
1356 |
-
with gr.Row():
|
1357 |
-
dynamic_slider = gr.Slider(
|
1358 |
-
label="Dyn. Temp",
|
1359 |
-
minimum=0,
|
1360 |
-
maximum=1,
|
1361 |
-
value=0.1,
|
1362 |
-
step=0.01,
|
1363 |
-
)
|
1364 |
-
|
1365 |
-
# with gr.Row():
|
1366 |
-
# max tokens slider
|
1367 |
-
max_loops_slider = gr.Slider(
|
1368 |
-
label="Max Loops",
|
1369 |
-
minimum=1,
|
1370 |
-
maximum=10,
|
1371 |
-
value=1,
|
1372 |
-
step=1,
|
1373 |
-
)
|
1374 |
-
|
1375 |
-
with gr.Row():
|
1376 |
-
# max tokens slider
|
1377 |
-
max_tokens_slider = gr.Slider(
|
1378 |
-
label="Max Tokens",
|
1379 |
-
minimum=100,
|
1380 |
-
maximum=10000,
|
1381 |
-
value=4000,
|
1382 |
-
step=100,
|
1383 |
-
)
|
1384 |
-
|
1385 |
-
with gr.Column(scale=2, min_width=200):
|
1386 |
-
with gr.Column(scale=1):
|
1387 |
-
# Get available agent prompts
|
1388 |
-
available_prompts = (
|
1389 |
-
list(AGENT_PROMPTS.keys())
|
1390 |
-
if AGENT_PROMPTS
|
1391 |
-
else ["No agents available"]
|
1392 |
-
)
|
1393 |
-
agent_prompt_selector = gr.Dropdown(
|
1394 |
-
label="Select Agent Prompts",
|
1395 |
-
choices=available_prompts,
|
1396 |
-
value=[available_prompts[0]]
|
1397 |
-
if available_prompts
|
1398 |
-
else None,
|
1399 |
-
multiselect=True,
|
1400 |
-
interactive=True,
|
1401 |
-
)
|
1402 |
-
# with gr.Column(scale=1):
|
1403 |
-
# Get available swarm types
|
1404 |
-
swarm_types = [
|
1405 |
-
"SequentialWorkflow",
|
1406 |
-
"ConcurrentWorkflow",
|
1407 |
-
"AgentRearrange",
|
1408 |
-
"MixtureOfAgents",
|
1409 |
-
"SpreadSheetSwarm",
|
1410 |
-
"auto",
|
1411 |
-
]
|
1412 |
-
agent_selector = gr.Dropdown(
|
1413 |
-
label="Select Swarm",
|
1414 |
-
choices=swarm_types,
|
1415 |
-
value=swarm_types[0],
|
1416 |
-
multiselect=False,
|
1417 |
-
interactive=True,
|
1418 |
-
)
|
1419 |
-
|
1420 |
-
# Flow configuration components for AgentRearrange
|
1421 |
-
with gr.Column(visible=False) as flow_config:
|
1422 |
-
flow_text = gr.Textbox(
|
1423 |
-
label="Agent Flow Configuration",
|
1424 |
-
placeholder="Enter agent flow !",
|
1425 |
-
lines=2,
|
1426 |
-
)
|
1427 |
-
gr.Markdown(
|
1428 |
-
"""
|
1429 |
-
**Flow Configuration Help:**
|
1430 |
-
- Enter agent names separated by ' -> '
|
1431 |
-
- Example: Agent1 -> Agent2 -> Agent3
|
1432 |
-
- Use exact agent names from the prompts above
|
1433 |
-
"""
|
1434 |
-
)
|
1435 |
-
# Create Agent Prompt Section
|
1436 |
-
with gr.Accordion(
|
1437 |
-
"Create Agent Prompt", open=False
|
1438 |
-
) as create_prompt_accordion:
|
1439 |
-
with gr.Row():
|
1440 |
-
with gr.Column():
|
1441 |
-
new_agent_name_input = gr.Textbox(
|
1442 |
-
label="New Agent Name"
|
1443 |
-
)
|
1444 |
-
with gr.Column():
|
1445 |
-
new_agent_prompt_input = (
|
1446 |
-
gr.Textbox(
|
1447 |
-
label="New Agent Prompt",
|
1448 |
-
lines=3,
|
1449 |
-
)
|
1450 |
-
)
|
1451 |
-
with gr.Row():
|
1452 |
-
with gr.Column():
|
1453 |
-
create_agent_button = gr.Button(
|
1454 |
-
"Save New Prompt"
|
1455 |
-
)
|
1456 |
-
with gr.Column():
|
1457 |
-
create_agent_status = gr.Textbox(
|
1458 |
-
label="Status",
|
1459 |
-
interactive=False,
|
1460 |
-
)
|
1461 |
-
|
1462 |
-
# with gr.Row():
|
1463 |
-
# temperature_slider = gr.Slider(
|
1464 |
-
# label="Temperature",
|
1465 |
-
# minimum=0,
|
1466 |
-
# maximum=1,
|
1467 |
-
# value=0.1,
|
1468 |
-
# step=0.01
|
1469 |
-
# )
|
1470 |
-
|
1471 |
-
# Hidden textbox to store API Key
|
1472 |
-
env_api_key_textbox = gr.Textbox(
|
1473 |
-
value="", visible=False
|
1474 |
-
)
|
1475 |
-
|
1476 |
-
with gr.Row():
|
1477 |
-
with gr.Column(scale=1):
|
1478 |
-
run_button = gr.Button(
|
1479 |
-
"Run Task", variant="primary"
|
1480 |
-
)
|
1481 |
-
cancel_button = gr.Button(
|
1482 |
-
"Cancel", variant="secondary"
|
1483 |
-
)
|
1484 |
-
with gr.Column(scale=1):
|
1485 |
-
with gr.Row():
|
1486 |
-
loading_status = gr.Textbox(
|
1487 |
-
label="Status",
|
1488 |
-
value="Ready",
|
1489 |
-
interactive=False,
|
1490 |
-
)
|
1491 |
-
|
1492 |
-
# Add loading indicator and status
|
1493 |
-
with gr.Row():
|
1494 |
-
agent_output_display = gr.Textbox(
|
1495 |
-
label="Agent Responses",
|
1496 |
-
placeholder="Responses will appear here...",
|
1497 |
-
interactive=False,
|
1498 |
-
lines=10,
|
1499 |
-
)
|
1500 |
-
with gr.Row():
|
1501 |
-
log_display = gr.Textbox(
|
1502 |
-
label="Logs",
|
1503 |
-
placeholder="Logs will be displayed here...",
|
1504 |
-
interactive=False,
|
1505 |
-
lines=5,
|
1506 |
-
visible=False,
|
1507 |
-
)
|
1508 |
-
error_display = gr.Textbox(
|
1509 |
-
label="Error",
|
1510 |
-
placeholder="Errors will be displayed here...",
|
1511 |
-
interactive=False,
|
1512 |
-
lines=5,
|
1513 |
-
visible=False,
|
1514 |
-
)
|
1515 |
-
def update_agent_dropdown():
|
1516 |
-
"""Update agent dropdown when a new agent is added"""
|
1517 |
-
global AGENT_PROMPTS
|
1518 |
-
AGENT_PROMPTS = load_prompts_from_json()
|
1519 |
-
available_prompts = (
|
1520 |
-
list(AGENT_PROMPTS.keys())
|
1521 |
-
if AGENT_PROMPTS
|
1522 |
-
else ["No agents available"]
|
1523 |
-
)
|
1524 |
-
return gr.update(
|
1525 |
-
choices=available_prompts,
|
1526 |
-
value=available_prompts[0]
|
1527 |
-
if available_prompts
|
1528 |
-
else None,
|
1529 |
-
)
|
1530 |
-
|
1531 |
-
def update_ui_for_swarm_type(swarm_type):
|
1532 |
-
"""Update UI components based on selected swarm type."""
|
1533 |
-
is_agent_rearrange = swarm_type == "AgentRearrange"
|
1534 |
-
is_mixture = swarm_type == "MixtureOfAgents"
|
1535 |
-
is_spreadsheet = swarm_type == "SpreadSheetSwarm"
|
1536 |
-
|
1537 |
-
max_loops = (
|
1538 |
-
5 if is_mixture or is_spreadsheet else 10
|
1539 |
-
)
|
1540 |
-
|
1541 |
-
# Return visibility state for flow configuration and max loops update
|
1542 |
-
return (
|
1543 |
-
gr.update(visible=is_agent_rearrange), # For flow_config
|
1544 |
-
gr.update(
|
1545 |
-
maximum=max_loops
|
1546 |
-
), # For max_loops_slider
|
1547 |
-
f"Selected {swarm_type}", # For loading_status
|
1548 |
-
)
|
1549 |
-
|
1550 |
-
def update_model_dropdown(provider):
|
1551 |
-
"""Update model dropdown based on selected provider."""
|
1552 |
-
models = filtered_models.get(provider, [])
|
1553 |
-
return gr.update(
|
1554 |
-
choices=models,
|
1555 |
-
value=models[0] if models else None,
|
1556 |
-
)
|
1557 |
-
|
1558 |
-
def save_new_agent_prompt(agent_name, agent_prompt):
|
1559 |
-
"""Saves a new agent prompt to the JSON file."""
|
1560 |
-
try:
|
1561 |
-
if not agent_name or not agent_prompt:
|
1562 |
-
return (
|
1563 |
-
"Error: Agent name and prompt cannot be"
|
1564 |
-
" empty."
|
1565 |
-
)
|
1566 |
-
|
1567 |
-
if (
|
1568 |
-
not agent_name.isalnum()
|
1569 |
-
and "_" not in agent_name
|
1570 |
-
):
|
1571 |
-
return (
|
1572 |
-
"Error : Agent name must be alphanumeric or"
|
1573 |
-
" underscore(_) "
|
1574 |
-
)
|
1575 |
-
|
1576 |
-
if "agent." + agent_name in AGENT_PROMPTS:
|
1577 |
-
return "Error : Agent name already exists"
|
1578 |
-
|
1579 |
-
with open(
|
1580 |
-
PROMPT_JSON_PATH, "r+", encoding="utf-8"
|
1581 |
-
) as f:
|
1582 |
-
try:
|
1583 |
-
data = json.load(f)
|
1584 |
-
except json.JSONDecodeError:
|
1585 |
-
data = {}
|
1586 |
-
|
1587 |
-
data[agent_name] = {
|
1588 |
-
"system_prompt": agent_prompt
|
1589 |
-
}
|
1590 |
-
f.seek(0)
|
1591 |
-
json.dump(data, f, indent=4)
|
1592 |
-
f.truncate()
|
1593 |
-
|
1594 |
-
return "New agent prompt saved successfully"
|
1595 |
-
|
1596 |
-
except Exception as e:
|
1597 |
-
return f"Error saving agent prompt {str(e)}"
|
1598 |
-
|
1599 |
-
async def run_task_wrapper(
|
1600 |
-
task,
|
1601 |
-
max_loops,
|
1602 |
-
dynamic_temp,
|
1603 |
-
swarm_type,
|
1604 |
-
agent_prompt_selector,
|
1605 |
-
flow_text,
|
1606 |
-
provider,
|
1607 |
-
model_name,
|
1608 |
-
api_key,
|
1609 |
-
temperature,
|
1610 |
-
max_tokens,
|
1611 |
-
):
|
1612 |
-
"""Execute the task and update the UI with progress."""
|
1613 |
-
try:
|
1614 |
-
# Update status
|
1615 |
-
yield "Processing...", "Running task...", "", gr.update(visible=False), gr.update(visible=False)
|
1616 |
-
|
1617 |
-
|
1618 |
-
# Prepare flow for AgentRearrange
|
1619 |
-
flow = None
|
1620 |
-
if swarm_type == "AgentRearrange":
|
1621 |
-
if not flow_text:
|
1622 |
-
yield (
|
1623 |
-
"Please provide the agent flow"
|
1624 |
-
" configuration.",
|
1625 |
-
"Error: Flow not configured",
|
1626 |
-
"",
|
1627 |
-
gr.update(visible=True),
|
1628 |
-
gr.update(visible=False)
|
1629 |
-
)
|
1630 |
-
return
|
1631 |
-
flow = flow_text
|
1632 |
-
|
1633 |
-
print(
|
1634 |
-
f"Flow string: {flow}"
|
1635 |
-
) # Debug: Print flow string
|
1636 |
-
|
1637 |
-
# Save API key to .env
|
1638 |
-
env_path = find_dotenv()
|
1639 |
-
if provider == "openai":
|
1640 |
-
set_key(env_path, "OPENAI_API_KEY", api_key)
|
1641 |
-
elif provider == "anthropic":
|
1642 |
-
set_key(
|
1643 |
-
env_path, "ANTHROPIC_API_KEY", api_key
|
1644 |
-
)
|
1645 |
-
elif provider == "cohere":
|
1646 |
-
set_key(env_path, "COHERE_API_KEY", api_key)
|
1647 |
-
elif provider == "gemini":
|
1648 |
-
set_key(env_path, "GEMINI_API_KEY", api_key)
|
1649 |
-
elif provider == "mistral":
|
1650 |
-
set_key(env_path, "MISTRAL_API_KEY", api_key)
|
1651 |
-
elif provider == "groq":
|
1652 |
-
set_key(env_path, "GROQ_API_KEY", api_key)
|
1653 |
-
elif provider == "perplexity":
|
1654 |
-
set_key(
|
1655 |
-
env_path, "PERPLEXITY_API_KEY", api_key
|
1656 |
-
)
|
1657 |
-
else:
|
1658 |
-
yield (
|
1659 |
-
f"Error: {provider} this provider is not"
|
1660 |
-
" present",
|
1661 |
-
f"Error: {provider} not supported",
|
1662 |
-
"",
|
1663 |
-
gr.update(visible=True),
|
1664 |
-
gr.update(visible=False)
|
1665 |
-
)
|
1666 |
-
return
|
1667 |
-
|
1668 |
-
agents = initialize_agents(
|
1669 |
-
dynamic_temp,
|
1670 |
-
agent_prompt_selector,
|
1671 |
-
model_name,
|
1672 |
-
provider,
|
1673 |
-
api_key,
|
1674 |
-
temperature,
|
1675 |
-
max_tokens,
|
1676 |
-
)
|
1677 |
-
print(
|
1678 |
-
"Agents passed to SwarmRouter:"
|
1679 |
-
f" {[agent.agent_name for agent in agents]}"
|
1680 |
-
) # Debug: Print agent list
|
1681 |
-
|
1682 |
-
# Convert agent list to dictionary
|
1683 |
-
agents_dict = {
|
1684 |
-
agent.agent_name: agent for agent in agents
|
1685 |
-
}
|
1686 |
-
|
1687 |
-
# Execute task
|
1688 |
-
async for result, router, error in execute_task(
|
1689 |
-
task=task,
|
1690 |
-
max_loops=max_loops,
|
1691 |
-
dynamic_temp=dynamic_temp,
|
1692 |
-
swarm_type=swarm_type,
|
1693 |
-
agent_keys=agent_prompt_selector,
|
1694 |
-
flow=flow,
|
1695 |
-
model_name=model_name,
|
1696 |
-
provider=provider,
|
1697 |
-
api_key=api_key,
|
1698 |
-
temperature=temperature,
|
1699 |
-
max_tokens=max_tokens,
|
1700 |
-
agents=agents_dict, # Changed here
|
1701 |
-
log_display=log_display,
|
1702 |
-
error_display = error_display
|
1703 |
-
):
|
1704 |
-
if error:
|
1705 |
-
yield f"Error: {error}", f"Error: {error}", "", gr.update(visible=True), gr.update(visible=True)
|
1706 |
-
return
|
1707 |
-
if result is not None:
|
1708 |
-
formatted_output = format_output(result, swarm_type, error_display)
|
1709 |
-
yield formatted_output, "Completed", api_key, gr.update(visible=False), gr.update(visible=False)
|
1710 |
-
return
|
1711 |
-
except Exception as e:
|
1712 |
-
yield f"Error: {str(e)}", f"Error: {str(e)}", "", gr.update(visible=True), gr.update(visible=True)
|
1713 |
-
return
|
1714 |
-
|
1715 |
-
# Connect the update functions
|
1716 |
-
agent_selector.change(
|
1717 |
-
fn=update_ui_for_swarm_type,
|
1718 |
-
inputs=[agent_selector],
|
1719 |
-
outputs=[
|
1720 |
-
flow_config,
|
1721 |
-
max_loops_slider,
|
1722 |
-
loading_status,
|
1723 |
-
],
|
1724 |
-
)
|
1725 |
-
provider_dropdown.change(
|
1726 |
-
fn=update_model_dropdown,
|
1727 |
-
inputs=[provider_dropdown],
|
1728 |
-
outputs=[model_dropdown],
|
1729 |
-
)
|
1730 |
-
# Event for creating new agent prompts
|
1731 |
-
create_agent_button.click(
|
1732 |
-
fn=save_new_agent_prompt,
|
1733 |
-
inputs=[new_agent_name_input, new_agent_prompt_input],
|
1734 |
-
outputs=[create_agent_status],
|
1735 |
-
).then(
|
1736 |
-
fn=update_agent_dropdown,
|
1737 |
-
inputs=None,
|
1738 |
-
outputs=[agent_prompt_selector],
|
1739 |
-
)
|
1740 |
-
|
1741 |
-
# Create event trigger
|
1742 |
-
# Create event trigger for run button
|
1743 |
-
run_event = run_button.click(
|
1744 |
-
fn=run_task_wrapper,
|
1745 |
-
inputs=[
|
1746 |
-
task_input,
|
1747 |
-
max_loops_slider,
|
1748 |
-
dynamic_slider,
|
1749 |
-
agent_selector,
|
1750 |
-
agent_prompt_selector,
|
1751 |
-
flow_text,
|
1752 |
-
provider_dropdown,
|
1753 |
-
model_dropdown,
|
1754 |
-
api_key_input,
|
1755 |
-
max_tokens_slider
|
1756 |
-
],
|
1757 |
-
outputs=[
|
1758 |
-
agent_output_display,
|
1759 |
-
loading_status,
|
1760 |
-
env_api_key_textbox,
|
1761 |
-
error_display,
|
1762 |
-
log_display,
|
1763 |
-
],
|
1764 |
-
)
|
1765 |
-
|
1766 |
-
# Connect cancel button to interrupt processing
|
1767 |
-
def cancel_task():
|
1768 |
-
return "Task cancelled.", "Cancelled", "", gr.update(visible=False), gr.update(visible=False)
|
1769 |
-
|
1770 |
-
cancel_button.click(
|
1771 |
-
fn=cancel_task,
|
1772 |
-
inputs=None,
|
1773 |
-
outputs=[
|
1774 |
-
agent_output_display,
|
1775 |
-
loading_status,
|
1776 |
-
env_api_key_textbox,
|
1777 |
-
error_display,
|
1778 |
-
log_display
|
1779 |
-
],
|
1780 |
-
cancels=run_event,
|
1781 |
-
)
|
1782 |
-
|
1783 |
-
with gr.Column(scale=1): # Right column
|
1784 |
-
with gr.Tabs():
|
1785 |
-
with gr.Tab("Agent Details"):
|
1786 |
-
ui.create_agent_details_tab()
|
1787 |
-
|
1788 |
-
with gr.Tab("Logs"):
|
1789 |
-
logs_display = ui.create_logs_tab()
|
1790 |
-
|
1791 |
-
def update_logs_display():
|
1792 |
-
"""Update logs display with current logs."""
|
1793 |
-
return ""
|
1794 |
-
|
1795 |
-
# Update logs when tab is selected
|
1796 |
-
logs_tab = gr.Tab("Logs")
|
1797 |
-
logs_tab.select(
|
1798 |
-
fn=update_logs_display,
|
1799 |
-
inputs=None,
|
1800 |
-
outputs=[logs_display],
|
1801 |
-
)
|
1802 |
-
|
1803 |
-
return ui.build()
|
1804 |
|
1805 |
if __name__ == "__main__":
|
1806 |
-
app = create_app()
|
1807 |
-
app.launch()
|
|
|
1 |
+
from swarms.structs.ui.ui import create_app # Adjust import as per your directory structure
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
if __name__ == "__main__":
|
4 |
+
app = create_app() # Create the Gradio app using the function from `ui.py`
|
5 |
+
app.launch() # Launch the app
|