From 884b4b3b84ca9e63547d37241cf5b870b42f58a3 Mon Sep 17 00:00:00 2001 From: James Briggs <james.briggs@hotmail.com> Date: Thu, 13 Jun 2024 16:32:44 +0800 Subject: [PATCH] feat: pinecone openai async example --- docs/indexes/pinecone_async.ipynb | 574 ++++++++++++++++++++++++++++++ 1 file changed, 574 insertions(+) create mode 100644 docs/indexes/pinecone_async.ipynb diff --git a/docs/indexes/pinecone_async.ipynb b/docs/indexes/pinecone_async.ipynb new file mode 100644 index 00000000..9019db2f --- /dev/null +++ b/docs/indexes/pinecone_async.ipynb @@ -0,0 +1,574 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install -qU \"semantic-router[pinecone]==0.0.47\"" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from semantic_router import Route\n", + "\n", + "# we could use this as a guide for our chatbot to avoid political conversations\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", + "\n", + "# this could be used as an indicator to our chatbot to switch to a more\n", + "# conversational prompt\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", + "# we place both of our decisions together into single list\n", + "routes = [politics, chitchat]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As of 13 June 2024, two encoders support async functionality:\n", + "\n", + "* `AzureOpenAIEncoder`\n", + "* `OpenAIEncoder`\n", + "\n", + "To use either of these encoders in async mode we simply initialize them as we usually would. When we then include them within a `RouteLayer` and run `acall` the route layer will automatically run the encoders in async mode.\n", + "\n", + "**Azure OpenAI:**\n", + "\n", + "```python\n", + "from semantic_router.encoders import AzureOpenAIEncoder\n", + "\n", + "encoder = AzureOpenAIEncoder(\n", + " api_key=\"YOUR_AZURE_OPENAI_API_KEY\",\n", + " deployment_name=\"YOUR_DEPLOYMENT_NAME\",\n", + " azure_endpoint=\"YOUR_ENDPOINT\",\n", + " api_version=\"2024-02-01\",\n", + " model=\"text-embedding-3-small\",\n", + ")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**OpenAI:**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from getpass import getpass\n", + "from semantic_router.encoders import OpenAIEncoder\n", + "\n", + "# get at platform.openai.com\n", + "os.environ[\"OPENAI_API_KEY\"] = os.environ.get(\"OPENAI_API_KEY\") or getpass(\n", + " \"Enter OpenAI API key: \"\n", + ")\n", + "encoder = OpenAIEncoder(name=\"text-embedding-3-small\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see encoder details, including default `score_threshold` like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "OpenAIEncoder(name='text-embedding-3-small', score_threshold=0.3, type='openai', client=<openai.OpenAI object at 0x117d35e50>, async_client=<openai.AsyncOpenAI object at 0x117d47ad0>, dimensions=NOT_GIVEN, token_limit=8192)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "encoder" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can create embeddings asynchronously via our encoder using the `encoder.acall` method:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[-0.009877119213342667,\n", + " 0.0015331337926909328,\n", + " 0.015642808750271797,\n", + " -0.05476367473602295,\n", + " -0.006405937951058149,\n", + " ...],\n", + " [0.012598802335560322,\n", + " -0.0037690235767513514,\n", + " 0.025685198605060577,\n", + " -0.08883649855852127,\n", + " 0.0013644769787788391,\n", + " ...]]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "await encoder.acall(docs=[\"test\", \"test 2\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For our `PineconeIndex` we do the exact same thing, ie we initialize as usual:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from semantic_router.index.pinecone import PineconeIndex\n", + "\n", + "# get at app.pinecone.io\n", + "os.environ[\"PINECONE_API_KEY\"] = os.environ.get(\"PINECONE_API_KEY\") or getpass(\n", + " \"Enter Pinecone API key: \"\n", + ")\n", + "pc_index = PineconeIndex(dimensions=1536)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are several async methods we can call directly:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'indexes': []}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "await pc_index._async_list_indexes()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But unless we're using the index directly, we don't need to use these. As with the encoder, once we pass the `PineconeIndex` to our route layer, the route layer will call all async methods automatically when we hit the `acall` method." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Async RouteLayer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `RouteLayer` class supports both sync and async operations by default, so we initialize as usual:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "from semantic_router.layer import RouteLayer\n", + "\n", + "rl = RouteLayer(encoder=encoder, routes=routes, index=pc_index)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can check our route layer and index information as usual:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['politics', 'chitchat']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl.list_route_names()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(rl.index)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also view all of the records for a given route:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['politics#64069085d9d6e98e5a80915f69fabe82bac6c742f801bc305c5001dce88f0d19',\n", + " 'politics#af8b76111f260cf44fb34f04fcf82927dcbe08e8f47c30f4d571379c1512fac8',\n", + " 'politics#d1bb40236c3d95b9c695bfa86b314b6da4eb87e136699563fccae47fccea23e2',\n", + " 'politics#ed0f3dd7bd5dea12e55b1953bcd2c562a5ab19f501f6d5ff8c8927652c3904b8',\n", + " 'politics#fc6d15f9e6075e6de82b3fbef6722b64353e4eadc8d663b7312a4ed60c43e6f6']" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl.index._get_route_ids(route_name=\"politics\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now for async vs. sync usage! To call in synchronous mode we simply hit `rl(...)`, to switch to async mode we hit `rl.acall(...)`:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'politics'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl(\"don't you love politics\").name # SYNC mode" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'politics'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out = await rl.acall(\"don't you love politics?\") # ASYNC mode\n", + "out.name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's try a few more sync and async requests:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'chitchat'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl(\"how's the weather today?\").name" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'chitchat'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out = await rl.acall(\"how's the weather today?\")\n", + "out.name" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "rl(\"I'm interested in learning about llama 2\").name" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "out = await rl.acall(\"I'm interested in learning about llama 2\")\n", + "out.name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can delete or update routes using the usual synchronous methods:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(rl.index)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import time\n", + "\n", + "rl.delete(route_name=\"chitchat\")\n", + "time.sleep(3)\n", + "len(rl.index)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "out = await rl.acall(\"how's the weather today?\")\n", + "out.name" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('politics', \"why don't you tell me about your political opinions\"),\n", + " ('politics',\n", + " \"don't you just love the presidentdon't you just hate the president\"),\n", + " ('politics', \"isn't politics the best thing ever\"),\n", + " ('politics', \"they're going to destroy this country!\"),\n", + " ('politics', 'they will save the country!')]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl.index.get_routes()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'type': 'pinecone', 'dimensions': 1536, 'vectors': 5}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl.index.describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "semantic_router_1", + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} -- GitLab