{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Project Manager Assistant Agent" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "This tutorial demonstrates how to create a an AI agent that assists in project management tasks including creating actionable tasks from a given project description, identify the dependency within the tasks, create a task execution schedule for the project, and assign the individual tasks to project members based on their expertise and experience. This application uses a combination of custom functions, structured output, and an agent that can streamline the project management, in particular during the project initation / setup process. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Motivation\n", "Effective management is key to project success. It already starts, with the setup of the project, definition of tasks, scheduling and allocation of team members. However, with increasing complexity of the project, this task becomes more and more challenging and time consuming frequently requiring days of planning involving several members of the organization.\n", "\n", "The ```Project Manager Assistant Agent``` was created to transfrom how projects are initiated by introducing automation, intelligence, and precision into the process. It enables project managers to seamless translate project description into structure, actionable plans, mapping dependencies for better workflow alignment and assign tasks based on team members' expertise and experience. In addition, it creates risks scores for the individual tasks allowing overall project risk assessment. This overall project risk score is used as part of a self-reflection (along insights generations on the actual plan) to further improve the schedule and task assignment to reduce the project risks. (see details on the implementation).\n", "\n", "### Benefits\n", "This AI-driven approach reduces the burden of manual planning and eliminates redundancies, allowing project managers to shift their focus to higher-level strategy and decision. making. \n", "\n", "Example visaulized output for an agent derived project plan:\n", "![Project Manager Assistant Agent Gantt-chart](../images/project_manager_assistant_agent_ganttchart.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Key Components\n", "
    \n", "
  1. \n", " LangGraph: Organize the overall workflow of the agent, managing the flow of information between different nodes and stages of the agent\n", "
  2. \n", "
  3. \n", " GPT-4o-mini: Extracts actionable items from the project description, map dependencies, schedules tasks, allocate tasks to team, and assess the risks\n", "
  4. \n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Key Classes\n", "State Management\n", "
\n", "
    \n", "
  1. \n", " AgentState\n", " \n", "
  2. \n", "
  3. \n", " Task\n", " \n", "
  4. \n", "
  5. \n", " TaskDependency\n", " \n", "
  6. \n", "
  7. \n", " Team Member\n", " \n", "
  8. \n", "
  9. \n", " Team\n", " \n", "
  10. \n", "
  11. \n", " TaskAllocation\n", " \n", "
  12. \n", "
  13. \n", " TaskSchedule\n", " \n", "
  14. \n", "
  15. \n", " TaskList\n", " \n", "
  16. \n", "
  17. \n", " DependencyList\n", " \n", "
  18. \n", "
  19. \n", " Schedule\n", " \n", "
  20. \n", "
  21. \n", " TaskAllocationList\n", " \n", "
  22. \n", "
  23. \n", " Risk\n", " \n", "
  24. \n", "
  25. \n", " RiskList\n", " \n", "
  26. \n", "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Key Nodes and Functions\n", "
    \n", "
  1. \n", " task_generation: Node that will extract tasks from given project description\n", "
  2. \n", "
  3. \n", " task_dependencies: Node that will evaluate the dependencies between the tasks\n", "
  4. \n", "
  5. \n", " task_scheduler: Node that will schedule tasks based on dependencies and team availability\n", "
  6. \n", "
  7. \n", " task_allocator: Node that will allocate tasks to team members\n", "
  8. \n", "
  9. \n", " risk_assessor: Node that analyze risk associated with schedule and allocation of task\n", "
  10. \n", "
  11. \n", " insight_generator: Node that generate insights from the schedule, task allocation and risk associated\n", "
  12. \n", "
  13. \n", " router: A helper function that will route the agent to the appropriate node based on the project description\n", "
  14. \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visual Representation of the Agent" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Project\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Implementation\n", "In the following section, we provide a detailed overview how to implement the Project Manager Assistant Agent." ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "plaintext" } }, "source": [ "### Install and import tutorial specific libraries" ] }, { "cell_type": "code", "execution_count": 397, "metadata": {}, "outputs": [], "source": [ "!pip install langchain langgraph langchain-openai pandas plotly networkx pyvis openai python-dotenv -q" ] }, { "cell_type": "code", "execution_count": 398, "metadata": {}, "outputs": [], "source": [ "import os\n", "import uuid\n", "import pandas as pd\n", "import plotly.express as px\n", "from datetime import datetime, timedelta\n", "from typing import List, TypedDict\n", "from pydantic import BaseModel, Field\n", "from langchain_openai import AzureChatOpenAI, ChatOpenAI\n", "from langgraph.graph import StateGraph, START,END\n", "from langgraph.checkpoint.memory import MemorySaver\n", "from IPython.display import Image, display, Markdown, HTML\n", "from dotenv import load_dotenv\n", "\n", "# Load environment variables\n", "load_dotenv(override=True)\n", "\n", "# Define your model provider\n", "model_provider = 'Azure' # 'Azure' or 'OpenAI'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Instantiate LLM model" ] }, { "cell_type": "code", "execution_count": 399, "metadata": {}, "outputs": [], "source": [ "# Based on model_provider load the language model\n", "if model_provider == 'Azure':\n", " \"\"\"\n", " Define your environmental variables under .venv:\n", " - AZURE_OPENAI_API_KEY \n", " - OPENAI_API_VERSION\n", " - AZURE_OPENAI_ENDPOINT\n", " \"\"\"\n", " llm = AzureChatOpenAI(\n", " deployment_name='gpt-4o-mini', # Your actual deployment name\n", " )\n", "elif model_provider == 'OpenAI':\n", " \"\"\"\n", " Define your environmental variables under .venv:\n", " - OPENAI_API_KEY\n", " - OPENAI_API_BASE\n", " \"\"\"\n", " llm = ChatOpenAI(model=\"gpt-4o-mini\")\n", "else:\n", " print('Implement your own llm loader')" ] }, { "cell_type": "code", "execution_count": 400, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AIMessage(content=\"Hello! I'm just a computer program, so I don't have feelings, but I'm here and ready to help you. How can I assist you today?\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 30, 'prompt_tokens': 13, 'total_tokens': 43, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_04751d0b65', 'prompt_filter_results': [{'prompt_index': 0, 'content_filter_results': {'hate': {'filtered': False, 'severity': 'safe'}, 'jailbreak': {'filtered': False, 'detected': False}, 'self_harm': {'filtered': False, 'severity': 'safe'}, 'sexual': {'filtered': False, 'severity': 'safe'}, 'violence': {'filtered': False, 'severity': 'safe'}}}], 'finish_reason': 'stop', 'logprobs': None, 'content_filter_results': {'hate': {'filtered': False, 'severity': 'safe'}, 'self_harm': {'filtered': False, 'severity': 'safe'}, 'sexual': {'filtered': False, 'severity': 'safe'}, 'violence': {'filtered': False, 'severity': 'safe'}}}, id='run-9bbab967-9fae-47d5-84bd-a1b38555873a-0', usage_metadata={'input_tokens': 13, 'output_tokens': 30, 'total_tokens': 43, 'input_token_details': {}, 'output_token_details': {}})" ] }, "execution_count": 400, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Test your LLM\n", "llm.invoke(\"Hello, how are you?\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the following section, we will step-by-step implement:\n", "- The data classes,\n", "- Agent state,\n", "- Nodes and function (used as a router),\n", "- and the workflow of the agent.\n", "\n", "So let's create all required data classes first:" ] }, { "cell_type": "code", "execution_count": 401, "metadata": {}, "outputs": [], "source": [ "# Data Models\n", "class Task(BaseModel):\n", " id: uuid.UUID = Field(default_factory=uuid.uuid4, description=\"Unique identifier for the task\")\n", " task_name: str = Field(description=\"Name of the task\")\n", " task_description: str = Field(description=\"Description of the task\")\n", " estimated_day: int = Field(description=\"Estimated number of days to complete the task\")\n", "\n", "class TaskList(BaseModel):\n", " tasks: List[Task] = Field(description=\"List of tasks\")\n", "\n", "class TaskDependency(BaseModel):\n", " \"\"\"Task dependency model\"\"\"\n", " task: Task = Field(description=\"Task\")\n", " dependent_tasks: List[Task] = Field(description=\"List of dependent tasks\")\n", "\n", "class TeamMember(BaseModel):\n", " name: str = Field(description=\"Name of the team member\")\n", " profile: str = Field(description=\"Profile of the team member\")\n", "\n", "class Team(BaseModel):\n", " team_members: List[TeamMember] = Field(description=\"List of team members\")\n", "\n", "# Iterative assessment\n", "class TaskAllocation(BaseModel):\n", " \"\"\"Task allocation class\"\"\"\n", " task: Task = Field(description=\"Task\")\n", " team_member: TeamMember = Field(description=\"Team members assigned to the task\")\n", "\n", "class TaskSchedule(BaseModel):\n", " \"\"\"Schedule schedule class\"\"\"\n", " task: Task = Field(description=\"Task\")\n", " start_day: int = Field(description=\"Start day of the task\")\n", " end_day: int = Field(description=\"End day of the task\")\n", "\n", "# Lists\n", "class DependencyList(BaseModel):\n", " \"\"\"List of task dependencies\"\"\"\n", " dependencies: List[TaskDependency] = Field(description=\"List of task dependencies\")\n", "\n", "class Schedule(BaseModel):\n", " \"\"\"List of task schedules\"\"\"\n", " schedule: List[TaskSchedule] = Field(description=\"List of task schedules\")\n", "\n", "class TaskAllocationList(BaseModel):\n", " \"\"\"List of task allocations\"\"\"\n", " task_allocations: List[TaskAllocation] = Field(description=\"List of task allocations\")\n", "\n", "# Iteration\n", "class TaskAllocationListIteration(BaseModel):\n", " \"\"\"List of task allocations for each iteration\"\"\"\n", " task_allocations_iteration: List[TaskAllocationList] = Field(description=\"List of task allocations for each iteration\")\n", "\n", "class ScheduleIteration(BaseModel):\n", " \"\"\"List of task schedules for each iteration\"\"\"\n", " schedule: List[Schedule] = Field(description=\"List of task schedules for each iteration\")\n", "\n", "class Risk(BaseModel):\n", " \"\"\"Risk of a task\"\"\"\n", " task: Task = Field(description=\"Task\")\n", " score: str = Field(description=\"Risk associated with the task\")\n", "\n", "class RiskList(BaseModel):\n", " \"\"\"List of risks for each iteration\"\"\"\n", " risks: List[Risk] = Field(description=\"List of risks\")\n", "\n", "class RiskListIteration(BaseModel):\n", " \"\"\"List of risks for each iteration\"\"\"\n", " risks_iteration: List[RiskList] = Field(description=\"List of risks for each iteration\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the next step, let's create the AgentState. The `schedule_iteration`, `task_allocations_iteration`, `risks_iteration` are introduced to generate structured 'memory' for the self-reflection cycles." ] }, { "cell_type": "code", "execution_count": 402, "metadata": {}, "outputs": [], "source": [ "class AgentState(TypedDict):\n", " \"\"\"The project manager agent state.\"\"\"\n", " project_description: str\n", " team: Team\n", " tasks: TaskList\n", " dependencies: DependencyList\n", " schedule: Schedule\n", " task_allocations: TaskAllocationList\n", " risks: RiskList\n", " iteration_number: int\n", " max_iteration: int\n", " insights: List[str]\n", " schedule_iteration: List[Schedule]\n", " task_allocations_iteration: List[TaskAllocationList]\n", " risks_iteration: List[RiskListIteration]\n", " project_risk_score_iterations: List[int]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Well done, let's create the required nodes. As a quick recap:\n", "\n", " In LangGraph a node is defined as a function which has an argument the `AgentState`. Within the node certain attributes of the field state is updated which at the end of the node is returned to the workflow manager and passed to the next node. Inside the nodes, LLM's are used to generate (non)-structured response.\n", "\n", "In this tutorial we have implemented the nodes based on th following pattern:\n", "\n", "```\n", "def task_generation_node(state: AgentState):\n", " \"\"\"LangGraph node that will extract tasks from given project description\"\"\"\n", " description = state[\"project_description\"]\n", " prompt = f\"\"\"You are an experienced project description analyzer. Analyze the \n", " project description '{description}' and create a list of actionable and\n", " realistic tasks with estimated time (in days) to complete each task.\n", " If the task takes longer than 5 days, break it down into independent smaller tasks.\n", " \"\"\"\n", " structure_llm = llm.with_structured_output(TaskList)\n", " tasks: TaskList = structure_llm.invoke(prompt)\n", " state['tasks'] = tasks\n", " return state\n", "```\n", "In almost all nodes, we used:\n", "- `llm.with_structured_output()` - generating structured output. \n", "\n", "The .with_structured_output() method enables models with native APIs for structured outputs, such as function calling or JSON mode, to reliably produce outputs as objects based on a defined schema. The schema can be specified using a TypedDict, JSON Schema, or a Pydantic class, determining whether the output is a dictionary or a Pydantic object.\n", "\n", "The only exception is the insight_generation_node where only `str` as requested from the llm and the required interface only `llm.invoke(prompt)`" ] }, { "cell_type": "code", "execution_count": 403, "metadata": {}, "outputs": [], "source": [ "# Workflow Nodes\n", "def task_generation_node(state: AgentState):\n", " \"\"\"LangGraph node that will extract tasks from given project description\"\"\"\n", " description = state[\"project_description\"]\n", " prompt = f\"\"\"\n", " You are an expert project manager tasked with analyzing the following project description: {description}\n", " Your objectives are to: \n", " 1. **Extract Actionable Tasks:**\n", " - Identify and list all actionable and realistic tasks necessary to complete the project.\n", " - Provide an estimated number of days required to complete each task.\n", " 2. **Refine Long-Term Tasks:**\n", " - For any task estimated to take longer than 5 days, break it down into smaller, independent sub-tasks.\n", " **Requirements:** - Ensure each task is clearly defined and achievable.\n", " - Maintain logical sequencing of tasks to facilitate smooth project execution.\"\"\"\n", "\n", " structure_llm = llm.with_structured_output(TaskList)\n", " tasks: TaskList = structure_llm.invoke(prompt)\n", " return {\"tasks\": tasks}\n", "\n", "def task_dependency_node(state: AgentState):\n", " \"\"\"Evaluate the dependencies between the tasks\"\"\"\n", " tasks = state[\"tasks\"]\n", " prompt = f\"\"\"\n", " You are a skilled project scheduler responsible for mapping out task dependencies.\n", " Given the following list of tasks: {tasks}\n", " Your objectives are to:\n", " 1. **Identify Dependencies:**\n", " - For each task, determine which other tasks must be completed before it can begin (blocking tasks).\n", " 2. **Map Dependent Tasks:** \n", " - For every task, list all tasks that depend on its completion.\n", " \"\"\"\n", " structure_llm = llm.with_structured_output(DependencyList)\n", " dependencies: DependencyList = structure_llm.invoke(prompt)\n", " return {\"dependencies\": dependencies}\n", "\n", "def task_scheduler_node(state: AgentState):\n", " \"\"\"LangGraph node that will schedule tasks based on dependencies and team availability\"\"\"\n", " dependencies = state[\"dependencies\"]\n", " tasks = state[\"tasks\"]\n", " insights = state[\"insights\"] #\"\" if state[\"insights\"] is None else state[\"insights\"].insights[-1]\n", " prompt = f\"\"\"\n", " You are an experienced project scheduler tasked with creating an optimized project timeline.\n", " **Given:**\n", " - **Tasks:** {tasks}\n", " - **Dependencies:** {dependencies}\n", " - **Previous Insights:** {insights}\n", " - **Previous Schedule Iterations (if any):** {state[\"schedule_iteration\"]}\n", " **Your objectives are to: **\n", " 1. **Develop a Task Schedule:**\n", " - Assign start and end days to each task, ensuring that all dependencies are respected.\n", " - Optimize the schedule to minimize the overall project duration.\n", " - If possible parallelize the tasks to reduce the overall project duration.\n", " - Try not to increase the project duration compared to previous iterations.\n", " 2. **Incorporate Insights:** \n", " - Utilize insights from previous iterations to enhance scheduling efficiency and address any identified issues.\n", " \"\"\"\n", " schedule_llm = llm.with_structured_output(Schedule)\n", " schedule: Schedule = schedule_llm.invoke(prompt)\n", " state[\"schedule\"] = schedule\n", " state[\"schedule_iteration\"].append(schedule)\n", " return state\n", "\n", "def task_allocation_node(state: AgentState):\n", " \"\"\"LangGraph node that will allocate tasks to team members\"\"\"\n", " tasks = state[\"tasks\"]\n", " schedule = state[\"schedule\"]\n", " team = state[\"team\"]\n", " insights = state[\"insights\"] #\"\" if state[\"insights\"] is None else state[\"insights\"].insights[-1]\n", " prompt = f\"\"\"\n", " You are a proficient project manager responsible for allocating tasks to team members efficiently.\n", " **Given:** \n", " - **Tasks:** {tasks} \n", " - **Schedule:** {schedule} \n", " - **Team Members:** {team} \n", " - **Previous Insights:** {insights} \n", " - **Previous Task Allocations (if any):** {state[\"task_allocations_iteration\"]} \n", " **Your objectives are to:** \n", " 1. **Allocate Tasks:** \n", " - Assign each task to a team member based on their expertise and current availability. \n", " - Ensure that no team member is assigned overlapping tasks during the same time period. \n", " 2. **Optimize Assignments:** \n", " - Utilize insights from previous iterations to improve task allocations. \n", " - Balance the workload evenly among team members to enhance productivity and prevent burnout.\n", " **Constraints:** \n", " - Each team member can handle only one task at a time. \n", " - Assignments should respect the skills and experience of each team member.\n", " \"\"\"\n", " structure_llm = llm.with_structured_output(TaskAllocationList)\n", " task_allocations: TaskAllocationList = structure_llm.invoke(prompt)\n", " state[\"task_allocations\"] = task_allocations\n", " state[\"task_allocations_iteration\"].append(task_allocations)\n", " return state\n", "\n", "def risk_assessment_node(state: AgentState):\n", " \"\"\"LangGraph node that analyse risk associated with schedule and allocation of task\"\"\"\n", " schedule = state[\"schedule\"]\n", " task_allocations=state[\"task_allocations\"]\n", " prompt = f\"\"\"\n", " You are a seasoned project risk analyst tasked with evaluating the risks associated with the current project plan.\n", " **Given:**\n", " - **Task Allocations:** {task_allocations}\n", " - **Schedule:** {schedule}\n", " - **Previous Risk Assessments (if any):** {state['risks_iteration']}\n", " **Your objectives are to:**\n", " 1. **Assess Risks:**\n", " - Analyze each allocated task and its scheduled timeline to identify potential risks.\n", " - Consider factors such as task complexity, resource availability, and dependency constraints.\n", " 2. **Assign Risk Scores:**\n", " - Assign a risk score to each task on a scale from 0 (no risk) to 10 (high risk).\n", " - If a task assignment remains unchanged from a previous iteration (same team member and task), retain the existing risk score to ensure consistency.\n", " - If the team member has more time between tasks - assign lower risk score for the tasks\n", " - If the task is assigned to a more senior person - assign lower risk score for the tasks\n", " 3. **Calculate Overall Project Risk:**\n", " - Sum the individual task risk scores to determine the overall project risk score.\n", " \"\"\"\n", " structure_llm = llm.with_structured_output(RiskList)\n", " risks: RiskList = structure_llm.invoke(prompt)\n", " project_task_risk_scores = [int(risk.score) for risk in risks.risks]\n", " project_risk_score = sum(project_task_risk_scores)\n", " state[\"risks\"] = risks\n", " state[\"project_risk_score\"] = project_risk_score\n", " state[\"iteration_number\"] += 1\n", " state[\"project_risk_score_iterations\"].append(project_risk_score)\n", " state[\"risks_iteration\"].append(risks)\n", " return state\n", "\n", "def insight_generation_node(state: AgentState):\n", " \"\"\"LangGraph node that generate insights from the schedule, task allocation, and risk associated\"\"\"\n", " schedule = state[\"schedule\"]\n", " task_allocations=state[\"task_allocations\"]\n", " risks = state[\"risks\"]\n", " prompt = f\"\"\"\n", " You are an expert project manager responsible for generating actionable insights to enhance the project plan.\n", " **Given:**\n", " - **Task Allocations:** {task_allocations}\n", " - **Schedule:** {schedule}\n", " - **Risk Analysis:** {risks}\n", " **Your objectives are to:**\n", " 1. **Generate Critical Insights:**\n", " - Analyze the current task allocations, schedule, and risk assessments to identify areas for improvement.\n", " - Highlight any potential bottlenecks, resource conflicts, or high-risk tasks that may jeopardize project success.\n", " 2. **Recommend Enhancements:**\n", " - Suggest adjustments to task assignments or scheduling to mitigate identified risks.\n", " - Propose strategies to optimize resource utilization and streamline workflow.\n", " **Requirements:**\n", " - Ensure that all recommendations aim to reduce the overall project risk score.\n", " - Provide clear and actionable suggestions that can be implemented in subsequent iterations.\n", " \"\"\"\n", " insights = llm.invoke(prompt).content\n", " return {\"insights\": insights}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The proposed agentic workflow contains a conditional routing in which the logic was built around the overall risk score of the project plan. The task scheduling and task assignment is carried out at least twice in a 'self-reflection' in order to minimize the overall project risk assigned in each iteration as part of the `risk_assessment_node`. If the risk was reduced the agent finishes its task, otherwise tries to self-reflect using an `insight_generation_node` from which the insights fed back to the scheduler_node." ] }, { "cell_type": "code", "execution_count": 404, "metadata": {}, "outputs": [], "source": [ "def router(state: AgentState):\n", " \"\"\"LangGraph node that will route the agent to the appropriate node based on the project description\"\"\"\n", " max_iteration = state[\"max_iteration\"]\n", " iteration_number = state[\"iteration_number\"]\n", "\n", " if iteration_number < max_iteration:\n", " if len(state[\"project_risk_score_iterations\"])>1:\n", " if state[\"project_risk_score_iterations\"][-1] < state[\"project_risk_score_iterations\"][0]:\n", " return END\n", " else:\n", " return \"insight_generator\"\n", " else:\n", " return \"insight_generator\"\n", " else:\n", " return END" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a last remainign step, let's create an agentic workflow using LangGraph." ] }, { "cell_type": "code", "execution_count": 405, "metadata": {}, "outputs": [], "source": [ "# Instantiate the workflow \n", "workflow = StateGraph(AgentState)\n", "\n", "# Add nodes to the workflow\n", "workflow.add_node(\"task_generation\", task_generation_node)\n", "workflow.add_node(\"task_dependencies\", task_dependency_node)\n", "workflow.add_node(\"task_scheduler\", task_scheduler_node)\n", "workflow.add_node(\"task_allocator\", task_allocation_node)\n", "workflow.add_node(\"risk_assessor\", risk_assessment_node)\n", "workflow.add_node(\"insight_generator\", insight_generation_node)\n", "\n", "# Add edges to the workflow\n", "workflow.set_entry_point(\"task_generation\")\n", "workflow.add_edge(\"task_generation\", \"task_dependencies\")\n", "workflow.add_edge(\"task_dependencies\", \"task_scheduler\")\n", "workflow.add_edge(\"task_scheduler\", \"task_allocator\")\n", "workflow.add_edge(\"task_allocator\", \"risk_assessor\")\n", "workflow.add_conditional_edges(\"risk_assessor\", router, [\"insight_generator\", END])\n", "workflow.add_edge(\"insight_generator\", \"task_scheduler\")\n", "\n", "# Set up memory\n", "memory = MemorySaver()\n", "\n", "# Compile the workflow\n", "graph_plan = workflow.compile(checkpointer=memory)" ] }, { "cell_type": "code", "execution_count": 406, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# To visualize the created workflow, we can use \n", "display(Image(graph_plan.get_graph(xray=1).draw_mermaid_png()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Usage Example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Initiate of the AgentState by defining an input\n", "Our Project Manager Agent requires a project description (str) and a team (Team) input next to other initialization parameters.\n", "In this tutorial we provide two dummy input under `data`. The team is defined as a csv file, composed of 2 colums: Name,Profile Description" ] }, { "cell_type": "code", "execution_count": 407, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Our business aims to deliver a chatbot application for our customers to ensure 24/7 support and advice on product choices.\n", "team_members=[TeamMember(name='Alice', profile=' Alice is a Frontend Developer skilled in HTML CSS JavaScript and React.'), TeamMember(name='Bob', profile=' Bob is a Backend Developer proficient in Python Django SQL and RESTful APIs.'), TeamMember(name='Charlie', profile=' Charlie is a Project Manager experienced in Agile methodologies team leadership project planning and risk management.'), TeamMember(name='David', profile=' David is a Full Stack Developer with expertise in both frontend (HTML CSS JavaScript) and backend (Node.js MongoDB) technologies.'), TeamMember(name='Eve', profile=' Eve is a DevOps Engineer skilled in CI/CD pipelines Docker Kubernetes and cloud services like AWS and Azure.'), TeamMember(name='Frank', profile=' Frank is a Junior Frontend Developer with knowledge in HTML CSS JavaScript and basic React.'), TeamMember(name='Grace', profile=' Grace is a Senior Data Scientist with expertise in machine learning data analysis Python R and big data technologies like Hadoop and Spark.')]\n" ] } ], "source": [ "def get_project_description(file_path:str):\n", " \"\"\"Read the project description from the file\"\"\"\n", " with open(file_path, 'r') as file:\n", " content = file.read()\n", "\n", " return content\n", "\n", "def get_team(file_path:str):\n", " \"\"\"Read the team members from the CSV file\"\"\"\n", " team_df = pd.read_csv(file_path)\n", " team_members = [\n", " TeamMember(name=row['Name'], profile=row['Profile Description'])\n", " for _, row in team_df.iterrows()\n", " ]\n", " team = Team(team_members=team_members)\n", "\n", " return team\n", "\n", "project_description = get_project_description(\"../data/project_manager_assistant/project_description.txt\")\n", "team = get_team(\"../data/project_manager_assistant/team.csv\")\n", "\n", "print(project_description)\n", "print(team)" ] }, { "cell_type": "code", "execution_count": 408, "metadata": {}, "outputs": [], "source": [ "# Definition of the AgentState \n", "state_input = {\n", " \"project_description\": project_description,\n", " \"team\": team,\n", " \"insights\": \"\",\n", " \"iteration_number\": 0,\n", " \"max_iteration\": 3,\n", " \"schedule_iteration\": [],\n", " \"task_allocations_iteration\": [],\n", " \"risks_iteration\": [],\n", " \"project_risk_score_iterations\": []\n", "}" ] }, { "cell_type": "code", "execution_count": 409, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Current node: task_generation\n", "Current node: task_dependencies\n", "Current node: task_scheduler\n", "Current node: task_allocator\n", "Current node: risk_assessor\n", "Current node: insight_generator\n", "Current node: task_scheduler\n", "Current node: task_allocator\n", "Current node: risk_assessor\n", "Current node: insight_generator\n", "Current node: task_scheduler\n", "Current node: task_allocator\n", "Current node: risk_assessor\n" ] } ], "source": [ "# Invoke the agent\n", "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", "for event in graph_plan.stream(state_input, config, stream_mode=[\"updates\"]):\n", " \"Print the different nodes as the agent progresses\"\n", " print(f\"Current node: {next(iter(event[1]))}\")\n" ] }, { "cell_type": "code", "execution_count": 410, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "[38, 38, 38]\n" ] } ], "source": [ "# Retrive the final state\n", "final_state = graph_plan.get_state(config).values\n", "print(final_state['iteration_number'])\n", "print(final_state['project_risk_score_iterations'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see from the final_state the agentic workflow ended up having at least 2 iterations, and under `project_risk_score_iterations` we may see evolution of the project risk score. Even if the overall risk score does not descrease between iterations (additional prompt engineering can potentially improve it), we can assume that by increasing the project timeline (e.g., iteration #2) - the risk should descrease." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Visualize the results\n", "To better understand the output of the agentic workflow - here we provide visualizations for:\n", "- Project plan - Gantt-char for all created scenarios" ] }, { "cell_type": "code", "execution_count": 411, "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "alignmentgroup": "True", "base": [ "2024-12-15T00:04:41.375174", "2024-12-26T00:04:41.375174" ], "hovertemplate": "Team Member=Alice
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Alice", "marker": { "color": "#636efa", "pattern": { "shape": "" } }, "name": "Alice", "offsetgroup": "Alice", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 518400000, 345600000 ], "xaxis": "x", "y": [ "User Acceptance Testing (UAT)", "Create User Documentation" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-27T00:04:41.375174" ], "hovertemplate": "Team Member=Bob
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Bob", "marker": { "color": "#EF553B", "pattern": { "shape": "" } }, "name": "Bob", "offsetgroup": "Bob", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 604800000 ], "xaxis": "x", "y": [ "Design Chatbot Architecture" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-19T00:04:41.375174" ], "hovertemplate": "Team Member=Charlie
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Charlie", "marker": { "color": "#00cc96", "pattern": { "shape": "" } }, "name": "Charlie", "offsetgroup": "Charlie", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 172800000 ], "xaxis": "x", "y": [ "Define Project Scope" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-05T00:04:41.375174" ], "hovertemplate": "Team Member=David
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "David", "marker": { "color": "#ab63fa", "pattern": { "shape": "" } }, "name": "David", "offsetgroup": "David", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 777600000 ], "xaxis": "x", "y": [ "Develop Chatbot Prototype" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-22T00:04:41.375174" ], "hovertemplate": "Team Member=Eve
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Eve", "marker": { "color": "#FFA15A", "pattern": { "shape": "" } }, "name": "Eve", "offsetgroup": "Eve", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 259200000 ], "xaxis": "x", "y": [ "Deploy Chatbot Application" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-26T00:04:41.375174" ], "hovertemplate": "Team Member=Frank
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Frank", "marker": { "color": "#19d3f3", "pattern": { "shape": "" } }, "name": "Frank", "offsetgroup": "Frank", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 432000000 ], "xaxis": "x", "y": [ "Monitor and Optimize Performance" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-22T00:04:41.375174", "2024-12-26T00:04:41.375174" ], "hovertemplate": "Team Member=Grace
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Grace", "marker": { "color": "#FF6692", "pattern": { "shape": "" } }, "name": "Grace", "offsetgroup": "Grace", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 345600000, 518400000 ], "xaxis": "x", "y": [ "Conduct Market Research", "Marketing and Promotion" ], "yaxis": "y" } ], "layout": { "barmode": "overlay", "legend": { "title": { "text": "Team Member" }, "tracegroupgap": 0 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "fillpattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } }, "title": { "text": "Gantt Chart - Iteration:1 ", "x": 0.5 }, "xaxis": { "anchor": "y", "domain": [ 0, 1 ], "title": { "text": "Timeline" }, "type": "date" }, "yaxis": { "anchor": "x", "autorange": "reversed", "domain": [ 0, 1 ], "title": { "text": "Tasks" } } } } }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "alignmentgroup": "True", "base": [ "2024-12-15T00:04:41.449895" ], "hovertemplate": "Team Member=Alice
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Alice", "marker": { "color": "#636efa", "pattern": { "shape": "" } }, "name": "Alice", "offsetgroup": "Alice", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 518400000 ], "xaxis": "x", "y": [ "User Acceptance Testing (UAT)" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-27T00:04:41.449895", "2025-01-06T00:04:41.449895" ], "hovertemplate": "Team Member=Bob
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Bob", "marker": { "color": "#EF553B", "pattern": { "shape": "" } }, "name": "Bob", "offsetgroup": "Bob", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 604800000, 518400000 ], "xaxis": "x", "y": [ "Design Chatbot Architecture", "Marketing and Promotion" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-19T00:04:41.449895" ], "hovertemplate": "Team Member=Charlie
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Charlie", "marker": { "color": "#00cc96", "pattern": { "shape": "" } }, "name": "Charlie", "offsetgroup": "Charlie", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 172800000 ], "xaxis": "x", "y": [ "Define Project Scope" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-05T00:04:41.449895" ], "hovertemplate": "Team Member=David
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "David", "marker": { "color": "#ab63fa", "pattern": { "shape": "" } }, "name": "David", "offsetgroup": "David", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 777600000 ], "xaxis": "x", "y": [ "Develop Chatbot Prototype" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-22T00:04:41.449895" ], "hovertemplate": "Team Member=Eve
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Eve", "marker": { "color": "#FFA15A", "pattern": { "shape": "" } }, "name": "Eve", "offsetgroup": "Eve", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 259200000 ], "xaxis": "x", "y": [ "Deploy Chatbot Application" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-26T00:04:41.449895", "2025-01-01T00:04:41.449895" ], "hovertemplate": "Team Member=Frank
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Frank", "marker": { "color": "#19d3f3", "pattern": { "shape": "" } }, "name": "Frank", "offsetgroup": "Frank", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 432000000, 345600000 ], "xaxis": "x", "y": [ "Monitor and Optimize Performance", "Create User Documentation" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-22T00:04:41.449895" ], "hovertemplate": "Team Member=Grace
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Grace", "marker": { "color": "#FF6692", "pattern": { "shape": "" } }, "name": "Grace", "offsetgroup": "Grace", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 345600000 ], "xaxis": "x", "y": [ "Conduct Market Research" ], "yaxis": "y" } ], "layout": { "barmode": "overlay", "legend": { "title": { "text": "Team Member" }, "tracegroupgap": 0 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "fillpattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } }, "title": { "text": "Gantt Chart - Iteration:2 ", "x": 0.5 }, "xaxis": { "anchor": "y", "domain": [ 0, 1 ], "title": { "text": "Timeline" }, "type": "date" }, "yaxis": { "anchor": "x", "autorange": "reversed", "domain": [ 0, 1 ], "title": { "text": "Tasks" } } } } }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "alignmentgroup": "True", "base": [ "2024-12-15T00:04:41.518581", "2024-12-26T00:04:41.518581" ], "hovertemplate": "Team Member=Alice
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Alice", "marker": { "color": "#636efa", "pattern": { "shape": "" } }, "name": "Alice", "offsetgroup": "Alice", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 518400000, 345600000 ], "xaxis": "x", "y": [ "User Acceptance Testing (UAT)", "Create User Documentation" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-27T00:04:41.518581", "2025-01-01T00:04:41.518581" ], "hovertemplate": "Team Member=Bob
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Bob", "marker": { "color": "#EF553B", "pattern": { "shape": "" } }, "name": "Bob", "offsetgroup": "Bob", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 604800000, 518400000 ], "xaxis": "x", "y": [ "Design Chatbot Architecture", "Marketing and Promotion" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-19T00:04:41.518581" ], "hovertemplate": "Team Member=Charlie
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Charlie", "marker": { "color": "#00cc96", "pattern": { "shape": "" } }, "name": "Charlie", "offsetgroup": "Charlie", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 172800000 ], "xaxis": "x", "y": [ "Define Project Scope" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-05T00:04:41.518581" ], "hovertemplate": "Team Member=David
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "David", "marker": { "color": "#ab63fa", "pattern": { "shape": "" } }, "name": "David", "offsetgroup": "David", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 777600000 ], "xaxis": "x", "y": [ "Develop Chatbot Prototype" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-22T00:04:41.518581" ], "hovertemplate": "Team Member=Eve
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Eve", "marker": { "color": "#FFA15A", "pattern": { "shape": "" } }, "name": "Eve", "offsetgroup": "Eve", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 259200000 ], "xaxis": "x", "y": [ "Deploy Chatbot Application" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-26T00:04:41.518581" ], "hovertemplate": "Team Member=Frank
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Frank", "marker": { "color": "#19d3f3", "pattern": { "shape": "" } }, "name": "Frank", "offsetgroup": "Frank", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 432000000 ], "xaxis": "x", "y": [ "Monitor and Optimize Performance" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-22T00:04:41.518581" ], "hovertemplate": "Team Member=Grace
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Grace", "marker": { "color": "#FF6692", "pattern": { "shape": "" } }, "name": "Grace", "offsetgroup": "Grace", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 345600000 ], "xaxis": "x", "y": [ "Conduct Market Research" ], "yaxis": "y" } ], "layout": { "barmode": "overlay", "legend": { "title": { "text": "Team Member" }, "tracegroupgap": 0 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "fillpattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } }, "title": { "text": "Gantt Chart - Iteration:3 ", "x": 0.5 }, "xaxis": { "anchor": "y", "domain": [ 0, 1 ], "title": { "text": "Timeline" }, "type": "date" }, "yaxis": { "anchor": "x", "autorange": "reversed", "domain": [ 0, 1 ], "title": { "text": "Tasks" } } } } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Visalize Project timeline\n", "number_of_iterations = final_state['iteration_number']\n", "\n", "for i in range(number_of_iterations):\n", " ## Tasks schedule\n", " task_schedules = final_state['schedule_iteration'][i].schedule\n", "\n", " t = []\n", " # Iterate over the task_schedules and append each task's data to the DataFrame\n", " for task_schedule in task_schedules:\n", " t.append([\n", " task_schedule.task.task_name,\n", " task_schedule.start_day,\n", " task_schedule.end_day\n", " ])\n", "\n", " df_schedule = pd.DataFrame(t,columns=['task_name', 'start', 'end'])\n", "\n", " ## Tasks allocation\n", " task_allocations = final_state['task_allocations_iteration'][i].task_allocations\n", "\n", " t = []\n", " # Iterate over the task_schedules and append each task's data to the DataFrame\n", " for task_allocation in task_allocations:\n", " t.append([\n", " task_allocation.task.task_name,\n", " task_allocation.team_member.name\n", " ])\n", "\n", " df_allocation = pd.DataFrame(t,columns=['task_name', 'team_member'])\n", "\n", " df = df_allocation.merge(df_schedule, on='task_name')\n", "\n", " import plotly.express as px\n", "\n", " from datetime import datetime, timedelta\n", " # Get the current date\n", " current_date = datetime.today()\n", "\n", " # Convert start and end offsets to actual dates\n", " df['start'] = df['start'].apply(lambda x: current_date + timedelta(days=x))\n", " df['end'] = df['end'].apply(lambda x: current_date + timedelta(days=x))\n", "\n", " df.rename(columns={'team_member': 'Team Member'}, inplace=True)\n", " df.sort_values(by='Team Member', inplace=True)\n", " # Create a Gantt chart\n", " fig = px.timeline(df, x_start=\"start\", x_end=\"end\", y=\"task_name\", color=\"Team Member\", title=f\"Gantt Chart - Iteration:{i+1} \")\n", "\n", " # Update layout for better visualization\n", " fig.update_layout(\n", " xaxis_title=\"Timeline\",\n", " yaxis_title=\"Tasks\",\n", " yaxis=dict(autorange=\"reversed\"), # Reverse the y-axis to have tasks in the vertical side\n", " title_x=0.5\n", " )\n", "\n", " # Show the plot\n", " fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparison\n", "\n", "As a comparison, we have implemented a simple agent composed of only 1 node aiming create a project plan as a 1-short.\n", "The input remained the `project_description` and the `team`. The prompt became the combination of the each node - except the risk and insight generations.\n", "The single node agent with the simplied stage could create a project plan.\n", "\n", "However, the expected complex structured response may not always be achieved by the LLM, resulting in error at downstream processing steps. In addition, a multi-agent solution allows for incorporation of self-reflection at different stages of the planning (in the future even human-in-the-loop) even including new information via user interactions (e.g. sickness , holidays of people team members).\n", "\n" ] }, { "cell_type": "code", "execution_count": 412, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "class ProjectPlan(BaseModel):\n", " tasks: TaskList\n", " dependencies: DependencyList\n", " schedule: Schedule\n", " task_allocations: TaskAllocationList\n", "\n", "class SimpleAgentState(TypedDict):\n", " \"\"\"The project manager agent state.\"\"\"\n", " project_description: str\n", " team: Team\n", " tasks: TaskList\n", " dependencies: DependencyList\n", " schedule: Schedule\n", " task_allocations: TaskAllocationList\n", "\n", "def project_plan_generation_node(state: SimpleAgentState):\n", " \"\"\"LangGraph node that will extract tasks from given project description\"\"\"\n", " description = state[\"project_description\"]\n", " team = state[\"team\"]\n", " prompt = f\"\"\"You are an experienced project description analyzer, who needs to create a project plan.\n", " Create the project plan using the following steps:\n", " - Analyze the project description '{description}' and create a list of actionable and realistic tasks with estimated time (in days) to complete each task. If the task takes longer than 5 days, break it down into independent smaller tasks.\n", " - Assess dependency between tasks. For each task, identify the blocking tasks. Provide for each task the list of dependent tasks.\n", " - Schedule tasks based on the dependencies.\n", " - Allocate tasks to team members {team} based on their skills and availability, such that there is no overlapping task assigned for a team member. Ensure that no team member has 2 tasks assigned for the same time period.\n", " \"\"\"\n", " structure_llm = llm.with_structured_output(ProjectPlan)\n", " project_plan: ProjectPlan = structure_llm.invoke(prompt)\n", " print(project_plan)\n", " return {\"tasks\": project_plan.tasks, \"dependencies\": project_plan.dependencies, \"schedule\": project_plan.schedule, \"task_allocations\": project_plan.task_allocations}\n", "\n", "\n", "# Instantiate the workflow \n", "simple_workflow = StateGraph(SimpleAgentState)\n", "\n", "# Add nodes to the workflow\n", "simple_workflow.add_node(\"create_project_plan\", project_plan_generation_node)\n", "\n", "# Add edges to the workflow\n", "simple_workflow.set_entry_point(\"create_project_plan\")\n", "simple_workflow.add_edge(\"create_project_plan\", END)\n", "\n", "# Set up memory\n", "simple_memory = MemorySaver()\n", "\n", "# Compile the workflow\n", "simple_graph_plan = simple_workflow.compile(checkpointer=memory)\n", "\n", "# To visualize the created workflow, we can use \n", "display(Image(simple_graph_plan.get_graph(xray=1).draw_mermaid_png()))\n", "\n" ] }, { "cell_type": "code", "execution_count": 413, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tasks=TaskList(tasks=[Task(id=UUID('4addec1e-c3a4-41b8-886e-3bfecc9e4ebe'), task_name='Requirements Gathering', task_description='Gather requirements from stakeholders about the chatbot features and functionalities.', estimated_day=3), Task(id=UUID('cd3b2ccd-a274-4122-87e5-792c416e63bc'), task_name='Design Chatbot Architecture', task_description='Create the architecture of the chatbot application including frontend and backend design.', estimated_day=5), Task(id=UUID('e41834d4-afe8-46b9-8519-e4a2cd8aae15'), task_name='Frontend Development', task_description='Develop the user interface for the chatbot using HTML, CSS, and JavaScript.', estimated_day=7), Task(id=UUID('7b2710d8-b9e9-4028-8a26-435e6e89159c'), task_name='Backend Development', task_description='Set up the backend for the chatbot using Python and Django.', estimated_day=7), Task(id=UUID('232113dc-aef2-4c86-b8ba-43747e58d264'), task_name='Integrate Frontend and Backend', task_description='Integrate the frontend and backend components of the chatbot application.', estimated_day=3), Task(id=UUID('ca7f94ed-4eb3-4af0-88c5-c0b0aa478168'), task_name='Testing and QA', task_description='Conduct testing and quality assurance for the chatbot application.', estimated_day=4), Task(id=UUID('de60cddf-9831-4307-a5eb-cd19f2475bc6'), task_name='Deployment', task_description='Deploy the chatbot application to a cloud platform.', estimated_day=3), Task(id=UUID('a7f21afa-d2bb-4cb2-9f91-8985eeaac71b'), task_name='Post-Deployment Support', task_description='Provide post-deployment support and bug fixes for the chatbot application.', estimated_day=3)]) dependencies=DependencyList(dependencies=[TaskDependency(task=Task(id=UUID('d2654503-74f3-432b-b455-f9024f688a43'), task_name='Requirements Gathering', task_description='Gather requirements from stakeholders about the chatbot features and functionalities.', estimated_day=3), dependent_tasks=[Task(id=UUID('c2541e7a-c96e-4024-83d2-15c2716c75d0'), task_name='Design Chatbot Architecture', task_description='Create the architecture of the chatbot application including frontend and backend design.', estimated_day=5)]), TaskDependency(task=Task(id=UUID('f75fd162-0c48-406c-954c-7bfb55533a5a'), task_name='Design Chatbot Architecture', task_description='Create the architecture of the chatbot application including frontend and backend design.', estimated_day=5), dependent_tasks=[Task(id=UUID('2d58b977-bf73-4969-b569-ea5796e25431'), task_name='Frontend Development', task_description='Develop the user interface for the chatbot using HTML, CSS, and JavaScript.', estimated_day=7), Task(id=UUID('97a551b1-bf24-47a9-b1a3-353cbde711e2'), task_name='Backend Development', task_description='Set up the backend for the chatbot using Python and Django.', estimated_day=7)]), TaskDependency(task=Task(id=UUID('05d335b9-7733-49c7-962b-be3d81d1dfed'), task_name='Backend Development', task_description='Set up the backend for the chatbot using Python and Django.', estimated_day=7), dependent_tasks=[Task(id=UUID('0d5d648f-d12a-4d00-9357-61468a1fd9aa'), task_name='Integrate Frontend and Backend', task_description='Integrate the frontend and backend components of the chatbot application.', estimated_day=3)]), TaskDependency(task=Task(id=UUID('8340fd6d-e8a5-430b-97ae-46de2141c0f4'), task_name='Frontend Development', task_description='Develop the user interface for the chatbot using HTML, CSS, and JavaScript.', estimated_day=7), dependent_tasks=[Task(id=UUID('80382386-eacc-45b3-b147-af6b3c8a1ebf'), task_name='Integrate Frontend and Backend', task_description='Integrate the frontend and backend components of the chatbot application.', estimated_day=3)]), TaskDependency(task=Task(id=UUID('fa43ac3a-01f9-4cad-b900-cb33a08e2323'), task_name='Integrate Frontend and Backend', task_description='Integrate the frontend and backend components of the chatbot application.', estimated_day=3), dependent_tasks=[Task(id=UUID('54068596-0ac9-4b36-8963-930bbc5f89a1'), task_name='Testing and QA', task_description='Conduct testing and quality assurance for the chatbot application.', estimated_day=4)]), TaskDependency(task=Task(id=UUID('4b82aeb1-8d35-41a1-8924-55509f91b8bf'), task_name='Testing and QA', task_description='Conduct testing and quality assurance for the chatbot application.', estimated_day=4), dependent_tasks=[Task(id=UUID('be3cbd0a-5e34-4cd4-a9ba-7b7ecd252074'), task_name='Deployment', task_description='Deploy the chatbot application to a cloud platform.', estimated_day=3)]), TaskDependency(task=Task(id=UUID('a436ba1a-5804-4ca2-9534-7ff3e93e3864'), task_name='Deployment', task_description='Deploy the chatbot application to a cloud platform.', estimated_day=3), dependent_tasks=[Task(id=UUID('673909e0-3806-4e4d-9fd4-120d57dbf912'), task_name='Post-Deployment Support', task_description='Provide post-deployment support and bug fixes for the chatbot application.', estimated_day=3)])]) schedule=Schedule(schedule=[TaskSchedule(task=Task(id=UUID('d4d98552-61a5-433c-8454-83197da75e51'), task_name='Requirements Gathering', task_description='Gather requirements from stakeholders about the chatbot features and functionalities.', estimated_day=3), start_day=1, end_day=3), TaskSchedule(task=Task(id=UUID('f13cf1a8-2aeb-48ed-9dc9-35d6767c0a0a'), task_name='Design Chatbot Architecture', task_description='Create the architecture of the chatbot application including frontend and backend design.', estimated_day=5), start_day=4, end_day=8), TaskSchedule(task=Task(id=UUID('403fbfb2-ae48-4591-89de-ccb0bcea0122'), task_name='Frontend Development', task_description='Develop the user interface for the chatbot using HTML, CSS, and JavaScript.', estimated_day=7), start_day=9, end_day=15), TaskSchedule(task=Task(id=UUID('98016950-0f73-44b8-adbf-3c117d8f6685'), task_name='Backend Development', task_description='Set up the backend for the chatbot using Python and Django.', estimated_day=7), start_day=9, end_day=15), TaskSchedule(task=Task(id=UUID('2bf0bc35-71bf-4c01-834c-7c84cc57902f'), task_name='Integrate Frontend and Backend', task_description='Integrate the frontend and backend components of the chatbot application.', estimated_day=3), start_day=16, end_day=18), TaskSchedule(task=Task(id=UUID('60d20758-3067-46fa-b425-d6d67b666942'), task_name='Testing and QA', task_description='Conduct testing and quality assurance for the chatbot application.', estimated_day=4), start_day=19, end_day=22), TaskSchedule(task=Task(id=UUID('e2ef4752-0679-4caf-a773-3b06c94ac7f3'), task_name='Deployment', task_description='Deploy the chatbot application to a cloud platform.', estimated_day=3), start_day=23, end_day=25), TaskSchedule(task=Task(id=UUID('ba7a7fe3-094d-490b-bc47-bd54ca25d04b'), task_name='Post-Deployment Support', task_description='Provide post-deployment support and bug fixes for the chatbot application.', estimated_day=3), start_day=26, end_day=28)]) task_allocations=TaskAllocationList(task_allocations=[TaskAllocation(task=Task(id=UUID('eb47af24-a4d0-469a-945a-53be9baa4492'), task_name='Requirements Gathering', task_description='Gather requirements from stakeholders about the chatbot features and functionalities.', estimated_day=3), team_member=TeamMember(name='Charlie', profile=' Charlie is a Project Manager experienced in Agile methodologies team leadership project planning and risk management.')), TaskAllocation(task=Task(id=UUID('403a8a30-c1c9-4aec-a61f-3dfef18b0eb7'), task_name='Design Chatbot Architecture', task_description='Create the architecture of the chatbot application including frontend and backend design.', estimated_day=5), team_member=TeamMember(name='Bob', profile=' Bob is a Backend Developer proficient in Python Django SQL and RESTful APIs.')), TaskAllocation(task=Task(id=UUID('2a734eee-cbfa-49e8-b3ba-4e54eafa51c3'), task_name='Frontend Development', task_description='Develop the user interface for the chatbot using HTML, CSS, and JavaScript.', estimated_day=7), team_member=TeamMember(name='Alice', profile=' Alice is a Frontend Developer skilled in HTML CSS JavaScript and React.')), TaskAllocation(task=Task(id=UUID('e7ebeb83-5dc2-4b67-b8b3-a633f1daf551'), task_name='Backend Development', task_description='Set up the backend for the chatbot using Python and Django.', estimated_day=7), team_member=TeamMember(name='David', profile=' David is a Full Stack Developer with expertise in both frontend (HTML CSS JavaScript) and backend (Node.js MongoDB) technologies.')), TaskAllocation(task=Task(id=UUID('9d5f9e25-ab62-4dd0-b8eb-19538d3c9a87'), task_name='Integrate Frontend and Backend', task_description='Integrate the frontend and backend components of the chatbot application.', estimated_day=3), team_member=TeamMember(name='Frank', profile=' Frank is a Junior Frontend Developer with knowledge in HTML CSS JavaScript and basic React.')), TaskAllocation(task=Task(id=UUID('a0996072-a35e-499a-903e-a7ce04c2c681'), task_name='Testing and QA', task_description='Conduct testing and quality assurance for the chatbot application.', estimated_day=4), team_member=TeamMember(name='Eve', profile=' Eve is a DevOps Engineer skilled in CI/CD pipelines Docker Kubernetes and cloud services like AWS and Azure.')), TaskAllocation(task=Task(id=UUID('8db9696e-d68a-41cd-a884-388c8804b737'), task_name='Deployment', task_description='Deploy the chatbot application to a cloud platform.', estimated_day=3), team_member=TeamMember(name='Charlie', profile=' Charlie is a Project Manager experienced in Agile methodologies team leadership project planning and risk management.')), TaskAllocation(task=Task(id=UUID('f113d200-54b2-4593-858d-0ba7f3c92bb3'), task_name='Post-Deployment Support', task_description='Provide post-deployment support and bug fixes for the chatbot application.', estimated_day=3), team_member=TeamMember(name='Grace', profile=' Grace is a Senior Data Scientist with expertise in machine learning data analysis Python R and big data technologies like Hadoop and Spark.'))])\n", "Current node: create_project_plan\n" ] } ], "source": [ "# Invoke the agent\n", "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", "for event in simple_graph_plan.stream(state_input, config, stream_mode=[\"updates\"]):\n", " \"Print the different nodes as the agent progresses\"\n", " print(f\"Current node: {next(iter(event[1]))}\")\n", " \n", "simple_final_state = simple_graph_plan.get_state(config).values" ] }, { "cell_type": "code", "execution_count": 414, "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "alignmentgroup": "True", "base": [ "2024-11-27T00:04:52.792699" ], "hovertemplate": "Team Member=Alice
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Alice", "marker": { "color": "#636efa", "pattern": { "shape": "" } }, "name": "Alice", "offsetgroup": "Alice", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 518400000 ], "xaxis": "x", "y": [ "Frontend Development" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-22T00:04:52.792699" ], "hovertemplate": "Team Member=Bob
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Bob", "marker": { "color": "#EF553B", "pattern": { "shape": "" } }, "name": "Bob", "offsetgroup": "Bob", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 345600000 ], "xaxis": "x", "y": [ "Design Chatbot Architecture" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-19T00:04:52.792699", "2024-12-11T00:04:52.792699" ], "hovertemplate": "Team Member=Charlie
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Charlie", "marker": { "color": "#00cc96", "pattern": { "shape": "" } }, "name": "Charlie", "offsetgroup": "Charlie", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 172800000, 172800000 ], "xaxis": "x", "y": [ "Requirements Gathering", "Deployment" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-11-27T00:04:52.792699" ], "hovertemplate": "Team Member=David
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "David", "marker": { "color": "#ab63fa", "pattern": { "shape": "" } }, "name": "David", "offsetgroup": "David", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 518400000 ], "xaxis": "x", "y": [ "Backend Development" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-07T00:04:52.792699" ], "hovertemplate": "Team Member=Eve
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Eve", "marker": { "color": "#FFA15A", "pattern": { "shape": "" } }, "name": "Eve", "offsetgroup": "Eve", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 259200000 ], "xaxis": "x", "y": [ "Testing and QA" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-04T00:04:52.792699" ], "hovertemplate": "Team Member=Frank
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Frank", "marker": { "color": "#19d3f3", "pattern": { "shape": "" } }, "name": "Frank", "offsetgroup": "Frank", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 172800000 ], "xaxis": "x", "y": [ "Integrate Frontend and Backend" ], "yaxis": "y" }, { "alignmentgroup": "True", "base": [ "2024-12-14T00:04:52.792699" ], "hovertemplate": "Team Member=Grace
start=%{base}
end=%{x}
task_name=%{y}", "legendgroup": "Grace", "marker": { "color": "#FF6692", "pattern": { "shape": "" } }, "name": "Grace", "offsetgroup": "Grace", "orientation": "h", "showlegend": true, "textposition": "auto", "type": "bar", "x": [ 172800000 ], "xaxis": "x", "y": [ "Post-Deployment Support" ], "yaxis": "y" } ], "layout": { "barmode": "overlay", "legend": { "title": { "text": "Team Member" }, "tracegroupgap": 0 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "fillpattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } }, "title": { "text": "Gantt Chart - Oneshot Project Plan", "x": 0.5 }, "xaxis": { "anchor": "y", "domain": [ 0, 1 ], "title": { "text": "Timeline" }, "type": "date" }, "yaxis": { "anchor": "x", "autorange": "reversed", "domain": [ 0, 1 ], "title": { "text": "Tasks" } } } } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "## Tasks schedule\n", "task_schedules = simple_final_state['schedule'].schedule\n", "\n", "t = []\n", "# Iterate over the task_schedules and append each task's data to the DataFrame\n", "for task_schedule in task_schedules:\n", " t.append([\n", " task_schedule.task.task_name,\n", " task_schedule.start_day,\n", " task_schedule.end_day\n", " ])\n", "\n", "df_schedule = pd.DataFrame(t,columns=['task_name', 'start', 'end'])\n", "\n", "## Tasks allocation\n", "task_allocations = simple_final_state['task_allocations'].task_allocations\n", "\n", "t = []\n", "# Iterate over the task_schedules and append each task's data to the DataFrame\n", "for task_allocation in task_allocations:\n", " t.append([\n", " task_allocation.task.task_name,\n", " task_allocation.team_member.name\n", " ])\n", "\n", "df_allocation = pd.DataFrame(t,columns=['task_name', 'team_member'])\n", "\n", "df = df_allocation.merge(df_schedule, on='task_name')\n", "\n", "import plotly.express as px\n", "\n", "from datetime import datetime, timedelta\n", "# Get the current date\n", "current_date = datetime.today()\n", "\n", "# Convert start and end offsets to actual dates\n", "df['start'] = df['start'].apply(lambda x: current_date + timedelta(days=x))\n", "df['end'] = df['end'].apply(lambda x: current_date + timedelta(days=x))\n", "\n", "df.rename(columns={'team_member': 'Team Member'}, inplace=True)\n", "df.sort_values(by='Team Member', inplace=True)\n", "# Create a Gantt chart\n", "fig = px.timeline(df, x_start=\"start\", x_end=\"end\", y=\"task_name\", color=\"Team Member\", title=f\"Gantt Chart - Oneshot Project Plan\")\n", "\n", "# Update layout for better visualization\n", "fig.update_layout(\n", " xaxis_title=\"Timeline\",\n", " yaxis_title=\"Tasks\",\n", " yaxis=dict(autorange=\"reversed\"), # Reverse the y-axis to have tasks in the vertical side\n", " title_x=0.5\n", ")\n", "\n", "# Show the plot\n", "fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Additional Considerations\n", "\n", "Improvement Possibilities:\n", "- Incorporating a 'human-in-the-loop' mechanism as part of the self-reflection process can significantly enhance the system's effectiveness. This approach allows for the introduction of additional, real-time information about the schedule and the availability or status of team members. For instance, if a team member is currently sick, the agent would typically still assign tasks to them due to a lack of awareness. By integrating human oversight, such critical updates can be communicated to the system, ensuring that tasks are reassigned appropriately and the workload is distributed more efficiently.\n", "Limitations of the Approach:\n", "- Incorporating an optimizer based on extracted features generated by the LLM can provide better and more reproducible scheduling and task allocation. So only leveraging the agent to produce structured content from the project description, task dependencies and team member profiles, then use the optimizer to create the project plan (task assignment). \n", "\n", "Limitations:\n", "- The current approach relies on a Large Language Model (LLM) to assign risk scores to tasks. However, this method has inherent limitations. Even if the same person is assigned to the same task on the same schedule, the LLM may generate different risk scores each time. This inconsistency arises because the model's output can vary independently of the explicit details provided in the prompt. Consequently, this variability can lead to unpredictable risk assessments, potentially affecting the reliability and accuracy of task management.\n", "- Although the prompts instructs to fullfill certain criteria, it is not always guaranteed, that it will achieve it. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Currently no references are added to the tutorial." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://europe-west1-genai-agents-views-tracker.cloudfunctions.net/genai-agents-tracker?notebook=all-agents-tutorials--project-manager-assistant-agent)" ] } ], "metadata": { "kernelspec": { "display_name": "agents", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.7" } }, "nbformat": 4, "nbformat_minor": 2 }