harshalmore31 commited on
Commit
090f2af
·
verified ·
1 Parent(s): 3184466

Synced repo using 'sync_with_huggingface' Github Action

Browse files
Files changed (1) hide show
  1. app.py +3 -1805
app.py CHANGED
@@ -1,1807 +1,5 @@
1
- import os
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