From 5e55de89eeeb17059e076edc5185aeee202ab979 Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 10:13:13 -0700 Subject: [PATCH 1/8] removes LLM calls. adds multi-user example --- docs/user_guide/session_manager_07.ipynb | 547 ++++++----------------- 1 file changed, 140 insertions(+), 407 deletions(-) diff --git a/docs/user_guide/session_manager_07.ipynb b/docs/user_guide/session_manager_07.ipynb index 95a62dd8..2c855dd7 100644 --- a/docs/user_guide/session_manager_07.ipynb +++ b/docs/user_guide/session_manager_07.ipynb @@ -22,572 +22,305 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [], - "source": [ - "from typing import Dict, List\n", - "import cohere\n", - "import os\n", - "\n", - "class CohereClient():\n", - " def __init__(self, api_key: str = None, model: str = 'command-r-plus'):\n", - " api_key = api_key or os.getenv(\"COHERE_API_KEY\")\n", - " self.client = cohere.Client(api_key)\n", - " self._model = model\n", - "\n", - " def converse(self, prompt: str, context: List[Dict]) -> str:\n", - " context = self.remap(context)\n", - " response = self.client.chat(\n", - " model=self._model,\n", - " chat_history = context,\n", - " message=prompt,\n", - " )\n", - " return response.text\n", - "\n", - " def remap(self, context) -> List[Dict]:\n", - " ''' re-index the chat history to match the Cohere API requirements '''\n", - " new_context = []\n", - " for statement in context:\n", - " if statement[\"role\"] == \"user\":\n", - " new_statement = {\"role\": \"USER\", \"message\": statement[\"content\"]}\n", - " elif statement[\"role\"] == \"llm\":\n", - " new_statement = {\"role\": \"CHATBOT\", \"message\": statement[\"content\"]}\n", - " elif statement[\"role\"] == \"system\":\n", - " new_statement = {\"role\": \"SYSTEM\", \"message\": statement[\"content\"]}\n", - " else:\n", - " raise ValueError(f'Unknown chat role {statement[\"role\"]}')\n", - " new_context.append(new_statement)\n", - " return new_context" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "15:47:49 redisvl.index.index INFO Index already exists, not overwriting.\n" + "10:10:43 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], "source": [ - "from redisvl.extensions.session_manager import SemanticSessionManager\n", - "user_session = SemanticSessionManager(name='llm_chef')\n", - "user_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful chef, assisting people in making delicious meals\"})\n", - "\n", - "client = CohereClient()" + "from redisvl.extensions.session_manager import StandardSessionManager\n", + "chat_session = StandardSessionManager(name='student tutor')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "On each call to the LLM we can first retrieve the recent history of the conversation. On the first call it will just be the preamble we set." + "To align with common LLM APIs, Redis stores messages with `role` and `content` fields.\n", + "The supported roles are \"system\", \"user\" and \"llm\".\n", + "\n", + "You can store messages one at a time or all at once." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "USER: can you give me some ideas for breakfast?\n", - "\n", - "LLM: Certainly! Here are some delicious breakfast ideas to start your day off right:\n", - "\n", - "**1. Avocado Toast:**\n", - " - Spread mashed avocado on a slice of toasted bread. Top it with a sprinkle of salt and pepper, a squeeze of lemon or lime juice, and a drizzle of extra virgin olive oil. You can also add sliced tomatoes, chopped onions, or a fried egg on top.\n", - "\n", - "**2. Smoothie Bowl:**\n", - " - Blend your favorite fruits (such as bananas, strawberries, blueberries, and mango) with a liquid base (like milk, yogurt, or juice) to create a thick and creamy smoothie. Pour it into a bowl and top it with granola, nuts, seeds, shredded coconut, or fresh fruit slices.\n", - "\n", - "**3. Pancakes or Waffles:**\n", - " - Whip up a batch of fluffy pancakes or waffles and serve them with a variety of toppings. Some options include fresh fruit, maple syrup, butter, whipped cream, chocolate chips, or a dusting of powdered sugar.\n", - "\n", - "**4. Breakfast Burrito:**\n", - " - Fill a flour tortilla with scrambled eggs, sautéed vegetables (such as bell peppers, onions, and mushrooms), shredded cheese, and your choice of breakfast meat (bacon, sausage, or ham). Roll it up and enjoy it as a handheld breakfast.\n", - "\n", - "**5. Overnight Oats:**\n", - " - Combine rolled oats, milk, yogurt, and your choice of mix-ins (such as chia seeds, flaxseeds, nuts, dried fruit, or fresh fruit) in a jar or container. Stir well, cover, and refrigerate overnight. In the morning, you'll have a delicious, creamy, and nutritious breakfast ready to go.\n", - "\n", - "**6. Eggs Benedict:**\n", - " - Poach an egg and place it on top of a toasted English muffin halved. Add a slice of Canadian bacon or ham and top it with a generous drizzle of hollandaise sauce. This classic breakfast dish is indulgent and satisfying.\n", - "\n", - "**7. Yogurt Parfait:**\n", - " - Layer yogurt, granola, and fresh fruit in a glass or bowl to create a beautiful and tasty parfait. Drizzle with honey and top with a sprinkle of chopped nuts or seeds for some crunch.\n", - "\n", - "**8. Breakfast Sandwich:**\n", - " - Toast two slices of bread and fill them with scrambled or fried eggs, cheese, and your choice of breakfast meat. You can also add vegetables like spinach, tomatoes, or avocado slices.\n", - "\n", - "**9. Fruit and Nut Butter:**\n", - " - Spread your favorite nut butter (such as peanut butter, almond butter, or cashew butter) on a slice of toast or a bagel. Top it with sliced bananas, apples, or berries for a nutritious and filling breakfast.\n", - "\n", - "**10. Quiche:**\n", - " - Bake a quiche filled with eggs, milk or cream, cheese, and your choice of vegetables and/or meat. It's a delicious and elegant breakfast option that can be served warm or at room temperature.\n", - "\n", - "These breakfast ideas offer a variety of flavors, textures, and nutritional profiles to suit different tastes and preferences. Feel free to experiment, get creative, and customize these dishes to your liking!\n" - ] - } - ], + "outputs": [], "source": [ - "prompt = \"can you give me some ideas for breakfast?\"\n", - "context = user_session.get_recent()\n", - "response = client.converse(prompt=prompt, context=context)\n", - "user_session.store(prompt, response)\n", - "print('USER: ', prompt)\n", - "print('\\nLLM: ', response)" + "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.\"})\n", + "chat_session.add_messages([\n", + " {\"role\":\"user\", \"content\":\"What is the capital of France?\"},\n", + " {\"role\":\"llm\", \"content\":\"The capital is Paris.\"},\n", + " {\"role\":\"user\", \"content\":\"And what is the capital of Spain?\"},\n", + " {\"role\":\"llm\", \"content\":\"The capital is Madrid.\"},\n", + " {\"role\":\"user\", \"content\":\"What is the population of Great Britain?\"},\n", + " {\"role\":\"llm\", \"content\":\"As of 2023 the population of Great Britain is approximately 67 million people.\"},\n", + " ]\n", + " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's continue this conversation and inspect the context we're passing to the LLM as we go." + "At any point we can retrieve the recent history of the conversation. It will be ordered by entry time." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "USER: can you give me the recipe for those pancakes?\n", - "\n", - "LLM: Of course! Here is a classic recipe for fluffy and delicious pancakes:\n", - "\n", - "**Ingredients:**\n", - "\n", - "- 2 cups (250 grams) all-purpose flour\n", - "- 2 teaspoons baking powder\n", - "- 1 teaspoon salt\n", - "- 2 tablespoons sugar\n", - "- 2 cups milk\n", - "- 2 eggs\n", - "- 3 tablespoons melted butter, plus more for the pan\n", - "- 1 teaspoon vanilla extract (optional)\n", - "\n", - "**Instructions:**\n", - "\n", - "1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until well blended.\n", - "\n", - "2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, eggs, melted butter, and vanilla extract (if using). Make sure the melted butter has cooled down a bit so it doesn't cook the eggs.\n", - "\n", - "3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking until you have a smooth batter. Be careful not to overmix; a few small lumps are okay.\n", - "\n", - "4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat and add a small amount of butter to grease the surface. Let the butter melt and coat the cooking surface.\n", - "\n", - "5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until the edges look dry and small bubbles appear on the surface, about 2-3 minutes.\n", - "\n", - "6. Flip the pancakes: Use a spatula to carefully flip the pancakes. Cook the other side for another 1-2 minutes until lightly browned.\n", - "\n", - "7. Repeat: Repeat this process until you've cooked all your batter, adding more butter to the pan as needed.\n", - "\n", - "8. Serve: Stack the pancakes on a plate and serve them with your favorite toppings. Some popular options include butter, maple syrup, fresh fruit, whipped cream, or a dusting of powdered sugar.\n", - "\n", - "**Variations and Tips:**\n", - "- For extra fluffy pancakes, you can separate the eggs and gently fold in the whipped egg whites after combining the other ingredients.\n", - "- Feel free to add mix-ins to your batter, such as chocolate chips, blueberries, or chopped nuts.\n", - "- If you like thicker pancakes, you can add a little less milk to the batter. For thinner pancakes, add a bit more.\n", - "- To keep pancakes warm while you cook a large batch, preheat your oven to its lowest setting and place the cooked pancakes on a baking sheet or oven-safe plate.\n", - "\n", - "Enjoy your homemade pancakes! They are a classic breakfast treat and can be tailored to your taste preferences.\n" + "{'role': 'llm', 'content': 'The capital is Paris.'}\n", + "{'role': 'user', 'content': 'And what is the capital of Spain?'}\n", + "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n" ] } ], "source": [ - "prompt = \"can you give me the recipe for those pancakes?\"\n", - "context = user_session.get_recent()\n", - "response = client.converse(prompt=prompt, context=context)\n", - "user_session.store(prompt, response)\n", - "print('USER: ', prompt)\n", - "print('\\nLLM: ', response)" + "context = chat_session.get_recent()\n", + "for message in context:\n", + " print(message)" ] }, { - "cell_type": "code", - "execution_count": 5, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'user', 'content': 'I changed my mind. Can you give me the first recipe from your list?'}\n", - "{'role': 'llm', 'content': 'Sure! Here is the recipe for \"Easy One-Pot Pasta\":\\n\\n**Ingredients:**\\n- 2 cups (500 mL) of short pasta (such as penne, macaroni, or fusilli)\\n- 1 tablespoon (15 mL) of olive oil\\n- 1 onion, diced\\n- 2 cloves of garlic, minced\\n- 1 red or green bell pepper, diced\\n- 1 can (28 ounces/796 mL) of diced tomatoes\\n- 1 teaspoon (5 mL) of dried basil\\n- 1 teaspoon (5 mL) of dried oregano\\n- Salt and pepper to taste\\n- 4 cups (1 L) of vegetable broth\\n- 1 cup (250 mL) of grated mozzarella cheese (optional)\\n\\n**Instructions:**\\n\\n1. Heat the olive oil in a large pot over medium heat. Add the onion and garlic, and cook until softened, about 3-4 minutes.\\n\\n2. Add the bell pepper and cook for another 2-3 minutes.\\n\\n3. Stir in the diced tomatoes, basil, oregano, salt, and pepper. Let the mixture simmer for 5 minutes.\\n\\n4. Pour in the vegetable broth and bring the mixture to a boil.\\n\\n5. Add the pasta to the pot and stir well. Ensure that the pasta is fully submerged in the liquid.\\n\\n6. Reduce the heat to medium-low and let the pasta simmer uncovered for about 10-12 minutes, or until the pasta is al dente and most of the liquid has been absorbed. Stir occasionally to prevent the pasta from sticking to the bottom of the pot.\\n\\n7. If desired, sprinkle the grated mozzarella cheese over the pasta and cover the pot until the cheese has melted.\\n\\n8. Serve the pasta hot and enjoy!\\n\\nThis recipe is simple, quick, and perfect for a busy weeknight meal. You can also easily customize it by adding your favorite vegetables or spices. Enjoy the delicious, hearty comfort of this one-pot pasta!'}\n", - "{'role': 'system', 'content': 'You are a helpful chef, assisting people in making delicious meals'}\n", - "{'role': 'user', 'content': 'can you give me some ideas for breakfast?'}\n", - "{'role': 'llm', 'content': \"Certainly! Here are some delicious breakfast ideas to start your day off right:\\n\\n**1. Avocado Toast:**\\n - Spread mashed avocado on a slice of toasted bread. Top it with a sprinkle of salt and pepper, a squeeze of lemon or lime juice, and a drizzle of extra virgin olive oil. You can also add sliced tomatoes, chopped onions, or a fried egg on top.\\n\\n**2. Smoothie Bowl:**\\n - Blend your favorite fruits (such as bananas, strawberries, blueberries, and mango) with a liquid base (like milk, yogurt, or juice) to create a thick and creamy smoothie. Pour it into a bowl and top it with granola, nuts, seeds, shredded coconut, or fresh fruit slices.\\n\\n**3. Pancakes or Waffles:**\\n - Whip up a batch of fluffy pancakes or waffles and serve them with a variety of toppings. Some options include fresh fruit, maple syrup, butter, whipped cream, chocolate chips, or a dusting of powdered sugar.\\n\\n**4. Breakfast Burrito:**\\n - Fill a flour tortilla with scrambled eggs, sautéed vegetables (such as bell peppers, onions, and mushrooms), shredded cheese, and your choice of breakfast meat (bacon, sausage, or ham). Roll it up and enjoy it as a handheld breakfast.\\n\\n**5. Overnight Oats:**\\n - Combine rolled oats, milk, yogurt, and your choice of mix-ins (such as chia seeds, flaxseeds, nuts, dried fruit, or fresh fruit) in a jar or container. Stir well, cover, and refrigerate overnight. In the morning, you'll have a delicious, creamy, and nutritious breakfast ready to go.\\n\\n**6. Eggs Benedict:**\\n - Poach an egg and place it on top of a toasted English muffin halved. Add a slice of Canadian bacon or ham and top it with a generous drizzle of hollandaise sauce. This classic breakfast dish is indulgent and satisfying.\\n\\n**7. Yogurt Parfait:**\\n - Layer yogurt, granola, and fresh fruit in a glass or bowl to create a beautiful and tasty parfait. Drizzle with honey and top with a sprinkle of chopped nuts or seeds for some crunch.\\n\\n**8. Breakfast Sandwich:**\\n - Toast two slices of bread and fill them with scrambled or fried eggs, cheese, and your choice of breakfast meat. You can also add vegetables like spinach, tomatoes, or avocado slices.\\n\\n**9. Fruit and Nut Butter:**\\n - Spread your favorite nut butter (such as peanut butter, almond butter, or cashew butter) on a slice of toast or a bagel. Top it with sliced bananas, apples, or berries for a nutritious and filling breakfast.\\n\\n**10. Quiche:**\\n - Bake a quiche filled with eggs, milk or cream, cheese, and your choice of vegetables and/or meat. It's a delicious and elegant breakfast option that can be served warm or at room temperature.\\n\\nThese breakfast ideas offer a variety of flavors, textures, and nutritional profiles to suit different tastes and preferences. Feel free to experiment, get creative, and customize these dishes to your liking!\"}\n" - ] - } - ], "source": [ - "for ctx in context:\n", - " print(ctx)" + "In many LLM flows the conversation progresses in a series of prompt and response pairs. session managers offer a convienience function `store()` to add these simply." ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "USER: I am vegetarian. Can you remove the eggs?\n", - "\n", - "LLM: Absolutely! You can make delicious vegetarian pancakes by omitting the eggs. Here's the modified recipe:\n", - "\n", - "**Ingredients:**\n", - "\n", - "- 2 cups (250 grams) all-purpose flour\n", - "- 2 teaspoons baking powder\n", - "- 1 teaspoon salt\n", - "- 2 tablespoons sugar\n", - "- 2 cups milk (dairy or plant-based alternative)\n", - "- 3 tablespoons melted butter, plus more for the pan\n", - "- 1 teaspoon vanilla extract (optional)\n", - "\n", - "**Instructions:**\n", - "\n", - "1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until well blended.\n", - "\n", - "2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, melted butter, and vanilla extract (if using). Make sure the melted butter has cooled down a bit so it doesn't curdle the milk.\n", - "\n", - "3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking until you have a smooth batter. Again, don't overmix; a few small lumps are fine.\n", - "\n", - "4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat and add a small amount of butter to grease the surface.\n", - "\n", - "5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until you see small bubbles appear on the surface and the edges look dry, which should take around 2-3 minutes.\n", - "\n", - "6. Flip the pancakes: Use a spatula to gently flip the pancakes. Cook the other side for an additional 1-2 minutes until lightly browned.\n", - "\n", - "7. Repeat: Continue this process until you've cooked all your batter, adding more butter to the pan as needed.\n", - "\n", - "8. Serve: Stack the pancakes on a plate and serve with your favorite toppings. Maple syrup, butter, fresh fruit, whipped cream, or a sprinkle of powdered sugar are all great choices.\n", - "\n", - "**Tips for Eggless Pancakes:**\n", - "- The eggs in the original recipe act as a binding agent and provide structure to the pancakes. By omitting them, your pancakes may be a bit more delicate, but they will still taste delicious.\n", - "- You can add a little extra milk (1-2 tablespoons) if you feel the batter is too thick. This will help compensate for the absence of eggs.\n", - "- For extra leavening, you can increase the amount of baking powder by 1/2 teaspoon to ensure your pancakes still rise nicely.\n", - "\n", - "Enjoy your vegetarian pancakes! They are a tasty and versatile breakfast option that can be customized with various toppings and mix-ins.\n" + "{'role': 'user', 'content': 'And what is the capital of Spain?'}\n", + "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" ] } ], "source": [ - "prompt = \"I am vegetarian. Can you remove the eggs?\"\n", - "context = user_session.get_recent()\n", - "response = client.converse(prompt=prompt, context=context)\n", - "user_session.store(prompt, response)\n", - "print('USER: ', prompt)\n", - "print('\\nLLM: ', response)" + "prompt = \"what is the size of England compared to Portugal?\"\n", + "response = \"England is larger in land area than Portal by about 15000 square miles.\"\n", + "chat_session.store(prompt, response)\n", + "\n", + "context = chat_session.get_recent(top_k=6)\n", + "for message in context:\n", + " print(message)" ] }, { - "cell_type": "code", - "execution_count": 7, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'system', 'content': 'You are a helpful chef, assisting people in making delicious meals'}\n", - "{'role': 'user', 'content': 'can you give me some ideas for breakfast?'}\n", - "{'role': 'llm', 'content': \"Certainly! Here are some delicious breakfast ideas to start your day off right:\\n\\n**1. Avocado Toast:**\\n - Spread mashed avocado on a slice of toasted bread. Top it with a sprinkle of salt and pepper, a squeeze of lemon or lime juice, and a drizzle of extra virgin olive oil. You can also add sliced tomatoes, chopped onions, or a fried egg on top.\\n\\n**2. Smoothie Bowl:**\\n - Blend your favorite fruits (such as bananas, strawberries, blueberries, and mango) with a liquid base (like milk, yogurt, or juice) to create a thick and creamy smoothie. Pour it into a bowl and top it with granola, nuts, seeds, shredded coconut, or fresh fruit slices.\\n\\n**3. Pancakes or Waffles:**\\n - Whip up a batch of fluffy pancakes or waffles and serve them with a variety of toppings. Some options include fresh fruit, maple syrup, butter, whipped cream, chocolate chips, or a dusting of powdered sugar.\\n\\n**4. Breakfast Burrito:**\\n - Fill a flour tortilla with scrambled eggs, sautéed vegetables (such as bell peppers, onions, and mushrooms), shredded cheese, and your choice of breakfast meat (bacon, sausage, or ham). Roll it up and enjoy it as a handheld breakfast.\\n\\n**5. Overnight Oats:**\\n - Combine rolled oats, milk, yogurt, and your choice of mix-ins (such as chia seeds, flaxseeds, nuts, dried fruit, or fresh fruit) in a jar or container. Stir well, cover, and refrigerate overnight. In the morning, you'll have a delicious, creamy, and nutritious breakfast ready to go.\\n\\n**6. Eggs Benedict:**\\n - Poach an egg and place it on top of a toasted English muffin halved. Add a slice of Canadian bacon or ham and top it with a generous drizzle of hollandaise sauce. This classic breakfast dish is indulgent and satisfying.\\n\\n**7. Yogurt Parfait:**\\n - Layer yogurt, granola, and fresh fruit in a glass or bowl to create a beautiful and tasty parfait. Drizzle with honey and top with a sprinkle of chopped nuts or seeds for some crunch.\\n\\n**8. Breakfast Sandwich:**\\n - Toast two slices of bread and fill them with scrambled or fried eggs, cheese, and your choice of breakfast meat. You can also add vegetables like spinach, tomatoes, or avocado slices.\\n\\n**9. Fruit and Nut Butter:**\\n - Spread your favorite nut butter (such as peanut butter, almond butter, or cashew butter) on a slice of toast or a bagel. Top it with sliced bananas, apples, or berries for a nutritious and filling breakfast.\\n\\n**10. Quiche:**\\n - Bake a quiche filled with eggs, milk or cream, cheese, and your choice of vegetables and/or meat. It's a delicious and elegant breakfast option that can be served warm or at room temperature.\\n\\nThese breakfast ideas offer a variety of flavors, textures, and nutritional profiles to suit different tastes and preferences. Feel free to experiment, get creative, and customize these dishes to your liking!\"}\n", - "{'role': 'user', 'content': 'can you give me the recipe for those pancakes?'}\n", - "{'role': 'llm', 'content': \"Of course! Here is a classic recipe for fluffy and delicious pancakes:\\n\\n**Ingredients:**\\n\\n- 2 cups (250 grams) all-purpose flour\\n- 2 teaspoons baking powder\\n- 1 teaspoon salt\\n- 2 tablespoons sugar\\n- 2 cups milk\\n- 2 eggs\\n- 3 tablespoons melted butter, plus more for the pan\\n- 1 teaspoon vanilla extract (optional)\\n\\n**Instructions:**\\n\\n1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until well blended.\\n\\n2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, eggs, melted butter, and vanilla extract (if using). Make sure the melted butter has cooled down a bit so it doesn't cook the eggs.\\n\\n3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking until you have a smooth batter. Be careful not to overmix; a few small lumps are okay.\\n\\n4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat and add a small amount of butter to grease the surface. Let the butter melt and coat the cooking surface.\\n\\n5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until the edges look dry and small bubbles appear on the surface, about 2-3 minutes.\\n\\n6. Flip the pancakes: Use a spatula to carefully flip the pancakes. Cook the other side for another 1-2 minutes until lightly browned.\\n\\n7. Repeat: Repeat this process until you've cooked all your batter, adding more butter to the pan as needed.\\n\\n8. Serve: Stack the pancakes on a plate and serve them with your favorite toppings. Some popular options include butter, maple syrup, fresh fruit, whipped cream, or a dusting of powdered sugar.\\n\\n**Variations and Tips:**\\n- For extra fluffy pancakes, you can separate the eggs and gently fold in the whipped egg whites after combining the other ingredients.\\n- Feel free to add mix-ins to your batter, such as chocolate chips, blueberries, or chopped nuts.\\n- If you like thicker pancakes, you can add a little less milk to the batter. For thinner pancakes, add a bit more.\\n- To keep pancakes warm while you cook a large batch, preheat your oven to its lowest setting and place the cooked pancakes on a baking sheet or oven-safe plate.\\n\\nEnjoy your homemade pancakes! They are a classic breakfast treat and can be tailored to your taste preferences.\"}\n" - ] - } - ], "source": [ - "for ctx in context:\n", - " print(ctx)" + "## Managing multiple users and conversations" ] }, { - "cell_type": "code", - "execution_count": 8, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "USER: I am also vegan. Can you replace the butter too?\n", - "\n", - "LLM: Certainly! For a vegan version of fluffy pancakes, you can replace both the eggs and butter with plant-based alternatives. Here's the recipe tailored for vegan dietary preferences:\n", - "\n", - "**Ingredients:**\n", - "\n", - "- 2 cups (250 grams) all-purpose flour\n", - "- 2 teaspoons baking powder\n", - "- 1 teaspoon salt\n", - "- 2 tablespoons sugar\n", - "- 2 cups plant-based milk (such as soy, almond, or oat milk)\n", - "- 2 tablespoons neutral-flavored oil (such as canola or vegetable oil), plus more for the pan\n", - "- 1 teaspoon vanilla extract (optional)\n", - "\n", - "**Instructions:**\n", - "\n", - "1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Mix well to ensure there are no lumps.\n", - "\n", - "2. Combine the wet ingredients: In a separate mixing bowl, whisk together the plant-based milk, oil, and vanilla extract (if using).\n", - "\n", - "3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients, whisking continuously until you have a smooth batter. It's okay if there are a few small lumps.\n", - "\n", - "4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat. Add a small amount of oil to grease the surface, ensuring it coats the cooking area evenly.\n", - "\n", - "5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until you notice small bubbles appearing on the surface and the edges look dry, which should take about 2-3 minutes.\n", - "\n", - "6. Flip the pancakes: Use a spatula to carefully flip the pancakes. Cook the other side for an additional 1-2 minutes until lightly browned.\n", - "\n", - "7. Repeat: Repeat this process until you've cooked all your batter, adding more oil to the pan as needed to prevent sticking.\n", - "\n", - "8. Serve: Stack the pancakes on a plate and serve them with your favorite vegan toppings. Some options include maple syrup, vegan butter, fresh fruit, or a dustable amount of powdered sugar.\n", - "\n", - "**Tips for Vegan Pancakes:**\n", - "- The oil replaces the butter in this recipe, providing moisture and helping to create a crispy edge on the pancakes.\n", - "- Feel free to experiment with different plant-based milk alternatives to find your preferred taste and texture. Soy milk tends to be creamier, while almond or oat milk can lend a subtle nutty flavor.\n", - "- If you like your pancakes with a hint of sweetness, you can add a bit more sugar to the batter or top them with sweet vegan toppings like agave nectar or fruit compote.\n", - "\n", - "Enjoy your vegan pancakes! They are a delicious and inclusive breakfast option that can be tailored to suit your dietary needs and preferences.\n" - ] - } - ], "source": [ - "prompt = \"I am also vegan. Can you replace the butter too?\"\n", - "context = user_session.get_recent()\n", - "response = client.converse(prompt=prompt, context=context)\n", - "user_session.store(prompt, response)\n", - "print('USER: ', prompt)\n", - "print('\\nLLM: ', response)" + "For applications that need to handle multiple conversations concurrently, Redis supports tagging messages to keep conversations separated." ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'role': 'llm', 'content': \"Certainly! Here are some delicious breakfast ideas to start your day off right:\\n\\n**1. Avocado Toast:**\\n - Spread mashed avocado on a slice of toasted bread. Top it with a sprinkle of salt and pepper, a squeeze of lemon or lime juice, and a drizzle of extra virgin olive oil. You can also add sliced tomatoes, chopped onions, or a fried egg on top.\\n\\n**2. Smoothie Bowl:**\\n - Blend your favorite fruits (such as bananas, strawberries, blueberries, and mango) with a liquid base (like milk, yogurt, or juice) to create a thick and creamy smoothie. Pour it into a bowl and top it with granola, nuts, seeds, shredded coconut, or fresh fruit slices.\\n\\n**3. Pancakes or Waffles:**\\n - Whip up a batch of fluffy pancakes or waffles and serve them with a variety of toppings. Some options include fresh fruit, maple syrup, butter, whipped cream, chocolate chips, or a dusting of powdered sugar.\\n\\n**4. Breakfast Burrito:**\\n - Fill a flour tortilla with scrambled eggs, sautéed vegetables (such as bell peppers, onions, and mushrooms), shredded cheese, and your choice of breakfast meat (bacon, sausage, or ham). Roll it up and enjoy it as a handheld breakfast.\\n\\n**5. Overnight Oats:**\\n - Combine rolled oats, milk, yogurt, and your choice of mix-ins (such as chia seeds, flaxseeds, nuts, dried fruit, or fresh fruit) in a jar or container. Stir well, cover, and refrigerate overnight. In the morning, you'll have a delicious, creamy, and nutritious breakfast ready to go.\\n\\n**6. Eggs Benedict:**\\n - Poach an egg and place it on top of a toasted English muffin halved. Add a slice of Canadian bacon or ham and top it with a generous drizzle of hollandaise sauce. This classic breakfast dish is indulgent and satisfying.\\n\\n**7. Yogurt Parfait:**\\n - Layer yogurt, granola, and fresh fruit in a glass or bowl to create a beautiful and tasty parfait. Drizzle with honey and top with a sprinkle of chopped nuts or seeds for some crunch.\\n\\n**8. Breakfast Sandwich:**\\n - Toast two slices of bread and fill them with scrambled or fried eggs, cheese, and your choice of breakfast meat. You can also add vegetables like spinach, tomatoes, or avocado slices.\\n\\n**9. Fruit and Nut Butter:**\\n - Spread your favorite nut butter (such as peanut butter, almond butter, or cashew butter) on a slice of toast or a bagel. Top it with sliced bananas, apples, or berries for a nutritious and filling breakfast.\\n\\n**10. Quiche:**\\n - Bake a quiche filled with eggs, milk or cream, cheese, and your choice of vegetables and/or meat. It's a delicious and elegant breakfast option that can be served warm or at room temperature.\\n\\nThese breakfast ideas offer a variety of flavors, textures, and nutritional profiles to suit different tastes and preferences. Feel free to experiment, get creative, and customize these dishes to your liking!\"}\n", - "{'role': 'user', 'content': 'can you give me the recipe for those pancakes?'}\n", - "{'role': 'llm', 'content': \"Of course! Here is a classic recipe for fluffy and delicious pancakes:\\n\\n**Ingredients:**\\n\\n- 2 cups (250 grams) all-purpose flour\\n- 2 teaspoons baking powder\\n- 1 teaspoon salt\\n- 2 tablespoons sugar\\n- 2 cups milk\\n- 2 eggs\\n- 3 tablespoons melted butter, plus more for the pan\\n- 1 teaspoon vanilla extract (optional)\\n\\n**Instructions:**\\n\\n1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until well blended.\\n\\n2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, eggs, melted butter, and vanilla extract (if using). Make sure the melted butter has cooled down a bit so it doesn't cook the eggs.\\n\\n3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking until you have a smooth batter. Be careful not to overmix; a few small lumps are okay.\\n\\n4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat and add a small amount of butter to grease the surface. Let the butter melt and coat the cooking surface.\\n\\n5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until the edges look dry and small bubbles appear on the surface, about 2-3 minutes.\\n\\n6. Flip the pancakes: Use a spatula to carefully flip the pancakes. Cook the other side for another 1-2 minutes until lightly browned.\\n\\n7. Repeat: Repeat this process until you've cooked all your batter, adding more butter to the pan as needed.\\n\\n8. Serve: Stack the pancakes on a plate and serve them with your favorite toppings. Some popular options include butter, maple syrup, fresh fruit, whipped cream, or a dusting of powdered sugar.\\n\\n**Variations and Tips:**\\n- For extra fluffy pancakes, you can separate the eggs and gently fold in the whipped egg whites after combining the other ingredients.\\n- Feel free to add mix-ins to your batter, such as chocolate chips, blueberries, or chopped nuts.\\n- If you like thicker pancakes, you can add a little less milk to the batter. For thinner pancakes, add a bit more.\\n- To keep pancakes warm while you cook a large batch, preheat your oven to its lowest setting and place the cooked pancakes on a baking sheet or oven-safe plate.\\n\\nEnjoy your homemade pancakes! They are a classic breakfast treat and can be tailored to your taste preferences.\"}\n", - "{'role': 'user', 'content': 'I am vegetarian. Can you remove the eggs?'}\n", - "{'role': 'llm', 'content': \"Absolutely! You can make delicious vegetarian pancakes by omitting the eggs. Here's the modified recipe:\\n\\n**Ingredients:**\\n\\n- 2 cups (250 grams) all-purpose flour\\n- 2 teaspoons baking powder\\n- 1 teaspoon salt\\n- 2 tablespoons sugar\\n- 2 cups milk (dairy or plant-based alternative)\\n- 3 tablespoons melted butter, plus more for the pan\\n- 1 teaspoon vanilla extract (optional)\\n\\n**Instructions:**\\n\\n1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until well blended.\\n\\n2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, melted butter, and vanilla extract (if using). Make sure the melted butter has cooled down a bit so it doesn't curdle the milk.\\n\\n3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking until you have a smooth batter. Again, don't overmix; a few small lumps are fine.\\n\\n4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat and add a small amount of butter to grease the surface.\\n\\n5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until you see small bubbles appear on the surface and the edges look dry, which should take around 2-3 minutes.\\n\\n6. Flip the pancakes: Use a spatula to gently flip the pancakes. Cook the other side for an additional 1-2 minutes until lightly browned.\\n\\n7. Repeat: Continue this process until you've cooked all your batter, adding more butter to the pan as needed.\\n\\n8. Serve: Stack the pancakes on a plate and serve with your favorite toppings. Maple syrup, butter, fresh fruit, whipped cream, or a sprinkle of powdered sugar are all great choices.\\n\\n**Tips for Eggless Pancakes:**\\n- The eggs in the original recipe act as a binding agent and provide structure to the pancakes. By omitting them, your pancakes may be a bit more delicate, but they will still taste delicious.\\n- You can add a little extra milk (1-2 tablespoons) if you feel the batter is too thick. This will help compensate for the absence of eggs.\\n- For extra leavening, you can increase the amount of baking powder by 1/2 teaspoon to ensure your pancakes still rise nicely.\\n\\nEnjoy your vegetarian pancakes! They are a tasty and versatile breakfast option that can be customized with various toppings and mix-ins.\"}\n" + "{'role': 'system', 'content': 'You are a helpful algebra tutor, giving simple answers to math problems.'}\n", + "{'role': 'user', 'content': 'What is the value of x in the equation 2x + 3 = 7?'}\n", + "{'role': 'llm', 'content': 'The value of x is 2.'}\n", + "{'role': 'user', 'content': 'What is the value of y in the equation 3y - 5 = 7?'}\n", + "{'role': 'llm', 'content': 'The value of y is 4.'}\n" ] } ], "source": [ - "for ctx in context:\n", - " print(ctx)" + "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful algebra tutor, giving simple answers to math problems.\"}, session_tag='student two')\n", + "chat_session.add_messages([\n", + " {\"role\":\"user\", \"content\":\"What is the value of x in the equation 2x + 3 = 7?\"},\n", + " {\"role\":\"llm\", \"content\":\"The value of x is 2.\"},\n", + " {\"role\":\"user\", \"content\":\"What is the value of y in the equation 3y - 5 = 7?\"},\n", + " {\"role\":\"llm\", \"content\":\"The value of y is 4.\"}\n", + " ], session_tag='student two')\n", + "\n", + "for math_message in chat_session.get_recent(session_tag='student two'):\n", + " print(math_message)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This works, but our context keeps growing, increasing our LLM token count, which increases latency and cost.\n", - "Conversation histories can be truncated, but that can break quickly." + "## Semantic conversation memory\n", + "For longer conversations our list of messages keeps growing. Since LLMs are stateless we have to continue to pass this conversation history on each subsequent call to ensure the LLM has the correct context.\n", + "\n", + "A typical flow looks like this:\n", + "```\n", + "while True:\n", + " prompt = input('enter your next question')\n", + " context = chat_session.get_recent()\n", + " response = LLM_api_call(prompt=prompt, context=context)\n", + " chat_session.store(prompt, response)\n", + "```\n", + "\n", + "This works, but as context keeps growing so too does our LLM token count, which increases latency and cost.\n", + "\n", + "Conversation histories can be truncated, but that can lead to losing relevant information that appeared early on.\n", + "\n", + "A better solution is to pass only the relevant conversational context on each subsequent call.\n", + "\n", + "For this, RedisVL has the `SemanticSessionManager`, which uses vector similarity search to return only semantically relevant sections of the conversation." ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "USER: I changed my mind. Can you give me the first recipe from your list?\n", - "\n", - "LLM: Sure! Here's the recipe for classic fluffy pancakes with eggs and butter:\n", - "\n", - "**Ingredients:**\n", - "\n", - "- 2 cups (250 grams) all-purpose flour\n", - "- 2 teaspoons baking powder\n", - "- 1 teaspoon salt\n", - "- 2 tablespoons sugar\n", - "- 2 cups milk\n", - "- 2 eggs\n", - "- 3 tablespoons melted butter, plus more for the pan\n", - "- 1 teaspoon vanilla extract (optional)\n", - "\n", - "**Instructions:**\n", - "\n", - "1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until the ingredients are well incorporated and there are no lumps.\n", - "\n", - "2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, eggs, melted butter, and vanilla extract (if using). Ensure the melted butter has cooled down slightly so it doesn't cook the eggs.\n", - "\n", - "3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking. Mix until you have a smooth batter, but be careful not to overmix. A few small lumps are okay.\n", - "\n", - "4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat. Add a small amount of butter to grease the surface, spreading it evenly across the cooking area.\n", - "\n", - "5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until you see the edges looking dry and small bubbles appearing on the surface, which should take around 2-3 minutes.\n", - "\n", - "6. Flip the pancakes: Use a spatula to gently flip the pancakes over. Cook the other side for an additional 1-2 minutes until lightly browned.\n", - "\n", - "7. Repeat: Continue this process until you've cooked all your batter, adding more butter to the pan as needed between batches.\n", - "\n", - "8. Serve: Stack the pancakes on a plate and serve them with your choice of toppings. Classic options include butter, maple syrup, fresh fruit, or a dusting of powdered sugar.\n", - "\n", - "**Tips for Classic Fluffy Pancakes:**\n", - "- For extra fluffy pancakes, you can separate the eggs and gently fold in the whipped egg whites after combining the other ingredients. This will give them an even lighter texture.\n", - "- If you prefer thicker pancakes, you can add a little less milk to the batter. For thinner, crepe-like pancakes, add a bit more milk.\n", - "- Feel free to experiment with mix-ins like chocolate chips, blueberries, or chopped nuts. Simply sprinkle them onto the pancakes as soon as you pour the batter onto the griddle or pan.\n", - "\n", - "Enjoy your classic fluffy pancakes! They are a breakfast staple and can be tailored to your taste preferences with various toppings and add-ins.\n" + "10:10:47 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], "source": [ - "prompt = \"I changed my mind. Can you give me the first recipe from your list?\"\n", - "context = user_session.get_recent(top_k=5)\n", - "response = client.converse(prompt=prompt, context=context)\n", - "user_session.store(prompt, response)\n", - "print('USER: ', prompt)\n", - "print('\\nLLM: ', response)" + "from redisvl.extensions.session_manager import SemanticSessionManager\n", + "semantic_session = SemanticSessionManager(name='student tutor')\n", + "\n", + "semantic_session.add_messages(chat_session.get_recent(top_k=8))" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'role': 'llm', 'content': \"Of course! Here is a classic recipe for fluffy and delicious pancakes:\\n\\n**Ingredients:**\\n\\n- 2 cups (250 grams) all-purpose flour\\n- 2 teaspoons baking powder\\n- 1 teaspoon salt\\n- 2 tablespoons sugar\\n- 2 cups milk\\n- 2 eggs\\n- 3 tablespoons melted butter, plus more for the pan\\n- 1 teaspoon vanilla extract (optional)\\n\\n**Instructions:**\\n\\n1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until well blended.\\n\\n2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, eggs, melted butter, and vanilla extract (if using). Make sure the melted butter has cooled down a bit so it doesn't cook the eggs.\\n\\n3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking until you have a smooth batter. Be careful not to overmix; a few small lumps are okay.\\n\\n4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat and add a small amount of butter to grease the surface. Let the butter melt and coat the cooking surface.\\n\\n5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until the edges look dry and small bubbles appear on the surface, about 2-3 minutes.\\n\\n6. Flip the pancakes: Use a spatula to carefully flip the pancakes. Cook the other side for another 1-2 minutes until lightly browned.\\n\\n7. Repeat: Repeat this process until you've cooked all your batter, adding more butter to the pan as needed.\\n\\n8. Serve: Stack the pancakes on a plate and serve them with your favorite toppings. Some popular options include butter, maple syrup, fresh fruit, whipped cream, or a dusting of powdered sugar.\\n\\n**Variations and Tips:**\\n- For extra fluffy pancakes, you can separate the eggs and gently fold in the whipped egg whites after combining the other ingredients.\\n- Feel free to add mix-ins to your batter, such as chocolate chips, blueberries, or chopped nuts.\\n- If you like thicker pancakes, you can add a little less milk to the batter. For thinner pancakes, add a bit more.\\n- To keep pancakes warm while you cook a large batch, preheat your oven to its lowest setting and place the cooked pancakes on a baking sheet or oven-safe plate.\\n\\nEnjoy your homemade pancakes! They are a classic breakfast treat and can be tailored to your taste preferences.\"}\n", - "{'role': 'user', 'content': 'I am vegetarian. Can you remove the eggs?'}\n", - "{'role': 'llm', 'content': \"Absolutely! You can make delicious vegetarian pancakes by omitting the eggs. Here's the modified recipe:\\n\\n**Ingredients:**\\n\\n- 2 cups (250 grams) all-purpose flour\\n- 2 teaspoons baking powder\\n- 1 teaspoon salt\\n- 2 tablespoons sugar\\n- 2 cups milk (dairy or plant-based alternative)\\n- 3 tablespoons melted butter, plus more for the pan\\n- 1 teaspoon vanilla extract (optional)\\n\\n**Instructions:**\\n\\n1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Whisk until well blended.\\n\\n2. Combine the wet ingredients: In a separate mixing bowl, whisk together the milk, melted butter, and vanilla extract (if using). Make sure the melted butter has cooled down a bit so it doesn't curdle the milk.\\n\\n3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients while continuously whisking until you have a smooth batter. Again, don't overmix; a few small lumps are fine.\\n\\n4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat and add a small amount of butter to grease the surface.\\n\\n5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until you see small bubbles appear on the surface and the edges look dry, which should take around 2-3 minutes.\\n\\n6. Flip the pancakes: Use a spatula to gently flip the pancakes. Cook the other side for an additional 1-2 minutes until lightly browned.\\n\\n7. Repeat: Continue this process until you've cooked all your batter, adding more butter to the pan as needed.\\n\\n8. Serve: Stack the pancakes on a plate and serve with your favorite toppings. Maple syrup, butter, fresh fruit, whipped cream, or a sprinkle of powdered sugar are all great choices.\\n\\n**Tips for Eggless Pancakes:**\\n- The eggs in the original recipe act as a binding agent and provide structure to the pancakes. By omitting them, your pancakes may be a bit more delicate, but they will still taste delicious.\\n- You can add a little extra milk (1-2 tablespoons) if you feel the batter is too thick. This will help compensate for the absence of eggs.\\n- For extra leavening, you can increase the amount of baking powder by 1/2 teaspoon to ensure your pancakes still rise nicely.\\n\\nEnjoy your vegetarian pancakes! They are a tasty and versatile breakfast option that can be customized with various toppings and mix-ins.\"}\n", - "{'role': 'user', 'content': 'I am also vegan. Can you replace the butter too?'}\n", - "{'role': 'llm', 'content': \"Certainly! For a vegan version of fluffy pancakes, you can replace both the eggs and butter with plant-based alternatives. Here's the recipe tailored for vegan dietary preferences:\\n\\n**Ingredients:**\\n\\n- 2 cups (250 grams) all-purpose flour\\n- 2 teaspoons baking powder\\n- 1 teaspoon salt\\n- 2 tablespoons sugar\\n- 2 cups plant-based milk (such as soy, almond, or oat milk)\\n- 2 tablespoons neutral-flavored oil (such as canola or vegetable oil), plus more for the pan\\n- 1 teaspoon vanilla extract (optional)\\n\\n**Instructions:**\\n\\n1. Whisk together the dry ingredients: In a large mixing bowl, combine the flour, baking powder, salt, and sugar. Mix well to ensure there are no lumps.\\n\\n2. Combine the wet ingredients: In a separate mixing bowl, whisk together the plant-based milk, oil, and vanilla extract (if using).\\n\\n3. Mix dry and wet ingredients: Slowly pour the wet ingredients into the dry ingredients, whisking continuously until you have a smooth batter. It's okay if there are a few small lumps.\\n\\n4. Heat your griddle or pan: Place a nonstick pan or griddle over medium heat. Add a small amount of oil to grease the surface, ensuring it coats the cooking area evenly.\\n\\n5. Pour the batter: Once the pan is hot, pour about 1/4 cup of batter for each pancake onto the griddle or pan. Cook until you notice small bubbles appearing on the surface and the edges look dry, which should take about 2-3 minutes.\\n\\n6. Flip the pancakes: Use a spatula to carefully flip the pancakes. Cook the other side for an additional 1-2 minutes until lightly browned.\\n\\n7. Repeat: Repeat this process until you've cooked all your batter, adding more oil to the pan as needed to prevent sticking.\\n\\n8. Serve: Stack the pancakes on a plate and serve them with your favorite vegan toppings. Some options include maple syrup, vegan butter, fresh fruit, or a dustable amount of powdered sugar.\\n\\n**Tips for Vegan Pancakes:**\\n- The oil replaces the butter in this recipe, providing moisture and helping to create a crispy edge on the pancakes.\\n- Feel free to experiment with different plant-based milk alternatives to find your preferred taste and texture. Soy milk tends to be creamier, while almond or oat milk can lend a subtle nutty flavor.\\n- If you like your pancakes with a hint of sweetness, you can add a bit more sugar to the batter or top them with sweet vegan toppings like agave nectar or fruit compote.\\n\\nEnjoy your vegan pancakes! They are a delicious and inclusive breakfast option that can be tailored to suit your dietary needs and preferences.\"}\n" + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" ] } ], "source": [ - "for ctx in context:\n", - " print(ctx)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The LLM has forgotten about the avocado toast it mentioned because that was too far back in it's conversation history!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Semantic session memory" + "prompt = \"what have I learned about the size of England?\"\n", + "semantic_session.set_distance_threshold(0.35)\n", + "context = semantic_session.get_relevant(prompt)\n", + "for message in context:\n", + " print(message)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Rather than naively pass the most recent conversation we can use RedisVL to find only the semantically relevant sections of our conversation based on our new prompt. We can do this with the `fetch_relevant()` method." + "You can adjust the degree of semantic similarity needed to be included in your context.\n", + "\n", + "Setting a distance threshold close to 0.0 will require an exact semantic match, while a distance threshold of 1.0 will include everthing." ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "USER: Can you give me the avocado one?\n", - "\n", - "LLM: Sure! Here's the first breakfast idea, Avocado Toast, with a simple recipe and some optional toppings:\n", - "\n", - "**Avocado Toast**\n", - "\n", - "**Ingredients:**\n", - "- 1 ripe avocado\n", - "- 2 slices of bread (preferably a hearty variety like sourdough, rye, or multigrain)\n", - "- Extra virgin olive oil\n", - "- Lemon or lime juice\n", - "- Salt and pepper, to taste\n", - "- Optional toppings: sliced tomatoes, chopped onions, chili flakes, or a fried egg\n", - "\n", - "**Instructions:**\n", - "\n", - "1. Toast the bread to your desired level of doneness.\n", - "2. While the bread is toasting, prepare the avocado. Cut the avocado in half, remove the pit, and scoop out the flesh into a small bowl.\n", - "3. Using a fork, mash the avocado until it reaches your desired consistency. You can leave it chunkier or make it smoother, depending on your preference.\n", - "4. Add a drizzle of extra virgin olive oil and a squeeze of lemon or lime juice to the mashed avocado. This will enhance the flavor and prevent the avocado from turning brown too quickly. Stir to combine.\n", - "5. Spread the mashed avocado mixture onto the toasted bread slices. Be generous!\n", - "6. Sprinkle salt and pepper on top to taste.\n", - "7. If desired, add your choice of optional toppings. Sliced tomatoes and a sprinkle of chopped onions go well with avocado toast. You could also add some chili flakes for a spicy kick.\n", - "8. For an even heartier breakfast, top the avocado toast with a fried egg. Simply fry an egg in a pan until the whites are set and the yolk is still runny (or cook it to your preferred doneness). Place the fried egg on top of the avocado toast.\n", - "9. Enjoy your delicious and nutritious avocado toast! It's a quick, easy, and healthy breakfast option.\n", - "\n", - "Feel free to experiment with different types of bread and toppings to create your own unique version of avocado toast. It's a simple dish that can be easily customized to your taste preferences. Enjoy!\n" + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n" ] } ], "source": [ - "prompt = \"Can you give me the avocado one?\"\n", - "user_session.set_distance_threshold(0.75)\n", - "context = user_session.get_relevant(prompt=prompt)\n", - "response = client.converse(prompt=prompt, context=context)\n", - "user_session.store(prompt, response)\n", - "print('USER: ', prompt)\n", - "print('\\nLLM: ', response)" + "semantic_session.set_distance_threshold(0.7)\n", + "\n", + "larger_context = semantic_session.get_relevant(prompt)\n", + "for message in larger_context:\n", + " print(message)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conversation control\n", + "\n", + "LLMs can hallucinate on occasion and when this happens it can be useful to prune incorrect information from conversational histories so this incorrect information doesn't continue to be passed as context." ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'role': 'user', 'content': 'can you give me some ideas for breakfast?'}\n", - "{'role': 'llm', 'content': \"Certainly! Here are some delicious breakfast ideas to start your day off right:\\n\\n**1. Avocado Toast:**\\n - Spread mashed avocado on a slice of toasted bread. Top it with a sprinkle of salt and pepper, a squeeze of lemon or lime juice, and a drizzle of extra virgin olive oil. You can also add sliced tomatoes, chopped onions, or a fried egg on top.\\n\\n**2. Smoothie Bowl:**\\n - Blend your favorite fruits (such as bananas, strawberries, blueberries, and mango) with a liquid base (like milk, yogurt, or juice) to create a thick and creamy smoothie. Pour it into a bowl and top it with granola, nuts, seeds, shredded coconut, or fresh fruit slices.\\n\\n**3. Pancakes or Waffles:**\\n - Whip up a batch of fluffy pancakes or waffles and serve them with a variety of toppings. Some options include fresh fruit, maple syrup, butter, whipped cream, chocolate chips, or a dusting of powdered sugar.\\n\\n**4. Breakfast Burrito:**\\n - Fill a flour tortilla with scrambled eggs, sautéed vegetables (such as bell peppers, onions, and mushrooms), shredded cheese, and your choice of breakfast meat (bacon, sausage, or ham). Roll it up and enjoy it as a handheld breakfast.\\n\\n**5. Overnight Oats:**\\n - Combine rolled oats, milk, yogurt, and your choice of mix-ins (such as chia seeds, flaxseeds, nuts, dried fruit, or fresh fruit) in a jar or container. Stir well, cover, and refrigerate overnight. In the morning, you'll have a delicious, creamy, and nutritious breakfast ready to go.\\n\\n**6. Eggs Benedict:**\\n - Poach an egg and place it on top of a toasted English muffin halved. Add a slice of Canadian bacon or ham and top it with a generous drizzle of hollandaise sauce. This classic breakfast dish is indulgent and satisfying.\\n\\n**7. Yogurt Parfait:**\\n - Layer yogurt, granola, and fresh fruit in a glass or bowl to create a beautiful and tasty parfait. Drizzle with honey and top with a sprinkle of chopped nuts or seeds for some crunch.\\n\\n**8. Breakfast Sandwich:**\\n - Toast two slices of bread and fill them with scrambled or fried eggs, cheese, and your choice of breakfast meat. You can also add vegetables like spinach, tomatoes, or avocado slices.\\n\\n**9. Fruit and Nut Butter:**\\n - Spread your favorite nut butter (such as peanut butter, almond butter, or cashew butter) on a slice of toast or a bagel. Top it with sliced bananas, apples, or berries for a nutritious and filling breakfast.\\n\\n**10. Quiche:**\\n - Bake a quiche filled with eggs, milk or cream, cheese, and your choice of vegetables and/or meat. It's a delicious and elegant breakfast option that can be served warm or at room temperature.\\n\\nThese breakfast ideas offer a variety of flavors, textures, and nutritional profiles to suit different tastes and preferences. Feel free to experiment, get creative, and customize these dishes to your liking!\"}\n" + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n", + "{'role': 'user', 'content': 'what is the smallest country in Europe?'}\n" ] } ], "source": [ - "for ctx in context:\n", - " print(ctx)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looking at the context we see that only the conversation section that had to do with avocados was retrieved. We don't need to know about pancakes to make avocado toast." + "semantic_session.store(prompt=\"what is the smallest country in Europe?\",\n", + " response=\"Monaco is the smallest country in Europe at 0.78 square miles.\" # Incorrect. Vatican City is the smallest country in Europe\n", + " )\n", + "\n", + "# get the key of the incorrect message\n", + "context = semantic_session.get_recent(top_k=1, raw=True)\n", + "bad_key = context[0]['entry_id']\n", + "semantic_session.drop(bad_key)\n", + "\n", + "corrected_context = semantic_session.get_recent()\n", + "for message in corrected_context:\n", + " print(message)" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "user_session.clear()" + "chat_session.clear()" ] } ], From 4162fca0cf155ba3dd50786711a4057ce575631d Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 11:13:42 -0700 Subject: [PATCH 2/8] testing GHA vector search --- docs/user_guide/session_manager_07.ipynb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/user_guide/session_manager_07.ipynb b/docs/user_guide/session_manager_07.ipynb index 2c855dd7..b2915589 100644 --- a/docs/user_guide/session_manager_07.ipynb +++ b/docs/user_guide/session_manager_07.ipynb @@ -235,7 +235,8 @@ "source": [ "prompt = \"what have I learned about the size of England?\"\n", "semantic_session.set_distance_threshold(0.35)\n", - "context = semantic_session.get_relevant(prompt)\n", + "##context = semantic_session.get_relevant(prompt)\n", + "context = semantic_session.get_recent() ## testing GHA\n", "for message in context:\n", " print(message)" ] @@ -268,7 +269,8 @@ "source": [ "semantic_session.set_distance_threshold(0.7)\n", "\n", - "larger_context = semantic_session.get_relevant(prompt)\n", + "##larger_context = semantic_session.get_relevant(prompt)\n", + "larger_context = semantic_session.get_recent() ##\n", "for message in larger_context:\n", " print(message)" ] From 8ea61c6befca9bcf643256d975000c74686ca4df Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 11:27:32 -0700 Subject: [PATCH 3/8] more testing GHA vector search --- docs/user_guide/session_manager_07.ipynb | 157 +++++++++-------------- 1 file changed, 63 insertions(+), 94 deletions(-) diff --git a/docs/user_guide/session_manager_07.ipynb b/docs/user_guide/session_manager_07.ipynb index b2915589..73f27713 100644 --- a/docs/user_guide/session_manager_07.ipynb +++ b/docs/user_guide/session_manager_07.ipynb @@ -27,7 +27,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "10:10:43 redisvl.index.index INFO Index already exists, not overwriting.\n" + "11:19:30 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], @@ -50,7 +50,53 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11:19:30 redisvl.index.index ERROR Error while loading data to Redis\n", + "Traceback (most recent call last):\n", + " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/storage.py\", line 70, in _create_key\n", + " key_value = obj[id_field] # type: ignore\n", + " ~~~^^^^^^^^^^\n", + "KeyError: '_id'\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/index.py\", line 587, in load\n", + " return self._storage.write(\n", + " ^^^^^^^^^^^^^^^^^^^^\n", + " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/storage.py\", line 220, in write\n", + " else self._create_key(obj, id_field)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/storage.py\", line 72, in _create_key\n", + " raise ValueError(f\"Key field {id_field} not found in record {obj}\")\n", + "ValueError: Key field _id not found in record {'entry_id': None, 'role': 'system', 'content': 'You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.', 'session_tag': 'c9cc1d8d-c7cb-4e33-887e-87f04594d44a', 'timestamp': 1722536370.422074}\n" + ] + }, + { + "ename": "ValueError", + "evalue": "Key field _id not found in record {'entry_id': None, 'role': 'system', 'content': 'You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.', 'session_tag': 'c9cc1d8d-c7cb-4e33-887e-87f04594d44a', 'timestamp': 1722536370.422074}", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/Documents/redisvl/redisvl/index/storage.py:70\u001b[0m, in \u001b[0;36mBaseStorage._create_key\u001b[0;34m(self, obj, id_field)\u001b[0m\n\u001b[1;32m 69\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 70\u001b[0m key_value \u001b[38;5;241m=\u001b[39m \u001b[43mobj\u001b[49m\u001b[43m[\u001b[49m\u001b[43mid_field\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 71\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n", + "\u001b[0;31mKeyError\u001b[0m: '_id'", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mchat_session\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_message\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mrole\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43msystem\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcontent\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mYou are a helpful geography tutor, giving simple and short answers to questions about Europen countries.\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2\u001b[0m chat_session\u001b[38;5;241m.\u001b[39madd_messages([\n\u001b[1;32m 3\u001b[0m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mWhat is the capital of France?\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[1;32m 4\u001b[0m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mllm\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe capital is Paris.\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 9\u001b[0m ]\n\u001b[1;32m 10\u001b[0m )\n", + "File \u001b[0;32m~/Documents/redisvl/redisvl/extensions/session_manager/standard_session.py:237\u001b[0m, in \u001b[0;36mStandardSessionManager.add_message\u001b[0;34m(self, message, session_tag)\u001b[0m\n\u001b[1;32m 225\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21madd_message\u001b[39m(\n\u001b[1;32m 226\u001b[0m \u001b[38;5;28mself\u001b[39m, message: Dict[\u001b[38;5;28mstr\u001b[39m, \u001b[38;5;28mstr\u001b[39m], session_tag: Optional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 227\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 228\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Insert a single prompt or response into the session memory.\u001b[39;00m\n\u001b[1;32m 229\u001b[0m \u001b[38;5;124;03m A timestamp is associated with it so that it can be later sorted\u001b[39;00m\n\u001b[1;32m 230\u001b[0m \u001b[38;5;124;03m in sequential ordering after retrieval.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 235\u001b[0m \u001b[38;5;124;03m session. Defaults to instance uuid.\u001b[39;00m\n\u001b[1;32m 236\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 237\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_messages\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mmessage\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msession_tag\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Documents/redisvl/redisvl/extensions/session_manager/standard_session.py:223\u001b[0m, in \u001b[0;36mStandardSessionManager.add_messages\u001b[0;34m(self, messages, session_tag)\u001b[0m\n\u001b[1;32m 219\u001b[0m chat_message\u001b[38;5;241m.\u001b[39mtool_call_id \u001b[38;5;241m=\u001b[39m message[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtool_field_name]\n\u001b[1;32m 221\u001b[0m chat_messages\u001b[38;5;241m.\u001b[39mappend(chat_message\u001b[38;5;241m.\u001b[39mto_dict())\n\u001b[0;32m--> 223\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_index\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchat_messages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mid_field\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mid_field_name\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Documents/redisvl/redisvl/index/index.py:587\u001b[0m, in \u001b[0;36mSearchIndex.load\u001b[0;34m(self, data, id_field, keys, ttl, preprocess, batch_size)\u001b[0m\n\u001b[1;32m 538\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Load objects to the Redis database. Returns the list of keys loaded\u001b[39;00m\n\u001b[1;32m 539\u001b[0m \u001b[38;5;124;03mto Redis.\u001b[39;00m\n\u001b[1;32m 540\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 584\u001b[0m \u001b[38;5;124;03m keys = index.load(data, preprocess=add_field)\u001b[39;00m\n\u001b[1;32m 585\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 586\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 587\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_storage\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwrite\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 588\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_redis_client\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore\u001b[39;49;00m\n\u001b[1;32m 589\u001b[0m \u001b[43m \u001b[49m\u001b[43mobjects\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 590\u001b[0m \u001b[43m \u001b[49m\u001b[43mid_field\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mid_field\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 591\u001b[0m \u001b[43m \u001b[49m\u001b[43mkeys\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mkeys\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 592\u001b[0m \u001b[43m \u001b[49m\u001b[43mttl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mttl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 593\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreprocess\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpreprocess\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 594\u001b[0m \u001b[43m \u001b[49m\u001b[43mbatch_size\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbatch_size\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 595\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 596\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[1;32m 597\u001b[0m logger\u001b[38;5;241m.\u001b[39mexception(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mError while loading data to Redis\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "File \u001b[0;32m~/Documents/redisvl/redisvl/index/storage.py:220\u001b[0m, in \u001b[0;36mBaseStorage.write\u001b[0;34m(self, redis_client, objects, id_field, keys, ttl, preprocess, batch_size)\u001b[0m\n\u001b[1;32m 214\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m redis_client\u001b[38;5;241m.\u001b[39mpipeline(transaction\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m pipe:\n\u001b[1;32m 215\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, obj \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(objects, start\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m):\n\u001b[1;32m 216\u001b[0m \u001b[38;5;66;03m# Construct key, validate, and write\u001b[39;00m\n\u001b[1;32m 217\u001b[0m key \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 218\u001b[0m \u001b[38;5;28mnext\u001b[39m(keys_iterator)\n\u001b[1;32m 219\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m keys_iterator\n\u001b[0;32m--> 220\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_create_key\u001b[49m\u001b[43m(\u001b[49m\u001b[43mobj\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mid_field\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 221\u001b[0m )\n\u001b[1;32m 222\u001b[0m obj \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_preprocess(obj, preprocess)\n\u001b[1;32m 223\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_validate(obj)\n", + "File \u001b[0;32m~/Documents/redisvl/redisvl/index/storage.py:72\u001b[0m, in \u001b[0;36mBaseStorage._create_key\u001b[0;34m(self, obj, id_field)\u001b[0m\n\u001b[1;32m 70\u001b[0m key_value \u001b[38;5;241m=\u001b[39m obj[id_field] \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 71\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[0;32m---> 72\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mKey field \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mid_field\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m not found in record \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mobj\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 74\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_key(\n\u001b[1;32m 75\u001b[0m key_value, prefix\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprefix, key_separator\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mkey_separator\n\u001b[1;32m 76\u001b[0m )\n", + "\u001b[0;31mValueError\u001b[0m: Key field _id not found in record {'entry_id': None, 'role': 'system', 'content': 'You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.', 'session_tag': 'c9cc1d8d-c7cb-4e33-887e-87f04594d44a', 'timestamp': 1722536370.422074}" + ] + } + ], "source": [ "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.\"})\n", "chat_session.add_messages([\n", @@ -73,21 +119,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'llm', 'content': 'The capital is Paris.'}\n", - "{'role': 'user', 'content': 'And what is the capital of Spain?'}\n", - "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", - "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", - "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n" - ] - } - ], + "outputs": [], "source": [ "context = chat_session.get_recent()\n", "for message in context:\n", @@ -103,22 +137,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'user', 'content': 'And what is the capital of Spain?'}\n", - "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", - "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", - "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", - "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", - "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" - ] - } - ], + "outputs": [], "source": [ "prompt = \"what is the size of England compared to Portugal?\"\n", "response = \"England is larger in land area than Portal by about 15000 square miles.\"\n", @@ -145,21 +166,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'system', 'content': 'You are a helpful algebra tutor, giving simple answers to math problems.'}\n", - "{'role': 'user', 'content': 'What is the value of x in the equation 2x + 3 = 7?'}\n", - "{'role': 'llm', 'content': 'The value of x is 2.'}\n", - "{'role': 'user', 'content': 'What is the value of y in the equation 3y - 5 = 7?'}\n", - "{'role': 'llm', 'content': 'The value of y is 4.'}\n" - ] - } - ], + "outputs": [], "source": [ "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful algebra tutor, giving simple answers to math problems.\"}, session_tag='student two')\n", "chat_session.add_messages([\n", @@ -200,17 +209,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "10:10:47 redisvl.index.index INFO Index already exists, not overwriting.\n" - ] - } - ], + "outputs": [], "source": [ "from redisvl.extensions.session_manager import SemanticSessionManager\n", "semantic_session = SemanticSessionManager(name='student tutor')\n", @@ -220,18 +221,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", - "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" - ] - } - ], + "outputs": [], "source": [ "prompt = \"what have I learned about the size of England?\"\n", "semantic_session.set_distance_threshold(0.35)\n", @@ -252,20 +244,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", - "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n", - "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", - "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n" - ] - } - ], + "outputs": [], "source": [ "semantic_session.set_distance_threshold(0.7)\n", "\n", @@ -286,21 +267,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", - "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", - "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", - "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n", - "{'role': 'user', 'content': 'what is the smallest country in Europe?'}\n" - ] - } - ], + "outputs": [], "source": [ "semantic_session.store(prompt=\"what is the smallest country in Europe?\",\n", " response=\"Monaco is the smallest country in Europe at 0.78 square miles.\" # Incorrect. Vatican City is the smallest country in Europe\n", @@ -318,7 +287,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ From b999b4737349ef495997772912eb1ffe9a206cea Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 11:27:57 -0700 Subject: [PATCH 4/8] even more testing GHA vector search --- docs/user_guide/session_manager_07.ipynb | 163 ++++++++++++++--------- 1 file changed, 99 insertions(+), 64 deletions(-) diff --git a/docs/user_guide/session_manager_07.ipynb b/docs/user_guide/session_manager_07.ipynb index 73f27713..c418b03f 100644 --- a/docs/user_guide/session_manager_07.ipynb +++ b/docs/user_guide/session_manager_07.ipynb @@ -27,7 +27,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "11:19:30 redisvl.index.index INFO Index already exists, not overwriting.\n" + "11:26:12 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], @@ -50,53 +50,7 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "11:19:30 redisvl.index.index ERROR Error while loading data to Redis\n", - "Traceback (most recent call last):\n", - " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/storage.py\", line 70, in _create_key\n", - " key_value = obj[id_field] # type: ignore\n", - " ~~~^^^^^^^^^^\n", - "KeyError: '_id'\n", - "\n", - "During handling of the above exception, another exception occurred:\n", - "\n", - "Traceback (most recent call last):\n", - " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/index.py\", line 587, in load\n", - " return self._storage.write(\n", - " ^^^^^^^^^^^^^^^^^^^^\n", - " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/storage.py\", line 220, in write\n", - " else self._create_key(obj, id_field)\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"/Users/justin.cechmanek/Documents/redisvl/redisvl/index/storage.py\", line 72, in _create_key\n", - " raise ValueError(f\"Key field {id_field} not found in record {obj}\")\n", - "ValueError: Key field _id not found in record {'entry_id': None, 'role': 'system', 'content': 'You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.', 'session_tag': 'c9cc1d8d-c7cb-4e33-887e-87f04594d44a', 'timestamp': 1722536370.422074}\n" - ] - }, - { - "ename": "ValueError", - "evalue": "Key field _id not found in record {'entry_id': None, 'role': 'system', 'content': 'You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.', 'session_tag': 'c9cc1d8d-c7cb-4e33-887e-87f04594d44a', 'timestamp': 1722536370.422074}", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "File \u001b[0;32m~/Documents/redisvl/redisvl/index/storage.py:70\u001b[0m, in \u001b[0;36mBaseStorage._create_key\u001b[0;34m(self, obj, id_field)\u001b[0m\n\u001b[1;32m 69\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 70\u001b[0m key_value \u001b[38;5;241m=\u001b[39m \u001b[43mobj\u001b[49m\u001b[43m[\u001b[49m\u001b[43mid_field\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 71\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n", - "\u001b[0;31mKeyError\u001b[0m: '_id'", - "\nDuring handling of the above exception, another exception occurred:\n", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mchat_session\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_message\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mrole\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43msystem\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcontent\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mYou are a helpful geography tutor, giving simple and short answers to questions about Europen countries.\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2\u001b[0m chat_session\u001b[38;5;241m.\u001b[39madd_messages([\n\u001b[1;32m 3\u001b[0m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mWhat is the capital of France?\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[1;32m 4\u001b[0m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mllm\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m:\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe capital is Paris.\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 9\u001b[0m ]\n\u001b[1;32m 10\u001b[0m )\n", - "File \u001b[0;32m~/Documents/redisvl/redisvl/extensions/session_manager/standard_session.py:237\u001b[0m, in \u001b[0;36mStandardSessionManager.add_message\u001b[0;34m(self, message, session_tag)\u001b[0m\n\u001b[1;32m 225\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21madd_message\u001b[39m(\n\u001b[1;32m 226\u001b[0m \u001b[38;5;28mself\u001b[39m, message: Dict[\u001b[38;5;28mstr\u001b[39m, \u001b[38;5;28mstr\u001b[39m], session_tag: Optional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 227\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 228\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Insert a single prompt or response into the session memory.\u001b[39;00m\n\u001b[1;32m 229\u001b[0m \u001b[38;5;124;03m A timestamp is associated with it so that it can be later sorted\u001b[39;00m\n\u001b[1;32m 230\u001b[0m \u001b[38;5;124;03m in sequential ordering after retrieval.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 235\u001b[0m \u001b[38;5;124;03m session. Defaults to instance uuid.\u001b[39;00m\n\u001b[1;32m 236\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 237\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_messages\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mmessage\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msession_tag\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Documents/redisvl/redisvl/extensions/session_manager/standard_session.py:223\u001b[0m, in \u001b[0;36mStandardSessionManager.add_messages\u001b[0;34m(self, messages, session_tag)\u001b[0m\n\u001b[1;32m 219\u001b[0m chat_message\u001b[38;5;241m.\u001b[39mtool_call_id \u001b[38;5;241m=\u001b[39m message[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtool_field_name]\n\u001b[1;32m 221\u001b[0m chat_messages\u001b[38;5;241m.\u001b[39mappend(chat_message\u001b[38;5;241m.\u001b[39mto_dict())\n\u001b[0;32m--> 223\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_index\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchat_messages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mid_field\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mid_field_name\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Documents/redisvl/redisvl/index/index.py:587\u001b[0m, in \u001b[0;36mSearchIndex.load\u001b[0;34m(self, data, id_field, keys, ttl, preprocess, batch_size)\u001b[0m\n\u001b[1;32m 538\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Load objects to the Redis database. Returns the list of keys loaded\u001b[39;00m\n\u001b[1;32m 539\u001b[0m \u001b[38;5;124;03mto Redis.\u001b[39;00m\n\u001b[1;32m 540\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 584\u001b[0m \u001b[38;5;124;03m keys = index.load(data, preprocess=add_field)\u001b[39;00m\n\u001b[1;32m 585\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 586\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 587\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_storage\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwrite\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 588\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_redis_client\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore\u001b[39;49;00m\n\u001b[1;32m 589\u001b[0m \u001b[43m \u001b[49m\u001b[43mobjects\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 590\u001b[0m \u001b[43m \u001b[49m\u001b[43mid_field\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mid_field\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 591\u001b[0m \u001b[43m \u001b[49m\u001b[43mkeys\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mkeys\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 592\u001b[0m \u001b[43m \u001b[49m\u001b[43mttl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mttl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 593\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreprocess\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpreprocess\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 594\u001b[0m \u001b[43m \u001b[49m\u001b[43mbatch_size\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbatch_size\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 595\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 596\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[1;32m 597\u001b[0m logger\u001b[38;5;241m.\u001b[39mexception(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mError while loading data to Redis\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "File \u001b[0;32m~/Documents/redisvl/redisvl/index/storage.py:220\u001b[0m, in \u001b[0;36mBaseStorage.write\u001b[0;34m(self, redis_client, objects, id_field, keys, ttl, preprocess, batch_size)\u001b[0m\n\u001b[1;32m 214\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m redis_client\u001b[38;5;241m.\u001b[39mpipeline(transaction\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m pipe:\n\u001b[1;32m 215\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, obj \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(objects, start\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m):\n\u001b[1;32m 216\u001b[0m \u001b[38;5;66;03m# Construct key, validate, and write\u001b[39;00m\n\u001b[1;32m 217\u001b[0m key \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 218\u001b[0m \u001b[38;5;28mnext\u001b[39m(keys_iterator)\n\u001b[1;32m 219\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m keys_iterator\n\u001b[0;32m--> 220\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_create_key\u001b[49m\u001b[43m(\u001b[49m\u001b[43mobj\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mid_field\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 221\u001b[0m )\n\u001b[1;32m 222\u001b[0m obj \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_preprocess(obj, preprocess)\n\u001b[1;32m 223\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_validate(obj)\n", - "File \u001b[0;32m~/Documents/redisvl/redisvl/index/storage.py:72\u001b[0m, in \u001b[0;36mBaseStorage._create_key\u001b[0;34m(self, obj, id_field)\u001b[0m\n\u001b[1;32m 70\u001b[0m key_value \u001b[38;5;241m=\u001b[39m obj[id_field] \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 71\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[0;32m---> 72\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mKey field \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mid_field\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m not found in record \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mobj\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 74\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_key(\n\u001b[1;32m 75\u001b[0m key_value, prefix\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprefix, key_separator\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mkey_separator\n\u001b[1;32m 76\u001b[0m )\n", - "\u001b[0;31mValueError\u001b[0m: Key field _id not found in record {'entry_id': None, 'role': 'system', 'content': 'You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.', 'session_tag': 'c9cc1d8d-c7cb-4e33-887e-87f04594d44a', 'timestamp': 1722536370.422074}" - ] - } - ], + "outputs": [], "source": [ "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.\"})\n", "chat_session.add_messages([\n", @@ -119,9 +73,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'role': 'llm', 'content': 'The capital is Paris.'}\n", + "{'role': 'user', 'content': 'And what is the capital of Spain?'}\n", + "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n" + ] + } + ], "source": [ "context = chat_session.get_recent()\n", "for message in context:\n", @@ -137,9 +103,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'role': 'user', 'content': 'And what is the capital of Spain?'}\n", + "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" + ] + } + ], "source": [ "prompt = \"what is the size of England compared to Portugal?\"\n", "response = \"England is larger in land area than Portal by about 15000 square miles.\"\n", @@ -166,9 +145,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'role': 'system', 'content': 'You are a helpful algebra tutor, giving simple answers to math problems.'}\n", + "{'role': 'user', 'content': 'What is the value of x in the equation 2x + 3 = 7?'}\n", + "{'role': 'llm', 'content': 'The value of x is 2.'}\n", + "{'role': 'user', 'content': 'What is the value of y in the equation 3y - 5 = 7?'}\n", + "{'role': 'llm', 'content': 'The value of y is 4.'}\n" + ] + } + ], "source": [ "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful algebra tutor, giving simple answers to math problems.\"}, session_tag='student two')\n", "chat_session.add_messages([\n", @@ -209,9 +200,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11:26:15 redisvl.index.index INFO Index already exists, not overwriting.\n" + ] + } + ], "source": [ "from redisvl.extensions.session_manager import SemanticSessionManager\n", "semantic_session = SemanticSessionManager(name='student tutor')\n", @@ -221,9 +220,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" + ] + } + ], "source": [ "prompt = \"what have I learned about the size of England?\"\n", "semantic_session.set_distance_threshold(0.35)\n", @@ -244,9 +255,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" + ] + } + ], "source": [ "semantic_session.set_distance_threshold(0.7)\n", "\n", @@ -267,9 +290,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", + "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n", + "{'role': 'user', 'content': 'what is the smallest country in Europe?'}\n" + ] + } + ], "source": [ "semantic_session.store(prompt=\"what is the smallest country in Europe?\",\n", " response=\"Monaco is the smallest country in Europe at 0.78 square miles.\" # Incorrect. Vatican City is the smallest country in Europe\n", @@ -277,7 +312,7 @@ "\n", "# get the key of the incorrect message\n", "context = semantic_session.get_recent(top_k=1, raw=True)\n", - "bad_key = context[0]['entry_id']\n", + "bad_key = context[0]['_id']\n", "semantic_session.drop(bad_key)\n", "\n", "corrected_context = semantic_session.get_recent()\n", @@ -287,7 +322,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ From 6be56b8dcffbfbafafbbf2acb3866be65925461e Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 12:47:25 -0700 Subject: [PATCH 5/8] changes _id to entry_id --- docs/user_guide/session_manager_07.ipynb | 53 +++++++++---------- .../session_manager/base_session.py | 2 +- redisvl/extensions/session_manager/schema.py | 21 ++++---- 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/docs/user_guide/session_manager_07.ipynb b/docs/user_guide/session_manager_07.ipynb index c418b03f..48d671b2 100644 --- a/docs/user_guide/session_manager_07.ipynb +++ b/docs/user_guide/session_manager_07.ipynb @@ -27,7 +27,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "11:26:12 redisvl.index.index INFO Index already exists, not overwriting.\n" + "12:15:37 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], @@ -54,14 +54,13 @@ "source": [ "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful geography tutor, giving simple and short answers to questions about Europen countries.\"})\n", "chat_session.add_messages([\n", - " {\"role\":\"user\", \"content\":\"What is the capital of France?\"},\n", - " {\"role\":\"llm\", \"content\":\"The capital is Paris.\"},\n", - " {\"role\":\"user\", \"content\":\"And what is the capital of Spain?\"},\n", - " {\"role\":\"llm\", \"content\":\"The capital is Madrid.\"},\n", - " {\"role\":\"user\", \"content\":\"What is the population of Great Britain?\"},\n", - " {\"role\":\"llm\", \"content\":\"As of 2023 the population of Great Britain is approximately 67 million people.\"},\n", - " ]\n", - " )" + " {\"role\":\"user\", \"content\":\"What is the capital of France?\"},\n", + " {\"role\":\"llm\", \"content\":\"The capital is Paris.\"},\n", + " {\"role\":\"user\", \"content\":\"And what is the capital of Spain?\"},\n", + " {\"role\":\"llm\", \"content\":\"The capital is Madrid.\"},\n", + " {\"role\":\"user\", \"content\":\"What is the population of Great Britain?\"},\n", + " {\"role\":\"llm\", \"content\":\"As of 2023 the population of Great Britain is approximately 67 million people.\"},]\n", + " )" ] }, { @@ -163,11 +162,12 @@ "source": [ "chat_session.add_message({\"role\":\"system\", \"content\":\"You are a helpful algebra tutor, giving simple answers to math problems.\"}, session_tag='student two')\n", "chat_session.add_messages([\n", - " {\"role\":\"user\", \"content\":\"What is the value of x in the equation 2x + 3 = 7?\"},\n", - " {\"role\":\"llm\", \"content\":\"The value of x is 2.\"},\n", - " {\"role\":\"user\", \"content\":\"What is the value of y in the equation 3y - 5 = 7?\"},\n", - " {\"role\":\"llm\", \"content\":\"The value of y is 4.\"}\n", - " ], session_tag='student two')\n", + " {\"role\":\"user\", \"content\":\"What is the value of x in the equation 2x + 3 = 7?\"},\n", + " {\"role\":\"llm\", \"content\":\"The value of x is 2.\"},\n", + " {\"role\":\"user\", \"content\":\"What is the value of y in the equation 3y - 5 = 7?\"},\n", + " {\"role\":\"llm\", \"content\":\"The value of y is 4.\"}],\n", + " session_tag='student two'\n", + " )\n", "\n", "for math_message in chat_session.get_recent(session_tag='student two'):\n", " print(math_message)" @@ -207,7 +207,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "11:26:15 redisvl.index.index INFO Index already exists, not overwriting.\n" + "12:15:41 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], @@ -227,9 +227,6 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", - "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", - "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" ] @@ -238,8 +235,7 @@ "source": [ "prompt = \"what have I learned about the size of England?\"\n", "semantic_session.set_distance_threshold(0.35)\n", - "##context = semantic_session.get_relevant(prompt)\n", - "context = semantic_session.get_recent() ## testing GHA\n", + "context = semantic_session.get_relevant(prompt)\n", "for message in context:\n", " print(message)" ] @@ -262,19 +258,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'role': 'llm', 'content': 'The capital is Madrid.'}\n", - "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", - "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n", "{'role': 'user', 'content': 'what is the size of England compared to Portugal?'}\n", - "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n" + "{'role': 'llm', 'content': 'England is larger in land area than Portal by about 15000 square miles.'}\n", + "{'role': 'user', 'content': 'What is the population of Great Britain?'}\n", + "{'role': 'llm', 'content': 'As of 2023 the population of Great Britain is approximately 67 million people.'}\n" ] } ], "source": [ "semantic_session.set_distance_threshold(0.7)\n", "\n", - "##larger_context = semantic_session.get_relevant(prompt)\n", - "larger_context = semantic_session.get_recent() ##\n", + "larger_context = semantic_session.get_relevant(prompt)\n", "for message in larger_context:\n", " print(message)" ] @@ -306,9 +300,10 @@ } ], "source": [ - "semantic_session.store(prompt=\"what is the smallest country in Europe?\",\n", - " response=\"Monaco is the smallest country in Europe at 0.78 square miles.\" # Incorrect. Vatican City is the smallest country in Europe\n", - " )\n", + "semantic_session.store(\n", + " prompt=\"what is the smallest country in Europe?\",\n", + " response=\"Monaco is the smallest country in Europe at 0.78 square miles.\" # Incorrect. Vatican City is the smallest country in Europe\n", + " )\n", "\n", "# get the key of the incorrect message\n", "context = semantic_session.get_recent(top_k=1, raw=True)\n", diff --git a/redisvl/extensions/session_manager/base_session.py b/redisvl/extensions/session_manager/base_session.py index c2cddb2b..ebf3ad9a 100644 --- a/redisvl/extensions/session_manager/base_session.py +++ b/redisvl/extensions/session_manager/base_session.py @@ -5,7 +5,7 @@ class BaseSessionManager: - id_field_name: str = "_id" + id_field_name: str = "entry_id" role_field_name: str = "role" content_field_name: str = "content" tool_field_name: str = "tool_call_id" diff --git a/redisvl/extensions/session_manager/schema.py b/redisvl/extensions/session_manager/schema.py index 4394d4cb..96357f19 100644 --- a/redisvl/extensions/session_manager/schema.py +++ b/redisvl/extensions/session_manager/schema.py @@ -10,7 +10,7 @@ class ChatMessage(BaseModel): """A single chat message exchanged between a user and an LLM.""" - _id: Optional[str] = Field(default=None) + entry_id: str """A unique identifier for the message.""" role: str # TODO -- do we enumify this? """The role of the message sender (e.g., 'user' or 'llm').""" @@ -18,7 +18,7 @@ class ChatMessage(BaseModel): """The content of the message.""" session_tag: str """Tag associated with the current session.""" - timestamp: float = Field(default_factory=current_timestamp) + timestamp: float """The time the message was sent, in UTC, rounded to milliseconds.""" tool_call_id: Optional[str] = Field(default=None) """An optional identifier for a tool call associated with the message.""" @@ -28,24 +28,21 @@ class ChatMessage(BaseModel): class Config: arbitrary_types_allowed = True - @root_validator(pre=False) + @root_validator(pre=True) @classmethod def generate_id(cls, values): - if "_id" not in values: - values["_id"] = f'{values["session_tag"]}:{values["timestamp"]}' + if "timestamp" not in values: + values["timestamp"] = current_timestamp() + if "entry_id" not in values: + values["entry_id"] = f'{values["session_tag"]}:{values["timestamp"]}' return values def to_dict(self) -> Dict: - data = self.dict() + data = self.dict(exclude_none=True) # handle optional fields - if data["vector_field"] is not None: + if "vector_field" in data: data["vector_field"] = array_to_buffer(data["vector_field"]) - else: - del data["vector_field"] - - if self.tool_call_id is None: - del data["tool_call_id"] return data From f4ab76dcc4c7cc0b2be5a2121b355ee997d06ac3 Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 12:54:49 -0700 Subject: [PATCH 6/8] sets default values in schema --- redisvl/extensions/session_manager/schema.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redisvl/extensions/session_manager/schema.py b/redisvl/extensions/session_manager/schema.py index 96357f19..0e35edd2 100644 --- a/redisvl/extensions/session_manager/schema.py +++ b/redisvl/extensions/session_manager/schema.py @@ -10,7 +10,7 @@ class ChatMessage(BaseModel): """A single chat message exchanged between a user and an LLM.""" - entry_id: str + entry_id: Optional[str] = Field(default=None) """A unique identifier for the message.""" role: str # TODO -- do we enumify this? """The role of the message sender (e.g., 'user' or 'llm').""" @@ -18,7 +18,7 @@ class ChatMessage(BaseModel): """The content of the message.""" session_tag: str """Tag associated with the current session.""" - timestamp: float + timestamp: Optional[float] = Field(default=None) """The time the message was sent, in UTC, rounded to milliseconds.""" tool_call_id: Optional[str] = Field(default=None) """An optional identifier for a tool call associated with the message.""" From af4a12b2dd265dd370f064a595f17be3725a55cd Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 13:35:23 -0700 Subject: [PATCH 7/8] fixes session unit tests to use entry_id --- tests/unit/test_session_schema.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit/test_session_schema.py b/tests/unit/test_session_schema.py index 292a0d0a..b25f6564 100644 --- a/tests/unit/test_session_schema.py +++ b/tests/unit/test_session_schema.py @@ -14,14 +14,14 @@ def test_chat_message_creation(): content = "Hello, world!" chat_message = ChatMessage( - _id=f"{session_tag}:{timestamp}", + entry_id=f"{session_tag}:{timestamp}", role="user", content=content, session_tag=session_tag, timestamp=timestamp, ) - assert chat_message._id == f"{session_tag}:{timestamp}" + assert chat_message.entry_id == f"{session_tag}:{timestamp}" assert chat_message.role == "user" assert chat_message.content == content assert chat_message.session_tag == session_tag @@ -42,7 +42,7 @@ def test_chat_message_default_id_generation(): timestamp=timestamp, ) - assert chat_message._id == f"{session_tag}:{timestamp}" + assert chat_message.entry_id == f"{session_tag}:{timestamp}" def test_chat_message_with_tool_call_id(): @@ -52,7 +52,7 @@ def test_chat_message_with_tool_call_id(): tool_call_id = create_uuid() chat_message = ChatMessage( - _id=f"{session_tag}:{timestamp}", + entry_id=f"{session_tag}:{timestamp}", role="user", content=content, session_tag=session_tag, @@ -70,7 +70,7 @@ def test_chat_message_with_vector_field(): vector_field = [0.1, 0.2, 0.3] chat_message = ChatMessage( - _id=f"{session_tag}:{timestamp}", + entry_id=f"{session_tag}:{timestamp}", role="user", content=content, session_tag=session_tag, @@ -88,7 +88,7 @@ def test_chat_message_to_dict(): vector_field = [0.1, 0.2, 0.3] chat_message = ChatMessage( - _id=f"{session_tag}:{timestamp}", + entry_id=f"{session_tag}:{timestamp}", role="user", content=content, session_tag=session_tag, @@ -98,7 +98,7 @@ def test_chat_message_to_dict(): data = chat_message.to_dict() - assert data["_id"] == f"{session_tag}:{timestamp}" + assert data["entry_id"] == f"{session_tag}:{timestamp}" assert data["role"] == "user" assert data["content"] == content assert data["session_tag"] == session_tag @@ -126,7 +126,7 @@ def test_chat_message_invalid_role(): with pytest.raises(ValidationError): ChatMessage( - _id=f"{session_tag}:{timestamp}", + entry_id=f"{session_tag}:{timestamp}", role=[1, 2, 3], # Invalid role type content=content, session_tag=session_tag, From fca30dcef8aab692e888fce3a870b52b73dcf41f Mon Sep 17 00:00:00 2001 From: Justin Cechmanek Date: Thu, 1 Aug 2024 14:28:12 -0700 Subject: [PATCH 8/8] changes second index name --- docs/user_guide/session_manager_07.ipynb | 8 ++++---- tests/integration/test_session_manager.py | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/user_guide/session_manager_07.ipynb b/docs/user_guide/session_manager_07.ipynb index 48d671b2..ed6c61e4 100644 --- a/docs/user_guide/session_manager_07.ipynb +++ b/docs/user_guide/session_manager_07.ipynb @@ -27,7 +27,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "12:15:37 redisvl.index.index INFO Index already exists, not overwriting.\n" + "12:24:11 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], @@ -207,13 +207,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "12:15:41 redisvl.index.index INFO Index already exists, not overwriting.\n" + "12:24:15 redisvl.index.index INFO Index already exists, not overwriting.\n" ] } ], "source": [ "from redisvl.extensions.session_manager import SemanticSessionManager\n", - "semantic_session = SemanticSessionManager(name='student tutor')\n", + "semantic_session = SemanticSessionManager(name='tutor')\n", "\n", "semantic_session.add_messages(chat_session.get_recent(top_k=8))" ] @@ -307,7 +307,7 @@ "\n", "# get the key of the incorrect message\n", "context = semantic_session.get_recent(top_k=1, raw=True)\n", - "bad_key = context[0]['_id']\n", + "bad_key = context[0]['entry_id']\n", "semantic_session.drop(bad_key)\n", "\n", "corrected_context = semantic_session.get_recent()\n", diff --git a/tests/integration/test_session_manager.py b/tests/integration/test_session_manager.py index ce6b9943..d21e6651 100644 --- a/tests/integration/test_session_manager.py +++ b/tests/integration/test_session_manager.py @@ -32,7 +32,6 @@ def test_specify_redis_url(client, redis_url): session = StandardSessionManager( name="test_app", session_tag="abc", - user_tag="123", redis_url=redis_url, ) assert isinstance(session._index.client, type(client))