diff --git a/docs/02-dynamic-routes.ipynb b/docs/02-dynamic-routes.ipynb index bb2e439b..b7ea5412 100644 --- a/docs/02-dynamic-routes.ipynb +++ b/docs/02-dynamic-routes.ipynb @@ -1,1439 +1,1443 @@ { - "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": [ - { - "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/" - }, - "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/" - }, - "id": "_rNREh7gur0y", - "outputId": "f3a1dc0b-d760-4efb-b634-d3547011dcb7" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "RouteChoice(name='chitchat', function_call=None, similarity_score=None)" - ] - }, - "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)" - ] - }, - "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'" - ] - }, - "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']}}}]" - ] - }, - "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 - }, - "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" - ] - }, - { - "data": { - "text/plain": [ - "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" - ] - }, - "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" - ] - }, - { - "data": { - "text/plain": [ - "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" - ] - }, - "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": [ - { - "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": [ - { - "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": 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)" - ] - }, - "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)" - ] - }, - "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)" - ] - }, - "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)" - ] - }, - "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" - ] - }, - { - "data": { - "text/plain": [ - "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" - ] - }, - "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": [ - { - "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" - ] - }, - { - "data": { - "text/plain": [ - "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" - ] - }, - "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": [ - { - "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" - ] - }, - { - "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": 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" - ] - }, - { - "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": [ - { - "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" - ] - }, - { - "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": 94, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# async\n", - "response = await rl2.acall(\"What is the time difference between Los Angeles and Istanbul?\")\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" - ] - }, - { - "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": [ - { - "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" - ] - }, - { - "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": 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": [ - { - "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" - ] - }, - { - "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": 98, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# async\n", - "response = await rl2.acall(\"What is 23:02 Dubai time in Tokyo time? Please and thank you.\")\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": [ - { - "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": [ - { - "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": 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" - ] - }, - { - "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": [ - { - "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", - ")" - ] + "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": [ + { + "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/" + }, + "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/" }, + "id": "_rNREh7gur0y", + "outputId": "f3a1dc0b-d760-4efb-b634-d3547011dcb7" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "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" - ] - }, - { - "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)" + "data": { + "text/plain": [ + "RouteChoice(name='chitchat', function_call=None, similarity_score=None)" ] + }, + "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)" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" } - ], - "metadata": { + ], + "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": { - "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" + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "YyFKV8jMur0z", + "outputId": "29cf80f4-552c-47bb-fbf9-019f5dfdf00a" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'07:25'" + ] + }, + "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']}}}]" + ] + }, + "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 + }, + "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" + ] + }, + { + "data": { + "text/plain": [ + "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" + ] + }, + "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" + ] + }, + { + "data": { + "text/plain": [ + "RouteChoice(name='get_time', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" + ] + }, + "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": [ + { + "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": [ + { + "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": 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)" + ] + }, + "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)" + ] + }, + "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)" + ] + }, + "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)" + ] + }, + "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" + ] + }, + { + "data": { + "text/plain": [ + "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" + ] + }, + "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": [ + { + "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" + ] + }, + { + "data": { + "text/plain": [ + "RouteChoice(name='timezone_management', function_call=[{'function_name': 'get_time', 'arguments': {'timezone': 'America/New_York'}}], similarity_score=None)" + ] + }, + "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": [ + { + "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" + ] + }, + { + "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": 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" + ] + }, + { + "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": [ + { + "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" + ] + }, + { + "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": 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" + ] + }, + { + "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": [ + { + "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" + ] + }, + { + "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": 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": [ + { + "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" + ] + }, + { + "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": 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": [ + { + "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": [ + { + "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": 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" + ] + }, + { + "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": [ + { + "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": [ + { + "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" + ] + }, + { + "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)" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "decision-layer", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 0 + "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 }