From 6c8b10f62297ed0d8bf8697028fa11b7ef291eef Mon Sep 17 00:00:00 2001
From: tolgadevAI <164843802+tolgadevAI@users.noreply.github.com>
Date: Wed, 17 Jul 2024 17:34:29 +0300
Subject: [PATCH] update the notebooks

---
 docs/02-dynamic-routes.ipynb                  | 2455 ++++++++---------
 docs/03-async-dynamic-routes.ipynb            | 1051 +++++++
 ...t.ipynb => 04-basic-langchain-agent.ipynb} |    0
 ...at-history.ipynb => 05-chat-history.ipynb} |    0
 ...ecution.ipynb => 06-local-execution.ipynb} |    0
 ....ipynb => 07-threshold-optimization.ipynb} |    0
 ...multi-modal.ipynb => 08-multi-modal.ipynb} |    0
 7 files changed, 2146 insertions(+), 1360 deletions(-)
 create mode 100644 docs/03-async-dynamic-routes.ipynb
 rename docs/{03-basic-langchain-agent.ipynb => 04-basic-langchain-agent.ipynb} (100%)
 rename docs/{04-chat-history.ipynb => 05-chat-history.ipynb} (100%)
 rename docs/{05-local-execution.ipynb => 06-local-execution.ipynb} (100%)
 rename docs/{06-threshold-optimization.ipynb => 07-threshold-optimization.ipynb} (100%)
 rename docs/{07-multi-modal.ipynb => 08-multi-modal.ipynb} (100%)

diff --git a/docs/02-dynamic-routes.ipynb b/docs/02-dynamic-routes.ipynb
index b7ea5412..6353e71a 100644
--- a/docs/02-dynamic-routes.ipynb
+++ b/docs/02-dynamic-routes.ipynb
@@ -1,1443 +1,1178 @@
 {
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "UxqB7_Ieur0s"
-   },
-   "source": [
-    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "EduhQaNAur0u"
-   },
-   "source": [
-    "# Dynamic Routes"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "_4JgNeX4ur0v"
-   },
-   "source": [
-    "In semantic-router there are two types of routes that can be chosen. Both routes belong to the `Route` object, the only difference between them is that _static_ routes return a `Route.name` when chosen, whereas _dynamic_ routes use an LLM call to produce parameter input values.\n",
-    "\n",
-    "For example, a _static_ route will tell us if a query is talking about mathematics by returning the route name (which could be `\"math\"` for example). A _dynamic_ route does the same thing, but it also extracts key information from the input utterance to be used in a function associated with that route.\n",
-    "\n",
-    "For example we could provide a dynamic route with associated utterances:\n",
-    "\n",
-    "```\n",
-    "\"what is x to the power of y?\"\n",
-    "\"what is 9 to the power of 4?\"\n",
-    "\"calculate the result of base x and exponent y\"\n",
-    "\"calculate the result of base 10 and exponent 3\"\n",
-    "\"return x to the power of y\"\n",
-    "```\n",
-    "\n",
-    "and we could also provide the route with a schema outlining key features of the function:\n",
-    "\n",
-    "```\n",
-    "def power(base: float, exponent: float) -> float:\n",
-    "    \"\"\"Raise base to the power of exponent.\n",
-    "\n",
-    "    Args:\n",
-    "        base (float): The base number.\n",
-    "        exponent (float): The exponent to which the base is raised.\n",
-    "\n",
-    "    Returns:\n",
-    "        float: The result of base raised to the power of exponent.\n",
-    "    \"\"\"\n",
-    "    return base ** exponent\n",
-    "```\n",
-    "\n",
-    "Then, if the users input utterance is \"What is 2 to the power of 3?\", the route will be triggered, as the input utterance is semantically similar to the route utterances. Furthermore, the route utilizes an LLM to identify that `base=2` and `expoenent=3`. These values are returned in such a way that they can be used in the above `power` function. That is, the dynamic router automates the process of calling relevant functions from natural language inputs.\n",
-    "\n",
-    "***⚠️ Note: We have a fully local version of dynamic routes available at [docs/05-local-execution.ipynb](https://github.com/aurelio-labs/semantic-router/blob/main/docs/05-local-execution.ipynb). The local 05 version tends to outperform the OpenAI version we demo in this notebook, so we'd recommend trying [05](https://github.com/aurelio-labs/semantic-router/blob/main/docs/05-local-execution.ipynb)!***"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "bbmw8CO4ur0v"
-   },
-   "source": [
-    "## Installing the Library"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 63,
-   "metadata": {
-    "id": "dLElfRhgur0v",
-    "outputId": "da0e506e-24cf-43da-9243-894a7c4955db"
-   },
-   "outputs": [
+  "cells": [
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Requirement already satisfied: tzdata in /opt/anaconda3/envs/semantic-router/lib/python3.12/site-packages (2024.1)\n"
-     ]
-    }
-   ],
-   "source": [
-    "!pip install tzdata\n",
-    "!pip install -qU semantic-router"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "BixZd6Eour0w"
-   },
-   "source": [
-    "## Initializing Routes and RouteLayer"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "PxnW9qBvur0x"
-   },
-   "source": [
-    "Dynamic routes are treated in the same way as static routes, let's begin by initializing a `RouteLayer` consisting of static routes."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 64,
-   "metadata": {
-    "id": "kc9Ty6Lgur0x",
-    "outputId": "f32e3a25-c073-4802-ced3-d7a5663670c1"
-   },
-   "outputs": [],
-   "source": [
-    "from semantic_router import Route\n",
-    "\n",
-    "politics = Route(\n",
-    "    name=\"politics\",\n",
-    "    utterances=[\n",
-    "        \"isn't politics the best thing ever\",\n",
-    "        \"why don't you tell me about your political opinions\",\n",
-    "        \"don't you just love the president\" \"don't you just hate the president\",\n",
-    "        \"they're going to destroy this country!\",\n",
-    "        \"they will save the country!\",\n",
-    "    ],\n",
-    ")\n",
-    "chitchat = Route(\n",
-    "    name=\"chitchat\",\n",
-    "    utterances=[\n",
-    "        \"how's the weather today?\",\n",
-    "        \"how are things going?\",\n",
-    "        \"lovely weather today\",\n",
-    "        \"the weather is horrendous\",\n",
-    "        \"let's go to the chippy\",\n",
-    "    ],\n",
-    ")\n",
-    "\n",
-    "routes = [politics, chitchat]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "voWyqmffur0x"
-   },
-   "source": [
-    "We initialize our `RouteLayer` with our `encoder` and `routes`. We can use popular encoder APIs like `CohereEncoder` and `OpenAIEncoder`, or local alternatives like `FastEmbedEncoder`."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 65,
-   "metadata": {
-    "colab": {
-     "base_uri": "https://localhost:8080/"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "UxqB7_Ieur0s"
+      },
+      "source": [
+        "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb)"
+      ]
     },
-    "id": "BI9AiDspur0y",
-    "outputId": "27329a54-3f16-44a5-ac20-13a6b26afb97"
-   },
-   "outputs": [],
-   "source": [
-    "import os\n",
-    "from getpass import getpass\n",
-    "from semantic_router import RouteLayer\n",
-    "from semantic_router.encoders import CohereEncoder, OpenAIEncoder\n",
-    "\n",
-    "# dashboard.cohere.ai\n",
-    "# os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n",
-    "#     \"Enter Cohere API Key: \"\n",
-    "# )\n",
-    "# platform.openai.com\n",
-    "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n",
-    "    \"Enter OpenAI API Key: \"\n",
-    ")\n",
-    "\n",
-    "# encoder = CohereEncoder()\n",
-    "encoder = OpenAIEncoder()\n",
-    "\n",
-    "rl = RouteLayer(encoder=encoder, routes=routes)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "GuLCeIS5ur0y"
-   },
-   "source": [
-    "We run the solely static routes layer:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 66,
-   "metadata": {
-    "colab": {
-     "base_uri": "https://localhost:8080/"
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "EduhQaNAur0u"
+      },
+      "source": [
+        "# Dynamic Routes"
+      ]
     },
-    "id": "_rNREh7gur0y",
-    "outputId": "f3a1dc0b-d760-4efb-b634-d3547011dcb7"
-   },
-   "outputs": [
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "_4JgNeX4ur0v"
+      },
+      "source": [
+        "In semantic-router there are two types of routes that can be chosen. Both routes belong to the `Route` object, the only difference between them is that _static_ routes return a `Route.name` when chosen, whereas _dynamic_ routes use an LLM call to produce parameter input values.\n",
+        "\n",
+        "For example, a _static_ route will tell us if a query is talking about mathematics by returning the route name (which could be `\"math\"` for example). A _dynamic_ route does the same thing, but it also extracts key information from the input utterance to be used in a function associated with that route.\n",
+        "\n",
+        "For example we could provide a dynamic route with associated utterances:\n",
+        "\n",
+        "```\n",
+        "\"what is x to the power of y?\"\n",
+        "\"what is 9 to the power of 4?\"\n",
+        "\"calculate the result of base x and exponent y\"\n",
+        "\"calculate the result of base 10 and exponent 3\"\n",
+        "\"return x to the power of y\"\n",
+        "```\n",
+        "\n",
+        "and we could also provide the route with a schema outlining key features of the function:\n",
+        "\n",
+        "```\n",
+        "def power(base: float, exponent: float) -> float:\n",
+        "    \"\"\"Raise base to the power of exponent.\n",
+        "\n",
+        "    Args:\n",
+        "        base (float): The base number.\n",
+        "        exponent (float): The exponent to which the base is raised.\n",
+        "\n",
+        "    Returns:\n",
+        "        float: The result of base raised to the power of exponent.\n",
+        "    \"\"\"\n",
+        "    return base ** exponent\n",
+        "```\n",
+        "\n",
+        "Then, if the users input utterance is \"What is 2 to the power of 3?\", the route will be triggered, as the input utterance is semantically similar to the route utterances. Furthermore, the route utilizes an LLM to identify that `base=2` and `expoenent=3`. These values are returned in such a way that they can be used in the above `power` function. That is, the dynamic router automates the process of calling relevant functions from natural language inputs.\n",
+        "\n",
+        "***⚠️ Note: We have a fully local version of dynamic routes available at [docs/05-local-execution.ipynb](https://github.com/aurelio-labs/semantic-router/blob/main/docs/05-local-execution.ipynb). The local 05 version tends to outperform the OpenAI version we demo in this notebook, so we'd recommend trying [05](https://github.com/aurelio-labs/semantic-router/blob/main/docs/05-local-execution.ipynb)!***"
       ]
-     },
-     "execution_count": 66,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "rl(\"how's the weather today?\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 67,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "bbmw8CO4ur0v"
+      },
+      "source": [
+        "## Installing the Library"
       ]
-     },
-     "execution_count": 67,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# async\n",
-    "await rl.acall(\"how's the weather today?\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "McbLKO26ur0y"
-   },
-   "source": [
-    "## Creating a Dynamic Route"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "ANAoEjxYur0y"
-   },
-   "source": [
-    "As with static routes, we must create a dynamic route before adding it to our route layer. To make a route dynamic, we need to provide the `function_schemas` as a list. Each function schema provides instructions on what a function is, so that an LLM can decide how to use it correctly."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 68,
-   "metadata": {
-    "id": "5jaF1Xa5ur0y"
-   },
-   "outputs": [],
-   "source": [
-    "from datetime import datetime\n",
-    "from zoneinfo import ZoneInfo\n",
-    "\n",
-    "\n",
-    "def get_time(timezone: str) -> str:\n",
-    "    \"\"\"Finds the current time in a specific timezone.\n",
-    "\n",
-    "    :param timezone: The timezone to find the current time in, should\n",
-    "        be a valid timezone from the IANA Time Zone Database like\n",
-    "        \"America/New_York\" or \"Europe/London\". Do NOT put the place\n",
-    "        name itself like \"rome\", or \"new york\", you must provide\n",
-    "        the IANA format.\n",
-    "    :type timezone: str\n",
-    "    :return: The current time in the specified timezone.\"\"\"\n",
-    "    now = datetime.now(ZoneInfo(timezone))\n",
-    "    return now.strftime(\"%H:%M\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 69,
-   "metadata": {
-    "colab": {
-     "base_uri": "https://localhost:8080/",
-     "height": 35
     },
-    "id": "YyFKV8jMur0z",
-    "outputId": "29cf80f4-552c-47bb-fbf9-019f5dfdf00a"
-   },
-   "outputs": [
     {
-     "data": {
-      "text/plain": [
-       "'07:25'"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "dLElfRhgur0v",
+        "outputId": "da0e506e-24cf-43da-9243-894a7c4955db"
+      },
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "Requirement already satisfied: tzdata in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\virtual environments\\semantic_router_3\\lib\\site-packages (2024.1)\n"
+          ]
+        },
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\n",
+            "[notice] A new release of pip is available: 23.1.2 -> 24.0\n",
+            "[notice] To update, run: python.exe -m pip install --upgrade pip\n"
+          ]
+        }
+      ],
+      "source": [
+        "!pip install tzdata\n",
+        "!pip install -qU semantic-router"
       ]
-     },
-     "execution_count": 69,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "get_time(\"America/New_York\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "4qyaRuNXur0z"
-   },
-   "source": [
-    "To get the function schema we can use the `get_schema` function from the `function_call` module."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 70,
-   "metadata": {
-    "colab": {
-     "base_uri": "https://localhost:8080/"
     },
-    "id": "tOjuhp5Xur0z",
-    "outputId": "ca88a3ea-d70a-4950-be9a-63fab699de3b"
-   },
-   "outputs": [
     {
-     "data": {
-      "text/plain": [
-       "[{'type': 'function',\n",
-       "  'function': {'name': 'get_time',\n",
-       "   'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
-       "   'parameters': {'type': 'object',\n",
-       "    'properties': {'timezone': {'type': 'string',\n",
-       "      'description': 'The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.'}},\n",
-       "    'required': ['timezone']}}}]"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "BixZd6Eour0w"
+      },
+      "source": [
+        "## Initializing Routes and RouteLayer"
       ]
-     },
-     "execution_count": 70,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "from semantic_router.llms.openai import get_schemas_openai\n",
-    "\n",
-    "schemas = get_schemas_openai([get_time])\n",
-    "schemas"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "HcF7jGjAur0z"
-   },
-   "source": [
-    "We use this to define our dynamic route:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 71,
-   "metadata": {
-    "id": "iesBG9P3ur0z"
-   },
-   "outputs": [],
-   "source": [
-    "time_route = Route(\n",
-    "    name=\"get_time\",\n",
-    "    utterances=[\n",
-    "        \"what is the time in new york city?\",\n",
-    "        \"what is the time in london?\",\n",
-    "        \"I live in Rome, what time is it?\",\n",
-    "    ],\n",
-    "    function_schemas=schemas,\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "ZiUs3ovpur0z"
-   },
-   "source": [
-    "Add the new route to our `layer`:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 72,
-   "metadata": {
-    "colab": {
-     "base_uri": "https://localhost:8080/"
     },
-    "id": "-0vY8PRXur0z",
-    "outputId": "db01e14c-eab3-4f93-f4c2-e30f508c8b5d"
-   },
-   "outputs": [
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:25:29 INFO semantic_router.utils.logger Adding `get_time` route\u001b[0m\n"
-     ]
-    }
-   ],
-   "source": [
-    "rl.add(time_route)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "7yoE0IrNur0z"
-   },
-   "source": [
-    "Now we can ask our layer a time related question to trigger our new dynamic route."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 73,
-   "metadata": {
-    "colab": {
-     "base_uri": "https://localhost:8080/",
-     "height": 53
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "PxnW9qBvur0x"
+      },
+      "source": [
+        "Dynamic routes are treated in the same way as static routes, let's begin by initializing a `RouteLayer` consisting of static routes."
+      ]
     },
-    "id": "Wfb68M0-ur0z",
-    "outputId": "79923883-2a4d-4744-f8ce-e818cb5f14c3"
-   },
-   "outputs": [
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[33m2024-07-16 14:25:31 WARNING semantic_router.utils.logger No LLM provided for dynamic route, will use OpenAI LLM default. Ensure API key is set in OPENAI_API_KEY environment variable.\u001b[0m\n",
-      "\u001b[32m2024-07-16 14:25:32 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
-     ]
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "kc9Ty6Lgur0x",
+        "outputId": "f32e3a25-c073-4802-ced3-d7a5663670c1"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "c:\\Users\\Siraj\\Documents\\Personal\\Work\\Aurelio\\Virtual Environments\\semantic_router_3\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
+            "  from .autonotebook import tqdm as notebook_tqdm\n"
+          ]
+        }
+      ],
+      "source": [
+        "from semantic_router import Route\n",
+        "\n",
+        "politics = Route(\n",
+        "    name=\"politics\",\n",
+        "    utterances=[\n",
+        "        \"isn't politics the best thing ever\",\n",
+        "        \"why don't you tell me about your political opinions\",\n",
+        "        \"don't you just love the president\" \"don't you just hate the president\",\n",
+        "        \"they're going to destroy this country!\",\n",
+        "        \"they will save the country!\",\n",
+        "    ],\n",
+        ")\n",
+        "chitchat = Route(\n",
+        "    name=\"chitchat\",\n",
+        "    utterances=[\n",
+        "        \"how's the weather today?\",\n",
+        "        \"how are things going?\",\n",
+        "        \"lovely weather today\",\n",
+        "        \"the weather is horrendous\",\n",
+        "        \"let's go to the chippy\",\n",
+        "    ],\n",
+        ")\n",
+        "\n",
+        "routes = [politics, chitchat]"
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "voWyqmffur0x"
+      },
+      "source": [
+        "We initialize our `RouteLayer` with our `encoder` and `routes`. We can use popular encoder APIs like `CohereEncoder` and `OpenAIEncoder`, or local alternatives like `FastEmbedEncoder`."
       ]
-     },
-     "execution_count": 73,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "response = rl(\"what is the time in new york city?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 74,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:25:35 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
-     ]
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "BI9AiDspur0y",
+        "outputId": "27329a54-3f16-44a5-ac20-13a6b26afb97"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[32m2024-05-08 01:57:55 INFO semantic_router.utils.logger local\u001b[0m\n"
+          ]
+        }
+      ],
+      "source": [
+        "import os\n",
+        "from getpass import getpass\n",
+        "from semantic_router import RouteLayer\n",
+        "from semantic_router.encoders import CohereEncoder, OpenAIEncoder\n",
+        "\n",
+        "# dashboard.cohere.ai\n",
+        "# os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n",
+        "#     \"Enter Cohere API Key: \"\n",
+        "# )\n",
+        "# platform.openai.com\n",
+        "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n",
+        "    \"Enter OpenAI API Key: \"\n",
+        ")\n",
+        "\n",
+        "# encoder = CohereEncoder()\n",
+        "encoder = OpenAIEncoder()\n",
+        "\n",
+        "rl = RouteLayer(encoder=encoder, routes=routes)"
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "GuLCeIS5ur0y"
+      },
+      "source": [
+        "We run the solely static routes layer:"
       ]
-     },
-     "execution_count": 74,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# async\n",
-    "response = await rl.acall(\"what is the time in new york city?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 75,
-   "metadata": {
-    "id": "92x96x1Og9hr",
-    "outputId": "c1e46a81-b681-4a10-fff6-71e03342a88e"
-   },
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\n"
-     ]
-    }
-   ],
-   "source": [
-    "print(response.function_call)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 76,
-   "metadata": {
-    "id": "xvdyUPKqg9hr",
-    "outputId": "4161e7e0-ab6d-4e76-f068-2d66728305ff"
-   },
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "_rNREh7gur0y",
+        "outputId": "f3a1dc0b-d760-4efb-b634-d3547011dcb7"
+      },
+      "outputs": [
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+            ]
+          },
+          "execution_count": 4,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "rl(\"how's the weather today?\")"
+      ]
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "07:25\n"
-     ]
-    }
-   ],
-   "source": [
-    "import json\n",
-    "\n",
-    "for call in response.function_call:\n",
-    "    if call[\"function_name\"] == \"get_time\":\n",
-    "        args = call[\"arguments\"]\n",
-    "        result = get_time(**args)\n",
-    "print(result)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "Qt0vkq2Xur00"
-   },
-   "source": [
-    "Our dynamic route provides both the route itself _and_ the input parameters required to use the route."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "jToYBo8Ug9hr"
-   },
-   "source": [
-    "## Dynamic Routes with Multiple Functions"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "J0oD1dxIur00"
-   },
-   "source": [
-    "---"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "vEkTpoVAg9hr"
-   },
-   "source": [
-    "Routes can be assigned multiple functions. Then, when that particular Route is selected by the Route Layer, a number of those functions might be invoked due to the users utterance containing relevant information that fits their arguments."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "BHUlB3org9hs"
-   },
-   "source": [
-    "Let's define a Route that has multiple functions."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 77,
-   "metadata": {
-    "id": "dtrksov0g9hs"
-   },
-   "outputs": [],
-   "source": [
-    "from datetime import datetime, timedelta\n",
-    "from zoneinfo import ZoneInfo\n",
-    "\n",
-    "\n",
-    "# Function with one argument\n",
-    "def get_time(timezone: str) -> str:\n",
-    "    \"\"\"Finds the current time in a specific timezone.\n",
-    "\n",
-    "    :param timezone: The timezone to find the current time in, should\n",
-    "        be a valid timezone from the IANA Time Zone Database like\n",
-    "        \"America/New_York\" or \"Europe/London\". Do NOT put the place\n",
-    "        name itself like \"rome\", or \"new york\", you must provide\n",
-    "        the IANA format.\n",
-    "    :type timezone: str\n",
-    "    :return: The current time in the specified timezone.\"\"\"\n",
-    "    now = datetime.now(ZoneInfo(timezone))\n",
-    "    return now.strftime(\"%H:%M\")\n",
-    "\n",
-    "\n",
-    "def get_time_difference(timezone1: str, timezone2: str) -> str:\n",
-    "    \"\"\"Calculates the time difference between two timezones.\n",
-    "    :param timezone1: The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\n",
-    "    :param timezone2: The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\n",
-    "    :type timezone1: str\n",
-    "    :type timezone2: str\n",
-    "    :return: The time difference in hours between the two timezones.\"\"\"\n",
-    "    # Get the current time in UTC\n",
-    "    now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n",
-    "\n",
-    "    # Convert the UTC time to the specified timezones\n",
-    "    tz1_time = now_utc.astimezone(ZoneInfo(timezone1))\n",
-    "    tz2_time = now_utc.astimezone(ZoneInfo(timezone2))\n",
-    "\n",
-    "    # Calculate the difference in offsets from UTC\n",
-    "    tz1_offset = tz1_time.utcoffset().total_seconds()\n",
-    "    tz2_offset = tz2_time.utcoffset().total_seconds()\n",
-    "\n",
-    "    # Calculate the difference in hours\n",
-    "    hours_difference = (tz2_offset - tz1_offset) / 3600\n",
-    "\n",
-    "    return f\"The time difference between {timezone1} and {timezone2} is {hours_difference} hours.\"\n",
-    "\n",
-    "\n",
-    "# Function with three arguments\n",
-    "def convert_time(time: str, from_timezone: str, to_timezone: str) -> str:\n",
-    "    \"\"\"Converts a specific time from one timezone to another.\n",
-    "    :param time: The time to convert in HH:MM format.\n",
-    "    :param from_timezone: The original timezone of the time, should be a valid IANA timezone.\n",
-    "    :param to_timezone: The target timezone for the time, should be a valid IANA timezone.\n",
-    "    :type time: str\n",
-    "    :type from_timezone: str\n",
-    "    :type to_timezone: str\n",
-    "    :return: The converted time in the target timezone.\n",
-    "    :raises ValueError: If the time format or timezone strings are invalid.\n",
-    "\n",
-    "    Example:\n",
-    "        convert_time(\"12:30\", \"America/New_York\", \"Asia/Tokyo\") -> \"03:30\"\n",
-    "    \"\"\"\n",
-    "    try:\n",
-    "        # Use today's date to avoid historical timezone issues\n",
-    "        today = datetime.now().date()\n",
-    "        datetime_string = f\"{today} {time}\"\n",
-    "        time_obj = datetime.strptime(datetime_string, \"%Y-%m-%d %H:%M\").replace(\n",
-    "            tzinfo=ZoneInfo(from_timezone)\n",
-    "        )\n",
-    "\n",
-    "        converted_time = time_obj.astimezone(ZoneInfo(to_timezone))\n",
-    "\n",
-    "        formatted_time = converted_time.strftime(\"%H:%M\")\n",
-    "        return formatted_time\n",
-    "    except Exception as e:\n",
-    "        raise ValueError(f\"Error converting time: {e}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 78,
-   "metadata": {
-    "id": "AjoYy7mFg9hs"
-   },
-   "outputs": [],
-   "source": [
-    "functions = [get_time, get_time_difference, convert_time]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 79,
-   "metadata": {
-    "id": "DoOkXV2Tg9hs",
-    "outputId": "f1e0fe08-b6ed-4f50-d845-5c54832ca677"
-   },
-   "outputs": [
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "McbLKO26ur0y"
+      },
+      "source": [
+        "## Creating a Dynamic Route"
+      ]
+    },
     {
-     "data": {
-      "text/plain": [
-       "[{'type': 'function',\n",
-       "  'function': {'name': 'get_time',\n",
-       "   'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
-       "   'parameters': {'type': 'object',\n",
-       "    'properties': {'timezone': {'type': 'string',\n",
-       "      'description': 'The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.'}},\n",
-       "    'required': ['timezone']}}},\n",
-       " {'type': 'function',\n",
-       "  'function': {'name': 'get_time_difference',\n",
-       "   'description': 'Calculates the time difference between two timezones.\\n:param timezone1: The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\\n:param timezone2: The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\\n:type timezone1: str\\n:type timezone2: str\\n:return: The time difference in hours between the two timezones.',\n",
-       "   'parameters': {'type': 'object',\n",
-       "    'properties': {'timezone1': {'type': 'string',\n",
-       "      'description': 'The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".'},\n",
-       "     'timezone2': {'type': 'string',\n",
-       "      'description': 'The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".'}},\n",
-       "    'required': ['timezone1', 'timezone2']}}},\n",
-       " {'type': 'function',\n",
-       "  'function': {'name': 'convert_time',\n",
-       "   'description': 'Converts a specific time from one timezone to another.\\n:param time: The time to convert in HH:MM format.\\n:param from_timezone: The original timezone of the time, should be a valid IANA timezone.\\n:param to_timezone: The target timezone for the time, should be a valid IANA timezone.\\n:type time: str\\n:type from_timezone: str\\n:type to_timezone: str\\n:return: The converted time in the target timezone.\\n:raises ValueError: If the time format or timezone strings are invalid.\\n\\nExample:\\n    convert_time(\"12:30\", \"America/New_York\", \"Asia/Tokyo\") -> \"03:30\"',\n",
-       "   'parameters': {'type': 'object',\n",
-       "    'properties': {'time': {'type': 'string',\n",
-       "      'description': 'The time to convert in HH:MM format.'},\n",
-       "     'from_timezone': {'type': 'string',\n",
-       "      'description': 'The original timezone of the time, should be a valid IANA timezone.'},\n",
-       "     'to_timezone': {'type': 'string',\n",
-       "      'description': 'The target timezone for the time, should be a valid IANA timezone.'}},\n",
-       "    'required': ['time', 'from_timezone', 'to_timezone']}}}]"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "ANAoEjxYur0y"
+      },
+      "source": [
+        "As with static routes, we must create a dynamic route before adding it to our route layer. To make a route dynamic, we need to provide the `function_schemas` as a list. Each function schema provides instructions on what a function is, so that an LLM can decide how to use it correctly."
       ]
-     },
-     "execution_count": 79,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# Generate schemas for all functions\n",
-    "from semantic_router.llms.openai import get_schemas_openai\n",
-    "\n",
-    "schemas = get_schemas_openai(functions)\n",
-    "schemas"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 80,
-   "metadata": {
-    "id": "YBRHxhnkg9hs"
-   },
-   "outputs": [],
-   "source": [
-    "# Define the dynamic route with multiple functions\n",
-    "multi_function_route = Route(\n",
-    "    name=\"timezone_management\",\n",
-    "    utterances=[\n",
-    "        # Utterances for get_time function\n",
-    "        \"what is the time in New York?\",\n",
-    "        \"current time in Berlin?\",\n",
-    "        \"tell me the time in Moscow right now\",\n",
-    "        \"can you show me the current time in Tokyo?\",\n",
-    "        \"please provide the current time in London\",\n",
-    "        # Utterances for get_time_difference function\n",
-    "        \"how many hours ahead is Tokyo from London?\",\n",
-    "        \"time difference between Sydney and Cairo\",\n",
-    "        \"what's the time gap between Los Angeles and New York?\",\n",
-    "        \"how much time difference is there between Paris and Sydney?\",\n",
-    "        \"calculate the time difference between Dubai and Toronto\",\n",
-    "        # Utterances for convert_time function\n",
-    "        \"convert 15:00 from New York time to Berlin time\",\n",
-    "        \"change 09:00 from Paris time to Moscow time\",\n",
-    "        \"adjust 20:00 from Rome time to London time\",\n",
-    "        \"convert 12:00 from Madrid time to Chicago time\",\n",
-    "        \"change 18:00 from Beijing time to Los Angeles time\"\n",
-    "        # All three functions\n",
-    "        \"What is the time in Seattle? What is the time difference between Mumbai and Tokyo? What is 5:53 Toronto time in Sydney time?\",\n",
-    "    ],\n",
-    "    function_schemas=schemas,\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 81,
-   "metadata": {
-    "id": "yEbQadQbg9ht"
-   },
-   "outputs": [],
-   "source": [
-    "routes = [politics, chitchat, multi_function_route]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 82,
-   "metadata": {
-    "id": "C0aYIXaog9ht",
-    "outputId": "74114a86-4a6f-49c5-8e2e-600f577d63f5"
-   },
-   "outputs": [],
-   "source": [
-    "rl2 = RouteLayer(encoder=encoder, routes=routes)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "cG98YLZ5g9ht"
-   },
-   "source": [
-    "### Function to Parse Route Layer Responses"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 83,
-   "metadata": {
-    "id": "PJR97klVg9ht"
-   },
-   "outputs": [],
-   "source": [
-    "def parse_response(response: str):\n",
-    "\n",
-    "    for call in response.function_call:\n",
-    "        args = call[\"arguments\"]\n",
-    "        if call[\"function_name\"] == \"get_time\":\n",
-    "            result = get_time(**args)\n",
-    "            print(result)\n",
-    "        if call[\"function_name\"] == \"get_time_difference\":\n",
-    "            result = get_time_difference(**args)\n",
-    "            print(result)\n",
-    "        if call[\"function_name\"] == \"convert_time\":\n",
-    "            result = convert_time(**args)\n",
-    "            print(result)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "OUbPbxZKg9ht"
-   },
-   "source": [
-    "### Checking that Politics Non-Dynamic Route Still Works"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 84,
-   "metadata": {
-    "id": "D2kXFv9Xg9ht",
-    "outputId": "569cf17f-2091-4aea-9cba-11bb0af2ebd4"
-   },
-   "outputs": [
+    },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='politics', function_call=None, similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "5jaF1Xa5ur0y"
+      },
+      "outputs": [],
+      "source": [
+        "from datetime import datetime\n",
+        "from zoneinfo import ZoneInfo\n",
+        "\n",
+        "\n",
+        "def get_time(timezone: str) -> str:\n",
+        "    \"\"\"Finds the current time in a specific timezone.\n",
+        "\n",
+        "    :param timezone: The timezone to find the current time in, should\n",
+        "        be a valid timezone from the IANA Time Zone Database like\n",
+        "        \"America/New_York\" or \"Europe/London\". Do NOT put the place\n",
+        "        name itself like \"rome\", or \"new york\", you must provide\n",
+        "        the IANA format.\n",
+        "    :type timezone: str\n",
+        "    :return: The current time in the specified timezone.\"\"\"\n",
+        "    now = datetime.now(ZoneInfo(timezone))\n",
+        "    return now.strftime(\"%H:%M\")"
       ]
-     },
-     "execution_count": 84,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "\n",
-    "response = rl2(\"What is your political leaning?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 85,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='politics', function_call=None, similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/",
+          "height": 35
+        },
+        "id": "YyFKV8jMur0z",
+        "outputId": "29cf80f4-552c-47bb-fbf9-019f5dfdf00a"
+      },
+      "outputs": [
+        {
+          "data": {
+            "text/plain": [
+              "'17:57'"
+            ]
+          },
+          "execution_count": 6,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "get_time(\"America/New_York\")"
       ]
-     },
-     "execution_count": 85,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# async\n",
-    "\n",
-    "response = await rl2.acall(\"What is your political leaning?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "ZHgw8QoWg9ht"
-   },
-   "source": [
-    "### Checking that Chitchat Non-Dynamic Route Still Works"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 86,
-   "metadata": {
-    "id": "YsI5O_bHg9ht",
-    "outputId": "a6e3814b-97e0-4406-ec9a-17b1c7103e40"
-   },
-   "outputs": [
+    },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "4qyaRuNXur0z"
+      },
+      "source": [
+        "To get the function schema we can use the `get_schema` function from the `function_call` module."
       ]
-     },
-     "execution_count": 86,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "response = rl2(\"Hello bot, how are you today?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 87,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "tOjuhp5Xur0z",
+        "outputId": "ca88a3ea-d70a-4950-be9a-63fab699de3b"
+      },
+      "outputs": [
+        {
+          "data": {
+            "text/plain": [
+              "[{'type': 'function',\n",
+              "  'function': {'name': 'get_time',\n",
+              "   'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
+              "   'parameters': {'type': 'object',\n",
+              "    'properties': {'timezone': {'type': 'string',\n",
+              "      'description': 'The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.'}},\n",
+              "    'required': ['timezone']}}}]"
+            ]
+          },
+          "execution_count": 7,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "from semantic_router.llms.openai import get_schemas_openai\n",
+        "\n",
+        "schemas = get_schemas_openai([get_time])\n",
+        "schemas"
       ]
-     },
-     "execution_count": 87,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# async\n",
-    "response = await rl2.acall(\"Hello bot, how are you today?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "uZDiY787g9hu"
-   },
-   "source": [
-    "### Testing the `multi_function_route` - The `get_time` Function"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 88,
-   "metadata": {
-    "id": "BdOfLx-wg9hu",
-    "outputId": "ef55a34c-7c34-4acc-918d-a173fac95171"
-   },
-   "outputs": [
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[33m2024-07-16 14:26:13 WARNING semantic_router.utils.logger No LLM provided for dynamic route, will use OpenAI LLM default. Ensure API key is set in OPENAI_API_KEY environment variable.\u001b[0m\n",
-      "\u001b[32m2024-07-16 14:26:14 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
-     ]
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "HcF7jGjAur0z"
+      },
+      "source": [
+        "We use this to define our dynamic route:"
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "iesBG9P3ur0z"
+      },
+      "outputs": [],
+      "source": [
+        "time_route = Route(\n",
+        "    name=\"get_time\",\n",
+        "    utterances=[\n",
+        "        \"what is the time in new york city?\",\n",
+        "        \"what is the time in london?\",\n",
+        "        \"I live in Rome, what time is it?\",\n",
+        "    ],\n",
+        "    function_schemas=schemas,\n",
+        ")"
       ]
-     },
-     "execution_count": 88,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "response = rl2(\"what is the time in New York?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 89,
-   "metadata": {
-    "id": "QrpF_JcHg9hu",
-    "outputId": "242d645f-43c3-4e9f-9a46-d3aa3105f02a"
-   },
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "07:26\n"
-     ]
-    }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 90,
-   "metadata": {},
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "jmVwEWEIg9hq"
+      },
+      "outputs": [],
+      "source": [
+        "time_route.llm"
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:26:18 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
-     ]
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "ZiUs3ovpur0z"
+      },
+      "source": [
+        "Add the new route to our `layer`:"
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "-0vY8PRXur0z",
+        "outputId": "db01e14c-eab3-4f93-f4c2-e30f508c8b5d"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[32m2024-05-08 01:57:56 INFO semantic_router.utils.logger Adding `get_time` route\u001b[0m\n"
+          ]
+        }
+      ],
+      "source": [
+        "rl.add(time_route)"
       ]
-     },
-     "execution_count": 90,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# async\n",
-    "response = await rl2.acall(\"what is the time in New York?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 91,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "07:26\n"
-     ]
-    }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "wcjQ4Dbpg9hu"
-   },
-   "source": [
-    "### Testing the `multi_function_route` - The `get_time_difference` Function"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 92,
-   "metadata": {
-    "id": "W85287lAg9hu",
-    "outputId": "4f247f13-046b-4a5c-f119-de17df29131f"
-   },
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "mbccVdy5g9hr"
+      },
+      "outputs": [],
+      "source": [
+        "time_route.llm"
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:26:24 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}]\u001b[0m\n"
-     ]
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "7yoE0IrNur0z"
+      },
+      "source": [
+        "Now we can ask our layer a time related question to trigger our new dynamic route."
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}], similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/",
+          "height": 53
+        },
+        "id": "Wfb68M0-ur0z",
+        "outputId": "79923883-2a4d-4744-f8ce-e818cb5f14c3"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[33m2024-05-08 01:57:57 WARNING semantic_router.utils.logger No LLM provided for dynamic route, will use OpenAI LLM default. Ensure API key is set in OPENAI_API_KEY environment variable.\u001b[0m\n",
+            "\u001b[32m2024-05-08 01:57:58 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
+          ]
+        },
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+            ]
+          },
+          "execution_count": 12,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "response = rl(\"what is the time in new york city?\")\n",
+        "response"
       ]
-     },
-     "execution_count": 92,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "response = rl2(\"What is the time difference between Los Angeles and Istanbul?\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 93,
-   "metadata": {
-    "id": "2jxAIi6rg9hv",
-    "outputId": "8abff974-602f-4c0d-8d21-3a275b0eee62"
-   },
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "The time difference between America/Los_Angeles and Europe/Istanbul is 10.0 hours.\n"
-     ]
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "92x96x1Og9hr",
+        "outputId": "c1e46a81-b681-4a10-fff6-71e03342a88e"
+      },
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\n"
+          ]
+        }
+      ],
+      "source": [
+        "print(response.function_call)"
+      ]
     },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "/var/folders/7b/r9z99rtd2zg774gf4bh8cr9m0000gn/T/ipykernel_86079/3683005204.py:28: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).\n",
-      "  now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n"
-     ]
-    }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 94,
-   "metadata": {},
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "xvdyUPKqg9hr",
+        "outputId": "4161e7e0-ab6d-4e76-f068-2d66728305ff"
+      },
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "17:57\n"
+          ]
+        }
+      ],
+      "source": [
+        "import json\n",
+        "\n",
+        "for call in response.function_call:\n",
+        "    if call[\"function_name\"] == \"get_time\":\n",
+        "        args = call[\"arguments\"]\n",
+        "        result = get_time(**args)\n",
+        "print(result)"
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:26:30 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}]\u001b[0m\n"
-     ]
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "Qt0vkq2Xur00"
+      },
+      "source": [
+        "Our dynamic route provides both the route itself _and_ the input parameters required to use the route."
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}], similarity_score=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "jToYBo8Ug9hr"
+      },
+      "source": [
+        "## Dynamic Routes with Multiple Functions"
       ]
-     },
-     "execution_count": 94,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# async\n",
-    "response = await rl2.acall(\n",
-    "    \"What is the time difference between Los Angeles and Istanbul?\"\n",
-    ")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 95,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "The time difference between America/Los_Angeles and Europe/Istanbul is 10.0 hours.\n"
-     ]
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "J0oD1dxIur00"
+      },
+      "source": [
+        "---"
+      ]
     },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "/var/folders/7b/r9z99rtd2zg774gf4bh8cr9m0000gn/T/ipykernel_86079/3683005204.py:28: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).\n",
-      "  now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n"
-     ]
-    }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "14qz-ApLg9hv"
-   },
-   "source": [
-    "### Testing the `multi_function_route` - The `convert_time` Function"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 96,
-   "metadata": {
-    "id": "PzM1HH7Rg9hv",
-    "outputId": "e123c86f-9754-453a-d895-bfcce26110d4"
-   },
-   "outputs": [
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "vEkTpoVAg9hr"
+      },
+      "source": [
+        "Routes can be assigned multiple functions. Then, when that particular Route is selected by the Route Layer, a number of those functions might be invoked due to the users utterance containing relevant information that fits their arguments."
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:26:35 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}]\u001b[0m\n"
-     ]
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "BHUlB3org9hs"
+      },
+      "source": [
+        "Let's define a Route that has multiple functions."
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}], similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "dtrksov0g9hs"
+      },
+      "outputs": [],
+      "source": [
+        "from datetime import datetime, timedelta\n",
+        "from zoneinfo import ZoneInfo\n",
+        "\n",
+        "\n",
+        "# Function with one argument\n",
+        "def get_time(timezone: str) -> str:\n",
+        "    \"\"\"Finds the current time in a specific timezone.\n",
+        "\n",
+        "    :param timezone: The timezone to find the current time in, should\n",
+        "        be a valid timezone from the IANA Time Zone Database like\n",
+        "        \"America/New_York\" or \"Europe/London\". Do NOT put the place\n",
+        "        name itself like \"rome\", or \"new york\", you must provide\n",
+        "        the IANA format.\n",
+        "    :type timezone: str\n",
+        "    :return: The current time in the specified timezone.\"\"\"\n",
+        "    now = datetime.now(ZoneInfo(timezone))\n",
+        "    return now.strftime(\"%H:%M\")\n",
+        "\n",
+        "\n",
+        "def get_time_difference(timezone1: str, timezone2: str) -> str:\n",
+        "    \"\"\"Calculates the time difference between two timezones.\n",
+        "    :param timezone1: The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\n",
+        "    :param timezone2: The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\n",
+        "    :type timezone1: str\n",
+        "    :type timezone2: str\n",
+        "    :return: The time difference in hours between the two timezones.\"\"\"\n",
+        "    # Get the current time in UTC\n",
+        "    now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n",
+        "\n",
+        "    # Convert the UTC time to the specified timezones\n",
+        "    tz1_time = now_utc.astimezone(ZoneInfo(timezone1))\n",
+        "    tz2_time = now_utc.astimezone(ZoneInfo(timezone2))\n",
+        "\n",
+        "    # Calculate the difference in offsets from UTC\n",
+        "    tz1_offset = tz1_time.utcoffset().total_seconds()\n",
+        "    tz2_offset = tz2_time.utcoffset().total_seconds()\n",
+        "\n",
+        "    # Calculate the difference in hours\n",
+        "    hours_difference = (tz2_offset - tz1_offset) / 3600\n",
+        "\n",
+        "    return f\"The time difference between {timezone1} and {timezone2} is {hours_difference} hours.\"\n",
+        "\n",
+        "\n",
+        "# Function with three arguments\n",
+        "def convert_time(time: str, from_timezone: str, to_timezone: str) -> str:\n",
+        "    \"\"\"Converts a specific time from one timezone to another.\n",
+        "    :param time: The time to convert in HH:MM format.\n",
+        "    :param from_timezone: The original timezone of the time, should be a valid IANA timezone.\n",
+        "    :param to_timezone: The target timezone for the time, should be a valid IANA timezone.\n",
+        "    :type time: str\n",
+        "    :type from_timezone: str\n",
+        "    :type to_timezone: str\n",
+        "    :return: The converted time in the target timezone.\n",
+        "    :raises ValueError: If the time format or timezone strings are invalid.\n",
+        "\n",
+        "    Example:\n",
+        "        convert_time(\"12:30\", \"America/New_York\", \"Asia/Tokyo\") -> \"03:30\"\n",
+        "    \"\"\"\n",
+        "    try:\n",
+        "        # Use today's date to avoid historical timezone issues\n",
+        "        today = datetime.now().date()\n",
+        "        datetime_string = f\"{today} {time}\"\n",
+        "        time_obj = datetime.strptime(datetime_string, \"%Y-%m-%d %H:%M\").replace(\n",
+        "            tzinfo=ZoneInfo(from_timezone)\n",
+        "        )\n",
+        "\n",
+        "        converted_time = time_obj.astimezone(ZoneInfo(to_timezone))\n",
+        "\n",
+        "        formatted_time = converted_time.strftime(\"%H:%M\")\n",
+        "        return formatted_time\n",
+        "    except Exception as e:\n",
+        "        raise ValueError(f\"Error converting time: {e}\")"
       ]
-     },
-     "execution_count": 96,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "response = rl2(\"What is 23:02 Dubai time in Tokyo time? Please and thank you.\")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 97,
-   "metadata": {
-    "id": "QFKZ757Pg9hv",
-    "outputId": "af5c1328-f6dd-4dc7-c104-e920198885fc"
-   },
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "04:02\n"
-     ]
-    }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 98,
-   "metadata": {},
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "AjoYy7mFg9hs"
+      },
+      "outputs": [],
+      "source": [
+        "functions = [get_time, get_time_difference, convert_time]"
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:26:40 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}]\u001b[0m\n"
-     ]
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "DoOkXV2Tg9hs",
+        "outputId": "f1e0fe08-b6ed-4f50-d845-5c54832ca677"
+      },
+      "outputs": [
+        {
+          "data": {
+            "text/plain": [
+              "[{'type': 'function',\n",
+              "  'function': {'name': 'get_time',\n",
+              "   'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
+              "   'parameters': {'type': 'object',\n",
+              "    'properties': {'timezone': {'type': 'string',\n",
+              "      'description': 'The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.'}},\n",
+              "    'required': ['timezone']}}},\n",
+              " {'type': 'function',\n",
+              "  'function': {'name': 'get_time_difference',\n",
+              "   'description': 'Calculates the time difference between two timezones.\\n:param timezone1: The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\\n:param timezone2: The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\\n:type timezone1: str\\n:type timezone2: str\\n:return: The time difference in hours between the two timezones.',\n",
+              "   'parameters': {'type': 'object',\n",
+              "    'properties': {'timezone1': {'type': 'string',\n",
+              "      'description': 'The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".'},\n",
+              "     'timezone2': {'type': 'string',\n",
+              "      'description': 'The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".'}},\n",
+              "    'required': ['timezone1', 'timezone2']}}},\n",
+              " {'type': 'function',\n",
+              "  'function': {'name': 'convert_time',\n",
+              "   'description': 'Converts a specific time from one timezone to another.\\n:param time: The time to convert in HH:MM format.\\n:param from_timezone: The original timezone of the time, should be a valid IANA timezone.\\n:param to_timezone: The target timezone for the time, should be a valid IANA timezone.\\n:type time: str\\n:type from_timezone: str\\n:type to_timezone: str\\n:return: The converted time in the target timezone.\\n:raises ValueError: If the time format or timezone strings are invalid.\\n\\nExample:\\n    convert_time(\"12:30\", \"America/New_York\", \"Asia/Tokyo\") -> \"03:30\"',\n",
+              "   'parameters': {'type': 'object',\n",
+              "    'properties': {'time': {'type': 'string',\n",
+              "      'description': 'The time to convert in HH:MM format.'},\n",
+              "     'from_timezone': {'type': 'string',\n",
+              "      'description': 'The original timezone of the time, should be a valid IANA timezone.'},\n",
+              "     'to_timezone': {'type': 'string',\n",
+              "      'description': 'The target timezone for the time, should be a valid IANA timezone.'}},\n",
+              "    'required': ['time', 'from_timezone', 'to_timezone']}}}]"
+            ]
+          },
+          "execution_count": 17,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "# Generate schemas for all functions\n",
+        "from semantic_router.llms.openai import get_schemas_openai\n",
+        "\n",
+        "schemas = get_schemas_openai(functions)\n",
+        "schemas"
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}], similarity_score=None)"
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "YBRHxhnkg9hs"
+      },
+      "outputs": [],
+      "source": [
+        "# Define the dynamic route with multiple functions\n",
+        "multi_function_route = Route(\n",
+        "    name=\"timezone_management\",\n",
+        "    utterances=[\n",
+        "        # Utterances for get_time function\n",
+        "        \"what is the time in New York?\",\n",
+        "        \"current time in Berlin?\",\n",
+        "        \"tell me the time in Moscow right now\",\n",
+        "        \"can you show me the current time in Tokyo?\",\n",
+        "        \"please provide the current time in London\",\n",
+        "        # Utterances for get_time_difference function\n",
+        "        \"how many hours ahead is Tokyo from London?\",\n",
+        "        \"time difference between Sydney and Cairo\",\n",
+        "        \"what's the time gap between Los Angeles and New York?\",\n",
+        "        \"how much time difference is there between Paris and Sydney?\",\n",
+        "        \"calculate the time difference between Dubai and Toronto\",\n",
+        "        # Utterances for convert_time function\n",
+        "        \"convert 15:00 from New York time to Berlin time\",\n",
+        "        \"change 09:00 from Paris time to Moscow time\",\n",
+        "        \"adjust 20:00 from Rome time to London time\",\n",
+        "        \"convert 12:00 from Madrid time to Chicago time\",\n",
+        "        \"change 18:00 from Beijing time to Los Angeles time\"\n",
+        "        # All three functions\n",
+        "        \"What is the time in Seattle? What is the time difference between Mumbai and Tokyo? What is 5:53 Toronto time in Sydney time?\",\n",
+        "    ],\n",
+        "    function_schemas=schemas,\n",
+        ")"
       ]
-     },
-     "execution_count": 98,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# async\n",
-    "response = await rl2.acall(\n",
-    "    \"What is 23:02 Dubai time in Tokyo time? Please and thank you.\"\n",
-    ")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 99,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "04:02\n"
-     ]
-    }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "TSRfC6JJg9hv"
-   },
-   "source": [
-    "### The Cool Bit - Testing `multi_function_route` - Multiple Functions at Once"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 100,
-   "metadata": {
-    "id": "Vnj6A3AVg9hv",
-    "outputId": "c8a61c3f-a504-430b-82fb-c211c0523dcb"
-   },
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "yEbQadQbg9ht"
+      },
+      "outputs": [],
+      "source": [
+        "routes = [politics, chitchat, multi_function_route]"
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:26:46 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'Europe/Prague'}}, {'function_name': 'get_time_difference', 'arguments': {'timezone1': 'Europe/Berlin', 'timezone2': 'Asia/Shanghai'}}, {'function_name': 'convert_time', 'arguments': {'time': '05:53', 'from_timezone': 'Europe/Lisbon', 'to_timezone': 'Asia/Bangkok'}}]\u001b[0m\n"
-     ]
-    }
-   ],
-   "source": [
-    "# sync\n",
-    "response = rl2(\n",
-    "    \"\"\"\n",
-    "    What is the time in Prague?\n",
-    "    What is the time difference between Frankfurt and Beijing?\n",
-    "    What is 5:53 Lisbon time in Bangkok time?\n",
-    "\"\"\"\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 101,
-   "metadata": {
-    "id": "L9jq_Yoag9hv",
-    "outputId": "50fae028-4af4-46f5-f6e9-4262b8874caa"
-   },
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "C0aYIXaog9ht",
+        "outputId": "74114a86-4a6f-49c5-8e2e-600f577d63f5"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[32m2024-05-08 01:57:58 INFO semantic_router.utils.logger local\u001b[0m\n"
+          ]
+        }
+      ],
+      "source": [
+        "rl2 = RouteLayer(encoder=encoder, routes=routes)"
+      ]
+    },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'Europe/Prague'}}, {'function_name': 'get_time_difference', 'arguments': {'timezone1': 'Europe/Berlin', 'timezone2': 'Asia/Shanghai'}}, {'function_name': 'convert_time', 'arguments': {'time': '05:53', 'from_timezone': 'Europe/Lisbon', 'to_timezone': 'Asia/Bangkok'}}], similarity_score=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "cG98YLZ5g9ht"
+      },
+      "source": [
+        "### Function to Parse Route Layer Responses"
       ]
-     },
-     "execution_count": 101,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "response"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 102,
-   "metadata": {
-    "id": "Hw3raSVBg9hv",
-    "outputId": "d30b9cba-979d-4bdf-86e0-37c550c4187d"
-   },
-   "outputs": [
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "13:26\n",
-      "The time difference between Europe/Berlin and Asia/Shanghai is 6.0 hours.\n",
-      "11:53\n"
-     ]
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "PJR97klVg9ht"
+      },
+      "outputs": [],
+      "source": [
+        "def parse_response(response: str):\n",
+        "\n",
+        "    for call in response.function_call:\n",
+        "        args = call[\"arguments\"]\n",
+        "        if call[\"function_name\"] == \"get_time\":\n",
+        "            result = get_time(**args)\n",
+        "            print(result)\n",
+        "        if call[\"function_name\"] == \"get_time_difference\":\n",
+        "            result = get_time_difference(**args)\n",
+        "            print(result)\n",
+        "        if call[\"function_name\"] == \"convert_time\":\n",
+        "            result = convert_time(**args)\n",
+        "            print(result)"
+      ]
     },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "/var/folders/7b/r9z99rtd2zg774gf4bh8cr9m0000gn/T/ipykernel_86079/3683005204.py:28: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).\n",
-      "  now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n"
-     ]
-    }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 103,
-   "metadata": {},
-   "outputs": [
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "OUbPbxZKg9ht"
+      },
+      "source": [
+        "### Checking that Politics Non-Dynamic Route Still Works"
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-07-16 14:26:52 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'Europe/Prague'}}, {'function_name': 'get_time_difference', 'arguments': {'timezone1': 'Europe/Berlin', 'timezone2': 'Asia/Shanghai'}}, {'function_name': 'convert_time', 'arguments': {'time': '05:53', 'from_timezone': 'Europe/Lisbon', 'to_timezone': 'Asia/Bangkok'}}]\u001b[0m\n"
-     ]
-    }
-   ],
-   "source": [
-    "# async\n",
-    "response = await rl2.acall(\n",
-    "    \"\"\"\n",
-    "    What is the time in Prague?\n",
-    "    What is the time difference between Frankfurt and Beijing?\n",
-    "    What is 5:53 Lisbon time in Bangkok time?\n",
-    "\"\"\"\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 104,
-   "metadata": {},
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "D2kXFv9Xg9ht",
+        "outputId": "569cf17f-2091-4aea-9cba-11bb0af2ebd4"
+      },
+      "outputs": [
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='politics', function_call=None, similarity_score=None)"
+            ]
+          },
+          "execution_count": 22,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "response = rl2(\"What is your political leaning?\")\n",
+        "response"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "ZHgw8QoWg9ht"
+      },
+      "source": [
+        "### Checking that Chitchat Non-Dynamic Route Still Works"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "YsI5O_bHg9ht",
+        "outputId": "a6e3814b-97e0-4406-ec9a-17b1c7103e40"
+      },
+      "outputs": [
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+            ]
+          },
+          "execution_count": 23,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "response = rl2(\"Hello bot, how are you today?\")\n",
+        "response"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "uZDiY787g9hu"
+      },
+      "source": [
+        "### Testing the `multi_function_route` - The `get_time` Function"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "BdOfLx-wg9hu",
+        "outputId": "ef55a34c-7c34-4acc-918d-a173fac95171"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[33m2024-05-08 01:58:00 WARNING semantic_router.utils.logger No LLM provided for dynamic route, will use OpenAI LLM default. Ensure API key is set in OPENAI_API_KEY environment variable.\u001b[0m\n",
+            "\u001b[32m2024-05-08 01:58:01 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
+          ]
+        },
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+            ]
+          },
+          "execution_count": 24,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "response = rl2(\"what is the time in New York?\")\n",
+        "response"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "QrpF_JcHg9hu",
+        "outputId": "242d645f-43c3-4e9f-9a46-d3aa3105f02a"
+      },
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "17:58\n"
+          ]
+        }
+      ],
+      "source": [
+        "parse_response(response)"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "wcjQ4Dbpg9hu"
+      },
+      "source": [
+        "### Testing the `multi_function_route` - The `get_time_difference` Function"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "W85287lAg9hu",
+        "outputId": "4f247f13-046b-4a5c-f119-de17df29131f"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[32m2024-05-08 01:58:02 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}]\u001b[0m\n"
+          ]
+        },
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}], similarity_score=None)"
+            ]
+          },
+          "execution_count": 26,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "response = rl2(\"What is the time difference between Los Angeles and Istanbul?\")\n",
+        "response"
+      ]
+    },
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "13:26\n",
-      "The time difference between Europe/Berlin and Asia/Shanghai is 6.0 hours.\n",
-      "11:53\n"
-     ]
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "2jxAIi6rg9hv",
+        "outputId": "8abff974-602f-4c0d-8d21-3a275b0eee62"
+      },
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "The time difference between America/Los_Angeles and Europe/Istanbul is 10.0 hours.\n"
+          ]
+        }
+      ],
+      "source": [
+        "parse_response(response)"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "14qz-ApLg9hv"
+      },
+      "source": [
+        "### Testing the `multi_function_route` - The `convert_time` Function"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "PzM1HH7Rg9hv",
+        "outputId": "e123c86f-9754-453a-d895-bfcce26110d4"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[32m2024-05-08 01:58:04 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}]\u001b[0m\n"
+          ]
+        },
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='timezone_management', function_call=[{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}], similarity_score=None)"
+            ]
+          },
+          "execution_count": 28,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "response = rl2(\"What is 23:02 Dubai time in Tokyo time? Please and thank you.\")\n",
+        "response"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "QFKZ757Pg9hv",
+        "outputId": "af5c1328-f6dd-4dc7-c104-e920198885fc"
+      },
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "04:02\n"
+          ]
+        }
+      ],
+      "source": [
+        "parse_response(response)"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "TSRfC6JJg9hv"
+      },
+      "source": [
+        "### The Cool Bit - Testing `multi_function_route` - Multiple Functions at Once"
+      ]
     },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "/var/folders/7b/r9z99rtd2zg774gf4bh8cr9m0000gn/T/ipykernel_86079/3683005204.py:28: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).\n",
-      "  now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n"
-     ]
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "Vnj6A3AVg9hv",
+        "outputId": "c8a61c3f-a504-430b-82fb-c211c0523dcb"
+      },
+      "outputs": [
+        {
+          "name": "stderr",
+          "output_type": "stream",
+          "text": [
+            "\u001b[32m2024-05-08 01:58:07 INFO semantic_router.utils.logger Function inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'Europe/Prague'}}, {'function_name': 'get_time_difference', 'arguments': {'timezone1': 'Europe/Berlin', 'timezone2': 'Asia/Shanghai'}}, {'function_name': 'convert_time', 'arguments': {'time': '05:53', 'from_timezone': 'Europe/Lisbon', 'to_timezone': 'Asia/Bangkok'}}]\u001b[0m\n"
+          ]
+        }
+      ],
+      "source": [
+        "response = rl2(\n",
+        "    \"\"\"\n",
+        "    What is the time in Prague?\n",
+        "    What is the time difference between Frankfurt and Beijing?\n",
+        "    What is 5:53 Lisbon time in Bangkok time?\n",
+        "\"\"\"\n",
+        ")"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "L9jq_Yoag9hv",
+        "outputId": "50fae028-4af4-46f5-f6e9-4262b8874caa"
+      },
+      "outputs": [
+        {
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'Europe/Prague'}}, {'function_name': 'get_time_difference', 'arguments': {'timezone1': 'Europe/Berlin', 'timezone2': 'Asia/Shanghai'}}, {'function_name': 'convert_time', 'arguments': {'time': '05:53', 'from_timezone': 'Europe/Lisbon', 'to_timezone': 'Asia/Bangkok'}}], similarity_score=None)"
+            ]
+          },
+          "execution_count": 31,
+          "metadata": {},
+          "output_type": "execute_result"
+        }
+      ],
+      "source": [
+        "response"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "Hw3raSVBg9hv",
+        "outputId": "d30b9cba-979d-4bdf-86e0-37c550c4187d"
+      },
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "23:58\n",
+            "The time difference between Europe/Berlin and Asia/Shanghai is 6.0 hours.\n",
+            "11:53\n"
+          ]
+        }
+      ],
+      "source": [
+        "parse_response(response)"
+      ]
+    }
+  ],
+  "metadata": {
+    "colab": {
+      "provenance": []
+    },
+    "kernelspec": {
+      "display_name": "decision-layer",
+      "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.11.4"
     }
-   ],
-   "source": [
-    "parse_response(response)"
-   ]
-  }
- ],
- "metadata": {
-  "colab": {
-   "provenance": []
-  },
-  "kernelspec": {
-   "display_name": "decision-layer",
-   "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.3"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
+  "nbformat": 4,
+  "nbformat_minor": 0
+}
\ No newline at end of file
diff --git a/docs/03-async-dynamic-routes.ipynb b/docs/03-async-dynamic-routes.ipynb
new file mode 100644
index 00000000..5875b432
--- /dev/null
+++ b/docs/03-async-dynamic-routes.ipynb
@@ -0,0 +1,1051 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "UxqB7_Ieur0s"
+   },
+   "source": [
+    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "EduhQaNAur0u"
+   },
+   "source": [
+    "# Dynamic Routes"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "_4JgNeX4ur0v"
+   },
+   "source": [
+    "In semantic-router there are two types of routes that can be chosen. Both routes belong to the `Route` object, the only difference between them is that _static_ routes return a `Route.name` when chosen, whereas _dynamic_ routes use an LLM call to produce parameter input values.\n",
+    "\n",
+    "For example, a _static_ route will tell us if a query is talking about mathematics by returning the route name (which could be `\"math\"` for example). A _dynamic_ route does the same thing, but it also extracts key information from the input utterance to be used in a function associated with that route.\n",
+    "\n",
+    "For example we could provide a dynamic route with associated utterances:\n",
+    "\n",
+    "```\n",
+    "\"what is x to the power of y?\"\n",
+    "\"what is 9 to the power of 4?\"\n",
+    "\"calculate the result of base x and exponent y\"\n",
+    "\"calculate the result of base 10 and exponent 3\"\n",
+    "\"return x to the power of y\"\n",
+    "```\n",
+    "\n",
+    "and we could also provide the route with a schema outlining key features of the function:\n",
+    "\n",
+    "```\n",
+    "def power(base: float, exponent: float) -> float:\n",
+    "    \"\"\"Raise base to the power of exponent.\n",
+    "\n",
+    "    Args:\n",
+    "        base (float): The base number.\n",
+    "        exponent (float): The exponent to which the base is raised.\n",
+    "\n",
+    "    Returns:\n",
+    "        float: The result of base raised to the power of exponent.\n",
+    "    \"\"\"\n",
+    "    return base ** exponent\n",
+    "```\n",
+    "\n",
+    "Then, if the users input utterance is \"What is 2 to the power of 3?\", the route will be triggered, as the input utterance is semantically similar to the route utterances. Furthermore, the route utilizes an LLM to identify that `base=2` and `expoenent=3`. These values are returned in such a way that they can be used in the above `power` function. That is, the dynamic router automates the process of calling relevant functions from natural language inputs.\n",
+    "\n",
+    "***⚠️ Note: We have a fully local version of dynamic routes available at [docs/05-local-execution.ipynb](https://github.com/aurelio-labs/semantic-router/blob/main/docs/05-local-execution.ipynb). The local 05 version tends to outperform the OpenAI version we demo in this notebook, so we'd recommend trying [05](https://github.com/aurelio-labs/semantic-router/blob/main/docs/05-local-execution.ipynb)!***"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "bbmw8CO4ur0v"
+   },
+   "source": [
+    "## Installing the Library"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "id": "dLElfRhgur0v",
+    "outputId": "da0e506e-24cf-43da-9243-894a7c4955db"
+   },
+   "outputs": [],
+   "source": [
+    "!pip install tzdata\n",
+    "!pip install -qU semantic-router"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "BixZd6Eour0w"
+   },
+   "source": [
+    "## Initializing Routes and RouteLayer"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "PxnW9qBvur0x"
+   },
+   "source": [
+    "Dynamic routes are treated in the same way as static routes, let's begin by initializing a `RouteLayer` consisting of static routes."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "id": "kc9Ty6Lgur0x",
+    "outputId": "f32e3a25-c073-4802-ced3-d7a5663670c1"
+   },
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/opt/anaconda3/envs/semantic-router/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
+      "  from .autonotebook import tqdm as notebook_tqdm\n"
+     ]
+    }
+   ],
+   "source": [
+    "from semantic_router import Route\n",
+    "\n",
+    "politics = Route(\n",
+    "    name=\"politics\",\n",
+    "    utterances=[\n",
+    "        \"isn't politics the best thing ever\",\n",
+    "        \"why don't you tell me about your political opinions\",\n",
+    "        \"don't you just love the president\" \"don't you just hate the president\",\n",
+    "        \"they're going to destroy this country!\",\n",
+    "        \"they will save the country!\",\n",
+    "    ],\n",
+    ")\n",
+    "chitchat = Route(\n",
+    "    name=\"chitchat\",\n",
+    "    utterances=[\n",
+    "        \"how's the weather today?\",\n",
+    "        \"how are things going?\",\n",
+    "        \"lovely weather today\",\n",
+    "        \"the weather is horrendous\",\n",
+    "        \"let's go to the chippy\",\n",
+    "    ],\n",
+    ")\n",
+    "\n",
+    "routes = [politics, chitchat]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "voWyqmffur0x"
+   },
+   "source": [
+    "We initialize our `RouteLayer` with our `encoder` and `routes`. We can use popular encoder APIs like `CohereEncoder` and `OpenAIEncoder`, or local alternatives like `FastEmbedEncoder`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/"
+    },
+    "id": "BI9AiDspur0y",
+    "outputId": "27329a54-3f16-44a5-ac20-13a6b26afb97"
+   },
+   "outputs": [],
+   "source": [
+    "import os\n",
+    "from getpass import getpass\n",
+    "from semantic_router import RouteLayer\n",
+    "from semantic_router.encoders import CohereEncoder, OpenAIEncoder\n",
+    "\n",
+    "\n",
+    "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n",
+    "    \"Enter OpenAI API Key: \"\n",
+    ")\n",
+    "\n",
+    "# encoder = CohereEncoder()\n",
+    "encoder = OpenAIEncoder()\n",
+    "\n",
+    "rl = RouteLayer(encoder=encoder, routes=routes)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "GuLCeIS5ur0y"
+   },
+   "source": [
+    "We run the solely static routes layer:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "await rl.acall(\"how's the weather today?\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "McbLKO26ur0y"
+   },
+   "source": [
+    "## Creating a Dynamic Route"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "ANAoEjxYur0y"
+   },
+   "source": [
+    "As with static routes, we must create a dynamic route before adding it to our route layer. To make a route dynamic, we need to provide the `function_schemas` as a list. Each function schema provides instructions on what a function is, so that an LLM can decide how to use it correctly."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "id": "5jaF1Xa5ur0y"
+   },
+   "outputs": [],
+   "source": [
+    "from datetime import datetime\n",
+    "from zoneinfo import ZoneInfo\n",
+    "\n",
+    "\n",
+    "def get_time(timezone: str) -> str:\n",
+    "    \"\"\"Finds the current time in a specific timezone.\n",
+    "\n",
+    "    :param timezone: The timezone to find the current time in, should\n",
+    "        be a valid timezone from the IANA Time Zone Database like\n",
+    "        \"America/New_York\" or \"Europe/London\". Do NOT put the place\n",
+    "        name itself like \"rome\", or \"new york\", you must provide\n",
+    "        the IANA format.\n",
+    "    :type timezone: str\n",
+    "    :return: The current time in the specified timezone.\"\"\"\n",
+    "    now = datetime.now(ZoneInfo(timezone))\n",
+    "    return now.strftime(\"%H:%M\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 35
+    },
+    "id": "YyFKV8jMur0z",
+    "outputId": "29cf80f4-552c-47bb-fbf9-019f5dfdf00a"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'10:26'"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "get_time(\"America/New_York\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "4qyaRuNXur0z"
+   },
+   "source": [
+    "To get the function schema we can use the `get_schema` function from the `function_call` module."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/"
+    },
+    "id": "tOjuhp5Xur0z",
+    "outputId": "ca88a3ea-d70a-4950-be9a-63fab699de3b"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'type': 'function',\n",
+       "  'function': {'name': 'get_time',\n",
+       "   'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
+       "   'parameters': {'type': 'object',\n",
+       "    'properties': {'timezone': {'type': 'string',\n",
+       "      'description': 'The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.'}},\n",
+       "    'required': ['timezone']}}}]"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "from semantic_router.llms.openai import get_schemas_openai\n",
+    "\n",
+    "schemas = get_schemas_openai([get_time])\n",
+    "schemas"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "HcF7jGjAur0z"
+   },
+   "source": [
+    "We use this to define our dynamic route:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "id": "iesBG9P3ur0z"
+   },
+   "outputs": [],
+   "source": [
+    "time_route = Route(\n",
+    "    name=\"get_time\",\n",
+    "    utterances=[\n",
+    "        \"what is the time in new york city?\",\n",
+    "        \"what is the time in london?\",\n",
+    "        \"I live in Rome, what time is it?\",\n",
+    "    ],\n",
+    "    function_schemas=schemas,\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "ZiUs3ovpur0z"
+   },
+   "source": [
+    "Add the new route to our `layer`:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/"
+    },
+    "id": "-0vY8PRXur0z",
+    "outputId": "db01e14c-eab3-4f93-f4c2-e30f508c8b5d"
+   },
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2024-07-17 17:26:51 INFO semantic_router.utils.logger Adding `get_time` route\u001b[0m\n"
+     ]
+    }
+   ],
+   "source": [
+    "rl.add(time_route)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "7yoE0IrNur0z"
+   },
+   "source": [
+    "Now we can ask our layer a time related question to trigger our new dynamic route."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[33m2024-07-17 17:26:53 WARNING semantic_router.utils.logger No LLM provided for dynamic route, will use OpenAI LLM default\u001b[0m\n",
+      "\u001b[32m2024-07-17 17:26:54 INFO semantic_router.utils.logger OpenAI => Function Inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "response = await rl.acall(\"what is the time in new york city?\")\n",
+    "response"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "id": "xvdyUPKqg9hr",
+    "outputId": "4161e7e0-ab6d-4e76-f068-2d66728305ff"
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10:26\n"
+     ]
+    }
+   ],
+   "source": [
+    "for call in response.function_call:\n",
+    "    if call[\"function_name\"] == \"get_time\":\n",
+    "        args = call[\"arguments\"]\n",
+    "        result = get_time(**args)\n",
+    "print(result)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "Qt0vkq2Xur00"
+   },
+   "source": [
+    "Our dynamic route provides both the route itself _and_ the input parameters required to use the route."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "jToYBo8Ug9hr"
+   },
+   "source": [
+    "## Dynamic Routes with Multiple Functions"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "J0oD1dxIur00"
+   },
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "vEkTpoVAg9hr"
+   },
+   "source": [
+    "Routes can be assigned multiple functions. Then, when that particular Route is selected by the Route Layer, a number of those functions might be invoked due to the users utterance containing relevant information that fits their arguments."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "BHUlB3org9hs"
+   },
+   "source": [
+    "Let's define a Route that has multiple functions."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "id": "dtrksov0g9hs"
+   },
+   "outputs": [],
+   "source": [
+    "from datetime import datetime, timedelta\n",
+    "from zoneinfo import ZoneInfo\n",
+    "\n",
+    "\n",
+    "# Function with one argument\n",
+    "def get_time(timezone: str) -> str:\n",
+    "    \"\"\"Finds the current time in a specific timezone.\n",
+    "\n",
+    "    :param timezone: The timezone to find the current time in, should\n",
+    "        be a valid timezone from the IANA Time Zone Database like\n",
+    "        \"America/New_York\" or \"Europe/London\". Do NOT put the place\n",
+    "        name itself like \"rome\", or \"new york\", you must provide\n",
+    "        the IANA format.\n",
+    "    :type timezone: str\n",
+    "    :return: The current time in the specified timezone.\"\"\"\n",
+    "    now = datetime.now(ZoneInfo(timezone))\n",
+    "    return now.strftime(\"%H:%M\")\n",
+    "\n",
+    "\n",
+    "def get_time_difference(timezone1: str, timezone2: str) -> str:\n",
+    "    \"\"\"Calculates the time difference between two timezones.\n",
+    "    :param timezone1: The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\n",
+    "    :param timezone2: The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\n",
+    "    :type timezone1: str\n",
+    "    :type timezone2: str\n",
+    "    :return: The time difference in hours between the two timezones.\"\"\"\n",
+    "    # Get the current time in UTC\n",
+    "    now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n",
+    "\n",
+    "    # Convert the UTC time to the specified timezones\n",
+    "    tz1_time = now_utc.astimezone(ZoneInfo(timezone1))\n",
+    "    tz2_time = now_utc.astimezone(ZoneInfo(timezone2))\n",
+    "\n",
+    "    # Calculate the difference in offsets from UTC\n",
+    "    tz1_offset = tz1_time.utcoffset().total_seconds()\n",
+    "    tz2_offset = tz2_time.utcoffset().total_seconds()\n",
+    "\n",
+    "    # Calculate the difference in hours\n",
+    "    hours_difference = (tz2_offset - tz1_offset) / 3600\n",
+    "\n",
+    "    return f\"The time difference between {timezone1} and {timezone2} is {hours_difference} hours.\"\n",
+    "\n",
+    "\n",
+    "# Function with three arguments\n",
+    "def convert_time(time: str, from_timezone: str, to_timezone: str) -> str:\n",
+    "    \"\"\"Converts a specific time from one timezone to another.\n",
+    "    :param time: The time to convert in HH:MM format.\n",
+    "    :param from_timezone: The original timezone of the time, should be a valid IANA timezone.\n",
+    "    :param to_timezone: The target timezone for the time, should be a valid IANA timezone.\n",
+    "    :type time: str\n",
+    "    :type from_timezone: str\n",
+    "    :type to_timezone: str\n",
+    "    :return: The converted time in the target timezone.\n",
+    "    :raises ValueError: If the time format or timezone strings are invalid.\n",
+    "\n",
+    "    Example:\n",
+    "        convert_time(\"12:30\", \"America/New_York\", \"Asia/Tokyo\") -> \"03:30\"\n",
+    "    \"\"\"\n",
+    "    try:\n",
+    "        # Use today's date to avoid historical timezone issues\n",
+    "        today = datetime.now().date()\n",
+    "        datetime_string = f\"{today} {time}\"\n",
+    "        time_obj = datetime.strptime(datetime_string, \"%Y-%m-%d %H:%M\").replace(\n",
+    "            tzinfo=ZoneInfo(from_timezone)\n",
+    "        )\n",
+    "\n",
+    "        converted_time = time_obj.astimezone(ZoneInfo(to_timezone))\n",
+    "\n",
+    "        formatted_time = converted_time.strftime(\"%H:%M\")\n",
+    "        return formatted_time\n",
+    "    except Exception as e:\n",
+    "        raise ValueError(f\"Error converting time: {e}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "id": "AjoYy7mFg9hs"
+   },
+   "outputs": [],
+   "source": [
+    "functions = [get_time, get_time_difference, convert_time]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "id": "DoOkXV2Tg9hs",
+    "outputId": "f1e0fe08-b6ed-4f50-d845-5c54832ca677"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[{'type': 'function',\n",
+       "  'function': {'name': 'get_time',\n",
+       "   'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
+       "   'parameters': {'type': 'object',\n",
+       "    'properties': {'timezone': {'type': 'string',\n",
+       "      'description': 'The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.'}},\n",
+       "    'required': ['timezone']}}},\n",
+       " {'type': 'function',\n",
+       "  'function': {'name': 'get_time_difference',\n",
+       "   'description': 'Calculates the time difference between two timezones.\\n:param timezone1: The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\\n:param timezone2: The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".\\n:type timezone1: str\\n:type timezone2: str\\n:return: The time difference in hours between the two timezones.',\n",
+       "   'parameters': {'type': 'object',\n",
+       "    'properties': {'timezone1': {'type': 'string',\n",
+       "      'description': 'The first timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".'},\n",
+       "     'timezone2': {'type': 'string',\n",
+       "      'description': 'The second timezone, should be a valid timezone from the IANA Time Zone Database like \"America/New_York\" or \"Europe/London\".'}},\n",
+       "    'required': ['timezone1', 'timezone2']}}},\n",
+       " {'type': 'function',\n",
+       "  'function': {'name': 'convert_time',\n",
+       "   'description': 'Converts a specific time from one timezone to another.\\n:param time: The time to convert in HH:MM format.\\n:param from_timezone: The original timezone of the time, should be a valid IANA timezone.\\n:param to_timezone: The target timezone for the time, should be a valid IANA timezone.\\n:type time: str\\n:type from_timezone: str\\n:type to_timezone: str\\n:return: The converted time in the target timezone.\\n:raises ValueError: If the time format or timezone strings are invalid.\\n\\nExample:\\n    convert_time(\"12:30\", \"America/New_York\", \"Asia/Tokyo\") -> \"03:30\"',\n",
+       "   'parameters': {'type': 'object',\n",
+       "    'properties': {'time': {'type': 'string',\n",
+       "      'description': 'The time to convert in HH:MM format.'},\n",
+       "     'from_timezone': {'type': 'string',\n",
+       "      'description': 'The original timezone of the time, should be a valid IANA timezone.'},\n",
+       "     'to_timezone': {'type': 'string',\n",
+       "      'description': 'The target timezone for the time, should be a valid IANA timezone.'}},\n",
+       "    'required': ['time', 'from_timezone', 'to_timezone']}}}]"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# Generate schemas for all functions\n",
+    "from semantic_router.llms.openai import get_schemas_openai\n",
+    "\n",
+    "schemas = get_schemas_openai(functions)\n",
+    "schemas"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "id": "YBRHxhnkg9hs"
+   },
+   "outputs": [],
+   "source": [
+    "# Define the dynamic route with multiple functions\n",
+    "multi_function_route = Route(\n",
+    "    name=\"timezone_management\",\n",
+    "    utterances=[\n",
+    "        # Utterances for get_time function\n",
+    "        \"what is the time in New York?\",\n",
+    "        \"current time in Berlin?\",\n",
+    "        \"tell me the time in Moscow right now\",\n",
+    "        \"can you show me the current time in Tokyo?\",\n",
+    "        \"please provide the current time in London\",\n",
+    "        # Utterances for get_time_difference function\n",
+    "        \"how many hours ahead is Tokyo from London?\",\n",
+    "        \"time difference between Sydney and Cairo\",\n",
+    "        \"what's the time gap between Los Angeles and New York?\",\n",
+    "        \"how much time difference is there between Paris and Sydney?\",\n",
+    "        \"calculate the time difference between Dubai and Toronto\",\n",
+    "        # Utterances for convert_time function\n",
+    "        \"convert 15:00 from New York time to Berlin time\",\n",
+    "        \"change 09:00 from Paris time to Moscow time\",\n",
+    "        \"adjust 20:00 from Rome time to London time\",\n",
+    "        \"convert 12:00 from Madrid time to Chicago time\",\n",
+    "        \"change 18:00 from Beijing time to Los Angeles time\"\n",
+    "        # All three functions\n",
+    "        \"What is the time in Seattle? What is the time difference between Mumbai and Tokyo? What is 5:53 Toronto time in Sydney time?\",\n",
+    "    ],\n",
+    "    function_schemas=schemas,\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "id": "yEbQadQbg9ht"
+   },
+   "outputs": [],
+   "source": [
+    "routes = [politics, chitchat, multi_function_route]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "id": "C0aYIXaog9ht",
+    "outputId": "74114a86-4a6f-49c5-8e2e-600f577d63f5"
+   },
+   "outputs": [],
+   "source": [
+    "rl2 = RouteLayer(encoder=encoder, routes=routes)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "cG98YLZ5g9ht"
+   },
+   "source": [
+    "### Function to Parse Route Layer Responses"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "id": "PJR97klVg9ht"
+   },
+   "outputs": [],
+   "source": [
+    "def parse_response(response: str):\n",
+    "\n",
+    "    for call in response.function_call:\n",
+    "        args = call[\"arguments\"]\n",
+    "        if call[\"function_name\"] == \"get_time\":\n",
+    "            result = get_time(**args)\n",
+    "            print(result)\n",
+    "        if call[\"function_name\"] == \"get_time_difference\":\n",
+    "            result = get_time_difference(**args)\n",
+    "            print(result)\n",
+    "        if call[\"function_name\"] == \"convert_time\":\n",
+    "            result = convert_time(**args)\n",
+    "            print(result)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "OUbPbxZKg9ht"
+   },
+   "source": [
+    "### Checking that Politics Non-Dynamic Route Still Works"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "RouteChoice(name='politics', function_call=None, similarity_score=None)"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "response = await rl2.acall(\"What is your political leaning?\")\n",
+    "response"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "ZHgw8QoWg9ht"
+   },
+   "source": [
+    "### Checking that Chitchat Non-Dynamic Route Still Works"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "RouteChoice(name='chitchat', function_call=None, similarity_score=None)"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "response = await rl2.acall(\"Hello bot, how are you today?\")\n",
+    "response"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "uZDiY787g9hu"
+   },
+   "source": [
+    "### Testing the `multi_function_route` - The `get_time` Function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[33m2024-07-17 17:27:24 WARNING semantic_router.utils.logger No LLM provided for dynamic route, will use OpenAI LLM default\u001b[0m\n",
+      "\u001b[32m2024-07-17 17:27:25 INFO semantic_router.utils.logger OpenAI => Function Inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}]\u001b[0m\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)"
+      ]
+     },
+     "execution_count": 20,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "response = await rl2.acall(\"what is the time in New York?\")\n",
+    "response"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10:27\n"
+     ]
+    }
+   ],
+   "source": [
+    "parse_response(response)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "wcjQ4Dbpg9hu"
+   },
+   "source": [
+    "### Testing the `multi_function_route` - The `get_time_difference` Function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2024-07-17 17:27:34 INFO semantic_router.utils.logger OpenAI => Function Inputs: [{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}]\u001b[0m\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time_difference', 'arguments': {'timezone1': 'America/Los_Angeles', 'timezone2': 'Europe/Istanbul'}}], similarity_score=None)"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "response = await rl2.acall(\n",
+    "    \"What is the time difference between Los Angeles and Istanbul?\"\n",
+    ")\n",
+    "response"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "The time difference between America/Los_Angeles and Europe/Istanbul is 10.0 hours.\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/var/folders/7b/r9z99rtd2zg774gf4bh8cr9m0000gn/T/ipykernel_71937/3683005204.py:28: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).\n",
+      "  now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n"
+     ]
+    }
+   ],
+   "source": [
+    "parse_response(response)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "14qz-ApLg9hv"
+   },
+   "source": [
+    "### Testing the `multi_function_route` - The `convert_time` Function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2024-07-17 17:27:51 INFO semantic_router.utils.logger OpenAI => Function Inputs: [{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}]\u001b[0m\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "RouteChoice(name='timezone_management', function_call=[{'function_name': 'convert_time', 'arguments': {'time': '23:02', 'from_timezone': 'Asia/Dubai', 'to_timezone': 'Asia/Tokyo'}}], similarity_score=None)"
+      ]
+     },
+     "execution_count": 24,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "response = await rl2.acall(\n",
+    "    \"What is 23:02 Dubai time in Tokyo time? Please and thank you.\"\n",
+    ")\n",
+    "response"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "04:02\n"
+     ]
+    }
+   ],
+   "source": [
+    "parse_response(response)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "TSRfC6JJg9hv"
+   },
+   "source": [
+    "### The Cool Bit - Testing `multi_function_route` - Multiple Functions at Once"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\u001b[32m2024-07-17 17:27:57 INFO semantic_router.utils.logger OpenAI => Function Inputs: [{'function_name': 'get_time', 'arguments': {'timezone': 'Europe/Prague'}}, {'function_name': 'get_time_difference', 'arguments': {'timezone1': 'Europe/Berlin', 'timezone2': 'Asia/Shanghai'}}, {'function_name': 'convert_time', 'arguments': {'time': '05:53', 'from_timezone': 'Europe/Lisbon', 'to_timezone': 'Asia/Bangkok'}}]\u001b[0m\n"
+     ]
+    }
+   ],
+   "source": [
+    "response = await rl2.acall(\n",
+    "    \"\"\"\n",
+    "    What is the time in Prague?\n",
+    "    What is the time difference between Frankfurt and Beijing?\n",
+    "    What is 5:53 Lisbon time in Bangkok time?\n",
+    "\"\"\"\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "16:27\n",
+      "The time difference between Europe/Berlin and Asia/Shanghai is 6.0 hours.\n",
+      "11:53\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/var/folders/7b/r9z99rtd2zg774gf4bh8cr9m0000gn/T/ipykernel_71937/3683005204.py:28: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).\n",
+      "  now_utc = datetime.utcnow().replace(tzinfo=ZoneInfo(\"UTC\"))\n"
+     ]
+    }
+   ],
+   "source": [
+    "parse_response(response)"
+   ]
+  }
+ ],
+ "metadata": {
+  "colab": {
+   "provenance": []
+  },
+  "kernelspec": {
+   "display_name": "decision-layer",
+   "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.3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/03-basic-langchain-agent.ipynb b/docs/04-basic-langchain-agent.ipynb
similarity index 100%
rename from docs/03-basic-langchain-agent.ipynb
rename to docs/04-basic-langchain-agent.ipynb
diff --git a/docs/04-chat-history.ipynb b/docs/05-chat-history.ipynb
similarity index 100%
rename from docs/04-chat-history.ipynb
rename to docs/05-chat-history.ipynb
diff --git a/docs/05-local-execution.ipynb b/docs/06-local-execution.ipynb
similarity index 100%
rename from docs/05-local-execution.ipynb
rename to docs/06-local-execution.ipynb
diff --git a/docs/06-threshold-optimization.ipynb b/docs/07-threshold-optimization.ipynb
similarity index 100%
rename from docs/06-threshold-optimization.ipynb
rename to docs/07-threshold-optimization.ipynb
diff --git a/docs/07-multi-modal.ipynb b/docs/08-multi-modal.ipynb
similarity index 100%
rename from docs/07-multi-modal.ipynb
rename to docs/08-multi-modal.ipynb
-- 
GitLab