From 452be5201368e1ca33ed452201e4f7011bb43e7f Mon Sep 17 00:00:00 2001 From: harshalmore31 <86048671+harshalmore31@users.noreply.github.com> Date: Thu, 26 Dec 2024 00:29:37 +0530 Subject: [PATCH] ui-v7 --- simple_example.py | 9 - swarms/structs/spreadsheet_swarm.py | 80 ++-- swarms/structs/ui/ui.py | 544 +++++++++++++++++++++++----- 3 files changed, 488 insertions(+), 145 deletions(-) delete mode 100644 simple_example.py diff --git a/simple_example.py b/simple_example.py deleted file mode 100644 index 1044958a..00000000 --- a/simple_example.py +++ /dev/null @@ -1,9 +0,0 @@ -from swarms import Agent - -Agent( - agent_name="Stock-Analysis-Agent", - model_name="gpt-4o-mini", - max_loops=1, - interactive=False, - streaming_on=True, -).run("What are 5 hft algorithms") diff --git a/swarms/structs/spreadsheet_swarm.py b/swarms/structs/spreadsheet_swarm.py index 9bbb36a7..8215bf2a 100644 --- a/swarms/structs/spreadsheet_swarm.py +++ b/swarms/structs/spreadsheet_swarm.py @@ -1,6 +1,6 @@ import asyncio import csv -import datetime +from datetime import datetime import os import uuid from typing import List, Union @@ -16,14 +16,8 @@ from swarms.utils.loguru_logger import initialize_logger logger = initialize_logger(log_folder="spreadsheet_swarm") -time = datetime.datetime.now().isoformat() -uuid_hex = uuid.uuid4().hex - -# --------------- NEW CHANGE START --------------- -# Format time variable to be compatible across operating systems -formatted_time = datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S") -# --------------- NEW CHANGE END --------------- - +# Replace timestamp-based time with a UUID for file naming +run_id = uuid.uuid4().hex # Unique identifier for each run class AgentOutput(BaseModel): agent_name: str @@ -34,13 +28,13 @@ class AgentOutput(BaseModel): class SwarmRunMetadata(BaseModel): run_id: str = Field( - default_factory=lambda: f"spreadsheet_swarm_run_{uuid_hex}" + default_factory=lambda: f"spreadsheet_swarm_run_{run_id}" ) name: str description: str agents: List[str] start_time: str = Field( - default_factory=lambda: time, + default_factory=lambda: str(datetime.now().timestamp()), # Numeric timestamp description="The start time of the swarm run.", ) end_time: str @@ -71,7 +65,7 @@ class SpreadSheetSwarm(BaseSwarm): def __init__( self, name: str = "Spreadsheet-Swarm", - description: str = "A swarm that that processes tasks concurrently using multiple agents and saves the metadata to a CSV file.", + description: str = "A swarm that processes tasks concurrently using multiple agents and saves the metadata to a CSV file.", agents: Union[Agent, List[Agent]] = [], autosave_on: bool = True, save_file_path: str = None, @@ -94,17 +88,18 @@ class SpreadSheetSwarm(BaseSwarm): self.max_loops = max_loops self.workspace_dir = workspace_dir - # --------------- NEW CHANGE START --------------- - # The save_file_path now uses the formatted_time and uuid_hex - self.save_file_path = f"spreadsheet_swarm_{formatted_time}_run_id_{uuid_hex}.csv" - # --------------- NEW CHANGE END --------------- + # Create a timestamp without colons or periods + timestamp = datetime.now().isoformat().replace(":", "_").replace(".", "_") + + # Use this timestamp in the CSV filename + self.save_file_path = f"spreadsheet_swarm_{timestamp}_run_id_{run_id}.csv" self.metadata = SwarmRunMetadata( - run_id=f"spreadsheet_swarm_run_{time}", + run_id=f"spreadsheet_swarm_run_{run_id}", name=name, description=description, agents=[agent.name for agent in agents], - start_time=time, + start_time=str(datetime.now().timestamp()), # Numeric timestamp end_time="", tasks_completed=0, outputs=[], @@ -147,12 +142,18 @@ class SpreadSheetSwarm(BaseSwarm): """ logger.info(f"Running the swarm with task: {task}") - self.metadata.start_time = time + self.metadata.start_time = str(datetime.now().timestamp()) # Numeric timestamp - # Run the asyncio event loop - asyncio.run(self._run_tasks(task, *args, **kwargs)) + # Check if we're already in an event loop + if asyncio.get_event_loop().is_running(): + # If so, create and run tasks directly using `create_task` without `asyncio.run` + task_future = asyncio.create_task(self._run_tasks(task, *args, **kwargs)) + asyncio.get_event_loop().run_until_complete(task_future) + else: + # If no event loop is running, run using `asyncio.run` + asyncio.run(self._run_tasks(task, *args, **kwargs)) - self.metadata.end_time = time + self.metadata.end_time = str(datetime.now().timestamp()) # Numeric timestamp # Synchronously save metadata logger.info("Saving metadata to CSV and JSON...") @@ -227,7 +228,7 @@ class SpreadSheetSwarm(BaseSwarm): agent_name=agent_name, task=task, result=result, - timestamp=time, + timestamp=str(datetime.now().timestamp()), # Numeric timestamp ) ) @@ -263,38 +264,19 @@ class SpreadSheetSwarm(BaseSwarm): """ Save the swarm metadata to a CSV file. """ - logger.info( - f"Saving swarm metadata to: {self.save_file_path}" - ) + logger.info(f"Saving swarm metadata to: {self.save_file_path}") run_id = uuid.uuid4() # Check if file exists before opening it file_exists = os.path.exists(self.save_file_path) - async with aiofiles.open( - self.save_file_path, mode="a" - ) as file: - writer = csv.writer(file) - + async with aiofiles.open(self.save_file_path, mode="a") as file: # Write header if file doesn't exist if not file_exists: - await writer.writerow( - [ - "Run ID", - "Agent Name", - "Task", - "Result", - "Timestamp", - ] - ) + header = "Run ID,Agent Name,Task,Result,Timestamp\n" + await file.write(header) + # Write each output as a new row for output in self.metadata.outputs: - await writer.writerow( - [ - str(run_id), - output.agent_name, - output.task, - output.result, - output.timestamp, - ] - ) + row = f"{run_id},{output.agent_name},{output.task},{output.result},{output.timestamp}\n" + await file.write(row) \ No newline at end of file diff --git a/swarms/structs/ui/ui.py b/swarms/structs/ui/ui.py index f91008d1..81de9bfb 100644 --- a/swarms/structs/ui/ui.py +++ b/swarms/structs/ui/ui.py @@ -8,9 +8,11 @@ import gradio as gr from swarms.structs.agent import Agent from swarms.structs.swarm_router import SwarmRouter from swarms.utils.loguru_logger import initialize_logger -from swarm_models import OpenAIChat -import re # Import the regular expression module - +import re +import csv # Import the csv module for csv parsing +from swarms.utils.litellm_wrapper import LiteLLM +from litellm import models_by_provider +from dotenv import set_key, find_dotenv # Initialize logger logger = initialize_logger(log_folder="swarm_ui") @@ -20,19 +22,7 @@ load_dotenv() # Get the OpenAI API key from the environment variable api_key = os.getenv("GROQ_API_KEY") -# changed to swarms_models -# adding functionality to view other models of swarms models - -# Model initialization -model = OpenAIChat( - openai_api_base="https://api.groq.com/openai/v1", - openai_api_key=api_key, - model_name="llama-3.1-70b-versatile", - temperature=0.1, -) - # Define the path to agent_prompts.json - # locates the json file and then fetches the promopts PROMPT_JSON_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "agent_prompts.json") @@ -94,7 +84,8 @@ def load_prompts_from_json() -> Dict[str, str]: AGENT_PROMPTS = load_prompts_from_json() -def initialize_agents(dynamic_temp: float, agent_keys: List[str]) -> List[Agent]: +def initialize_agents(dynamic_temp: float, agent_keys: List[str], model_name: str, + provider: str, api_key: str, temperature:float, max_tokens:int) -> List[Agent]: agents = [] seen_names = set() for agent_key in agent_keys: @@ -112,10 +103,18 @@ def initialize_agents(dynamic_temp: float, agent_keys: List[str]) -> List[Agent] counter += 1 seen_names.add(agent_name) + llm = LiteLLM( + model_name=model_name, + system_prompt=agent_prompt, + temperature=temperature, + max_tokens = max_tokens, + ) + + agent = Agent( agent_name=f"Agent-{agent_name}", system_prompt=agent_prompt, - llm=model, + llm=llm, max_loops=1, autosave=True, verbose=True, @@ -132,11 +131,12 @@ def initialize_agents(dynamic_temp: float, agent_keys: List[str]) -> List[Agent] return agents async def execute_task(task: str, max_loops: int, dynamic_temp: float, - swarm_type: str, agent_keys: List[str], flow: str = None) -> Tuple[Any, 'SwarmRouter', str]: + swarm_type: str, agent_keys: List[str], flow: str = None, model_name:str = "gpt-4o", + provider:str = "openai", api_key:str=None, temperature:float=0.5, max_tokens:int=4000) -> Tuple[Any, 'SwarmRouter', str]: try: # Initialize agents try: - agents = initialize_agents(dynamic_temp, agent_keys) + agents = initialize_agents(dynamic_temp, agent_keys, model_name, provider, api_key, temperature, max_tokens) except Exception as e: return None, None, str(e) @@ -160,27 +160,12 @@ async def execute_task(task: str, max_loops: int, dynamic_temp: float, if swarm_type == "MixtureOfAgents": if len(agents) < 2: return None, None, "MixtureOfAgents requires at least 2 agents" + + if swarm_type == "SequentialWorkflow": + if len(agents) < 2: + return None, None, "SequentialWorkflow requires at least 2 agents" - if swarm_type == "SpreadSheetSwarm": - # spread sheet swarm needs specific setup - output_dir = "swarm_outputs" - os.makedirs(output_dir, exist_ok=True) - - # Create a sanitized filename using only safe characters - timestamp = time.strftime("%Y%m%d_%H%M%S") - output_file = f"swarm_output_{timestamp}.csv" - output_path = os.path.join(output_dir, output_file) - # Validate the output path - try: - # Ensure the path is valid and writable - with open(output_path, 'w') as f: - pass - os.remove(output_path) # Clean up the test file - except OSError as e: - return None, None, str(e) - - router_kwargs["output_path"] = output_path # Create and execute SwarmRouter try: timeout = 450 if swarm_type != "SpreadSheetSwarm" else 900 # SpreadSheetSwarm will have different timeout. @@ -198,13 +183,6 @@ async def execute_task(task: str, max_loops: int, dynamic_temp: float, timeout=timeout ) - if swarm_type == "SpreadSheetSwarm": - # Verify the output file was created - if not os.path.exists(output_path): - return None, None, "Output file was not created" - - return output_path, router, "" - return result, router, "" except asyncio.TimeoutError: @@ -248,11 +226,11 @@ def parse_agent_rearrange_output(data: Optional[str]) -> str: overall_time = parsed_data["time"] - output = f"**Workflow Execution Details**\n\n" - output += f"* **Swarm ID:** `{swarm_id}`\n" - output += f"* **Swarm Name:** `{swarm_name}`\n" - output += f"* **Agent Flow:** `{agent_flow}`\n\n---\n" - output += f"**Agent Task Execution**\n\n" + output = f"Workflow Execution Details\n\n" + output += f"Swarm ID: `{swarm_id}`\n" + output += f"Swarm Name: `{swarm_name}`\n" + output += f"Agent Flow: `{agent_flow}`\n\n---\n" + output += f"Agent Task Execution\n\n" if "outputs" not in parsed_data: return "Error: 'outputs' key is missing" @@ -263,7 +241,7 @@ def parse_agent_rearrange_output(data: Optional[str]) -> str: if not isinstance(parsed_data["outputs"], list): return "Error: 'outputs' data is not a list." - for i, agent_output in enumerate(parsed_data["outputs"], start=1): + for i, agent_output in enumerate(parsed_data["outputs"], start=3): if not isinstance(agent_output, dict): return f"Error: Agent output at index {i} is not a dictionary" @@ -280,11 +258,11 @@ def parse_agent_rearrange_output(data: Optional[str]) -> str: return f"Error: 'steps' data is not a list at index {i}" agent_name = agent_output["agent_name"] - output += f"**Run {i} (Agent: `{agent_name}`)**\n\n" - output += "
\nShow/Hide Agent Steps\n\n" + output += f"Run {(3-i)} (Agent: `{agent_name}`)**\n\n" + # output += "
\nShow/Hide Agent Steps\n\n" # Iterate over steps - for j, step in enumerate(agent_output["steps"], start=1): + for j, step in enumerate(agent_output["steps"], start=3): if not isinstance(step, dict): return f"Error: step at index {j} is not a dictionary at {i} agent output." @@ -296,15 +274,16 @@ def parse_agent_rearrange_output(data: Optional[str]) -> str: if "content" not in step: return f"Error: 'content' key missing at step {j} at {i} agent output." - - role = step["role"] - content = step["content"] - output += f" **Step {j}:** ({role})\n" - output += f" > {content}\n\n" + + if step["role"].strip() != "System:": # Filter out system prompts + # role = step["role"] + content = step["content"] + output += f"Step {(3-j)}: \n" + output += f"Response :\n {content}\n\n" - output += "
\n\n---\n" + # output += "
\n\n---\n" - output += f"**Overall Completion Time:** `{overall_time}`" + output += f"Overall Completion Time: `{overall_time}`" return output except json.JSONDecodeError as e : return f"Error during parsing: json.JSONDecodeError {e}" @@ -312,6 +291,263 @@ def parse_agent_rearrange_output(data: Optional[str]) -> str: except Exception as e: return f"Error during parsing: {str(e)}" +def parse_mixture_of_agents_output(data: Optional[str]) -> str: + """Parses the MixtureOfAgents output string and formats it for display.""" + if data is None: + return "Error: No data provided for parsing." + + print(f"Raw data received for parsing:\n{data}") # Debug: Print raw data + + try: + parsed_data = json.loads(data) + + if "InputConfig" not in parsed_data or not isinstance(parsed_data["InputConfig"], dict): + return "Error: 'InputConfig' data is missing or not a dictionary." + + if "name" not in parsed_data["InputConfig"]: + return "Error: 'name' key is missing in 'InputConfig'." + if "description" not in parsed_data["InputConfig"]: + return "Error: 'description' key is missing in 'InputConfig'." + + if "agents" not in parsed_data["InputConfig"] or not isinstance(parsed_data["InputConfig"]["agents"], list) : + return "Error: 'agents' key is missing in 'InputConfig' or not a list." + + + name = parsed_data["InputConfig"]["name"] + description = parsed_data["InputConfig"]["description"] + + output = f"Mixture of Agents Workflow Details\n\n" + output += f"Name: `{name}`\n" + output += f"Description: `{description}`\n\n---\n" + output += f"Agent Task Execution\n\n" + + for agent in parsed_data["InputConfig"]["agents"]: + if not isinstance(agent, dict): + return "Error: agent is not a dict in InputConfig agents" + if "agent_name" not in agent: + return "Error: 'agent_name' key is missing in agents." + + if "system_prompt" not in agent: + return f"Error: 'system_prompt' key is missing in agents." + + agent_name = agent["agent_name"] + # system_prompt = agent["system_prompt"] + output += f"Agent: `{agent_name}`\n" + # output += f"* **System Prompt:** `{system_prompt}`\n\n" + + + if "normal_agent_outputs" not in parsed_data or not isinstance(parsed_data["normal_agent_outputs"], list) : + return "Error: 'normal_agent_outputs' key is missing or not a list." + + for i, agent_output in enumerate(parsed_data["normal_agent_outputs"], start=3): + if not isinstance(agent_output, dict): + return f"Error: agent output at index {i} is not a dictionary." + if "agent_name" not in agent_output: + return f"Error: 'agent_name' key is missing at index {i}" + if "steps" not in agent_output: + return f"Error: 'steps' key is missing at index {i}" + + if agent_output["steps"] is None: + return f"Error: 'steps' is None at index {i}" + if not isinstance(agent_output["steps"], list): + return f"Error: 'steps' data is not a list at index {i}." + + agent_name = agent_output["agent_name"] + output += f"Run {(3-i)} (Agent: `{agent_name}`)\n\n" + # output += "
\nShow/Hide Agent Steps\n\n" + for j, step in enumerate(agent_output["steps"], start=3): + if not isinstance(step, dict): + return f"Error: step at index {j} is not a dictionary at {i} agent output." + + if step is None: + return f"Error: step at index {j} is None at {i} agent output." + + if "role" not in step: + return f"Error: 'role' key missing at step {j} at {i} agent output." + + if "content" not in step: + return f"Error: 'content' key missing at step {j} at {i} agent output." + + if step["role"].strip() != "System:": # Filter out system prompts + # role = step["role"] + content = step["content"] + output += f"Step {(3-j)}: \n" + output += f"Response:\n {content}\n\n" + + # output += "
\n\n---\n" + + if "aggregator_agent_summary" in parsed_data: + output += f"\nAggregated Summary :\n{parsed_data['aggregator_agent_summary']}\n{'=' * 50}\n" + + return output + + except json.JSONDecodeError as e: + return f"Error during parsing json.JSONDecodeError : {e}" + + except Exception as e: + return f"Error during parsing: {str(e)}" + +def parse_sequential_workflow_output(data: Optional[str]) -> str: + """Parses the SequentialWorkflow output string and formats it for display.""" + if data is None: + return "Error: No data provided for parsing." + + print(f"Raw data received for parsing:\n{data}") # Debug: Print raw data + + try: + parsed_data = json.loads(data) + + if "input" not in parsed_data or not isinstance(parsed_data.get("input"), dict): + return "Error: 'input' data is missing or not a dictionary." + + if "swarm_id" not in parsed_data["input"] : + return "Error: 'swarm_id' key is missing in the 'input'." + + if "name" not in parsed_data["input"]: + return "Error: 'name' key is missing in the 'input'." + + if "flow" not in parsed_data["input"]: + return "Error: 'flow' key is missing in the 'input'." + + if "time" not in parsed_data : + return "Error: 'time' key is missing." + + swarm_id = parsed_data["input"]["swarm_id"] + swarm_name = parsed_data["input"]["name"] + agent_flow = parsed_data["input"]["flow"] + overall_time = parsed_data["time"] + + + output = f"Workflow Execution Details\n\n" + output += f"Swarm ID: `{swarm_id}`\n" + output += f"Swarm Name: `{swarm_name}`\n" + output += f"Agent Flow: `{agent_flow}`\n\n---\n" + output += f"Agent Task Execution\n\n" + + if "outputs" not in parsed_data: + return "Error: 'outputs' key is missing" + + if parsed_data["outputs"] is None: + return "Error: 'outputs' data is None" + + if not isinstance(parsed_data["outputs"], list): + return "Error: 'outputs' data is not a list." + + for i, agent_output in enumerate(parsed_data["outputs"], start=3): + if not isinstance(agent_output, dict): + return f"Error: Agent output at index {i} is not a dictionary" + + if "agent_name" not in agent_output: + return f"Error: 'agent_name' key is missing at index {i}" + + if "steps" not in agent_output: + return f"Error: 'steps' key is missing at index {i}" + + if agent_output["steps"] is None: + return f"Error: 'steps' data is None at index {i}" + + if not isinstance(agent_output["steps"], list): + return f"Error: 'steps' data is not a list at index {i}" + + agent_name = agent_output["agent_name"] + output += f"Run {(3-i)} (Agent: `{agent_name}`)\n\n" + # output += "
\nShow/Hide Agent Steps\n\n" + + # Iterate over steps + for j, step in enumerate(agent_output["steps"], start=3): + if not isinstance(step, dict): + return f"Error: step at index {j} is not a dictionary at {i} agent output." + + if step is None: + return f"Error: step at index {j} is None at {i} agent output" + + if "role" not in step: + return f"Error: 'role' key missing at step {j} at {i} agent output." + + if "content" not in step: + return f"Error: 'content' key missing at step {j} at {i} agent output." + + if step["role"].strip() != "System:": # Filter out system prompts + # role = step["role"] + content = step["content"] + output += f"Step {(3-j)}:\n" + output += f"Response : {content}\n\n" + + # output += "
\n\n---\n" + + output += f"Overall Completion Time: `{overall_time}`" + return output + + except json.JSONDecodeError as e : + return f"Error during parsing json.JSONDecodeError : {e}" + + except Exception as e: + return f"Error during parsing: {str(e)}" + + +def parse_spreadsheet_swarm_output(file_path: str) -> str: + """Parses the SpreadSheetSwarm output CSV file and formats it for display.""" + if not file_path: + return "Error: No file path provided for parsing." + + print(f"Parsing spreadsheet output from: {file_path}") + + try: + with open(file_path, 'r', encoding='utf-8') as file: + csv_reader = csv.reader(file) + header = next(csv_reader, None) # Read the header row + if not header: + return "Error: CSV file is empty or has no header" + + output = "### Spreadsheet Swarm Output ###\n\n" + output += "| " + " | ".join(header) + " |\n" # Adding header + output += "| " + " | ".join(["---"] * len(header)) + " |\n" # Adding header seperator + + for row in csv_reader: + output += "| " + " | ".join(row) + " |\n" # Adding row + + output += "\n" + return output + + except FileNotFoundError: + return "Error: CSV file not found." + except Exception as e: + return f"Error during parsing CSV file: {str(e)}" +def parse_json_output(data:str) -> str: + """Parses a JSON string and formats it for display.""" + if not data: + return "Error: No data provided for parsing." + + print(f"Parsing json output from: {data}") + try: + parsed_data = json.loads(data) + + output = "### Swarm Metadata ###\n\n" + + for key,value in parsed_data.items(): + if key == "outputs": + output += f"**{key}**:\n" + if isinstance(value, list): + for item in value: + output += f" - Agent Name : {item.get('agent_name', 'N/A')}\n" + output += f" Task : {item.get('task', 'N/A')}\n" + output += f" Result : {item.get('result', 'N/A')}\n" + output += f" Timestamp : {item.get('timestamp', 'N/A')}\n\n" + + else : + output += f" {value}\n" + + else : + output += f"**{key}**: {value}\n" + + return output + + except json.JSONDecodeError as e: + return f"Error: Invalid JSON format - {e}" + + except Exception as e: + return f"Error during JSON parsing: {str(e)}" + class UI: def __init__(self, theme): self.theme = theme @@ -345,7 +581,7 @@ class UI: label=label, interactive=True, ) - self.components[f'slider_{label}'] + self.components[f'slider_{label}'] = slider return slider def create_dropdown(self, label, choices, value=None, multiselect=False): @@ -414,9 +650,9 @@ class UI: @staticmethod def create_ui_theme(primary_color="red"): - return gr.themes.Soft( + return gr.themes.Ocean( primary_hue=primary_color, - secondary_hue="gray", + secondary_hue=primary_color, neutral_hue="gray", ).set( body_background_fill="#20252c", @@ -465,6 +701,25 @@ def create_app(): theme = UI.create_ui_theme(primary_color="red") ui = UI(theme=theme) + # Available providers and models + providers = [ + "openai", + "anthropic", + "cohere", + "gemini", + "mistral", + "groq", + "nvidia_nim", + "huggingface", + "perplexity" + ] + + filtered_models = {} + + for provider in providers: + filtered_models[provider] = models_by_provider.get(provider, []) + + with ui.blocks: with gr.Row(): with gr.Column(scale=4): # Left column (80% width) @@ -494,7 +749,7 @@ def create_app(): with gr.Column(scale=1): # Get available swarm types swarm_types = [ - "SequentialWorkflow", "ConcurrentWorkflow", "AgentRearrange", + "SequentialWorkflow", "ConcurrentWorkflow","AgentRearrange", "MixtureOfAgents", "SpreadSheetSwarm", "auto" ] agent_selector = gr.Dropdown( @@ -509,7 +764,7 @@ def create_app(): with gr.Column(visible=False) as flow_config: flow_text = gr.Textbox( label="Agent Flow Configuration", - placeholder="Enter agent flow (e.g., Agent1 -> Agent2 -> Agent3)", + placeholder="Enter agent flow !", lines=2 ) gr.Markdown( @@ -522,7 +777,48 @@ def create_app(): ) with gr.Column(scale=2, min_width=200): - with gr.Row(): + with gr.Row(): + # Provider selection dropdown + provider_dropdown = gr.Dropdown( + label="Select Provider", + choices=providers, + value=providers[0] if providers else None, + interactive=True, + ) + # with gr.Row(): + # # Model selection dropdown (initially empty) + model_dropdown = gr.Dropdown( + label="Select Model", + choices=[], + interactive=True, + ) + with gr.Row(): + # API key input + api_key_input = gr.Textbox( + label="API Key", + placeholder="Enter your API key", + type="password", + ) + with gr.Row(): + # temp slider + temperature_slider = gr.Slider( + label="Temperature", + minimum=0, + maximum=1, + value=0.1, + step=0.01 + ) + # with gr.Row(): + # max tokens slider + max_tokens_slider = gr.Slider( + label="Max Tokens", + minimum=100, + maximum=10000, + value=4000, + step=100, + ) + + with gr.Row(): max_loops_slider = gr.Slider( label="Max Loops", minimum=1, @@ -530,21 +826,25 @@ def create_app(): value=1, step=1 ) - - with gr.Row(): + with gr.Row(): dynamic_slider = gr.Slider( - label="Dynamic Temp", + label="Dyn. Temp", minimum=0, maximum=1, value=0.1, step=0.01 ) - with gr.Row(): + with gr.Row(): loading_status = gr.Textbox( label="Status", value="Ready", interactive=False ) + #Hidden textbox to store API Key + env_api_key_textbox = gr.Textbox( + value="", + visible=False + ) with gr.Row(): run_button = gr.Button("Run Task", variant="primary") @@ -587,29 +887,71 @@ def create_app(): gr.update(maximum=max_loops), # For max_loops_slider f"Selected {swarm_type}" # For loading_status ) + def update_model_dropdown(provider): + """Update model dropdown based on selected provider.""" + models = filtered_models.get(provider, []) + return gr.update(choices=models, value=models[0] if models else None) - async def run_task_wrapper(task, max_loops, dynamic_temp, swarm_type, agent_prompt_selector, flow_text): + async def run_task_wrapper(task, max_loops, dynamic_temp, swarm_type, agent_prompt_selector, flow_text, + provider, model_name, api_key, temperature, max_tokens): """Execute the task and update the UI with progress.""" try: if not task: - yield "Please provide a task description.", "Error: Missing task" + yield "Please provide a task description.", "Error: Missing task", "" return if not agent_prompt_selector or len(agent_prompt_selector) == 0: - yield "Please select at least one agent.", "Error: No agents selected" + yield "Please select at least one agent.", "Error: No agents selected", "" return + + if not provider: + yield "Please select a provider.", "Error: No provider selected", "" + return + + if not model_name: + yield "Please select a model.", "Error: No model selected", "" + return + + if not api_key: + yield "Please enter an API Key", "Error: API Key is required", "" + return + # Update status - yield "Processing...", "Running task..." + yield "Processing...", "Running task...", "" # Prepare flow for AgentRearrange flow = None if swarm_type == "AgentRearrange": if not flow_text: - yield "Please provide the agent flow configuration.", "Error: Flow not configured" + yield "Please provide the agent flow configuration.", "Error: Flow not configured", "" return flow = flow_text + # Save API key to .env + env_path = find_dotenv() + if provider == "openai": + set_key(env_path, "OPENAI_API_KEY", api_key) + elif provider == "anthropic": + set_key(env_path, "ANTHROPIC_API_KEY", api_key) + elif provider == "cohere": + set_key(env_path, "COHERE_API_KEY", api_key) + elif provider == "gemini": + set_key(env_path, "GEMINI_API_KEY", api_key) + elif provider == "mistral": + set_key(env_path, "MISTRAL_API_KEY", api_key) + elif provider == "groq": + set_key(env_path, "GROQ_API_KEY", api_key) + elif provider == "nvidia_nim": + set_key(env_path, "NVIDIA_NIM_API_KEY", api_key) + elif provider == "huggingface": + set_key(env_path, "HUGGINGFACE_API_KEY", api_key) + elif provider == "perplexity": + set_key(env_path, "PERPLEXITY_API_KEY", api_key) + else: + yield f"Error: {provider} this provider is not present", f"Error: {provider} not supported", "" + return + # Execute task result, router, error = await execute_task( task=task, @@ -617,22 +959,40 @@ def create_app(): dynamic_temp=dynamic_temp, swarm_type=swarm_type, agent_keys=agent_prompt_selector, - flow=flow + flow=flow, + model_name=model_name, + provider=provider, + api_key=api_key, + temperature=temperature, + max_tokens = max_tokens, ) if error: - yield f"Error: {error}", "Error occurred" + yield f"Error: {error}", f"Error: {error}", "" return # Format output based on swarm type output_lines = [] if swarm_type == "SpreadSheetSwarm": - output_lines.append(f"### Spreadsheet Output ###\n{result}\n{'=' * 50}\n") + # Check if the result is a file path or JSON + if os.path.exists(result): + parsed_output = parse_spreadsheet_swarm_output(result) + output_lines.append(parsed_output) + else: + parsed_output = parse_json_output(result) + output_lines.append(parsed_output) + elif swarm_type == "AgentRearrange": parsed_output = parse_agent_rearrange_output(result) output_lines.append(parsed_output) + elif swarm_type == "MixtureOfAgents": + parsed_output = parse_mixture_of_agents_output(result) + output_lines.append(parsed_output) + elif swarm_type == "SequentialWorkflow": + parsed_output = parse_sequential_workflow_output(result) + output_lines.append(parsed_output) elif isinstance(result, dict): # checking if result is dict or string. - + if swarm_type == "MixtureOfAgents": # Add individual agent outputs for key, value in result.items(): @@ -647,10 +1007,10 @@ def create_app(): elif isinstance(result, str): output_lines.append(str(result)) - yield "\n".join(output_lines), "Completed" - + yield "\n".join(output_lines), "Completed", api_key + except Exception as e: - yield f"Error: {str(e)}", "Error occurred" + yield f"Error: {str(e)}", f"Error: {str(e)}", "" # Connect the update functions agent_selector.change( @@ -658,6 +1018,11 @@ def create_app(): inputs=[agent_selector], outputs=[flow_config, max_loops_slider, loading_status] ) + provider_dropdown.change( + fn=update_model_dropdown, + inputs=[provider_dropdown], + outputs=[model_dropdown] + ) # Create event trigger # Create event trigger for run button @@ -669,19 +1034,24 @@ def create_app(): dynamic_slider, agent_selector, agent_prompt_selector, - flow_text + flow_text, + provider_dropdown, + model_dropdown, + api_key_input, + temperature_slider, + max_tokens_slider ], - outputs=[agent_output_display, loading_status] + outputs=[agent_output_display, loading_status, env_api_key_textbox] ) # Connect cancel button to interrupt processing def cancel_task(): - return "Task cancelled.", "Cancelled" + return "Task cancelled.", "Cancelled", "" cancel_button.click( fn=cancel_task, inputs=None, - outputs=[agent_output_display, loading_status], + outputs=[agent_output_display, loading_status, env_api_key_textbox], cancels=run_event )