Misc updates (#1022)

pull/1015/head
Logan Kilpatrick 3 months ago committed by GitHub
parent 2c441ab9a2
commit f1e13cfcc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -6,14 +6,14 @@
The magic of large language models is that by being trained to minimize this prediction error over vast quantities of text, the models end up learning concepts useful for these predictions. For example, they learn:
* how to spell
* how grammar works
* how to paraphrase
* how to answer questions
* how to hold a conversation
* how to write in many languages
* how to code
* etc.
- how to spell
- how grammar works
- how to paraphrase
- how to answer questions
- how to hold a conversation
- how to write in many languages
- how to code
- etc.
They do this by “reading” a large amount of existing text and learning how words tend to appear in context with other words, and uses what it has learned to predict the next most likely word that might appear in response to a user request, and each subsequent word after that.
@ -25,12 +25,12 @@ Of all the inputs to a large language model, by far the most influential is the
Large language models can be prompted to produce output in a few ways:
* **Instruction**: Tell the model what you want
* **Completion**: Induce the model to complete the beginning of what you want
* **Scenario**: Give the model a situation to play out
* **Demonstration**: Show the model what you want, with either:
* A few examples in the prompt
* Many hundreds or thousands of examples in a fine-tuning training dataset
- **Instruction**: Tell the model what you want
- **Completion**: Induce the model to complete the beginning of what you want
- **Scenario**: Give the model a situation to play out
- **Demonstration**: Show the model what you want, with either:
- A few examples in the prompt
- Many hundreds or thousands of examples in a fine-tuning training dataset
An example of each is shown below.
@ -77,6 +77,7 @@ Output:
Giving the model a scenario to follow or role to play out can be helpful for complex queries or when seeking imaginative responses. When using a hypothetical prompt, you set up a situation, problem, or story, and then ask the model to respond as if it were a character in that scenario or an expert on the topic.
Example scenario prompt:
```text
Your role is to extract the name of the author from any given text
@ -141,11 +142,11 @@ Large language models aren't only great at text - they can be great at code too.
GPT-4 powers [numerous innovative products][OpenAI Customer Stories], including:
* [GitHub Copilot] (autocompletes code in Visual Studio and other IDEs)
* [Replit](https://replit.com/) (can complete, explain, edit and generate code)
* [Cursor](https://cursor.sh/) (build software faster in an editor designed for pair-programming with AI)
- [GitHub Copilot] (autocompletes code in Visual Studio and other IDEs)
- [Replit](https://replit.com/) (can complete, explain, edit and generate code)
- [Cursor](https://cursor.sh/) (build software faster in an editor designed for pair-programming with AI)
GPT-4 is more advanced than previous models like `text-davinci-002`. But, to get the best out of GPT-4 for coding tasks, it's still important to give clear and specific instructions. As a result, designing good prompts can take more care.
GPT-4 is more advanced than previous models like `gpt-3.5-turbo-instruct`. But, to get the best out of GPT-4 for coding tasks, it's still important to give clear and specific instructions. As a result, designing good prompts can take more care.
### More prompt advice
@ -153,12 +154,10 @@ For more prompt examples, visit [OpenAI Examples][OpenAI Examples].
In general, the input prompt is the best lever for improving model outputs. You can try tricks like:
* **Be more specific** E.g., if you want the output to be a comma separated list, ask it to return a comma separated list. If you want it to say "I don't know" when it doesn't know the answer, tell it 'Say "I don't know" if you do not know the answer.' The more specific your instructions, the better the model can respond.
* **Provide Context**: Help the model understand the bigger picture of your request. This could be background information, examples/demonstrations of what you want or explaining the purpose of your task.
* **Ask the model to answer as if it was an expert.** Explicitly asking the model to produce high quality output or output as if it was written by an expert can induce the model to give higher quality answers that it thinks an expert would write. Phrases like "Explain in detail" or "Describe step-by-step" can be effective.
* **Prompt the model to write down the series of steps explaining its reasoning.** If understanding the 'why' behind an answer is important, prompt the model to include its reasoning. This can be done by simply adding a line like "[Let's think step by step](https://arxiv.org/abs/2205.11916)" before each answer.
- **Be more specific** E.g., if you want the output to be a comma separated list, ask it to return a comma separated list. If you want it to say "I don't know" when it doesn't know the answer, tell it 'Say "I don't know" if you do not know the answer.' The more specific your instructions, the better the model can respond.
- **Provide Context**: Help the model understand the bigger picture of your request. This could be background information, examples/demonstrations of what you want or explaining the purpose of your task.
- **Ask the model to answer as if it was an expert.** Explicitly asking the model to produce high quality output or output as if it was written by an expert can induce the model to give higher quality answers that it thinks an expert would write. Phrases like "Explain in detail" or "Describe step-by-step" can be effective.
- **Prompt the model to write down the series of steps explaining its reasoning.** If understanding the 'why' behind an answer is important, prompt the model to include its reasoning. This can be done by simply adding a line like "[Let's think step by step](https://arxiv.org/abs/2205.11916)" before each answer.
[Fine Tuning Docs]: https://platform.openai.com/docs/guides/fine-tuning
[OpenAI Customer Stories]: https://openai.com/customer-stories

@ -14,25 +14,25 @@ If you were asked to multiply 13 by 17, would the answer pop immediately into yo
Similarly, if you give GPT-3 a task that's too complex to do in the time it takes to calculate its next token, it may confabulate an incorrect guess. Yet, akin to humans, that doesn't necessarily mean the model is incapable of the task. With some time and space to reason things out, the model still may be able to answer reliably.
As an example, if you ask `text-davinci-002` the following math problem about juggling balls, it answers incorrectly:
As an example, if you ask `gpt-3.5-turbo-instruct` the following math problem about juggling balls, it answers incorrectly:
```text-davinci-002
```gpt-3.5-turbo-instruct
Q: A juggler has 16 balls. Half of the balls are golf balls and half of the golf balls are blue. How many blue golf balls are there?
A:
```
```text-davinci-002
```gpt-3.5-turbo-instruct
There are 8 blue golf balls.
```
Does this mean that GPT-3 cannot do simple math problems? No; in fact, it turns out that by prompting the model with `Let's think step by step`, the model solves the problem reliably:
```text-davinci-002
```gpt-3.5-turbo-instruct
Q: A juggler has 16 balls. Half of the balls are golf balls and half of the golf balls are blue. How many blue golf balls are there?
A: Let's think step by step.
```
```text-davinci-002
```gpt-3.5-turbo-instruct
There are 16 balls in total.
Half of the balls are golf balls.
That means that there are 8 golf balls.
@ -64,9 +64,9 @@ The rest of this article shares techniques for improving reliability of large la
One way to give a model more time and space to think is to break tasks into simpler pieces.
As an example, consider a task where we ask the model a multiple-choice question about some text - in this case, a game of Clue. When asked directly, `text-davinci-002` isn't able to put clues 3 & 5 together, and answers incorrectly:
As an example, consider a task where we ask the model a multiple-choice question about some text - in this case, a game of Clue. When asked directly, `gpt-3.5-turbo-instruct` isn't able to put clues 3 & 5 together, and answers incorrectly:
```text-davinci-002
```gpt-3.5-turbo-instruct
Use the following clues to answer the following multiple-choice question.
Clues:
@ -84,7 +84,7 @@ Question: Was Colonel Mustard in the observatory with the candlestick?
Solution:
```
```text-davinci-002
```gpt-3.5-turbo-instruct
(c) Unknown; there is not enough information to determine whether Colonel Mustard was in the observatory with the candlestick
```
@ -96,7 +96,7 @@ However, instead of asking for the answer directly, we can split the task into t
- Second, combine the relevant clues to reason out the answer to the question
- Third, write the final answer: either (a), (b), or (c)
```text-davinci-002
```gpt-3.5-turbo-instruct
Use the following clues to answer the following multiple-choice question, using the following procedure:
(1) First, go through the clues one by one and consider whether the clue is potentially relevant
(2) Second, combine the relevant clues to reason out the answer to the question
@ -118,7 +118,7 @@ Solution:
(1) First, go through the clues one by one and consider whether the clue is potentially relevant:
```
```text-davinci-002
```gpt-3.5-turbo-instruct
Clue 1: Miss Scarlett was the only person in the lounge. This clue is not relevant.
Clue 2: The person with the pipe was in the kitchen. This clue is not relevant.
Clue 3: Colonel Mustard was the only person in the observatory. This clue is relevant.
@ -136,9 +136,9 @@ By giving the model more time and space to think, and guiding it along a reasoni
Another benefit of splitting complex instructions into smaller subtasks is that it can help keep the model focused on each subtask.
For example, if we ask `text-davinci-002` to summarize a text in its original language, the model can lapse back into English:
For example, if we ask `gpt-3.5-turbo-instruct` to summarize a text in its original language, the model can lapse back into English:
```text-davinci-002
```gpt-3.5-turbo-instruct
Summarize the text using the original language of the text. The summary should be one sentence long.
Text:
@ -149,13 +149,13 @@ La estadística (la forma femenina del término alemán Statistik, derivado a su
Summary:
```
```text-davinci-002
```gpt-3.5-turbo-instruct
The text explains that statistics is a science that studies the variability, collection, organization, analysis, interpretation, and presentation of data, as well as the random process that generates them following the laws of probability.
```
However, if we first ask the model to identify the language of the text, and then summarize the text, it becomes more reliable:
```text-davinci-002
```gpt-3.5-turbo-instruct
First, identify the language of the text. Second, summarize the text using the original language of the text. The summary should be one sentence long.
Text:
@ -166,7 +166,7 @@ La estadística (la forma femenina del término alemán Statistik, derivado a su
Language:
```
```text-davinci-002
```gpt-3.5-turbo-instruct
Spanish
La estadística es una ciencia que estudia la variabilidad, colección, organización, análisis, interpretación, y presentación de los datos, así como el proceso aleatorio que los genera siguiendo las leyes de la probabilidad.
@ -203,7 +203,7 @@ To learn more, read the [full paper](https://arxiv.org/abs/2205.11916).
If you apply this technique to your own tasks, don't be afraid to experiment with customizing the instruction. `Let's think step by step` is rather generic, so you may find better performance with instructions that hew to a stricter format customized to your use case. For example, you can try more structured variants like `First, think step by step about why X might be true. Second, think step by step about why Y might be true. Third, think step by step about whether X or Y makes more sense.`. And you can even give the model an example format to help keep it on track, e.g.:
```text-davinci-002
```gpt-3.5-turbo-instruct
Using the IRS guidance below, answer the following questions using this format:
(1) For each criterion, determine whether it is met by the vehicle purchase
- {Criterion} Let's think step by step. {explanation} {yes or no, or if the question does not apply then N/A}.
@ -229,7 +229,7 @@ Solution:
- Does the vehicle have at least four wheels? Let's think step by step.
```
```text-davinci-002
```gpt-3.5-turbo-instruct
The Toyota Prius Prime has four wheels, so the answer is yes.
- Does the vehicle weigh less than 14,000 pounds? Let's think step by step. The Toyota Prius Prime weighs less than 14,000 pounds, so the answer is yes.
- Does the vehicle draw energy from a battery with at least 4 kilowatt hours that may be recharged from an external source? Let's think step by step. The Toyota Prius Prime has a battery with at least 4 kilowatt hours that may be recharged from an external source, so the answer is yes.

@ -8,8 +8,8 @@ Embeddings can be used for semantic search, recommendations, cluster analysis, n
For more information, read OpenAI's blog post announcements:
* [Introducing Text and Code Embeddings (Jan 2022)](https://openai.com/blog/introducing-text-and-code-embeddings/)
* [New and Improved Embedding Model (Dec 2022)](https://openai.com/blog/new-and-improved-embedding-model/)
- [Introducing Text and Code Embeddings (Jan 2022)](https://openai.com/blog/introducing-text-and-code-embeddings/)
- [New and Improved Embedding Model (Dec 2022)](https://openai.com/blog/new-and-improved-embedding-model/)
For comparison with other embedding models, see [Massive Text Embedding Benchmark (MTEB) Leaderboard](https://huggingface.co/spaces/mteb/leaderboard)
@ -19,14 +19,14 @@ Embeddings can be used for search either by themselves or as a feature in a larg
The simplest way to use embeddings for search is as follows:
* Before the search (precompute):
* Split your text corpus into chunks smaller than the token limit (8,191 tokens for `text-embedding-ada-002`)
* Embed each chunk of text
* Store those embeddings in your own database or in a vector search provider like [Pinecone](https://www.pinecone.io), [Weaviate](https://weaviate.io) or [Qdrant](https://qdrant.tech)
* At the time of the search (live compute):
* Embed the search query
* Find the closest embeddings in your database
* Return the top results
- Before the search (precompute):
- Split your text corpus into chunks smaller than the token limit (8,191 tokens for `text-embedding-3-small`)
- Embed each chunk of text
- Store those embeddings in your own database or in a vector search provider like [Pinecone](https://www.pinecone.io), [Weaviate](https://weaviate.io) or [Qdrant](https://qdrant.tech)
- At the time of the search (live compute):
- Embed the search query
- Find the closest embeddings in your database
- Return the top results
An example of how to use embeddings for search is shown in [Semantic_text_search_using_embeddings.ipynb](../examples/Semantic_text_search_using_embeddings.ipynb).

File diff suppressed because one or more lines are too long

@ -22,7 +22,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
@ -110,15 +110,15 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total number of .py files: 57\n",
"Total number of functions extracted: 118\n"
"Total number of .py files: 51\n",
"Total number of functions extracted: 97\n"
]
}
],
@ -138,12 +138,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that we have our content, we can pass the data to the text-embedding-ada-002 endpoint to get back our vector embeddings."
"Now that we have our content, we can pass the data to the `text-embedding-3-small` model and get back our vector embeddings."
]
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 3,
"metadata": {},
"outputs": [
{
@ -179,35 +179,35 @@
" <td>def _console_log_level():\\n if openai.log i...</td>\n",
" <td>_console_log_level</td>\n",
" <td>openai/util.py</td>\n",
" <td>[0.033906757831573486, -0.00418944051489234, 0...</td>\n",
" <td>[0.005937571171671152, 0.05450401455163956, 0....</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>def log_debug(message, **params):\\n msg = l...</td>\n",
" <td>log_debug</td>\n",
" <td>openai/util.py</td>\n",
" <td>[-0.004059609025716782, 0.004895503632724285, ...</td>\n",
" <td>[0.017557814717292786, 0.05647840350866318, -0...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>def log_info(message, **params):\\n msg = lo...</td>\n",
" <td>log_info</td>\n",
" <td>openai/util.py</td>\n",
" <td>[0.0048639848828315735, 0.0033139237202703953,...</td>\n",
" <td>[0.022524144500494003, 0.06219055876135826, -0...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>def log_warn(message, **params):\\n msg = lo...</td>\n",
" <td>log_warn</td>\n",
" <td>openai/util.py</td>\n",
" <td>[0.0024026145692914724, -0.010721310041844845,...</td>\n",
" <td>[0.030524108558893204, 0.0667714849114418, -0....</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>def logfmt(props):\\n def fmt(key, val):\\n ...</td>\n",
" <td>logfmt</td>\n",
" <td>openai/util.py</td>\n",
" <td>[0.01664826273918152, 0.01730910874903202, 0.0...</td>\n",
" <td>[0.05337328091263771, 0.03697286546230316, -0....</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
@ -222,14 +222,14 @@
"4 def logfmt(props):\\n def fmt(key, val):\\n ... logfmt \n",
"\n",
" filepath code_embedding \n",
"0 openai/util.py [0.033906757831573486, -0.00418944051489234, 0... \n",
"1 openai/util.py [-0.004059609025716782, 0.004895503632724285, ... \n",
"2 openai/util.py [0.0048639848828315735, 0.0033139237202703953,... \n",
"3 openai/util.py [0.0024026145692914724, -0.010721310041844845,... \n",
"4 openai/util.py [0.01664826273918152, 0.01730910874903202, 0.0... "
"0 openai/util.py [0.005937571171671152, 0.05450401455163956, 0.... \n",
"1 openai/util.py [0.017557814717292786, 0.05647840350866318, -0... \n",
"2 openai/util.py [0.022524144500494003, 0.06219055876135826, -0... \n",
"3 openai/util.py [0.030524108558893204, 0.0667714849114418, -0.... \n",
"4 openai/util.py [0.05337328091263771, 0.03697286546230316, -0.... "
]
},
"execution_count": 11,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
@ -238,7 +238,7 @@
"from utils.embeddings_utils import get_embedding\n",
"\n",
"df = pd.DataFrame(all_funcs)\n",
"df['code_embedding'] = df['code'].apply(lambda x: get_embedding(x, model='text-embedding-ada-002'))\n",
"df['code_embedding'] = df['code'].apply(lambda x: get_embedding(x, model='text-embedding-3-small'))\n",
"df['filepath'] = df['filepath'].map(lambda x: Path(x).relative_to(code_root))\n",
"df.to_csv(\"data/code_search_openai-python.csv\", index=False)\n",
"df.head()"
@ -255,21 +255,21 @@
"\n",
"We define a search_functions method that takes our data that contains our embeddings, a query string, and some other configuration options. The process of searching our database works like such:\n",
"\n",
"1. We first embed our query string (code_query) with text-embedding-ada-002. The reasoning here is that a query string like 'a function that reverses a string' and a function like 'def reverse(string): return string[::-1]' will be very similar when embedded.\n",
"1. We first embed our query string (code_query) with `text-embedding-3-small`. The reasoning here is that a query string like 'a function that reverses a string' and a function like 'def reverse(string): return string[::-1]' will be very similar when embedded.\n",
"2. We then calculate the cosine similarity between our query string embedding and all data points in our database. This gives a distance between each point and our query.\n",
"3. We finally sort all of our data points by their distance to our query string and return the number of results requested in the function parameters. "
]
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"from utils.embeddings_utils import cosine_similarity\n",
"\n",
"def search_functions(df, code_query, n=3, pprint=True, n_lines=7):\n",
" embedding = get_embedding(code_query, model='text-embedding-ada-002')\n",
" embedding = get_embedding(code_query, model='text-embedding-3-small')\n",
" df['similarities'] = df.code_embedding.apply(lambda x: cosine_similarity(x, embedding))\n",
"\n",
" res = df.sort_values('similarities', ascending=False).head(n)\n",
@ -285,14 +285,14 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"openai/validators.py:format_inferrer_validator score=0.751\n",
"openai/validators.py:format_inferrer_validator score=0.453\n",
"def format_inferrer_validator(df):\n",
" \"\"\"\n",
" This validator will infer the likely fine-tuning format of the data, and display it to the user if it is classification.\n",
@ -301,16 +301,7 @@
" ft_type = infer_task_type(df)\n",
" immediate_msg = None\n",
"----------------------------------------------------------------------\n",
"openai/validators.py:get_validators score=0.748\n",
"def get_validators():\n",
" return [\n",
" num_examples_validator,\n",
" lambda x: necessary_column_validator(x, \"prompt\"),\n",
" lambda x: necessary_column_validator(x, \"completion\"),\n",
" additional_column_validator,\n",
" non_empty_field_validator,\n",
"----------------------------------------------------------------------\n",
"openai/validators.py:infer_task_type score=0.739\n",
"openai/validators.py:infer_task_type score=0.37\n",
"def infer_task_type(df):\n",
" \"\"\"\n",
" Infer the likely fine-tuning task type from the data\n",
@ -318,6 +309,15 @@
" CLASSIFICATION_THRESHOLD = 3 # min_average instances of each class\n",
" if sum(df.prompt.str.len()) == 0:\n",
" return \"open-ended generation\"\n",
"----------------------------------------------------------------------\n",
"openai/validators.py:apply_validators score=0.369\n",
"def apply_validators(\n",
" df,\n",
" fname,\n",
" remediation,\n",
" validators,\n",
" auto_accept,\n",
" write_out_file_func,\n",
"----------------------------------------------------------------------\n"
]
}
@ -328,14 +328,14 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"openai/validators.py:get_common_xfix score=0.794\n",
"openai/validators.py:get_common_xfix score=0.487\n",
"def get_common_xfix(series, xfix=\"suffix\"):\n",
" \"\"\"\n",
" Finds the longest common suffix or prefix of all the values in a series\n",
@ -347,7 +347,7 @@
" if xfix == \"suffix\"\n",
" else series.str[: len(common_xfix) + 1]\n",
"----------------------------------------------------------------------\n",
"openai/validators.py:common_completion_suffix_validator score=0.778\n",
"openai/validators.py:common_completion_suffix_validator score=0.449\n",
"def common_completion_suffix_validator(df):\n",
" \"\"\"\n",
" This validator will suggest to add a common suffix to the completion if one doesn't already exist in case of classification or conditional generation.\n",
@ -368,14 +368,14 @@
},
{
"cell_type": "code",
"execution_count": 15,
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"openai/cli.py:tools_register score=0.78\n",
"openai/cli.py:tools_register score=0.391\n",
"def tools_register(parser):\n",
" subparsers = parser.add_subparsers(\n",
" title=\"Tools\", help=\"Convenience client side tools\"\n",
@ -421,7 +421,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
"version": "3.11.5"
},
"orig_nbformat": 4
},

@ -78,7 +78,7 @@
"source": [
"# input parameters\n",
"embedding_cache_path = \"data/snli_embedding_cache.pkl\" # embeddings will be saved/loaded here\n",
"default_embedding_engine = \"babbage-similarity\" # text-embedding-ada-002 is recommended\n",
"default_embedding_engine = \"text-embedding-3-small\"\n",
"num_pairs_to_embed = 1000 # 1000 is arbitrary\n",
"local_dataset_path = \"data/snli_1.0_train_2k.csv\" # download from: https://nlp.stanford.edu/projects/snli/\n",
"\n",

@ -606,8 +606,7 @@
}
],
"source": [
"# calculate embeddings\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\" # OpenAI's best embeddings as of Apr 2023\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"BATCH_SIZE = 1000 # you can submit up to 2048 embedding inputs per request\n",
"\n",
"embeddings = []\n",

@ -9,7 +9,7 @@
"\n",
"OpenAI's embedding models cannot embed text that exceeds a maximum length. The maximum length varies by model, and is measured by _tokens_, not string length. If you are unfamiliar with tokenization, check out [How to count tokens with tiktoken](How_to_count_tokens_with_tiktoken.ipynb).\n",
"\n",
"This notebook shows how to handle texts that are longer than a model's maximum context length. We'll demonstrate using embeddings from `text-embedding-ada-002`, but the same ideas can be applied to other models and tasks. To learn more about embeddings, check out the [OpenAI Embeddings Guide](https://beta.openai.com/docs/guides/embeddings).\n"
"This notebook shows how to handle texts that are longer than a model's maximum context length. We'll demonstrate using embeddings from `text-embedding-3-small`, but the same ideas can be applied to other models and tasks. To learn more about embeddings, check out the [OpenAI Embeddings Guide](https://beta.openai.com/docs/guides/embeddings).\n"
]
},
{
@ -35,7 +35,7 @@
"\n",
"client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\", \"<your OpenAI API key if not set as env var>\"))\n",
"\n",
"EMBEDDING_MODEL = 'text-embedding-ada-002'\n",
"EMBEDDING_MODEL = 'text-embedding-3-small'\n",
"EMBEDDING_CTX_LENGTH = 8191\n",
"EMBEDDING_ENCODING = 'cl100k_base'\n",
"\n",
@ -49,7 +49,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The `text-embedding-ada-002` model has a context length of 8191 tokens with the `cl100k_base` encoding, and we can see that going over that limit causes an error."
"The `text-embedding-3-small` model has a context length of 8191 tokens with the `cl100k_base` encoding, and we can see that going over that limit causes an error."
]
},
{

@ -26,32 +26,30 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"# imports\n",
"import pandas as pd\n",
"import tiktoken\n",
"\n",
"from utils.embeddings_utils import get_embedding\n"
"from utils.embeddings_utils import get_embedding"
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# embedding model parameters\n",
"embedding_model = \"text-embedding-ada-002\"\n",
"embedding_encoding = \"cl100k_base\" # this the encoding for text-embedding-ada-002\n",
"max_tokens = 8000 # the maximum for text-embedding-ada-002 is 8191\n"
"embedding_model = \"text-embedding-3-small\"\n",
"embedding_encoding = \"cl100k_base\"\n",
"max_tokens = 8000 # the maximum for text-embedding-3-small is 8191"
]
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 17,
"metadata": {},
"outputs": [
{
@ -127,7 +125,7 @@
"1 Title: Arrived in pieces; Content: Not pleased... "
]
},
"execution_count": 8,
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
@ -141,12 +139,12 @@
"df[\"combined\"] = (\n",
" \"Title: \" + df.Summary.str.strip() + \"; Content: \" + df.Text.str.strip()\n",
")\n",
"df.head(2)\n"
"df.head(2)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 18,
"metadata": {},
"outputs": [
{
@ -155,7 +153,7 @@
"1000"
]
},
"execution_count": 9,
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
@ -171,7 +169,7 @@
"# omit reviews that are too long to embed\n",
"df[\"n_tokens\"] = df.combined.apply(lambda x: len(encoding.encode(x)))\n",
"df = df[df.n_tokens <= max_tokens].tail(top_n)\n",
"len(df)\n"
"len(df)"
]
},
{
@ -184,7 +182,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
@ -192,7 +190,16 @@
"\n",
"# This may take a few minutes\n",
"df[\"embedding\"] = df.combined.apply(lambda x: get_embedding(x, model=embedding_model))\n",
"df.to_csv(\"data/fine_food_reviews_with_embeddings_1k.csv\")\n"
"df.to_csv(\"data/fine_food_reviews_with_embeddings_1k.csv\")"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"a = get_embedding(\"hi\", model=embedding_model)"
]
}
],
@ -212,7 +219,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.11.5"
},
"orig_nbformat": 4,
"vscode": {

@ -662,7 +662,7 @@
"import wget\n",
"\n",
"# Here is a URL to a zip archive containing the transcribed podcasts\n",
"# Note that this data has already been split into chunks and embeddings from OpenAI's text-embedding-ada-002 embedding model are included\n",
"# Note that this data has already been split into chunks and embeddings from OpenAI's `text-embedding-3-small` embedding model are included\n",
"content_url = 'https://cdn.openai.com/API/examples/data/sysk_podcast_transcripts_embedded.json.zip'\n",
"\n",
"# Download the file (it is ~541 MB so this will take some time)\n",

@ -22,7 +22,7 @@
"\n",
"| Encoding name | OpenAI models |\n",
"|-------------------------|-----------------------------------------------------|\n",
"| `cl100k_base` | `gpt-4`, `gpt-3.5-turbo`, `text-embedding-ada-002` |\n",
"| `cl100k_base` | `gpt-4`, `gpt-3.5-turbo`, `text-embedding-ada-002`, `text-embedding-3-small`, `text-embedding-3-large` |\n",
"| `p50k_base` | Codex models, `text-davinci-002`, `text-davinci-003`|\n",
"| `r50k_base` (or `gpt2`) | GPT-3 models like `davinci` |\n",
"\n",

@ -92,7 +92,7 @@
"\n",
"\n",
"def embeddings(input: list[str]) -> list[list[str]]:\n",
" response = client.embeddings.create(model=\"text-embedding-ada-002\", input=input)\n",
" response = client.embeddings.create(model=\"text-embedding-3-small\", input=input)\n",
" return [data.embedding for data in response.data]"
]
},

@ -403,7 +403,7 @@
"source": [
"from langchain.vectorstores.neo4j_vector import Neo4jVector\n",
"from langchain.embeddings.openai import OpenAIEmbeddings\n",
"embeddings_model = \"text-embedding-ada-002\""
"embeddings_model = \"text-embedding-3-small\""
]
},
{

File diff suppressed because it is too large Load Diff

@ -14,14 +14,14 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ada-002 embedding performance on 1k Amazon reviews: mse=0.62, mae=0.53\n"
"text-embedding-3-small performance on 1k Amazon reviews: mse=0.65, mae=0.52\n"
]
}
],
@ -48,12 +48,12 @@
"mse = mean_squared_error(y_test, preds)\n",
"mae = mean_absolute_error(y_test, preds)\n",
"\n",
"print(f\"ada-002 embedding performance on 1k Amazon reviews: mse={mse:.2f}, mae={mae:.2f}\")\n"
"print(f\"text-embedding-3-small performance on 1k Amazon reviews: mse={mse:.2f}, mae={mae:.2f}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 3,
"metadata": {},
"outputs": [
{
@ -105,7 +105,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
"version": "3.11.5"
},
"orig_nbformat": 4,
"vscode": {

@ -12,7 +12,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
@ -36,18 +36,18 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Good Buy: I liked the beans. They were vacuum sealed, plump and moist. Would recommend them for any use. I personally split and stuck them in some vodka to make vanilla extract. Yum!\n",
"Delicious!: I enjoy this white beans seasoning, it gives a rich flavor to the beans I just love it, my mother in law didn't know about this Zatarain's brand and now she is traying different seasoning\n",
"\n",
"Jamaican Blue beans: Excellent coffee bean for roasting. Our family just purchased another 5 pounds for more roasting. Plenty of flavor and mild on acidity when roasted to a dark brown bean and befor\n",
"Fantastic Instant Refried beans: Fantastic Instant Refried Beans have been a staple for my family now for nearly 20 years. All 7 of us love it and my grown kids are passing on the tradition.\n",
"\n",
"Delicious!: I enjoy this white beans seasoning, it gives a rich flavor to the beans I just love it, my mother in law didn't know about this Zatarain's brand and now she is traying different seasoning\n",
"Delicious: While there may be better coffee beans available, this is my first purchase and my first time grinding my own beans. I read several reviews before purchasing this brand, and am extremely \n",
"\n"
]
}
@ -59,7 +59,7 @@
"def search_reviews(df, product_description, n=3, pprint=True):\n",
" product_embedding = get_embedding(\n",
" product_description,\n",
" model=\"text-embedding-ada-002\"\n",
" model=\"text-embedding-3-small\"\n",
" )\n",
" df[\"similarity\"] = df.embedding.apply(lambda x: cosine_similarity(x, product_embedding))\n",
"\n",
@ -81,7 +81,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 4,
"metadata": {},
"outputs": [
{
@ -92,7 +92,7 @@
"\n",
"sooo good: tastes so good. Worth the money. My boyfriend hates wheat pasta and LOVES this. cooks fast tastes great.I love this brand and started buying more of their pastas. Bulk is best.\n",
"\n",
"Handy: Love the idea of ready in a minute pasta and for that alone this product gets praise. The pasta is whole grain so that's a big plus and it actually comes out al dente. The vegetable marinara\n",
"Bland and vaguely gamy tasting, skip this one: As far as prepared dinner kits go, \"Barilla Whole Grain Mezze Penne with Tomato and Basil Sauce\" just did not do it for me...and this is coming from a p\n",
"\n"
]
}
@ -111,7 +111,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 5,
"metadata": {},
"outputs": [
{
@ -137,14 +137,14 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Extremely dissapointed: Hi,<br />I am very disappointed with the past shipment I received of the ONE coconut water. 3 of the boxes were leaking and the coconut water was spoiled.<br /><br />Thanks.<b\n",
"Disappointed: The metal cover has severely disformed. And most of the cookies inside have been crushed into small pieces. Shopping experience is awful. I'll never buy it online again.\n",
"\n"
]
}
@ -155,16 +155,16 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Good food: The only dry food my queen cat will eat. Helps prevent hair balls. Good packaging. Arrives promptly. Recommended by a friend who sells pet food.\n",
"Great food!: I wanted a food for a a dog with skin problems. His skin greatly improved with the switch, though he still itches some. He loves the food. No recalls, American made with American ingred\n",
"\n",
"The cats like it: My 7 cats like this food but it is a little yucky for the human. Pieces of mackerel swimming in a dark broth. It is billed as a \"complete\" food and contains carrots, peas and pasta.\n",
"Great food!: I wanted a food for a a dog with skin problems. His skin greatly improved with the switch, though he still itches some. He loves the food. No recalls, American made with American ingred\n",
"\n"
]
}
@ -190,7 +190,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
"version": "3.11.5"
},
"orig_nbformat": 4,
"vscode": {

@ -0,0 +1,451 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Unit test writing using a multi-step prompt (with the older API)\n",
"\n",
"Complex tasks, such as writing unit tests, can benefit from multi-step prompts. In contrast to a single prompt, a multi-step prompt generates text from GPT-3 and then feeds that text back into subsequent prompts. This can help in cases where you want GPT-3 to explain its reasoning before answering, or brainstorm a plan before executing it.\n",
"\n",
"In this notebook, we use a 3-step prompt to write unit tests in Python using the following steps:\n",
"\n",
"1. Given a Python function, we first prompt GPT-3 to explain what the function is doing.\n",
"2. Second, we prompt GPT-3 to plan a set of unit tests for the function.\n",
" - If the plan is too short, we ask GPT-3 to elaborate with more ideas for unit tests.\n",
"3. Finally, we prompt GPT-3 to write the unit tests.\n",
"\n",
"The code example illustrates a few optional embellishments on the chained, multi-step prompt:\n",
"\n",
"- Conditional branching (e.g., only asking for elaboration if the first plan is too short)\n",
"- Different models for different steps (e.g., `gpt-3.5-turbo-instruct` for the text planning steps and `gpt-4` for the code writing step)\n",
"- A check that re-runs the function if the output is unsatisfactory (e.g., if the output code cannot be parsed by Python's `ast` module)\n",
"- Streaming output so that you can start reading the output before it's fully generated (useful for long, multi-step outputs)\n",
"\n",
"The full 3-step prompt looks like this (using as an example `pytest` for the unit test framework and `is_palindrome` as the function):\n",
"\n",
" # How to write great unit tests with pytest\n",
"\n",
" In this advanced tutorial for experts, we'll use Python 3.9 and `pytest` to write a suite of unit tests to verify the behavior of the following function.\n",
" ```python\n",
" def is_palindrome(s):\n",
" return s == s[::-1]\n",
" ```\n",
"\n",
" Before writing any unit tests, let's review what each element of the function is doing exactly and what the author's intentions may have been.\n",
" - First,{GENERATED IN STEP 1}\n",
" \n",
" A good unit test suite should aim to:\n",
" - Test the function's behavior for a wide range of possible inputs\n",
" - Test edge cases that the author may not have foreseen\n",
" - Take advantage of the features of `pytest` to make the tests easy to write and maintain\n",
" - Be easy to read and understand, with clean code and descriptive names\n",
" - Be deterministic, so that the tests always pass or fail in the same way\n",
"\n",
" `pytest` has many convenient features that make it easy to write and maintain unit tests. We'll use them to write unit tests for the function above.\n",
"\n",
" For this particular function, we'll want our unit tests to handle the following diverse scenarios (and under each scenario, we include a few examples as sub-bullets):\n",
" -{GENERATED IN STEP 2}\n",
"\n",
" [OPTIONALLY APPENDED]In addition to the scenarios above, we'll also want to make sure we don't forget to test rare or unexpected edge cases (and under each edge case, we include a few examples as sub-bullets):\n",
" -{GENERATED IN STEP 2B}\n",
"\n",
" Before going into the individual tests, let's first look at the complete suite of unit tests as a cohesive whole. We've added helpful comments to explain what each line does.\n",
" ```python\n",
" import pytest # used for our unit tests\n",
"\n",
" def is_palindrome(s):\n",
" return s == s[::-1]\n",
"\n",
" #Below, each test case is represented by a tuple passed to the @pytest.mark.parametrize decorator\n",
" {GENERATED IN STEP 3}"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import ast # used for detecting whether generated Python code is valid\n",
"import openai\n",
"\n",
"# example of a function that uses a multi-step prompt to write unit tests\n",
"def unit_test_from_function(\n",
" function_to_test: str, # Python function to test, as a string\n",
" unit_test_package: str = \"pytest\", # unit testing package; use the name as it appears in the import statement\n",
" approx_min_cases_to_cover: int = 7, # minimum number of test case categories to cover (approximate)\n",
" print_text: bool = False, # optionally prints text; helpful for understanding the function & debugging\n",
" text_model: str = \"gpt-3.5-turbo-instruct\", # model used to generate text plans in steps 1, 2, and 2b\n",
" code_model: str = \"gpt-3.5-turbo-instruct\", # if you don't have access to code models, you can use text models here instead\n",
" max_tokens: int = 1000, # can set this high, as generations should be stopped earlier by stop sequences\n",
" temperature: float = 0.4, # temperature = 0 can sometimes get stuck in repetitive loops, so we use 0.4\n",
" reruns_if_fail: int = 1, # if the output code cannot be parsed, this will re-run the function up to N times\n",
") -> str:\n",
" \"\"\"Outputs a unit test for a given Python function, using a 3-step GPT-3 prompt.\"\"\"\n",
"\n",
" # Step 1: Generate an explanation of the function\n",
"\n",
" # create a markdown-formatted prompt that asks GPT-3 to complete an explanation of the function, formatted as a bullet list\n",
" prompt_to_explain_the_function = f\"\"\"# How to write great unit tests with {unit_test_package}\n",
"\n",
"In this advanced tutorial for experts, we'll use Python 3.9 and `{unit_test_package}` to write a suite of unit tests to verify the behavior of the following function.\n",
"```python\n",
"{function_to_test}\n",
"```\n",
"\n",
"Before writing any unit tests, let's review what each element of the function is doing exactly and what the author's intentions may have been.\n",
"- First,\"\"\"\n",
" if print_text:\n",
" text_color_prefix = \"\\033[30m\" # black; if you read against a dark background \\033[97m is white\n",
" print(text_color_prefix + prompt_to_explain_the_function, end=\"\") # end='' prevents a newline from being printed\n",
"\n",
" # send the prompt to the API, using \\n\\n as a stop sequence to stop at the end of the bullet list\n",
" explanation_response = openai.Completion.create(\n",
" model=text_model,\n",
" prompt=prompt_to_explain_the_function,\n",
" stop=[\"\\n\\n\", \"\\n\\t\\n\", \"\\n \\n\"],\n",
" max_tokens=max_tokens,\n",
" temperature=temperature,\n",
" stream=True,\n",
" )\n",
" explanation_completion = \"\"\n",
" if print_text:\n",
" completion_color_prefix = \"\\033[92m\" # green\n",
" print(completion_color_prefix, end=\"\")\n",
" for event in explanation_response:\n",
" event_text = event[\"choices\"][0][\"text\"]\n",
" explanation_completion += event_text\n",
" if print_text:\n",
" print(event_text, end=\"\")\n",
"\n",
" # Step 2: Generate a plan to write a unit test\n",
"\n",
" # create a markdown-formatted prompt that asks GPT-3 to complete a plan for writing unit tests, formatted as a bullet list\n",
" prompt_to_explain_a_plan = f\"\"\"\n",
" \n",
"A good unit test suite should aim to:\n",
"- Test the function's behavior for a wide range of possible inputs\n",
"- Test edge cases that the author may not have foreseen\n",
"- Take advantage of the features of `{unit_test_package}` to make the tests easy to write and maintain\n",
"- Be easy to read and understand, with clean code and descriptive names\n",
"- Be deterministic, so that the tests always pass or fail in the same way\n",
"\n",
"`{unit_test_package}` has many convenient features that make it easy to write and maintain unit tests. We'll use them to write unit tests for the function above.\n",
"\n",
"For this particular function, we'll want our unit tests to handle the following diverse scenarios (and under each scenario, we include a few examples as sub-bullets):\n",
"-\"\"\"\n",
" if print_text:\n",
" print(text_color_prefix + prompt_to_explain_a_plan, end=\"\")\n",
"\n",
" # append this planning prompt to the results from step 1\n",
" prior_text = prompt_to_explain_the_function + explanation_completion\n",
" full_plan_prompt = prior_text + prompt_to_explain_a_plan\n",
"\n",
" # send the prompt to the API, using \\n\\n as a stop sequence to stop at the end of the bullet list\n",
" plan_response = openai.Completion.create(\n",
" model=text_model,\n",
" prompt=full_plan_prompt,\n",
" stop=[\"\\n\\n\", \"\\n\\t\\n\", \"\\n \\n\"],\n",
" max_tokens=max_tokens,\n",
" temperature=temperature,\n",
" stream=True,\n",
" )\n",
" plan_completion = \"\"\n",
" if print_text:\n",
" print(completion_color_prefix, end=\"\")\n",
" for event in plan_response:\n",
" event_text = event[\"choices\"][0][\"text\"]\n",
" plan_completion += event_text\n",
" if print_text:\n",
" print(event_text, end=\"\")\n",
"\n",
" # Step 2b: If the plan is short, ask GPT-3 to elaborate further\n",
" # this counts top-level bullets (e.g., categories), but not sub-bullets (e.g., test cases)\n",
" elaboration_needed = plan_completion.count(\"\\n-\") +1 < approx_min_cases_to_cover # adds 1 because the first bullet is not counted\n",
" if elaboration_needed:\n",
" prompt_to_elaborate_on_the_plan = f\"\"\"\n",
"\n",
"In addition to the scenarios above, we'll also want to make sure we don't forget to test rare or unexpected edge cases (and under each edge case, we include a few examples as sub-bullets):\n",
"-\"\"\"\n",
" if print_text:\n",
" print(text_color_prefix + prompt_to_elaborate_on_the_plan, end=\"\")\n",
"\n",
" # append this elaboration prompt to the results from step 2\n",
" prior_text = full_plan_prompt + plan_completion\n",
" full_elaboration_prompt = prior_text + prompt_to_elaborate_on_the_plan\n",
"\n",
" # send the prompt to the API, using \\n\\n as a stop sequence to stop at the end of the bullet list\n",
" elaboration_response = openai.Completion.create(\n",
" model=text_model,\n",
" prompt=full_elaboration_prompt,\n",
" stop=[\"\\n\\n\", \"\\n\\t\\n\", \"\\n \\n\"],\n",
" max_tokens=max_tokens,\n",
" temperature=temperature,\n",
" stream=True,\n",
" )\n",
" elaboration_completion = \"\"\n",
" if print_text:\n",
" print(completion_color_prefix, end=\"\")\n",
" for event in elaboration_response:\n",
" event_text = event[\"choices\"][0][\"text\"]\n",
" elaboration_completion += event_text\n",
" if print_text:\n",
" print(event_text, end=\"\")\n",
"\n",
" # Step 3: Generate the unit test\n",
"\n",
" # create a markdown-formatted prompt that asks GPT-3 to complete a unit test\n",
" starter_comment = \"\"\n",
" if unit_test_package == \"pytest\":\n",
" starter_comment = \"Below, each test case is represented by a tuple passed to the @pytest.mark.parametrize decorator\"\n",
" prompt_to_generate_the_unit_test = f\"\"\"\n",
"\n",
"Before going into the individual tests, let's first look at the complete suite of unit tests as a cohesive whole. We've added helpful comments to explain what each line does.\n",
"```python\n",
"import {unit_test_package} # used for our unit tests\n",
"\n",
"{function_to_test}\n",
"\n",
"#{starter_comment}\"\"\"\n",
" if print_text:\n",
" print(text_color_prefix + prompt_to_generate_the_unit_test, end=\"\")\n",
"\n",
" # append this unit test prompt to the results from step 3\n",
" if elaboration_needed:\n",
" prior_text = full_elaboration_prompt + elaboration_completion\n",
" else:\n",
" prior_text = full_plan_prompt + plan_completion\n",
" full_unit_test_prompt = prior_text + prompt_to_generate_the_unit_test\n",
"\n",
" # send the prompt to the API, using ``` as a stop sequence to stop at the end of the code block\n",
" unit_test_response = openai.Completion.create(\n",
" model=code_model,\n",
" prompt=full_unit_test_prompt,\n",
" stop=\"```\",\n",
" max_tokens=max_tokens,\n",
" temperature=temperature,\n",
" stream=True\n",
" )\n",
" unit_test_completion = \"\"\n",
" if print_text:\n",
" print(completion_color_prefix, end=\"\")\n",
" for event in unit_test_response:\n",
" event_text = event[\"choices\"][0][\"text\"]\n",
" unit_test_completion += event_text\n",
" if print_text:\n",
" print(event_text, end=\"\")\n",
"\n",
" # check the output for errors\n",
" code_start_index = prompt_to_generate_the_unit_test.find(\"```python\\n\") + len(\"```python\\n\")\n",
" code_output = prompt_to_generate_the_unit_test[code_start_index:] + unit_test_completion\n",
" try:\n",
" ast.parse(code_output)\n",
" except SyntaxError as e:\n",
" print(f\"Syntax error in generated code: {e}\")\n",
" if reruns_if_fail > 0:\n",
" print(\"Rerunning...\")\n",
" return unit_test_from_function(\n",
" function_to_test=function_to_test,\n",
" unit_test_package=unit_test_package,\n",
" approx_min_cases_to_cover=approx_min_cases_to_cover,\n",
" print_text=print_text,\n",
" text_model=text_model,\n",
" code_model=code_model,\n",
" max_tokens=max_tokens,\n",
" temperature=temperature,\n",
" reruns_if_fail=reruns_if_fail-1, # decrement rerun counter when calling again\n",
" )\n",
"\n",
" # return the unit test as a string\n",
" return unit_test_completion\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[30m# How to write great unit tests with pytest\n",
"\n",
"In this advanced tutorial for experts, we'll use Python 3.9 and `pytest` to write a suite of unit tests to verify the behavior of the following function.\n",
"```python\n",
"def is_palindrome(s):\n",
" return s == s[::-1]\n",
"```\n",
"\n",
"Before writing any unit tests, let's review what each element of the function is doing exactly and what the author's intentions may have been.\n",
"- First,\u001b[92m we have a function definition. This is where we give the function a name, `is_palindrome`, and specify the arguments that the function accepts. In this case, the function accepts a single string argument, `s`.\n",
"- Next, we have a return statement. This is where we specify the value that the function returns. In this case, the function returns `s == s[::-1]`.\n",
"- Finally, we have a function call. This is where we actually call the function with a specific set of arguments. In this case, we're calling the function with the string `\"racecar\"`.\u001b[30m\n",
" \n",
"A good unit test suite should aim to:\n",
"- Test the function's behavior for a wide range of possible inputs\n",
"- Test edge cases that the author may not have foreseen\n",
"- Take advantage of the features of `pytest` to make the tests easy to write and maintain\n",
"- Be easy to read and understand, with clean code and descriptive names\n",
"- Be deterministic, so that the tests always pass or fail in the same way\n",
"\n",
"`pytest` has many convenient features that make it easy to write and maintain unit tests. We'll use them to write unit tests for the function above.\n",
"\n",
"For this particular function, we'll want our unit tests to handle the following diverse scenarios (and under each scenario, we include a few examples as sub-bullets):\n",
"-\u001b[92m The input is a palindrome\n",
" - `\"racecar\"`\n",
" - `\"madam\"`\n",
" - `\"anna\"`\n",
"- The input is not a palindrome\n",
" - `\"python\"`\n",
" - `\"test\"`\n",
" - `\"1234\"`\n",
"- The input is an empty string\n",
" - `\"\"`\n",
"- The input is `None`\n",
"- The input is not a string\n",
" - `1`\n",
" - `1.0`\n",
" - `True`\n",
" - `False`\n",
" - `[]`\n",
" - `{}`\u001b[30m\n",
"\n",
"In addition to the scenarios above, we'll also want to make sure we don't forget to test rare or unexpected edge cases (and under each edge case, we include a few examples as sub-bullets):\n",
"-\u001b[92m The input is a palindrome with spaces\n",
" - `\"race car\"`\n",
" - `\" madam \"`\n",
" - `\" anna \"`\n",
"- The input is not a palindrome with spaces\n",
" - `\" python \"`\n",
" - `\" test \"`\n",
" - `\" 1234 \"`\n",
"- The input is a palindrome with punctuation\n",
" - `\"racecar!\"`\n",
" - `\"Madam, I'm Adam.\"`\n",
" - `\"Anna's\"`\n",
"- The input is not a palindrome with punctuation\n",
" - `\"python!\"`\n",
" - `\"test.\"`\n",
" - `\"1234!\"`\n",
"- The input is a palindrome with mixed case\n",
" - `\"Racecar\"`\n",
" - `\"Madam\"`\n",
" - `\"Anna\"`\n",
"- The input is not a palindrome with mixed case\n",
" - `\"Python\"`\n",
" - `\"Test\"`\n",
" - `\"1234\"`\u001b[30m\n",
"\n",
"Before going into the individual tests, let's first look at the complete suite of unit tests as a cohesive whole. We've added helpful comments to explain what each line does.\n",
"```python\n",
"import pytest # used for our unit tests\n",
"\n",
"def is_palindrome(s):\n",
" return s == s[::-1]\n",
"\n",
"#Below, each test case is represented by a tuple passed to the @pytest.mark.parametrize decorator\u001b[92m.\n",
"#The first element of the tuple is a name for the test case, and the second element is a list of arguments for the test case.\n",
"#The @pytest.mark.parametrize decorator will generate a separate test function for each test case.\n",
"#The generated test function will be named test_is_palindrome_<name> where <name> is the name of the test case.\n",
"#The generated test function will be given the arguments specified in the list of arguments for the test case.\n",
"#The generated test function will be given the fixture specified in the decorator, in this case the function itself.\n",
"#The generated test function will call the function with the arguments and assert that the result is equal to the expected value.\n",
"@pytest.mark.parametrize(\n",
" \"name,args,expected\",\n",
" [\n",
" # Test the function's behavior for a wide range of possible inputs\n",
" (\"palindrome\", [\"racecar\"], True),\n",
" (\"palindrome\", [\"madam\"], True),\n",
" (\"palindrome\", [\"anna\"], True),\n",
" (\"non-palindrome\", [\"python\"], False),\n",
" (\"non-palindrome\", [\"test\"], False),\n",
" (\"non-palindrome\", [\"1234\"], False),\n",
" (\"empty string\", [\"\"], True),\n",
" (\"None\", [None], False),\n",
" (\"non-string\", [1], False),\n",
" (\"non-string\", [1.0], False),\n",
" (\"non-string\", [True], False),\n",
" (\"non-string\", [False], False),\n",
" (\"non-string\", [[]], False),\n",
" (\"non-string\", [{}], False),\n",
" # Test edge cases that the author may not have foreseen\n",
" (\"palindrome with spaces\", [\"race car\"], True),\n",
" (\"palindrome with spaces\", [\" madam \"], True),\n",
" (\"palindrome with spaces\", [\" anna \"], True),\n",
" (\"non-palindrome with spaces\", [\" python \"], False),\n",
" (\"non-palindrome with spaces\", [\" test \"], False),\n",
" (\"non-palindrome with spaces\", [\" 1234 \"], False),\n",
" (\"palindrome with punctuation\", [\"racecar!\"], True),\n",
" (\"palindrome with punctuation\", [\"Madam, I'm Adam.\"], True),\n",
" (\"palindrome with punctuation\", [\"Anna's\"], True),\n",
" (\"non-palindrome with punctuation\", [\"python!\"], False),\n",
" (\"non-palindrome with punctuation\", [\"test.\"], False),\n",
" (\"non-palindrome with punctuation\", [\"1234!\"], False),\n",
" (\"palindrome with mixed case\", [\"Racecar\"], True),\n",
" (\"palindrome with mixed case\", [\"Madam\"], True),\n",
" (\"palindrome with mixed case\", [\"Anna\"], True),\n",
" (\"non-palindrome with mixed case\", [\"Python\"], False),\n",
" (\"non-palindrome with mixed case\", [\"Test\"], False),\n",
" (\"non-palindrome with mixed case\", [\"1234\"], False),\n",
" ],\n",
")\n",
"def test_is_palindrome(is_palindrome, args, expected):\n",
" assert is_palindrome(*args) == expected\n"
]
},
{
"data": {
"text/plain": [
"'.\\n#The first element of the tuple is a name for the test case, and the second element is a list of arguments for the test case.\\n#The @pytest.mark.parametrize decorator will generate a separate test function for each test case.\\n#The generated test function will be named test_is_palindrome_<name> where <name> is the name of the test case.\\n#The generated test function will be given the arguments specified in the list of arguments for the test case.\\n#The generated test function will be given the fixture specified in the decorator, in this case the function itself.\\n#The generated test function will call the function with the arguments and assert that the result is equal to the expected value.\\n@pytest.mark.parametrize(\\n \"name,args,expected\",\\n [\\n # Test the function\\'s behavior for a wide range of possible inputs\\n (\"palindrome\", [\"racecar\"], True),\\n (\"palindrome\", [\"madam\"], True),\\n (\"palindrome\", [\"anna\"], True),\\n (\"non-palindrome\", [\"python\"], False),\\n (\"non-palindrome\", [\"test\"], False),\\n (\"non-palindrome\", [\"1234\"], False),\\n (\"empty string\", [\"\"], True),\\n (\"None\", [None], False),\\n (\"non-string\", [1], False),\\n (\"non-string\", [1.0], False),\\n (\"non-string\", [True], False),\\n (\"non-string\", [False], False),\\n (\"non-string\", [[]], False),\\n (\"non-string\", [{}], False),\\n # Test edge cases that the author may not have foreseen\\n (\"palindrome with spaces\", [\"race car\"], True),\\n (\"palindrome with spaces\", [\" madam \"], True),\\n (\"palindrome with spaces\", [\" anna \"], True),\\n (\"non-palindrome with spaces\", [\" python \"], False),\\n (\"non-palindrome with spaces\", [\" test \"], False),\\n (\"non-palindrome with spaces\", [\" 1234 \"], False),\\n (\"palindrome with punctuation\", [\"racecar!\"], True),\\n (\"palindrome with punctuation\", [\"Madam, I\\'m Adam.\"], True),\\n (\"palindrome with punctuation\", [\"Anna\\'s\"], True),\\n (\"non-palindrome with punctuation\", [\"python!\"], False),\\n (\"non-palindrome with punctuation\", [\"test.\"], False),\\n (\"non-palindrome with punctuation\", [\"1234!\"], False),\\n (\"palindrome with mixed case\", [\"Racecar\"], True),\\n (\"palindrome with mixed case\", [\"Madam\"], True),\\n (\"palindrome with mixed case\", [\"Anna\"], True),\\n (\"non-palindrome with mixed case\", [\"Python\"], False),\\n (\"non-palindrome with mixed case\", [\"Test\"], False),\\n (\"non-palindrome with mixed case\", [\"1234\"], False),\\n ],\\n)\\ndef test_is_palindrome(is_palindrome, args, expected):\\n assert is_palindrome(*args) == expected\\n'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"example_function = \"\"\"def is_palindrome(s):\n",
" return s == s[::-1]\"\"\"\n",
"\n",
"unit_test_from_function(example_function, print_text=True)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.9.9 ('openai')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.9"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "365536dcbde60510dc9073d6b991cd35db2d9bac356a11f5b64279a5e6708b97"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because one or more lines are too long

@ -7,7 +7,7 @@
"source": [
"## Using embeddings\n",
"\n",
"This notebook contains some helpful snippets you can use to embed text with the 'text-embedding-ada-002' model via the OpenAI API."
"This notebook contains some helpful snippets you can use to embed text with the `text-embedding-3-small` model via the OpenAI API."
]
},
{
@ -27,11 +27,11 @@
}
],
"source": [
"from openai import OpenAI\n",
"import openai\n",
"\n",
"client = OpenAI()\n",
"\n",
"embedding = client.embeddings.create(input=\"Your text goes here\", model=\"text-embedding-ada-002\").data[0].embedding\n",
"embedding = openai.Embedding.create(\n",
" input=\"Your text goes here\", model=\"text-embedding-3-small\"\n",
")[\"data\"][0][\"embedding\"]\n",
"len(embedding)\n"
]
},
@ -50,13 +50,13 @@
"outputs": [],
"source": [
"# Negative example (slow and rate-limited)\n",
"from openai import OpenAI\n",
"\n",
"client = OpenAI()\n",
"import openai\n",
"\n",
"num_embeddings = 10000 # Some large number\n",
"for i in range(num_embeddings):\n",
" embedding = client.embeddings.create(input=\"Your text goes here\", model=\"text-embedding-ada-002\").data[0].embedding\n",
" embedding = openai.Embedding.create(\n",
" input=\"Your text goes here\", model=\"text-embedding-3-small\"\n",
" )[\"data\"][0][\"embedding\"]\n",
" print(len(embedding))"
]
},
@ -75,17 +75,15 @@
],
"source": [
"# Best practice\n",
"from openai import OpenAI\n",
"\n",
"client = OpenAI()\n",
"import openai\n",
"from tenacity import retry, wait_random_exponential, stop_after_attempt\n",
"\n",
"# Retry up to 6 times with exponential backoff, starting at 1 second and maxing out at 20 seconds delay\n",
"@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))\n",
"def get_embedding(text: str, model=\"text-embedding-ada-002\") -> list[float]:\n",
" return client.embeddings.create(input=[text], model=model).data[0].embedding\n",
"def get_embedding(text: str, model=\"text-embedding-3-small\") -> list[float]:\n",
" return openai.Embedding.create(input=[text], model=model)[\"data\"][0][\"embedding\"]\n",
"\n",
"embedding = get_embedding(\"Your text goes here\", model=\"text-embedding-ada-002\")\n",
"embedding = get_embedding(\"Your text goes here\", model=\"text-embedding-3-small\")\n",
"print(len(embedding))"
]
}

File diff suppressed because one or more lines are too long

@ -138,7 +138,7 @@
"source": [
"from utils.embeddings_utils import get_embeddings\n",
"# NOTE: The following code will send a query of batch size 200 to /embeddings\n",
"matrix = get_embeddings(samples[\"text\"].to_list(), model=\"text-embedding-ada-002\")\n"
"matrix = get_embeddings(samples[\"text\"].to_list(), model=\"text-embedding-3-small\")\n"
]
},
{

File diff suppressed because one or more lines are too long

@ -32,14 +32,14 @@ Inputs:
- requests_filepath : str
- path to the file containing the requests to be processed
- file should be a jsonl file, where each line is a json object with API parameters and an optional metadata field
- e.g., {"model": "text-embedding-ada-002", "input": "embed me", "metadata": {"row_id": 1}}
- e.g., {"model": "text-embedding-3-small", "input": "embed me", "metadata": {"row_id": 1}}
- as with all jsonl files, take care that newlines in the content are properly escaped (json.dumps does this automatically)
- an example file is provided at examples/data/example_requests_to_parallel_process.jsonl
- the code to generate the example file is appended to the bottom of this script
- save_filepath : str, optional
- path to the file where the results will be saved
- file will be a jsonl file, where each line is an array with the original request plus the API response
- e.g., [{"model": "text-embedding-ada-002", "input": "embed me"}, {...}]
- e.g., [{"model": "text-embedding-3-small", "input": "embed me"}, {...}]
- if omitted, results will be saved to {requests_filename}_results.jsonl
- request_url : str, optional
- URL of the API endpoint to call
@ -58,7 +58,7 @@ Inputs:
- if omitted, will default to 125,000
- token_encoding_name : str, optional
- name of the token encoding used, as defined in the `tiktoken` package
- if omitted, will default to "cl100k_base" (used by `text-embedding-ada-002`)
- if omitted, will default to "cl100k_base" (used by `text-embedding-3-small`)
- max_attempts : int, optional
- number of times to retry a failed request before giving up
- if omitted, will default to 5
@ -133,7 +133,7 @@ async def process_api_requests_from_file(
api_endpoint = api_endpoint_from_url(request_url)
request_header = {"Authorization": f"Bearer {api_key}"}
# use api-key header for Azure deployments
if '/deployments' in request_url:
if "/deployments" in request_url:
request_header = {"api-key": f"{api_key}"}
# initialize trackers
@ -371,7 +371,9 @@ def api_endpoint_from_url(request_url):
match = re.search("^https://[^/]+/v\\d+/(.+)$", request_url)
if match is None:
# for Azure OpenAI deployment urls
match = re.search(r"^https://[^/]+/openai/deployments/[^/]+/(.+?)(\?|$)", request_url)
match = re.search(
r"^https://[^/]+/openai/deployments/[^/]+/(.+?)(\?|$)", request_url
)
return match[1]
@ -488,7 +490,7 @@ if __name__ == "__main__":
"""
APPENDIX
The example requests file at openai-cookbook/examples/data/example_requests_to_parallel_process.jsonl contains 10,000 requests to text-embedding-ada-002.
The example requests file at openai-cookbook/examples/data/example_requests_to_parallel_process.jsonl contains 10,000 requests to text-embedding-3-small.
It was generated with the following code:
@ -497,7 +499,7 @@ import json
filename = "data/example_requests_to_parallel_process.jsonl"
n_requests = 10_000
jobs = [{"model": "text-embedding-ada-002", "input": str(x) + "\n"} for x in range(n_requests)]
jobs = [{"model": "text-embedding-3-small", "input": str(x) + "\n"} for x in range(n_requests)]
with open(filename, "w") as f:
for job in jobs:
json_string = json.dumps(job)

@ -174,7 +174,7 @@
"metadata": {},
"source": [
"## Deployments\n",
"In this section we are going to create a deployment using the `text-davinci-002` model that we can then use to create completions."
"In this section we are going to create a deployment using the `gpt-3.5-turbo-instruct` model that we can then use to create completions."
]
},
{
@ -183,7 +183,7 @@
"metadata": {},
"source": [
"### Deployments: Create manually\n",
"Create a new deployment by going to your Resource in your portal under \"Resource Management\" -> \"Model deployments\". Select `text-davinci-002` as the model."
"Create a new deployment by going to your Resource in your portal under \"Resource Management\" -> \"Model deployments\". Select `gpt-3.5-turbo-instruct` as the model."
]
},
{

File diff suppressed because one or more lines are too long

@ -134,7 +134,7 @@
},
"source": [
"Before we start, we can configure the LLM provider and model that will power our RAG system. \n",
"Here, we pick *text-davinci-003* from OpenAI, allow unlimited output tokens. "
"Here, we pick `gpt-3.5-turbo-instruct` from OpenAI. "
]
},
{
@ -146,7 +146,7 @@
},
"outputs": [],
"source": [
"llm = OpenAI(temperature=0, model_name=\"text-davinci-003\", max_tokens=-1)"
"llm = OpenAI(temperature=0, model_name=\"gpt-3.5-turbo-instruct\", max_tokens=-1)"
]
},
{

@ -7,18 +7,15 @@ from scipy import spatial
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.metrics import average_precision_score, precision_recall_curve
from tenacity import retry, stop_after_attempt, wait_random_exponential
from openai import OpenAI
import numpy as np
import pandas as pd
import os
client = OpenAI()
client = OpenAI(max_retries=5)
@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
def get_embedding(text: str, model="text-embedding-ada-002", **kwargs) -> List[float]:
def get_embedding(text: str, model="text-embedding-3-small", **kwargs) -> List[float]:
# replace newlines, which can negatively affect performance.
text = text.replace("\n", " ")
@ -27,20 +24,19 @@ def get_embedding(text: str, model="text-embedding-ada-002", **kwargs) -> List[f
return response.data[0].embedding
@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
async def aget_embedding(
text: str, model="text-embedding-ada-002", **kwargs
text: str, model="text-embedding-3-small", **kwargs
) -> List[float]:
# replace newlines, which can negatively affect performance.
text = text.replace("\n", " ")
return (await client.embeddings.create(input=[text], model=model, **kwargs)).data[0].embedding
return (await client.embeddings.create(input=[text], model=model, **kwargs))[
"data"
][0]["embedding"]
@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
def get_embeddings(
list_of_text: List[str], model="text-embedding-ada-002", **kwargs
list_of_text: List[str], model="text-embedding-3-small", **kwargs
) -> List[List[float]]:
assert len(list_of_text) <= 2048, "The batch size should not be larger than 2048."
@ -51,16 +47,17 @@ def get_embeddings(
return [d.embedding for d in data]
@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
async def aget_embeddings(
list_of_text: List[str], model="text-embedding-ada-002", **kwargs
list_of_text: List[str], model="text-embedding-3-small", **kwargs
) -> List[List[float]]:
assert len(list_of_text) <= 2048, "The batch size should not be larger than 2048."
# replace newlines, which can negatively affect performance.
list_of_text = [text.replace("\n", " ") for text in list_of_text]
data = (await client.embeddings.create(input=list_of_text, model=model, **kwargs)).data
data = (
await client.embeddings.create(input=list_of_text, model=model, **kwargs)
).data
return [d.embedding for d in data]

@ -371,7 +371,7 @@
"source": [
"## Search data\n",
"\n",
"Once the data is put into Qdrant we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-ada-002` OpenAI model we also have to use it during search."
"Once the data is put into Qdrant we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-3-small` OpenAI model we also have to use it during search."
]
},
{
@ -385,7 +385,7 @@
" # Creates embedding vector from user query\n",
" embedded_query = openai.Embedding.create(\n",
" input=query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
" )[\"data\"][0][\"embedding\"]\n",
"\n",
" # Convert the embedded_query to PostgreSQL compatible format\n",

@ -46,8 +46,7 @@
"source": [
"import openai\n",
"\n",
"# models\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"GPT_MODEL = \"gpt-3.5-turbo\"\n"
]
},

@ -429,7 +429,7 @@
"source": [
"## Search data\n",
"\n",
"Once the data is put into Qdrant we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-ada-002` OpenAI model we also have to use it during search.\n"
"Once the data is put into Qdrant we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-3-small` OpenAI model we also have to use it during search.\n"
]
},
{
@ -448,7 +448,7 @@
" # Creates embedding vector from user query\n",
" embedded_query = openai.Embedding.create(\n",
" input=query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
" )[\"data\"][0][\"embedding\"]\n",
"\n",
" # Convert the embedded_query to PostgreSQL compatible format\n",

@ -93,7 +93,7 @@
"openai.api_base = \"YOUR_AZURE_OPENAI_ENDPOINT\"\n",
"openai.api_version = \"2023-05-15\"\n",
"openai.api_key = \"YOUR_AZURE_OPENAI_KEY\"\n",
"model: str = \"text-embedding-ada-002\""
"model: str = \"text-embedding-3-small\""
]
},
{

@ -138,7 +138,7 @@
"metadata": {},
"outputs": [
{
"name": "stdin",
"name": "stdout",
"output_type": "stream",
"text": [
"Please enter your API Endpoint: https://4f835778-ec78-42b0-9ae3-29e3cf45b596-us-east1.apps.astra.datastax.com\n",
@ -222,7 +222,7 @@
"metadata": {},
"outputs": [
{
"name": "stdin",
"name": "stdout",
"output_type": "stream",
"text": [
"Please enter your OpenAI API Key: ········\n"
@ -251,7 +251,7 @@
"outputs": [],
"source": [
"client = openai.OpenAI(api_key=OPENAI_API_KEY)\n",
"embedding_model_name = \"text-embedding-ada-002\"\n",
"embedding_model_name = \"text-embedding-3-small\"\n",
"\n",
"result = client.embeddings.create(\n",
" input=[\n",

@ -165,7 +165,7 @@
"metadata": {},
"outputs": [
{
"name": "stdin",
"name": "stdout",
"output_type": "stream",
"text": [
"Please provide the full path to your Secure Connect Bundle zipfile: /path/to/secure-connect-DatabaseName.zip\n",
@ -406,7 +406,7 @@
"metadata": {},
"outputs": [
{
"name": "stdin",
"name": "stdout",
"output_type": "stream",
"text": [
"Please enter your OpenAI API Key: ········\n"
@ -435,7 +435,7 @@
"outputs": [],
"source": [
"client = openai.OpenAI(api_key=OPENAI_API_KEY)\n",
"embedding_model_name = \"text-embedding-ada-002\"\n",
"embedding_model_name = \"text-embedding-3-small\"\n",
"\n",
"result = client.embeddings.create(\n",
" input=[\n",

@ -145,7 +145,7 @@
"metadata": {},
"outputs": [
{
"name": "stdin",
"name": "stdout",
"output_type": "stream",
"text": [
"Please enter your Astra token ('AstraCS:...') ········\n",
@ -223,7 +223,7 @@
"metadata": {},
"outputs": [
{
"name": "stdin",
"name": "stdout",
"output_type": "stream",
"text": [
"Please enter your OpenAI API Key: ········\n"
@ -252,7 +252,7 @@
"outputs": [],
"source": [
"client = openai.OpenAI(api_key=OPENAI_API_KEY)\n",
"embedding_model_name = \"text-embedding-ada-002\"\n",
"embedding_model_name = \"text-embedding-3-small\"\n",
"\n",
"result = client.embeddings.create(\n",
" input=[\n",

@ -265,7 +265,7 @@
"import chromadb\n",
"\n",
"# I've set this to our new embeddings model, this can be changed to the embedding model of your choice\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Ignore unclosed SSL socket warnings - optional in case you get these errors\n",
"import warnings\n",

@ -306,7 +306,7 @@
"## Encode a question with OpenAI embedding model\n",
"\n",
"To perform kNN search, we need to encode queries with the same embedding model used to encode the documents at index time.\n",
"In this example, we need to use the `text-embedding-ada-002` model.\n",
"In this example, we need to use the `text-embedding-3-small` model.\n",
"\n",
"You'll need your OpenAI [API key](https://platform.openai.com/account/api-keys) to generate the embeddings."
]
@ -325,7 +325,7 @@
"openai.api_key = OPENAI_API_KEY\n",
"\n",
"# Define model\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Define question\n",
"question = 'Is the Atlantic the biggest ocean in the world?'\n",

@ -314,7 +314,7 @@
"## Encode a question with OpenAI embedding model\n",
"\n",
"To perform semantic search, we need to encode queries with the same embedding model used to encode the documents at index time.\n",
"In this example, we need to use the `text-embedding-ada-002` model.\n",
"In this example, we need to use the `text-embedding-3-small` model.\n",
"\n",
"You'll need your OpenAI [API key](https://platform.openai.com/account/api-keys) to generate the embeddings."
]
@ -333,7 +333,7 @@
"openai.api_key = OPENAI_API_KEY\n",
"\n",
"# Define model\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Define question\n",
"question = 'Is the Atlantic the biggest ocean in the world?'\n",

@ -707,7 +707,7 @@
"source": [
"## Search data\n",
"\n",
"Once the data is uploaded we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-ada-002` OpenAI model we also have to use it during search.\n"
"Once the data is uploaded we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-3-small` OpenAI model we also have to use it during search.\n"
]
},
{
@ -727,7 +727,7 @@
" # Creates embedding vector from user query\n",
" embedded_query = openai.Embedding.create(\n",
" input=query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
" )[\"data\"][0][\"embedding\"]\n",
"\n",
" # Convert the embedded_query to PostgreSQL compatible format\n",

File diff suppressed because one or more lines are too long

@ -175,7 +175,7 @@
"PORT = 19530\n",
"COLLECTION_NAME = 'movie_search'\n",
"DIMENSION = 1536\n",
"OPENAI_ENGINE = 'text-embedding-ada-002'\n",
"OPENAI_ENGINE = 'text-embedding-3-small'\n",
"openai.api_key = 'sk-your_key'\n",
"\n",
"INDEX_PARAM = {\n",

@ -275,7 +275,7 @@
"PORT = 19530\n",
"COLLECTION_NAME = 'book_search'\n",
"DIMENSION = 1536\n",
"OPENAI_ENGINE = 'text-embedding-ada-002'\n",
"OPENAI_ENGINE = 'text-embedding-3-small'\n",
"openai.api_key = 'sk-your_key'\n",
"\n",
"INDEX_PARAM = {\n",

@ -1,43 +1,29 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "flQYAhphJC5m"
},
"source": [
"\n",
"This notebook demonstrates how to build a semantic search application using OpenAI and [MongoDB Atlas vector search](https://www.mongodb.com/products/platform/atlas-vector-search)"
],
"metadata": {
"id": "flQYAhphJC5m"
}
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "iYMn0dXXdFbY",
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iYMn0dXXdFbY",
"outputId": "98dab421-f11b-40b8-8f82-6de42b25725a"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting pymongo\n",
" Downloading pymongo-4.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (677 kB)\n",
@ -80,6 +66,9 @@
},
{
"cell_type": "markdown",
"metadata": {
"id": "vLuKFvTwJXpu"
},
"source": [
"# Step 1: Setup the environment\n",
"\n",
@ -88,27 +77,18 @@
"1. **MongoDB Atlas cluster**: To create a forever free MongoDB Atlas cluster, first, you need to create a MongoDB Atlas account if you don't already have one. Visit the [MongoDB Atlas website](https://www.mongodb.com/atlas/database) and click on “Register.” Visit the [MongoDB Atlas](https://account.mongodb.com/account/login) dashboard and set up your cluster. In order to take advantage of the `$vectorSearch` operator in an aggregation pipeline, you need to run MongoDB Atlas 6.0.11 or higher. This tutorial can be built using a free cluster. When youre setting up your deployment, youll be prompted to set up a database user and rules for your network connection. Please ensure you save your username and password somewhere safe and have the correct IP address rules in place so your cluster can connect properly. If you need more help getting started, check out our [tutorial on MongoDB Atlas](https://www.mongodb.com/basics/mongodb-atlas-tutorial).\n",
"\n",
"2. **OpenAI API key** To create your OpenAI key, you'll need to create an account. Once you have that, visit the [OpenAI platform](https://platform.openai.com/). Click on your profile icon in the top right of the screen to get the dropdown menu and select “View API keys”.\n"
],
"metadata": {
"id": "vLuKFvTwJXpu"
}
]
},
{
"cell_type": "code",
"source": [
"import getpass\n",
"\n",
"MONGODB_ATLAS_CLUSTER_URI = getpass.getpass(\"MongoDB Atlas Cluster URI:\")\n",
"OPENAI_API_KEY = getpass.getpass(\"OpenAI API Key:\")\n"
],
"execution_count": null,
"metadata": {
"id": "qJHHIIKjIFUZ",
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qJHHIIKjIFUZ",
"outputId": "57ad72d4-8afb-4e34-aad1-1fea6eb3645b"
},
"execution_count": null,
"outputs": [
{
"name": "stdout",
@ -118,29 +98,40 @@
"OpenAI API Key:··········\n"
]
}
],
"source": [
"import getpass\n",
"\n",
"MONGODB_ATLAS_CLUSTER_URI = getpass.getpass(\"MongoDB Atlas Cluster URI:\")\n",
"OPENAI_API_KEY = getpass.getpass(\"OpenAI API Key:\")\n"
]
},
{
"cell_type": "markdown",
"source": [
"Note: After executing the step above you will be prompted to enter the credentials."
],
"metadata": {
"id": "Sarx9wdxb4Rr"
}
},
"source": [
"Note: After executing the step above you will be prompted to enter the credentials."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "sk1xXoyxMfil"
},
"source": [
"For this tutorial, we will be using the\n",
"[MongoDB sample dataset](https://www.mongodb.com/docs/atlas/sample-data/). Load the sample dataset using the Atlas UI. We'll be using the “sample_mflix” database, which contains a “movies” collection where each document contains fields like title, plot, genres, cast, directors, etc.\n"
],
"metadata": {
"id": "sk1xXoyxMfil"
}
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "k-G6WhNFdIvW"
},
"outputs": [],
"source": [
"import openai\n",
"import pymongo\n",
@ -150,72 +141,56 @@
"collection = db.movies\n",
"\n",
"openai.api_key = OPENAI_API_KEY"
],
"metadata": {
"id": "k-G6WhNFdIvW"
},
"execution_count": null,
"outputs": []
]
},
{
"cell_type": "code",
"source": [
"ATLAS_VECTOR_SEARCH_INDEX_NAME = \"default\"\n",
"EMBEDDING_FIELD_NAME = \"embedding_openai_nov19_23\""
],
"execution_count": null,
"metadata": {
"id": "On9e13ASwReq"
},
"execution_count": null,
"outputs": []
"outputs": [],
"source": [
"ATLAS_VECTOR_SEARCH_INDEX_NAME = \"default\"\n",
"EMBEDDING_FIELD_NAME = \"embedding_openai_nov19_23\""
]
},
{
"cell_type": "markdown",
"source": [
"# Step 2: Setup embeddings generation function"
],
"metadata": {
"id": "X-9gl2s-uGtw"
}
},
"source": [
"# Step 2: Setup embeddings generation function"
]
},
{
"cell_type": "code",
"source": [
"model = \"text-embedding-ada-002\"\n",
"def generate_embedding(text: str) -> list[float]:\n",
" return openai.embeddings.create(input = [text], model=model).data[0].embedding\n"
],
"execution_count": null,
"metadata": {
"id": "BMnE4BxSOCtH"
},
"execution_count": null,
"outputs": []
"outputs": [],
"source": [
"model = \"text-embedding-3-small\"\n",
"def generate_embedding(text: str) -> list[float]:\n",
" return openai.embeddings.create(input = [text], model=model).data[0].embedding\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "snSjiSNKwX6Z"
},
"source": [
"# Step 3: Create and store embeddings\n",
"\n",
"Each document in the sample dataset sample_mflix.movies corresponds to a movie; we will execute an operation to create a vector embedding for the data in the \"plot\" field and store it in the database. Creating vector embeddings using OpenAI embeddings endpoint is necessary for performing a similarity search based on intent."
],
"metadata": {
"id": "snSjiSNKwX6Z"
}
]
},
{
"cell_type": "code",
"source": [
"from pymongo import ReplaceOne\n",
"\n",
"# Update the collection with the embeddings\n",
"requests = []\n",
"\n",
"for doc in collection.find({'plot':{\"$exists\": True}}).limit(500):\n",
" doc[EMBEDDING_FIELD_NAME] = generate_embedding(doc['plot'])\n",
" requests.append(ReplaceOne({'_id': doc['_id']}, doc))\n",
"\n",
"collection.bulk_write(requests)"
],
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@ -223,42 +198,56 @@
"id": "t4i9gQM2xUFF",
"outputId": "ae558b67-9b06-4c83-c52a-a8047ecd40d5"
},
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"BulkWriteResult({'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 0, 'nUpserted': 0, 'nMatched': 50, 'nModified': 50, 'nRemoved': 0, 'upserted': []}, acknowledged=True)"
]
},
"execution_count": 15,
"metadata": {},
"execution_count": 15
"output_type": "execute_result"
}
],
"source": [
"from pymongo import ReplaceOne\n",
"\n",
"# Update the collection with the embeddings\n",
"requests = []\n",
"\n",
"for doc in collection.find({'plot':{\"$exists\": True}}).limit(500):\n",
" doc[EMBEDDING_FIELD_NAME] = generate_embedding(doc['plot'])\n",
" requests.append(ReplaceOne({'_id': doc['_id']}, doc))\n",
"\n",
"collection.bulk_write(requests)"
]
},
{
"cell_type": "markdown",
"source": [
"After executing the above, the documents in \"movies\" collection will contain an additional field of \"embedding\", as defined by the `EMBEDDDING_FIELD_NAME` variable, apart from already existing fields like title, plot, genres, cast, directors, etc."
],
"metadata": {
"id": "ShPbxQPaPvHD"
}
},
"source": [
"After executing the above, the documents in \"movies\" collection will contain an additional field of \"embedding\", as defined by the `EMBEDDDING_FIELD_NAME` variable, apart from already existing fields like title, plot, genres, cast, directors, etc."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Coq0tyjXyNIu"
},
"source": [
"Note: We are restricting this to just 500 documents in the interest of time. If you want to do this over the entire dataset of 23,000+ documents in our sample_mflix database, it will take a little while. Alternatively, you can use the [sample_mflix.embedded_movies collection](https://www.mongodb.com/docs/atlas/sample-data/sample-mflix/#sample_mflix.embedded_movies) which includes a pre-populated `plot_embedding` field that contains embeddings created using `OpenAI's text-embedding-ada-002` embedding model that you can use with the Atlas Search vector search feature.\n",
"Note: We are restricting this to just 500 documents in the interest of time. If you want to do this over the entire dataset of 23,000+ documents in our sample_mflix database, it will take a little while. Alternatively, you can use the [sample_mflix.embedded_movies collection](https://www.mongodb.com/docs/atlas/sample-data/sample-mflix/#sample_mflix.embedded_movies) which includes a pre-populated `plot_embedding` field that contains embeddings created using OpenAI's `text-embedding-3-small` embedding model that you can use with the Atlas Search vector search feature.\n",
"\n",
"\n"
],
"metadata": {
"id": "Coq0tyjXyNIu"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rCRCK6QOskqo"
},
"source": [
"# Step 4: Create a vector search index\n",
"\n",
@ -266,13 +255,13 @@
"We will cover 2 ways to create this index - Atlas UI and using MongoDB python driver.\n",
"\n",
"(Optional) [Documentation: Create a Vector Search Index ](https://www.mongodb.com/docs/atlas/atlas-search/field-types/knn-vector/)"
],
"metadata": {
"id": "rCRCK6QOskqo"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ymRTaFb1X5Tq"
},
"source": [
"Now head over to [Atlas UI](cloud.mongodb.com) and create an Atlas Vector Search index using the steps descibed [here](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-tutorial/#create-the-atlas-vector-search-index). The 'dimensions' field with value 1536, corresponds to openAI text-embedding-ada002.\n",
"\n",
@ -292,36 +281,21 @@
" }\n",
"}\n",
"```"
],
"metadata": {
"id": "ymRTaFb1X5Tq"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2l5BzUgncjiq"
},
"source": [
"(Optional) Alternatively, we can use [pymongo driver to create these vector search indexes programatically](https://pymongo.readthedocs.io/en/stable/api/pymongo/collection.html#pymongo.collection.Collection.create_search_index)\n",
"The python command given in the cell below will create the index (this only works for the most recent version of the Python Driver for MongoDB and MongoDB server version 7.0+ Atlas cluster)."
],
"metadata": {
"id": "2l5BzUgncjiq"
}
]
},
{
"cell_type": "code",
"source": [
"collection.create_search_index(\n",
" {\"definition\":\n",
" {\"mappings\": {\"dynamic\": True, \"fields\": {\n",
" EMBEDDING_FIELD_NAME : {\n",
" \"dimensions\": 1536,\n",
" \"similarity\": \"dotProduct\",\n",
" \"type\": \"knnVector\"\n",
" }}}},\n",
" \"name\": ATLAS_VECTOR_SEARCH_INDEX_NAME\n",
" }\n",
")"
],
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@ -330,38 +304,55 @@
"id": "54OWgiaPcmD0",
"outputId": "2cb9d1d8-4515-49ad-9fe7-5b4fa3c6c86b"
},
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"'default'"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
}
},
"text/plain": [
"'default'"
]
},
"execution_count": 16,
"metadata": {},
"execution_count": 16
"output_type": "execute_result"
}
],
"source": [
"collection.create_search_index(\n",
" {\"definition\":\n",
" {\"mappings\": {\"dynamic\": True, \"fields\": {\n",
" EMBEDDING_FIELD_NAME : {\n",
" \"dimensions\": 1536,\n",
" \"similarity\": \"dotProduct\",\n",
" \"type\": \"knnVector\"\n",
" }}}},\n",
" \"name\": ATLAS_VECTOR_SEARCH_INDEX_NAME\n",
" }\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6V9QKgm8caNb"
},
"source": [
"# Step 5: Query your data\n",
"\n",
"The results for the query here finds movies which have semantically similar plots to the text captured in the query string, rather than being based on the keyword search.\n",
"\n",
"(Optional) [Documentation: Run Vector Search Queries](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/)"
],
"metadata": {
"id": "6V9QKgm8caNb"
}
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "34tib9TrMPg4"
},
"outputs": [],
"source": [
"\n",
"def query_results(query, k):\n",
@ -377,28 +368,37 @@
" }\n",
" ])\n",
" return results"
],
"metadata": {
"id": "34tib9TrMPg4"
},
"execution_count": null,
"outputs": []
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"id": "kTqrip-hWULK"
},
"outputs": [],
"source": [
"query=\"imaginary characters from outerspace at war with earthlings\"\n",
"movies = query_results(query, 5)\n",
"\n",
"for movie in movies:\n",
" print(f'Movie Name: {movie[\"title\"]},\\nMovie Plot: {movie[\"plot\"]}\\n')"
],
"metadata": {
"collapsed": true,
"id": "kTqrip-hWULK"
},
"execution_count": null,
"outputs": []
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
]
}
},
"nbformat": 4,
"nbformat_minor": 0
}

@ -73,429 +73,14 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2023-02-16T12:05:05.730338Z",
"start_time": "2023-02-16T12:05:05.723351Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<OpenAIObject list at 0x118768f40> JSON: {\n",
" \"data\": [\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"babbage\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"davinci\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-davinci-edit-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"babbage-code-search-code\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-similarity-babbage-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"code-davinci-edit-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-davinci-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-davinci-003\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-internal\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"ada\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"babbage-code-search-text\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"babbage-similarity\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"code-search-babbage-text-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-curie-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"whisper-1\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-internal\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"code-search-babbage-code-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-ada-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-embedding-ada-002\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-internal\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-similarity-ada-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"curie-instruct-beta\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"ada-code-search-code\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"ada-similarity\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"code-search-ada-text-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-ada-query-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"davinci-search-document\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"gpt-3.5-turbo-0301\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"ada-code-search-text\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-ada-doc-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"davinci-instruct-beta\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-similarity-curie-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"code-search-ada-code-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"ada-search-query\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-davinci-query-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"curie-search-query\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"davinci-search-query\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"babbage-search-document\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"ada-search-document\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-curie-query-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-babbage-doc-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"curie-search-document\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-curie-doc-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"babbage-search-query\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-babbage-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-davinci-doc-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"gpt-3.5-turbo\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-search-babbage-query-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"curie-similarity\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"curie\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-similarity-davinci-001\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"text-davinci-002\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" },\n",
" {\n",
" \"created\": null,\n",
" \"id\": \"davinci-similarity\",\n",
" \"object\": \"engine\",\n",
" \"owner\": \"openai-dev\",\n",
" \"permissions\": null,\n",
" \"ready\": true\n",
" }\n",
" ],\n",
" \"object\": \"list\"\n",
"}"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"import openai\n",
"\n",
@ -744,7 +329,7 @@
"# creates embedding vector from user query\n",
"embed = openai.Embedding.create(\n",
" input=query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
")[\"data\"][0][\"embedding\"]\n",
"\n",
"# query the database to find the top K similar content to the given query\n",

@ -74,7 +74,7 @@
"import clickhouse_connect\n",
"\n",
"# I've set this to our new embeddings model, this can be changed to the embedding model of your choice\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Ignore unclosed SSL socket warnings - optional in case you get these errors\n",
"import warnings\n",
@ -476,7 +476,7 @@
"# creates embedding vector from user query\n",
"embed = openai.Embedding.create(\n",
" input=query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
")[\"data\"][0][\"embedding\"]\n",
"\n",
"# query the database to find the top K similar content to the given query\n",

@ -391,7 +391,7 @@
"\n",
"After the data is stored in your Neon database, you can query the data for nearest neighbors. \n",
"\n",
"Start by defining the `query_neon` function, which is executed when you run the vector similarity search. The function creates an embedding based on the user's query, prepares the SQL query, and runs the SQL query with the embedding. The pre-computed embeddings that you loaded into your database were created with `text-embedding-ada-002` OpenAI model, so you must use the same model to create an embedding for the similarity search.\n",
"Start by defining the `query_neon` function, which is executed when you run the vector similarity search. The function creates an embedding based on the user's query, prepares the SQL query, and runs the SQL query with the embedding. The pre-computed embeddings that you loaded into your database were created with `text-embedding-3-small` OpenAI model, so you must use the same model to create an embedding for the similarity search.\n",
"\n",
"A `vector_name` parameter is provided that allows you to search based on \"title\" or \"content\"."
]
@ -407,7 +407,7 @@
" # Create an embedding vector from the user query\n",
" embedded_query = openai.Embedding.create(\n",
" input=query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
" )[\"data\"][0][\"embedding\"]\n",
"\n",
" # Convert the embedded_query to PostgreSQL compatible format\n",

@ -387,7 +387,7 @@
"source": [
"## Initialize Embedding Model\n",
"\n",
"We use `text-embedding-ada-002` as the embedding model. We can embed text like so:"
"We use `text-embedding-3-small` as the embedding model. We can embed text like so:"
]
},
{
@ -401,9 +401,9 @@
"import openai\n",
"\n",
"# initialize openai API key\n",
"openai.api_key = \"sk-...\" #platform.openai.com\n",
"openai.api_key = \"sk-...\"\n",
"\n",
"embed_model = \"text-embedding-ada-002\"\n",
"embed_model = \"text-embedding-3-small\"\n",
"\n",
"res = openai.Embedding.create(\n",
" input=[\n",
@ -456,7 +456,7 @@
"id": "zStnHFpkNVIU"
},
"source": [
"Inside `'data'` we will find two records, one for each of the two sentences we just embedded. Each vector embedding contains `1536` dimensions (the output dimensionality of the `text-embedding-ada-002` model."
"Inside `'data'` we will find two records, one for each of the two sentences we just embedded. Each vector embedding contains `1536` dimensions (the output dimensionality of the `text-embedding-3-small` model."
]
},
{
@ -598,7 +598,7 @@
"id": "ezSTzN2rPa2o"
},
"source": [
"We can see the index is currently empty with a `total_vector_count` of `0`. We can begin populating it with OpenAI `text-embedding-ada-002` built embeddings like so:"
"We can see the index is currently empty with a `total_vector_count` of `0`. We can begin populating it with OpenAI `text-embedding-3-small` built embeddings like so:"
]
},
{

@ -104,9 +104,9 @@
"source": [
"query = \"who was the 12th person on the moon and when did they land?\"\n",
"\n",
"# now query text-davinci-003 WITHOUT context\n",
"# now query `gpt-3.5-turbo-instruct` WITHOUT context\n",
"res = openai.Completion.create(\n",
" engine='text-davinci-003',\n",
" engine='gpt-3.5-turbo-instruct',\n",
" prompt=query,\n",
" temperature=0,\n",
" max_tokens=400,\n",
@ -138,9 +138,8 @@
"outputs": [],
"source": [
"def complete(prompt):\n",
" # query text-davinci-003\n",
" res = openai.Completion.create(\n",
" engine='text-davinci-003',\n",
" engine='gpt-3.5-turbo-instruct',\n",
" prompt=prompt,\n",
" temperature=0,\n",
" max_tokens=400,\n",
@ -240,7 +239,7 @@
"\n",
"We will need to retrieve information that is semantically related to our queries, to do this we need to use _\"dense vector embeddings\"_. These can be thought of as numerical representations of the *meaning* behind our sentences.\n",
"\n",
"To create these dense vectors we use the `text-embedding-ada-002` model.\n",
"To create these dense vectors we use the `text-embedding-3-small` model.\n",
"\n",
"We have already authenticated our OpenAI connection, to create an embedding we just do:"
]
@ -304,7 +303,7 @@
"id": "MwSk-wiK62KO"
},
"source": [
"Inside `'data'` we will find two records, one for each of the two sentences we just embedded. Each vector embedding contains `1536` dimensions (the output dimensionality of the `text-embedding-ada-002` model."
"Inside `'data'` we will find two records, one for each of the two sentences we just embedded. Each vector embedding contains `1536` dimensions (the output dimensionality of the `text-embedding-3-small` model."
]
},
{
@ -615,7 +614,7 @@
"id": "nELBmqxxzeqL"
},
"source": [
"We can see the index is currently empty with a `total_vector_count` of `0`. We can begin populating it with OpenAI `text-embedding-ada-002` built embeddings like so:"
"We can see the index is currently empty with a `total_vector_count` of `0`. We can begin populating it with OpenAI `text-embedding-3-small` built embeddings like so:"
]
},
{
@ -673,13 +672,13 @@
" # get texts to encode\n",
" texts = [x['text'] for x in meta_batch]\n",
" # create embeddings (try-except added to avoid RateLimitError)\n",
" done = False\n",
" while not done:\n",
" try:\n",
" res = openai.Embedding.create(input=texts, engine=embed_model)\n",
" done = True\n",
" except:\n",
" sleep(5)\n",
" done = False\n",
" while not done:\n",
" try:\n",
" res = openai.Embedding.create(input=texts, engine=embed_model)\n",
" done = True\n",
" except:\n",
" sleep(5)\n",
" embeds = [record['embedding'] for record in res['data']]\n",
" # cleanup metadata\n",
" meta_batch = [{\n",

@ -3741,7 +3741,7 @@
}
],
"source": [
"MODEL = \"text-embedding-ada-002\"\n",
"MODEL = \"text-embedding-3-small\"\n",
"\n",
"res = openai.Embedding.create(\n",
" input=[\n",

@ -105,7 +105,7 @@
"import pinecone\n",
"\n",
"# I've set this to our new embeddings model, this can be changed to the embedding model of your choice\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Ignore unclosed SSL socket warnings - optional in case you get these errors\n",
"import warnings\n",

@ -60,10 +60,10 @@
"Successfully installed certifi-2023.5.7 grpcio-1.56.0 grpcio-tools-1.56.0 h11-0.14.0 h2-4.1.0 hpack-4.0.0 httpcore-0.17.2 httpx-0.24.1 hyperframe-6.0.1 numpy-1.25.0 portalocker-2.7.0 protobuf-4.23.3 pydantic-1.10.9 qdrant-client-1.3.1 typing-extensions-4.5.0 urllib3-1.26.16\r\n",
"Collecting wget\r\n",
" Using cached wget-3.2.zip (10 kB)\r\n",
" Preparing metadata (setup.py) ... \u001B[?25ldone\r\n",
"\u001B[?25hBuilding wheels for collected packages: wget\r\n",
" Building wheel for wget (setup.py) ... \u001B[?25ldone\r\n",
"\u001B[?25h Created wheel for wget: filename=wget-3.2-py3-none-any.whl size=9657 sha256=eb5f15f12150fc304e7b14973424f696fa8d95225772bc0cbc0b318bf92e04b9\r\n",
" Preparing metadata (setup.py) ... \u001b[?25ldone\r\n",
"\u001b[?25hBuilding wheels for collected packages: wget\r\n",
" Building wheel for wget (setup.py) ... \u001b[?25ldone\r\n",
"\u001b[?25h Created wheel for wget: filename=wget-3.2-py3-none-any.whl size=9657 sha256=eb5f15f12150fc304e7b14973424f696fa8d95225772bc0cbc0b318bf92e04b9\r\n",
" Stored in directory: /home/user/.cache/pip/wheels/04/5f/3e/46cc37c5d698415694d83f607f833f83f0149e49b3af9d0f38\r\n",
"Successfully built wget\r\n",
"Installing collected packages: wget\r\n",
@ -104,7 +104,7 @@
"import qdrant_client\n",
"\n",
"# I've set this to our new embeddings model, this can be changed to the embedding model of your choice\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Ignore unclosed SSL socket warnings - optional in case you get these errors\n",
"import warnings\n",
@ -136,7 +136,9 @@
"outputs": [
{
"data": {
"text/plain": "'vector_database_wikipedia_articles_embedded.zip'"
"text/plain": [
"'vector_database_wikipedia_articles_embedded.zip'"
]
},
"execution_count": 5,
"metadata": {},
@ -700,9 +702,9 @@
],
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"display_name": "Python 3 (ipykernel)"
"name": "python3"
},
"language_info": {
"codemirror_mode": {

@ -74,7 +74,7 @@
"import redis\n",
"\n",
"# I've set this to our new embeddings model, this can be changed to the embedding model of your choice\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Ignore unclosed SSL socket warnings - optional in case you get these errors\n",
"import warnings\n",

@ -518,7 +518,7 @@
"\n",
" # Creates embedding vector from user query\n",
" embedded_query = openai.Embedding.create(input=user_query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
" )[\"data\"][0]['embedding']\n",
"\n",
" # Prepare the Query\n",

@ -298,7 +298,6 @@
}
],
"source": [
"# imports\n",
"import pandas as pd\n",
"import numpy as np\n",
"from typing import List\n",
@ -311,8 +310,7 @@
" indices_of_nearest_neighbors_from_distances,\n",
")\n",
"\n",
"# constants\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# load in data and clean data types and drop null rows\n",
"df = pd.read_csv(\"../../data/styles_2k.csv\", on_bad_lines='skip')\n",
@ -633,7 +631,7 @@
"\n",
" # Use OpenAI to create embedding vector from user query\n",
" embedded_query = openai.Embedding.create(input=user_query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
" )[\"data\"][0]['embedding']\n",
"\n",
" # Prepare the Query\n",

@ -75,7 +75,7 @@
"load_dotenv()\n",
"openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n",
"\n",
"def get_vector(text, model=\"text-embedding-ada-002\"):\n",
"def get_vector(text, model=\"text-embedding-3-small\"):\n",
" text = text.replace(\"\\n\", \" \")\n",
" return openai.Embedding.create(input = [text], model = model)['data'][0]['embedding']\n",
"\n",

@ -251,7 +251,7 @@
"import openai\n",
"\n",
"directory = './assets/'\n",
"model='text-embedding-ada-002'\n",
"model='text-embedding-3-small'\n",
"i = 1\n",
"for file in os.listdir(directory):\n",
" with open(os.path.join(directory, file)) as f:\n",

@ -41,7 +41,7 @@ create table documents (
Since Supabase is built on Postgres, we're just using regular SQL here. You can modify this table however you like to better fit your application. If you have existing database tables, you can simply add a new `vector` column to the appropriate table.
The important piece to understand is the `vector` data type, which is a new data type that became available when we enabled the pgvector extension earlier. The size of the vector (1536 here) represents the number of dimensions in the embedding. Since we're using OpenAI's `text-embedding-ada-002` model in this example, we set the vector size to 1536.
The important piece to understand is the `vector` data type, which is a new data type that became available when we enabled the pgvector extension earlier. The size of the vector (1536 here) represents the number of dimensions in the embedding. Since we're using OpenAI's `text-embedding-3-small` model in this example, we set the vector size to 1536.
Let's go ahead and create a vector index on this table so that future queries remain performant as the table grows:
@ -74,27 +74,27 @@ npm install openai
then import it:
```js
import OpenAI from 'openai';
import OpenAI from "openai";
```
If you're using Deno or Supabase Edge Functions, you can import `openai` directly from a URL:
```js
import OpenAI from 'https://esm.sh/openai@4';
import OpenAI from "https://esm.sh/openai@4";
```
> In this example we import from https://esm.sh which is a CDN that automatically fetches the respective NPM module for you and serves it over HTTP.
Next we'll generate an OpenAI embedding using [`text-embedding-ada-002`](https://platform.openai.com/docs/guides/embeddings/embedding-models):
Next we'll generate an OpenAI embedding using [`text-embedding-3-small`](https://platform.openai.com/docs/guides/embeddings/embedding-models):
```js
const openai = new OpenAI();
const input = 'The cat chases the mouse';
const input = "The cat chases the mouse";
const result = await openai.embeddings.create({
input,
model: 'text-embedding-ada-002',
model: "text-embedding-3-small",
});
const [{ embedding }] = result.data;
@ -104,7 +104,7 @@ Remember that you will need an [OpenAI API key](https://platform.openai.com/api-
```js
const openai = new OpenAI({
apiKey: '<openai-api-key>',
apiKey: "<openai-api-key>",
});
```
@ -125,13 +125,13 @@ npm install @supabase/supabase-js
then import it:
```js
import { createClient } from '@supabase/supabase-js';
import { createClient } from "@supabase/supabase-js";
```
If you're using Deno or Supabase Edge Functions, you can import `@supabase/supabase-js` directly from a URL:
```js
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
```
Next we'll instantiate our Supabase client and configure it so that it points to your Supabase project. In this guide we'll store a reference to your Supabase URL and key in a `.env` file, but feel free to modify this based on how your application handles configuration.
@ -158,32 +158,32 @@ npm install dotenv
And retrieve the environment variables from `process.env`:
```js
import { config } from 'dotenv';
import { config } from "dotenv";
// Load .env file
config();
const supabaseUrl = process.env['SUPABASE_URL'];
const supabaseServiceRoleKey = process.env['SUPABASE_SERVICE_ROLE_KEY'];
const supabaseUrl = process.env["SUPABASE_URL"];
const supabaseServiceRoleKey = process.env["SUPABASE_SERVICE_ROLE_KEY"];
```
In Deno, load the `.env` file using the `dotenv` standard library:
```js
import { load } from 'https://deno.land/std@0.208.0/dotenv/mod.ts';
import { load } from "https://deno.land/std@0.208.0/dotenv/mod.ts";
// Load .env file
const env = await load();
const supabaseUrl = env['SUPABASE_URL'];
const supabaseServiceRoleKey = env['SUPABASE_SERVICE_ROLE_KEY'];
const supabaseUrl = env["SUPABASE_URL"];
const supabaseServiceRoleKey = env["SUPABASE_SERVICE_ROLE_KEY"];
```
In Supabase Edge Functions, simply load the injected environment variables directly:
```js
const supabaseUrl = Deno.env.get('SUPABASE_URL');
const supabaseServiceRoleKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY');
const supabaseUrl = Deno.env.get("SUPABASE_URL");
const supabaseServiceRoleKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY");
```
Next let's instantiate our `supabase` client:
@ -197,7 +197,7 @@ const supabase = createClient(supabaseUrl, supabaseServiceRoleKey, {
From here we use the `supabase` client to insert our text and embedding (generated earlier) into the database:
```js
const { error } = await supabase.from('documents').insert({
const { error } = await supabase.from("documents").insert({
content: input,
embedding,
});
@ -241,23 +241,23 @@ Inside the function we implement the query which does two things:
Now we can call this function from our application using the `supabase.rpc()` method:
```js
const query = 'What does the cat chase?';
const query = "What does the cat chase?";
// First create an embedding on the query itself
const result = await openai.embeddings.create({
input: query,
model: 'text-embedding-ada-002',
model: "text-embedding-3-small",
});
const [{ embedding }] = result.data;
// Then use this embedding to search for matches
const { data: documents, error: matchError } = await supabase
.rpc('match_documents', {
.rpc("match_documents", {
query_embedding: embedding,
match_threshold: 0.8,
})
.select('content')
.select("content")
.limit(5);
```

@ -423,7 +423,7 @@
"source": [
"## Search data\n",
"\n",
"Once the data is put into Tair we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-ada-002` OpenAI model, we also have to use it during search.\n"
"Once the data is put into Tair we will start querying the collection for the closest vectors. We may provide an additional parameter `vector_name` to switch from title to content based search. Since the precomputed embeddings were created with `text-embedding-3-small` OpenAI model, we also have to use it during search.\n"
]
},
{
@ -442,7 +442,7 @@
" # Creates embedding vector from user query\n",
" embedded_query = openai.Embedding.create(\n",
" input= query,\n",
" model=\"text-embedding-ada-002\",\n",
" model=\"text-embedding-3-small\",\n",
" )[\"data\"][0]['embedding']\n",
" embedded_query = np.array(embedded_query)\n",
"\n",

@ -74,7 +74,7 @@
"import typesense\n",
"\n",
"# I've set this to our new embeddings model, this can be changed to the embedding model of your choice\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Ignore unclosed SSL socket warnings - optional in case you get these errors\n",
"import warnings\n",

@ -74,7 +74,7 @@
"import weaviate\n",
"\n",
"# I've set this to our new embeddings model, this can be changed to the embedding model of your choice\n",
"EMBEDDING_MODEL = \"text-embedding-ada-002\"\n",
"EMBEDDING_MODEL = \"text-embedding-3-small\"\n",
"\n",
"# Ignore unclosed SSL socket warnings - optional in case you get these errors\n",
"import warnings\n",
@ -476,7 +476,7 @@
"client.schema.delete_all()\n",
"client.schema.get()\n",
"\n",
"# Define the Schema object to use `text-embedding-ada-002` on `title` and `content`, but skip it for `url`\n",
"# Define the Schema object to use `text-embedding-3-small` on `title` and `content`, but skip it for `url`\n",
"article_schema = {\n",
" \"class\": \"Article\",\n",
" \"description\": \"A collection of articles\",\n",

@ -283,7 +283,7 @@
"\n",
"We want to vectorize `title` and `content`, but not the `url`.\n",
"\n",
"To vectorize and query the data, we will use `text-embedding-ada-002`."
"To vectorize and query the data, we will use `text-embedding-3-small`."
]
},
{
@ -299,7 +299,7 @@
"client.schema.delete_all()\n",
"client.schema.get()\n",
"\n",
"# Define the Schema object to use `text-embedding-ada-002` on `title` and `content`, but skip it for `url`\n",
"# Define the Schema object to use `text-embedding-3-small` on `title` and `content`, but skip it for `url`\n",
"article_schema = {\n",
" \"class\": \"Article\",\n",
" \"description\": \"A collection of articles\",\n",

@ -283,7 +283,7 @@
"\n",
"We want to vectorize `title` and `content`, but not the `url`.\n",
"\n",
"To vectorize and query the data, we will use `text-embedding-ada-002`."
"To vectorize and query the data, we will use `text-embedding-3-small`."
]
},
{
@ -299,7 +299,7 @@
"client.schema.delete_all()\n",
"client.schema.get()\n",
"\n",
"# Define the Schema object to use `text-embedding-ada-002` on `title` and `content`, but skip it for `url`\n",
"# Define the Schema object to use `text-embedding-3-small` on `title` and `content`, but skip it for `url`\n",
"article_schema = {\n",
" \"class\": \"Article\",\n",
" \"description\": \"A collection of articles\",\n",

@ -282,7 +282,7 @@
"\n",
"We want to vectorize `title` and `content`, but not the `url`.\n",
"\n",
"To vectorize and query the data, we will use `text-embedding-ada-002`. For Q&A we will use `text-davinci-002`."
"To vectorize and query the data, we will use `text-embedding-3-small`. For Q&A we will use `gpt-3.5-turbo-instruct`."
]
},
{
@ -298,7 +298,7 @@
"client.schema.delete_all()\n",
"client.schema.get()\n",
"\n",
"# Define the Schema object to use `text-embedding-ada-002` on `title` and `content`, but skip it for `url`\n",
"# Define the Schema object to use `text-embedding-3-small` on `title` and `content`, but skip it for `url`\n",
"article_schema = {\n",
" \"class\": \"Article\",\n",
" \"description\": \"A collection of articles\",\n",
@ -310,7 +310,7 @@
" \"type\": \"text\"\n",
" }, \n",
" \"qna-openai\": {\n",
" \"model\": \"text-davinci-002\",\n",
" \"model\": \"gpt-3.5-turbo-instruct\",\n",
" \"maxTokens\": 16,\n",
" \"temperature\": 0.0,\n",
" \"topP\": 1,\n",

@ -56,7 +56,7 @@
"TOKEN = 'your_token' # TOKEN == user:password or api_key\n",
"COLLECTION_NAME = 'book_search'\n",
"DIMENSION = 1536\n",
"OPENAI_ENGINE = 'text-embedding-ada-002'\n",
"OPENAI_ENGINE = 'text-embedding-3-small'\n",
"openai.api_key = 'sk-your_key'\n",
"\n",
"INDEX_PARAM = {\n",

@ -102,7 +102,7 @@
"TOKEN = 'your_token' # TOKEN == user:password or api_key\n",
"COLLECTION_NAME = 'book_search'\n",
"DIMENSION = 1536\n",
"OPENAI_ENGINE = 'text-embedding-ada-002'\n",
"OPENAI_ENGINE = 'text-embedding-3-small'\n",
"openai.api_key = 'sk-your-key'\n",
"\n",
"INDEX_PARAM = {\n",

Loading…
Cancel
Save