{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"https://colab.research.google.com/github/microsoft/autogen/blob/main/notebook/agentchat_auto_feedback_from_code_execution.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Auto Generated Agent Chat: Task Solving with Code Generation, Execution & Debugging\n",
    "\n",
    "AutoGen offers conversable LLM agents, which can be used to solve various tasks with human or automatic feedback, including tasks that require using tools via code.\n",
    "Please find documentation about this feature [here](https://microsoft.github.io/autogen/docs/Use-Cases/agent_chat).\n",
    "\n",
    "In this notebook, we demonstrate how to use `AssistantAgent` and `UserProxyAgent` to write code and execute the code. Here `AssistantAgent` is an LLM-based agent that can write Python code (in a Python coding block) for a user to execute for a given task. `UserProxyAgent` is an agent which serves as a proxy for the human user to execute the code written by `AssistantAgent`, or automatically execute the code. Depending on the setting of `human_input_mode` and `max_consecutive_auto_reply`, the `UserProxyAgent` either solicits feedback from the human user or returns auto-feedback based on the result of code execution (success or failure and corresponding outputs) to `AssistantAgent`. `AssistantAgent` will debug the code and suggest new code if the result contains error. The two agents keep communicating to each other until the task is done.\n",
    "\n",
    "## Requirements\n",
    "\n",
    "AutoGen requires `Python>=3.8`. To run this notebook example, please install:\n",
    "```bash\n",
    "pip install pyautogen\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-02-13T23:40:52.317406Z",
     "iopub.status.busy": "2023-02-13T23:40:52.316561Z",
     "iopub.status.idle": "2023-02-13T23:40:52.321193Z",
     "shell.execute_reply": "2023-02-13T23:40:52.320628Z"
    }
   },
   "outputs": [],
   "source": [
    "# %pip install pyautogen~=0.1.0"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set your API Endpoint\n",
    "\n",
    "The [`config_list_from_json`](https://microsoft.github.io/autogen/docs/reference/oai/openai_utils#config_list_from_json) function loads a list of configurations from an environment variable or a json file.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import autogen\n",
    "\n",
    "config_list = autogen.config_list_from_json(\n",
    "    \"OAI_CONFIG_LIST\",\n",
    "    filter_dict={\n",
    "        \"model\": [\"gpt-4\", \"gpt-4-0314\", \"gpt4\", \"gpt-4-32k\", \"gpt-4-32k-0314\", \"gpt-4-32k-v0314\"],\n",
    "    },\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It first looks for environment variable \"OAI_CONFIG_LIST\" which needs to be a valid json string. If that variable is not found, it then looks for a json file named \"OAI_CONFIG_LIST\". It filters the configs by models (you can filter by other keys as well). Only the gpt-4 models are kept in the list based on the filter condition.\n",
    "\n",
    "The config list looks like the following:\n",
    "```python\n",
    "config_list = [\n",
    "    {\n",
    "        'model': 'gpt-4',\n",
    "        'api_key': '<your OpenAI API key here>',\n",
    "    },\n",
    "    {\n",
    "        'model': 'gpt-4',\n",
    "        'api_key': '<your Azure OpenAI API key here>',\n",
    "        'api_base': '<your Azure OpenAI API base here>',\n",
    "        'api_type': 'azure',\n",
    "        'api_version': '2023-06-01-preview',\n",
    "    },\n",
    "    {\n",
    "        'model': 'gpt-4-32k',\n",
    "        'api_key': '<your Azure OpenAI API key here>',\n",
    "        'api_base': '<your Azure OpenAI API base here>',\n",
    "        'api_type': 'azure',\n",
    "        'api_version': '2023-06-01-preview',\n",
    "    },\n",
    "]\n",
    "```\n",
    "\n",
    "If you open this notebook in colab, you can upload your files by clicking the file icon on the left panel and then choose \"upload file\" icon.\n",
    "\n",
    "You can set the value of config_list in other ways you prefer, e.g., loading from a YAML file."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example Task: Check Stock Price Change\n",
    "\n",
    "In the example below, let's see how to use the agents in AutoGen to write a python script and execute the script. This process involves constructing a `AssistantAgent` to serve as the assistant, along with a `UserProxyAgent` that acts as a proxy for the human user. In this example demonstrated below, when constructing the `UserProxyAgent`,  we select the `human_input_mode` to \"NEVER\". This means that the `UserProxyAgent` will not solicit feedback from the human user. It stops replying when the limit defined by `max_consecutive_auto_reply` is reached, or when `is_termination_msg()` returns true for the received message."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33muser_proxy\u001b[0m (to assistant):\n",
      "\n",
      "What date is today? Compare the year-to-date gain for META and TESLA.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to user_proxy):\n",
      "\n",
      "First, let's find out today's date. Then, we will fetch the stock prices for META (Facebook) and TESLA and calculate the year-to-date gain for both.\n",
      "\n",
      "Step 1: Get today's date\n",
      "```python\n",
      "from datetime import date\n",
      "today = date.today()\n",
      "print(\"Today's date:\", today)\n",
      "```\n",
      "\n",
      "Step 2: Fetch stock prices for META and TESLA\n",
      "We will use the `yfinance` library to fetch the stock prices. If you don't have it installed, please install it using the following command:\n",
      "\n",
      "```sh\n",
      "pip install yfinance\n",
      "```\n",
      "\n",
      "Step 3: Calculate the year-to-date gain for META and TESLA\n",
      "```python\n",
      "import yfinance as yf\n",
      "from datetime import datetime\n",
      "\n",
      "def get_ytd_gain(ticker):\n",
      "    stock = yf.Ticker(ticker)\n",
      "    start_date = datetime(today.year, 1, 1)\n",
      "    end_date = today\n",
      "    historical_data = stock.history(start=start_date, end=end_date)\n",
      "    start_price = historical_data.iloc[0]['Close']\n",
      "    end_price = historical_data.iloc[-1]['Close']\n",
      "    ytd_gain = (end_price - start_price) / start_price * 100\n",
      "    return ytd_gain\n",
      "\n",
      "meta_ytd_gain = get_ytd_gain(\"FB\")\n",
      "tesla_ytd_gain = get_ytd_gain(\"TSLA\")\n",
      "\n",
      "print(f\"Year-to-date gain for META (Facebook): {meta_ytd_gain:.2f}%\")\n",
      "print(f\"Year-to-date gain for TESLA: {tesla_ytd_gain:.2f}%\")\n",
      "```\n",
      "\n",
      "Please execute the code blocks in the order mentioned above.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 1 (inferred language is sh)...\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 2 (inferred language is python)...\u001b[0m\n",
      "\u001b[33muser_proxy\u001b[0m (to assistant):\n",
      "\n",
      "exitcode: 1 (execution failed)\n",
      "Code output: \n",
      "Today's date: 2023-08-29\n",
      "\n",
      "Defaulting to user installation because normal site-packages is not writeable\n",
      "Requirement already satisfied: yfinance in /home/vscode/.local/lib/python3.9/site-packages (0.2.26)\n",
      "Requirement already satisfied: numpy>=1.16.5 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.25.1)\n",
      "Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.9/site-packages (from yfinance) (2.31.0)\n",
      "Requirement already satisfied: lxml>=4.9.1 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (4.9.3)\n",
      "Requirement already satisfied: pytz>=2022.5 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (2023.3)\n",
      "Requirement already satisfied: frozendict>=2.3.4 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (2.3.8)\n",
      "Requirement already satisfied: multitasking>=0.0.7 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (0.0.11)\n",
      "Requirement already satisfied: beautifulsoup4>=4.11.1 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (4.12.2)\n",
      "Requirement already satisfied: pandas>=1.3.0 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.3.3)\n",
      "Requirement already satisfied: html5lib>=1.1 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.1)\n",
      "Requirement already satisfied: appdirs>=1.4.4 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.4.4)\n",
      "Requirement already satisfied: soupsieve>1.2 in /home/vscode/.local/lib/python3.9/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.4.1)\n",
      "Requirement already satisfied: six>=1.9 in /usr/local/lib/python3.9/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\n",
      "Requirement already satisfied: webencodings in /home/vscode/.local/lib/python3.9/site-packages (from html5lib>=1.1->yfinance) (0.5.1)\n",
      "Requirement already satisfied: python-dateutil>=2.7.3 in /home/vscode/.local/lib/python3.9/site-packages (from pandas>=1.3.0->yfinance) (2.8.2)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (2023.5.7)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (3.2.0)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (2.0.3)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (3.4)\n",
      "\n",
      "Traceback (most recent call last):\n",
      "  File \"\", line 14, in <module>\n",
      "    meta_ytd_gain = get_ytd_gain(\"FB\")\n",
      "  File \"\", line 6, in get_ytd_gain\n",
      "    start_date = datetime(today.year, 1, 1)\n",
      "NameError: name 'today' is not defined\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to user_proxy):\n",
      "\n",
      "Apologies for the error. It seems I forgot to include the `today` variable in the last code block. Here's the corrected code:\n",
      "\n",
      "```python\n",
      "import yfinance as yf\n",
      "from datetime import datetime, date\n",
      "\n",
      "today = date.today()\n",
      "\n",
      "def get_ytd_gain(ticker):\n",
      "    stock = yf.Ticker(ticker)\n",
      "    start_date = datetime(today.year, 1, 1)\n",
      "    end_date = today\n",
      "    historical_data = stock.history(start=start_date, end=end_date)\n",
      "    start_price = historical_data.iloc[0]['Close']\n",
      "    end_price = historical_data.iloc[-1]['Close']\n",
      "    ytd_gain = (end_price - start_price) / start_price * 100\n",
      "    return ytd_gain\n",
      "\n",
      "meta_ytd_gain = get_ytd_gain(\"FB\")\n",
      "tesla_ytd_gain = get_ytd_gain(\"TSLA\")\n",
      "\n",
      "print(f\"Year-to-date gain for META (Facebook): {meta_ytd_gain:.2f}%\")\n",
      "print(f\"Year-to-date gain for TESLA: {tesla_ytd_gain:.2f}%\")\n",
      "```\n",
      "\n",
      "Please execute this code block to get the year-to-date gain for META and TESLA.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n",
      "\u001b[33muser_proxy\u001b[0m (to assistant):\n",
      "\n",
      "exitcode: 1 (execution failed)\n",
      "Code output: \n",
      "FB: No timezone found, symbol may be delisted\n",
      "Traceback (most recent call last):\n",
      "  File \"\", line 16, in <module>\n",
      "    meta_ytd_gain = get_ytd_gain(\"FB\")\n",
      "  File \"\", line 11, in get_ytd_gain\n",
      "    start_price = historical_data.iloc[0]['Close']\n",
      "  File \"/home/vscode/.local/lib/python3.9/site-packages/pandas/core/indexing.py\", line 931, in __getitem__\n",
      "    return self._getitem_axis(maybe_callable, axis=axis)\n",
      "  File \"/home/vscode/.local/lib/python3.9/site-packages/pandas/core/indexing.py\", line 1566, in _getitem_axis\n",
      "    self._validate_integer(key, axis)\n",
      "  File \"/home/vscode/.local/lib/python3.9/site-packages/pandas/core/indexing.py\", line 1500, in _validate_integer\n",
      "    raise IndexError(\"single positional indexer is out-of-bounds\")\n",
      "IndexError: single positional indexer is out-of-bounds\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to user_proxy):\n",
      "\n",
      "I apologize for the error. It seems that the \"FB\" ticker symbol is not working as expected. Facebook has changed its parent company name to Meta Platforms, Inc., and its ticker symbol has been changed to \"META\". Let's update the code to use the new ticker symbol:\n",
      "\n",
      "```python\n",
      "import yfinance as yf\n",
      "from datetime import datetime, date\n",
      "\n",
      "today = date.today()\n",
      "\n",
      "def get_ytd_gain(ticker):\n",
      "    stock = yf.Ticker(ticker)\n",
      "    start_date = datetime(today.year, 1, 1)\n",
      "    end_date = today\n",
      "    historical_data = stock.history(start=start_date, end=end_date)\n",
      "    start_price = historical_data.iloc[0]['Close']\n",
      "    end_price = historical_data.iloc[-1]['Close']\n",
      "    ytd_gain = (end_price - start_price) / start_price * 100\n",
      "    return ytd_gain\n",
      "\n",
      "meta_ytd_gain = get_ytd_gain(\"META\")\n",
      "tesla_ytd_gain = get_ytd_gain(\"TSLA\")\n",
      "\n",
      "print(f\"Year-to-date gain for META (Facebook): {meta_ytd_gain:.2f}%\")\n",
      "print(f\"Year-to-date gain for TESLA: {tesla_ytd_gain:.2f}%\")\n",
      "```\n",
      "\n",
      "Please execute this updated code block to get the year-to-date gain for META and TESLA.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n",
      "\u001b[33muser_proxy\u001b[0m (to assistant):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: \n",
      "Year-to-date gain for META (Facebook): 132.69%\n",
      "Year-to-date gain for TESLA: 120.93%\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to user_proxy):\n",
      "\n",
      "Great! The code executed successfully. Here are the year-to-date gains for META (Facebook) and TESLA:\n",
      "\n",
      "- Year-to-date gain for META (Facebook): 132.69%\n",
      "- Year-to-date gain for TESLA: 120.93%\n",
      "\n",
      "Please note that these values are based on the stock market data at the time of execution and may change as the market fluctuates.\n",
      "\n",
      "TERMINATE\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# create an AssistantAgent named \"assistant\"\n",
    "assistant = autogen.AssistantAgent(\n",
    "    name=\"assistant\",\n",
    "    llm_config={\n",
    "        \"seed\": 42,  # seed for caching and reproducibility\n",
    "        \"config_list\": config_list,  # a list of OpenAI API configurations\n",
    "        \"temperature\": 0,  # temperature for sampling\n",
    "    },  # configuration for autogen's enhanced inference API which is compatible with OpenAI API\n",
    ")\n",
    "# create a UserProxyAgent instance named \"user_proxy\"\n",
    "user_proxy = autogen.UserProxyAgent(\n",
    "    name=\"user_proxy\",\n",
    "    human_input_mode=\"NEVER\",\n",
    "    max_consecutive_auto_reply=10,\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\").rstrip().endswith(\"TERMINATE\"),\n",
    "    code_execution_config={\n",
    "        \"work_dir\": \"coding\",\n",
    "        \"use_docker\": False,  # set to True or image name like \"python:3\" to use docker\n",
    "    },\n",
    ")\n",
    "# the assistant receives a message from the user_proxy, which contains the task description\n",
    "user_proxy.initiate_chat(\n",
    "    assistant,\n",
    "    message=\"\"\"What date is today? Compare the year-to-date gain for META and TESLA.\"\"\",\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The example above involves code execution. In AutoGen, code execution is triggered automatically by the `UserProxyAgent` when it detects an executable code block in a received message and no human user input is provided. This process occurs in a designated working directory, using a Docker container by default. Unless a specific directory is specified, AutoGen defaults to the `autogen/extensions` directory. Users have the option to specify a different working directory by setting the `work_dir` argument when constructing a new instance of the `UserProxyAgent`.\n",
    "\n",
    "The whole chat is auto generated."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example Task: Plot Chart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33muser_proxy\u001b[0m (to assistant):\n",
      "\n",
      "Plot a chart of their stock price change YTD and save to stock_price_ytd.png.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to user_proxy):\n",
      "\n",
      "To plot the chart and save it as an image, we will use the `matplotlib` library. If you don't have it installed, please install it using the following command:\n",
      "\n",
      "```sh\n",
      "pip install matplotlib\n",
      "```\n",
      "\n",
      "Now, let's plot the chart of the stock price change YTD for META and TESLA and save it to a file named \"stock_price_ytd.png\":\n",
      "\n",
      "```python\n",
      "# filename: plot_stock_price_ytd.py\n",
      "\n",
      "import yfinance as yf\n",
      "import matplotlib.pyplot as plt\n",
      "from datetime import datetime, date\n",
      "\n",
      "today = date.today()\n",
      "\n",
      "def get_stock_data(ticker):\n",
      "    stock = yf.Ticker(ticker)\n",
      "    start_date = datetime(today.year, 1, 1)\n",
      "    end_date = today\n",
      "    historical_data = stock.history(start=start_date, end=end_date)\n",
      "    return historical_data\n",
      "\n",
      "meta_data = get_stock_data(\"META\")\n",
      "tesla_data = get_stock_data(\"TSLA\")\n",
      "\n",
      "plt.figure(figsize=(12, 6))\n",
      "plt.plot(meta_data.index, meta_data['Close'], label='META (Facebook)')\n",
      "plt.plot(tesla_data.index, tesla_data['Close'], label='TESLA')\n",
      "plt.xlabel('Date')\n",
      "plt.ylabel('Stock Price')\n",
      "plt.title('Stock Price Change YTD for META and TESLA')\n",
      "plt.legend()\n",
      "plt.savefig('stock_price_ytd.png')\n",
      "plt.show()\n",
      "```\n",
      "\n",
      "Please save the above code in a file named \"plot_stock_price_ytd.py\" and execute it using the following command:\n",
      "\n",
      "```sh\n",
      "python plot_stock_price_ytd.py\n",
      "```\n",
      "\n",
      "This will create a chart of the stock price change YTD for META and TESLA and save it as \"stock_price_ytd.png\" in the same directory where the script is located.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is sh)...\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 1 (inferred language is python)...\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 2 (inferred language is sh)...\u001b[0m\n",
      "\u001b[33muser_proxy\u001b[0m (to assistant):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: \n",
      "Defaulting to user installation because normal site-packages is not writeable\n",
      "Requirement already satisfied: matplotlib in /home/vscode/.local/lib/python3.9/site-packages (3.7.2)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (4.41.1)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (1.4.4)\n",
      "Requirement already satisfied: cycler>=0.10 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (0.11.0)\n",
      "Requirement already satisfied: pillow>=6.2.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (10.0.0)\n",
      "Requirement already satisfied: importlib-resources>=3.2.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (6.0.0)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (2.8.2)\n",
      "Requirement already satisfied: pyparsing<3.1,>=2.3.1 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (3.0.9)\n",
      "Requirement already satisfied: packaging>=20.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (23.1)\n",
      "Requirement already satisfied: contourpy>=1.0.1 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (1.1.0)\n",
      "Requirement already satisfied: numpy>=1.20 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (1.25.1)\n",
      "Requirement already satisfied: zipp>=3.1.0 in /home/vscode/.local/lib/python3.9/site-packages (from importlib-resources>=3.2.0->matplotlib) (3.16.2)\n",
      "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\n",
      "\n",
      "Figure(1200x600)\n",
      "\n",
      "Figure(1200x600)\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to user_proxy):\n",
      "\n",
      "Great! The code executed successfully, and the chart of the stock price change YTD for META and TESLA has been saved as \"stock_price_ytd.png\" in the same directory where the script is located. You can now view the chart by opening the \"stock_price_ytd.png\" file.\n",
      "\n",
      "TERMINATE\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# followup of the previous question\n",
    "user_proxy.send(\n",
    "    recipient=assistant,\n",
    "    message=\"\"\"Plot a chart of their stock price change YTD and save to stock_price_ytd.png.\"\"\",\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's display the generated figure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 88360 characters]",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import Image\n",
    "\n",
    "Image(filename='coding/stock_price_ytd.png')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Use a Different Code Execution Environment\n",
    "\n",
    "The code execution happened in a separate process, so the plot is not directly displayed in the notebook. Is it possible to change the code execution environment into IPython?\n",
    "\n",
    "Yes! In the following we demonstrate how to extend the `UserProxyAgent` to use a different code execution environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Dict, Union\n",
    "from IPython import get_ipython\n",
    "\n",
    "class IPythonUserProxyAgent(autogen.UserProxyAgent):\n",
    "    def __init__(self, name: str, **kwargs):\n",
    "        super().__init__(name, **kwargs)\n",
    "        self._ipython = get_ipython()\n",
    "\n",
    "    def generate_init_message(self, *args, **kwargs) -> Union[str, Dict]:\n",
    "        return super().generate_init_message(*args, **kwargs) + \"\"\"\n",
    "If you suggest code, the code will be executed in IPython.\"\"\"\n",
    "\n",
    "    def run_code(self, code, **kwargs):\n",
    "        result = self._ipython.run_cell(\"%%capture --no-display cap\\n\" + code)\n",
    "        log = self._ipython.ev(\"cap.stdout\")\n",
    "        log += self._ipython.ev(\"cap.stderr\")\n",
    "        if result.result is not None:\n",
    "            log += str(result.result)\n",
    "        exitcode = 0 if result.success else 1\n",
    "        if result.error_before_exec is not None:\n",
    "            log += f\"\\n{result.error_before_exec}\"\n",
    "            exitcode = 1\n",
    "        if result.error_in_exec is not None:\n",
    "            log += f\"\\n{result.error_in_exec}\"\n",
    "            exitcode = 1\n",
    "        return exitcode, log, None"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The implementation overrides three functions in `UserProxyAgent`:\n",
    "* constructor. We get the ipython instance as the code execution environment.\n",
    "* `generate_init_message`. We generate a modified initial message to send to the assistant agent, by adding the info that the execution will be performed in IPython.\n",
    "* `run_code`. We execute the code with the ipython instance.\n",
    "\n",
    "With the new `IPythonUserProxyAgent`, we are able to run the code within the current notebook environment and display plot directly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mipython_user_proxy\u001b[0m (to assistant):\n",
      "\n",
      "Plot a chart of META and TESLA stock price gain YTD\n",
      "If you suggest code, the code will be executed in IPython.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to ipython_user_proxy):\n",
      "\n",
      "First, we need to install the necessary libraries to fetch stock data and plot the chart. Please execute the following code to install the required libraries:\n",
      "\n",
      "```python\n",
      "!pip install yfinance matplotlib\n",
      "```\n",
      "\n",
      "After installing the libraries, execute the following code to fetch the stock data and plot the chart:\n",
      "\n",
      "```python\n",
      "import yfinance as yf\n",
      "import matplotlib.pyplot as plt\n",
      "import datetime\n",
      "\n",
      "# Get the current date\n",
      "today = datetime.date.today()\n",
      "\n",
      "# Calculate the start date for YTD\n",
      "start_date = datetime.date(today.year, 1, 1)\n",
      "\n",
      "# Fetch stock data for META (Facebook) and TESLA\n",
      "meta = yf.download('FB', start=start_date, end=today)\n",
      "tesla = yf.download('TSLA', start=start_date, end=today)\n",
      "\n",
      "# Calculate the percentage gain for each stock\n",
      "meta['Gain'] = (meta['Close'] / meta['Close'][0]) * 100\n",
      "tesla['Gain'] = (tesla['Close'] / tesla['Close'][0]) * 100\n",
      "\n",
      "# Plot the chart\n",
      "plt.figure(figsize=(12, 6))\n",
      "plt.plot(meta.index, meta['Gain'], label='META (Facebook)')\n",
      "plt.plot(tesla.index, tesla['Gain'], label='TESLA')\n",
      "plt.xlabel('Date')\n",
      "plt.ylabel('Percentage Gain YTD')\n",
      "plt.title('META (Facebook) vs TESLA Stock Price Gain YTD')\n",
      "plt.legend()\n",
      "plt.grid()\n",
      "plt.show()\n",
      "```\n",
      "\n",
      "This code will fetch the stock data for META (Facebook) and TESLA from the start of the year to the current date, calculate the percentage gain, and plot the chart.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 1 (inferred language is python)...\u001b[0m\n"
     ]
    },
    {
     "ename": "IndexError",
     "evalue": "index 0 is out of bounds for axis 0 with size 0",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mIndexError\u001b[0m                                Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[7], line 16\u001b[0m\n\u001b[1;32m     13\u001b[0m tesla \u001b[39m=\u001b[39m yf\u001b[39m.\u001b[39mdownload(\u001b[39m'\u001b[39m\u001b[39mTSLA\u001b[39m\u001b[39m'\u001b[39m, start\u001b[39m=\u001b[39mstart_date, end\u001b[39m=\u001b[39mtoday)\n\u001b[1;32m     15\u001b[0m \u001b[39m# Calculate the percentage gain for each stock\u001b[39;00m\n\u001b[0;32m---> 16\u001b[0m meta[\u001b[39m'\u001b[39m\u001b[39mGain\u001b[39m\u001b[39m'\u001b[39m] \u001b[39m=\u001b[39m (meta[\u001b[39m'\u001b[39m\u001b[39mClose\u001b[39m\u001b[39m'\u001b[39m] \u001b[39m/\u001b[39m meta[\u001b[39m'\u001b[39;49m\u001b[39mClose\u001b[39;49m\u001b[39m'\u001b[39;49m][\u001b[39m0\u001b[39;49m]) \u001b[39m*\u001b[39m \u001b[39m100\u001b[39m\n\u001b[1;32m     17\u001b[0m tesla[\u001b[39m'\u001b[39m\u001b[39mGain\u001b[39m\u001b[39m'\u001b[39m] \u001b[39m=\u001b[39m (tesla[\u001b[39m'\u001b[39m\u001b[39mClose\u001b[39m\u001b[39m'\u001b[39m] \u001b[39m/\u001b[39m tesla[\u001b[39m'\u001b[39m\u001b[39mClose\u001b[39m\u001b[39m'\u001b[39m][\u001b[39m0\u001b[39m]) \u001b[39m*\u001b[39m \u001b[39m100\u001b[39m\n\u001b[1;32m     19\u001b[0m \u001b[39m# Plot the chart\u001b[39;00m\n",
      "File \u001b[0;32m~/.local/lib/python3.9/site-packages/pandas/core/series.py:939\u001b[0m, in \u001b[0;36mSeries.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m    936\u001b[0m     key \u001b[39m=\u001b[39m unpack_1tuple(key)\n\u001b[1;32m    938\u001b[0m \u001b[39mif\u001b[39;00m is_integer(key) \u001b[39mand\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mindex\u001b[39m.\u001b[39m_should_fallback_to_positional():\n\u001b[0;32m--> 939\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_values[key]\n\u001b[1;32m    941\u001b[0m \u001b[39melif\u001b[39;00m key_is_scalar:\n\u001b[1;32m    942\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_get_value(key)\n",
      "\u001b[0;31mIndexError\u001b[0m: index 0 is out of bounds for axis 0 with size 0"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mipython_user_proxy\u001b[0m (to assistant):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: \n",
      "Defaulting to user installation because normal site-packages is not writeable\n",
      "Requirement already satisfied: yfinance in /home/vscode/.local/lib/python3.9/site-packages (0.2.26)\n",
      "Requirement already satisfied: matplotlib in /home/vscode/.local/lib/python3.9/site-packages (3.7.2)\n",
      "Requirement already satisfied: html5lib>=1.1 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.1)\n",
      "Requirement already satisfied: pytz>=2022.5 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (2023.3)\n",
      "Requirement already satisfied: frozendict>=2.3.4 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (2.3.8)\n",
      "Requirement already satisfied: pandas>=1.3.0 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.3.3)\n",
      "Requirement already satisfied: lxml>=4.9.1 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (4.9.3)\n",
      "Requirement already satisfied: numpy>=1.16.5 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.25.1)\n",
      "Requirement already satisfied: appdirs>=1.4.4 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (1.4.4)\n",
      "Requirement already satisfied: beautifulsoup4>=4.11.1 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (4.12.2)\n",
      "Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.9/site-packages (from yfinance) (2.31.0)\n",
      "Requirement already satisfied: multitasking>=0.0.7 in /home/vscode/.local/lib/python3.9/site-packages (from yfinance) (0.0.11)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (1.4.4)\n",
      "Requirement already satisfied: importlib-resources>=3.2.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (6.0.0)\n",
      "Requirement already satisfied: pillow>=6.2.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (10.0.0)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (2.8.2)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (4.41.1)\n",
      "Requirement already satisfied: pyparsing<3.1,>=2.3.1 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (3.0.9)\n",
      "Requirement already satisfied: packaging>=20.0 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (23.1)\n",
      "Requirement already satisfied: contourpy>=1.0.1 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (1.1.0)\n",
      "Requirement already satisfied: cycler>=0.10 in /home/vscode/.local/lib/python3.9/site-packages (from matplotlib) (0.11.0)\n",
      "Requirement already satisfied: soupsieve>1.2 in /home/vscode/.local/lib/python3.9/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.4.1)\n",
      "Requirement already satisfied: six>=1.9 in /usr/local/lib/python3.9/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\n",
      "Requirement already satisfied: webencodings in /home/vscode/.local/lib/python3.9/site-packages (from html5lib>=1.1->yfinance) (0.5.1)\n",
      "Requirement already satisfied: zipp>=3.1.0 in /home/vscode/.local/lib/python3.9/site-packages (from importlib-resources>=3.2.0->matplotlib) (3.16.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (3.4)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (2.0.3)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (2023.5.7)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.9/site-packages (from requests>=2.31->yfinance) (3.2.0)\n",
      "\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.0.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.2.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
      "\n",
      "[*********************100%***********************]  1 of 1 completed\n",
      "[*********************100%***********************]  1 of 1 completed\n",
      "\n",
      "1 Failed download:\n",
      "['FB']: Exception('%ticker%: No timezone found, symbol may be delisted')\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to ipython_user_proxy):\n",
      "\n",
      "It seems that there was an issue with fetching the stock data for META (Facebook) using the ticker symbol 'FB'. The stock symbol for META has been changed to 'META' recently. Let's update the code to use the new symbol and try again:\n",
      "\n",
      "```python\n",
      "import yfinance as yf\n",
      "import matplotlib.pyplot as plt\n",
      "import datetime\n",
      "\n",
      "# Get the current date\n",
      "today = datetime.date.today()\n",
      "\n",
      "# Calculate the start date for YTD\n",
      "start_date = datetime.date(today.year, 1, 1)\n",
      "\n",
      "# Fetch stock data for META (Facebook) and TESLA\n",
      "meta = yf.download('META', start=start_date, end=today)\n",
      "tesla = yf.download('TSLA', start=start_date, end=today)\n",
      "\n",
      "# Calculate the percentage gain for each stock\n",
      "meta['Gain'] = (meta['Close'] / meta['Close'][0]) * 100\n",
      "tesla['Gain'] = (tesla['Close'] / tesla['Close'][0]) * 100\n",
      "\n",
      "# Plot the chart\n",
      "plt.figure(figsize=(12, 6))\n",
      "plt.plot(meta.index, meta['Gain'], label='META (Facebook)')\n",
      "plt.plot(tesla.index, tesla['Gain'], label='TESLA')\n",
      "plt.xlabel('Date')\n",
      "plt.ylabel('Percentage Gain YTD')\n",
      "plt.title('META (Facebook) vs TESLA Stock Price Gain YTD')\n",
      "plt.legend()\n",
      "plt.grid()\n",
      "plt.show()\n",
      "```\n",
      "\n",
      "Please execute the updated code to fetch the stock data and plot the chart.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 96208 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mipython_user_proxy\u001b[0m (to assistant):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: \n",
      "[*********************100%***********************]  1 of 1 completed\n",
      "[*********************100%***********************]  1 of 1 completed\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33massistant\u001b[0m (to ipython_user_proxy):\n",
      "\n",
      "I'm glad the code executed successfully. You should now see a chart comparing the YTD percentage gain of META (Facebook) and TESLA stocks. If you have any further questions or need assistance with another task, feel free to ask.\n",
      "\n",
      "TERMINATE\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "ipy_user = IPythonUserProxyAgent(\n",
    "    \"ipython_user_proxy\",\n",
    "    human_input_mode=\"NEVER\",\n",
    "    max_consecutive_auto_reply=10,\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\").rstrip().endswith(\"TERMINATE\") or x.get(\"content\", \"\").rstrip().endswith('\"TERMINATE\".'),\n",
    ")\n",
    "# the assistant receives a message from the user, which contains the task description\n",
    "ipy_user.initiate_chat(\n",
    "    assistant,\n",
    "    message=\"\"\"Plot a chart of META and TESLA stock price gain YTD\"\"\",\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.9.17"
  },
  "vscode": {
   "interpreter": {
    "hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1"
   }
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {
     "2d910cfd2d2a4fc49fc30fbbdc5576a7": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "454146d0f7224f038689031002906e6f": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_e4ae2b6f5a974fd4bafb6abb9d12ff26",
        "IPY_MODEL_577e1e3cc4db4942b0883577b3b52755",
        "IPY_MODEL_b40bdfb1ac1d4cffb7cefcb870c64d45"
       ],
       "layout": "IPY_MODEL_dc83c7bff2f241309537a8119dfc7555",
       "tabbable": null,
       "tooltip": null
      }
     },
     "577e1e3cc4db4942b0883577b3b52755": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "ProgressView",
       "bar_style": "success",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_2d910cfd2d2a4fc49fc30fbbdc5576a7",
       "max": 1,
       "min": 0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_74a6ba0c3cbc4051be0a83e152fe1e62",
       "tabbable": null,
       "tooltip": null,
       "value": 1
      }
     },
     "6086462a12d54bafa59d3c4566f06cb2": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "74a6ba0c3cbc4051be0a83e152fe1e62": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "7d3f3d9e15894d05a4d188ff4f466554": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "b40bdfb1ac1d4cffb7cefcb870c64d45": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_f1355871cc6f4dd4b50d9df5af20e5c8",
       "placeholder": "​",
       "style": "IPY_MODEL_ca245376fd9f4354af6b2befe4af4466",
       "tabbable": null,
       "tooltip": null,
       "value": " 1/1 [00:00&lt;00:00, 44.69it/s]"
      }
     },
     "ca245376fd9f4354af6b2befe4af4466": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "dc83c7bff2f241309537a8119dfc7555": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "e4ae2b6f5a974fd4bafb6abb9d12ff26": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_6086462a12d54bafa59d3c4566f06cb2",
       "placeholder": "​",
       "style": "IPY_MODEL_7d3f3d9e15894d05a4d188ff4f466554",
       "tabbable": null,
       "tooltip": null,
       "value": "100%"
      }
     },
     "f1355871cc6f4dd4b50d9df5af20e5c8": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     }
    },
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
