From 1491eaed41a10de0e5256ccf4eeda391ed5940b3 Mon Sep 17 00:00:00 2001 From: arnaud-openai <171722805+arnaud-openai@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:02:06 -0700 Subject: [PATCH] Af/update cookbook lauch 4o mini (#1292) --- ...bine_GPT4o_with_RAG_Outfit_Assistant.ipynb | 278 +- examples/How_to_stream_completions.ipynb | 612 ++- examples/How_to_use_guardrails.ipynb | 86 +- examples/How_to_use_moderation.ipynb | 10 +- examples/SDG1.ipynb | 3364 +++++++++++------ examples/Tag_caption_images_with_GPT4V.ipynb | 3100 ++++++++++++++- examples/batch_processing.ipynb | 82 +- examples/gpt4o/introduction_to_gpt4o.ipynb | 495 +-- registry.yaml | 12 +- 9 files changed, 5728 insertions(+), 2311 deletions(-) diff --git a/examples/How_to_combine_GPT4o_with_RAG_Outfit_Assistant.ipynb b/examples/How_to_combine_GPT4o_with_RAG_Outfit_Assistant.ipynb index 38d35619..f1c18601 100644 --- a/examples/How_to_combine_GPT4o_with_RAG_Outfit_Assistant.ipynb +++ b/examples/How_to_combine_GPT4o_with_RAG_Outfit_Assistant.ipynb @@ -4,21 +4,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# How to combine GPT-4o with RAG - Create a Clothing Matchmaker App\n", + "# How to Combine GPT-4o Mini with RAG - Create a Clothing Matchmaker App\n", "\n", - "Welcome to the Clothing Matchmaker App Jupyter Notebook! This project demonstrates the power of the GPT-4o model in analyzing images of clothing items and extracting key features such as color, style, and type. The core of our app relies on this advanced image analysis model developed by OpenAI, which enables us to accurately identify the characteristics of the input clothing item.\n", + "Welcome to the Clothing Matchmaker App Jupyter Notebook! This project demonstrates the power of the GPT-4o mini model in analyzing images of clothing items and extracting key features such as color, style, and type. The core of our app relies on this advanced image analysis model developed by OpenAI, which enables us to accurately identify the characteristics of the input clothing item.\n", "\n", - "GPT-4o is a model that combines natural language processing with image recognition, allowing it to understand and generate responses based on both text and visual inputs.\n", + "GPT-4o mini is a small model that combines natural language processing with image recognition, allowing it to understand and generate responses based on both text and visual inputs with low latency.\n", "\n", - "Building on the capabilities of the GPT-4o model, we employ a custom matching algorithm and the RAG technique to search our knowledge base for items that complement the identified features. This algorithm takes into account factors like color compatibility and style coherence to provide users with suitable recommendations. Through this notebook, we aim to showcase the practical application of these technologies in creating a clothing recommendation system.\n", + "Building on the capabilities of the GPT-4o mini model, we employ a custom matching algorithm and the RAG technique to search our knowledge base for items that complement the identified features. This algorithm takes into account factors like color compatibility and style coherence to provide users with suitable recommendations. Through this notebook, we aim to showcase the practical application of these technologies in creating a clothing recommendation system.\n", "\n", - "Using the combination of GPT-4o + RAG (Retrieval-Augmented Generation) offers several advantages:\n", + "Using the combination of GPT-4o mini + RAG (Retrieval-Augmented Generation) offers several advantages:\n", "\n", - "1. **Contextual Understanding**: GPT-4o can analyze input images and understand the context, such as the objects, scenes, and activities depicted. This allows for more accurate and relevant suggestions or information across various domains, whether it's interior design, cooking, or education.\n", + "1. **Contextual Understanding**: GPT-4o mini can analyze input images and understand the context, such as the objects, scenes, and activities depicted. This allows for more accurate and relevant suggestions or information across various domains, whether it's interior design, cooking, or education.\n", "2. **Rich Knowledge Base**: RAG combines the generative capabilities of GPT-4 with a retrieval component that accesses a large corpus of information across different fields. This means the system can provide suggestions or insights based on a wide range of knowledge, from historical facts to scientific concepts.\n", "3. **Customization**: The approach allows for easy customization to cater to specific user needs or preferences in various applications. Whether it's tailoring suggestions to a user's taste in art or providing educational content based on a student's learning level, the system can be adapted to deliver personalized experiences.\n", "\n", - "Overall, the GPT-4o + RAG approach offers a powerful and flexible solution for various fashion-related applications, leveraging the strengths of both generative and retrieval-based AI techniques." + "Overall, the GPT-4o mini + RAG approach offers a fast, powerful, and flexible solution for various fashion-related applications, leveraging the strengths of both generative and retrieval-based AI techniques.\n" ] }, { @@ -52,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -70,7 +70,7 @@ "\n", "client = OpenAI()\n", "\n", - "GPT_MODEL = \"gpt-4o\"\n", + "GPT_MODEL = \"gpt-4o-mini\"\n", "EMBEDDING_MODEL = \"text-embedding-3-large\"\n", "EMBEDDING_COST_PER_1K_TOKENS = 0.00013" ] @@ -85,30 +85,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " id gender masterCategory subCategory articleType baseColour season \\\n", - "0 27152 Men Apparel Topwear Shirts Blue Summer \n", - "1 10469 Men Apparel Topwear Tshirts Yellow Fall \n", - "2 17169 Men Apparel Topwear Shirts Maroon Fall \n", - "3 56702 Men Apparel Topwear Kurtas Blue Summer \n", - "4 47062 Women Apparel Bottomwear Patiala Multi Fall \n", - "\n", - " year usage productDisplayName \n", - "0 2012.0 Formal Mark Taylor Men Striped Blue Shirt \n", - "1 2011.0 Casual Flying Machine Men Yellow Polo Tshirts \n", - "2 2011.0 Casual U.S. Polo Assn. Men Checks Maroon Shirt \n", - "3 2012.0 Ethnic Fabindia Men Blue Kurta \n", - "4 2012.0 Ethnic Shree Women Multi Colored Patiala \n", - "Opened dataset successfully. Dataset has 1000 items of clothing.\n" - ] - } - ], + "outputs": [], "source": [ "styles_filepath = \"data/sample_clothes/sample_styles.csv\"\n", "styles_df = pd.read_csv(styles_filepath, on_bad_lines='skip')\n", @@ -125,7 +104,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -211,33 +190,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "num_articles=1000, num_tokens=8280, est_embedding_cost=0.00 USD\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "1024it [00:01, 724.12it/s] \n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Embeddings created successfully.\n", - "Writing embeddings to file ...\n", - "Embeddings successfully stored in sample_styles_with_embeddings.csv\n" - ] - } - ], + "outputs": [], "source": [ "generate_embeddings(styles_df, 'productDisplayName')\n", "print(\"Writing embeddings to file ...\")\n", @@ -247,37 +202,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " id gender masterCategory subCategory articleType baseColour season \\\n", - "0 27152 Men Apparel Topwear Shirts Blue Summer \n", - "1 10469 Men Apparel Topwear Tshirts Yellow Fall \n", - "2 17169 Men Apparel Topwear Shirts Maroon Fall \n", - "3 56702 Men Apparel Topwear Kurtas Blue Summer \n", - "4 47062 Women Apparel Bottomwear Patiala Multi Fall \n", - "\n", - " year usage productDisplayName \\\n", - "0 2012.0 Formal Mark Taylor Men Striped Blue Shirt \n", - "1 2011.0 Casual Flying Machine Men Yellow Polo Tshirts \n", - "2 2011.0 Casual U.S. Polo Assn. Men Checks Maroon Shirt \n", - "3 2012.0 Ethnic Fabindia Men Blue Kurta \n", - "4 2012.0 Ethnic Shree Women Multi Colored Patiala \n", - "\n", - " embeddings \n", - "0 [0.006903026718646288, 0.0004031236458104104, ... \n", - "1 [-0.04371623694896698, -0.008869604207575321, ... \n", - "2 [-0.027989011257886887, 0.05884069576859474, -... \n", - "3 [-0.004197604488581419, 0.029409468173980713, ... \n", - "4 [-0.05241541564464569, 0.015912825241684914, -... \n", - "Opened dataset successfully. Dataset has 1000 items of clothing along with their embeddings.\n" - ] - } - ], + "outputs": [], "source": [ "# styles_df = pd.read_csv('data/sample_clothes/sample_styles_with_embeddings.csv', on_bad_lines='skip')\n", "\n", @@ -307,7 +234,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -341,7 +268,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -371,7 +298,7 @@ "source": [ "### Analysis Module\n", "\n", - "In this module, we leverage `gpt-4o` to analyze input images and extract important features like detailed descriptions, styles, and types. The analysis is performed through a straightforward API call, where we provide the URL of the image for analysis and request the model to identify relevant features.\n", + "In this module, we leverage `gpt-4o-mini` to analyze input images and extract important features like detailed descriptions, styles, and types. The analysis is performed through a straightforward API call, where we provide the URL of the image for analysis and request the model to identify relevant features.\n", "\n", "To ensure the model returns accurate results, we use specific techniques in our prompt:\n", "\n", @@ -386,12 +313,12 @@ "3. **One Shot Example**: \n", " - To further clarify the expected output, we provide the model with an example input description and a corresponding example output. Although this may increase the number of tokens used (and thus the cost of the call), it helps to guide the model and results in better overall performance.\n", "\n", - "By following this structured approach, we aim to obtain precise and useful information from the `gpt-4o` model for further analysis and integration into our database." + "By following this structured approach, we aim to obtain precise and useful information from the `gpt-4o-mini` model for further analysis and integration into our database." ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -424,8 +351,7 @@ " }\n", " ],\n", " }\n", - " ],\n", - " max_tokens=300,\n", + " ]\n", " )\n", " # Extract relevant features from the response\n", " features = response.choices[0].message.content\n", @@ -456,7 +382,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -470,7 +396,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -485,27 +411,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'items': [\"Slim Fit Blue Men's Jeans\", \"White Men's Sneakers\", \"Men's Silver Watch\"], 'category': 'Shirts', 'gender': 'Men'}\n" - ] - } - ], + "outputs": [], "source": [ "# Select the unique subcategories from the DataFrame\n", "unique_subcategories = styles_df['articleType'].unique()\n", @@ -538,30 +446,9 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "513 Remaining Items\n", - "[\"Slim Fit Blue Men's Jeans\", \"White Men's Sneakers\", \"Men's Silver Watch\"]\n" - ] - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Extract the relevant features from the analysis\n", "item_descs = image_analysis['items']\n", @@ -600,7 +487,7 @@ "source": [ "### Guardrails\n", "\n", - "In the context of using Large Language Models (LLMs) like GPT-4o, \"guardrails\" refer to mechanisms or checks put in place to ensure that the model's output remains within desired parameters or boundaries. These guardrails are crucial for maintaining the quality and relevance of the model's responses, especially when dealing with complex or nuanced tasks.\n", + "In the context of using Large Language Models (LLMs) like GPT-4o mini, \"guardrails\" refer to mechanisms or checks put in place to ensure that the model's output remains within desired parameters or boundaries. These guardrails are crucial for maintaining the quality and relevance of the model's responses, especially when dealing with complex or nuanced tasks.\n", "\n", "Guardrails are useful for several reasons:\n", "\n", @@ -609,7 +496,7 @@ "3. **Safety**: They prevent the model from generating harmful, offensive, or inappropriate content.\n", "4. **Contextual Relevance**: They ensure that the model's output is contextually relevant to the specific task or domain it is being used for.\n", "\n", - "In our case, we are using GPT-4o to analyze fashion images and suggest items that would complement an original outfit. To implement guardrails, we can **refine results**: After obtaining initial suggestions from GPT-4o, we can send the original image and the suggested items back to the model. We can then ask GPT-4o to evaluate whether each suggested item would indeed be a good fit for the original outfit.\n", + "In our case, we are using GPT-4o mini to analyze fashion images and suggest items that would complement an original outfit. To implement guardrails, we can **refine results**: After obtaining initial suggestions from GPT-4o mini, we can send the original image and the suggested items back to the model. We can then ask GPT-4o mini to evaluate whether each suggested item would indeed be a good fit for the original outfit.\n", "\n", "This gives the model the ability to self-correct and adjust its own output based on feedback or additional information. By implementing these guardrails and enabling self-correction, we can enhance the reliability and usefulness of the model's output in the context of fashion analysis and recommendation.\n", "\n", @@ -618,7 +505,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -672,100 +559,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The items match!\n", - "The black shirt and blue jeans create a classic and casual outfit that works well together.\n" - ] - }, - { - "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQEASABIAAD/7RR2UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAB8cAVoAAxslRxwBWgADGyVHHAFaAAMbJUccAgAAAgAAADhCSU0EJQAAAAAAENPJn0s9jeoohUg1aoQVnCs4QklNBDoAAAAAAJMAAAAQAAAAAQAAAAAAC3ByaW50T3V0cHV0AAAABQAAAABDbHJTZW51bQAAAABDbHJTAAAAAFJHQkMAAAAASW50ZWVudW0AAAAASW50ZQAAAABDbHJtAAAAAE1wQmxib29sAQAAAA9wcmludFNpeHRlZW5CaXRib29sAAAAAAtwcmludGVyTmFtZVRFWFQAAAABAAAAOEJJTQQ7AAAAAAGyAAAAEAAAAAEAAAAAABJwcmludE91dHB1dE9wdGlvbnMAAAASAAAAAENwdG5ib29sAAAAAABDbGJyYm9vbAAAAAAAUmdzTWJvb2wAAAAAAENybkNib29sAAAAAABDbnRDYm9vbAAAAAAATGJsc2Jvb2wAAAAAAE5ndHZib29sAAAAAABFbWxEYm9vbAAAAAAASW50cmJvb2wAAAAAAEJja2dPYmpjAAAAAQAAAAAAAFJHQkMAAAADAAAAAFJkICBkb3ViQG/gAAAAAAAAAAAAR3JuIGRvdWJAb+AAAAAAAAAAAABCbCAgZG91YkBv4AAAAAAAAAAAAEJyZFRVbnRGI1JsdAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBSAAAAAAAAAAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVudEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkAAAAAAAA4QklNA+0AAAAAABAASAAAAAEAAgBIAAAAAQACOEJJTQQmAAAAAAAOAAAAAAAAAAAAAD+AAAA4QklNBA0AAAAAAAQAAAAeOEJJTQQZAAAAAAAEAAAAHjhCSU0D8wAAAAAACQAAAAAAAAAAAQA4QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAAM3AAAABgAAAAAAAAAAAAAFoAAABDgAAAABADEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAABDgAAAWgAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAAWgAAAAAFJnaHRsb25nAAAEOAAAAAZzbGljZXNWbExzAAAAAU9iamMAAAABAAAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAAGb3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQAAAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAFoAAAAABSZ2h0bG9uZwAABDgAAAADdXJsVEVYVAAAAAEAAAAAAABudWxsVEVYVAAAAAEAAAAAAABNc2dlVEVYVAAAAAEAAAAAAAZhbHRUYWdURVhUAAAAAQAAAAAADmNlbGxUZXh0SXNIVE1MYm9vbAEAAAAIY2VsbFRleHRURVhUAAAAAQAAAAAACWhvcnpBbGlnbmVudW0AAAAPRVNsaWNlSG9yekFsaWduAAAAB2RlZmF1bHQAAAAJdmVydEFsaWduZW51bQAAAA9FU2xpY2VWZXJ0QWxpZ24AAAAHZGVmYXVsdAAAAAti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bG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InV1aWQ6MjExQUQ0Q0FBRTQwRTAxMTlGMzdERDJFRjA1ODEzREYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTBBOUQ4MDNBNEQxMTFFMUJBMjY5RkFEMzkxM0JENDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QTRFQTRGRUM3OEE1RTExMUIxREU5RTY2NjM3QzZENUIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcDpDcmVhdGVEYXRlPSIyMDEyLTA1LTIzVDE3OjQ5OjM3KzA1OjMwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxMi0wNS0yNFQxMzo1MjowNiswNTozMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxMi0wNS0yNFQxMzo1MjowNiswNTozMCIgY3JzOkFscmVhZHlBcHBsaWVkPSJUcnVlIiBwaG90b3Nob3A6TGVnYWN5SVBUQ0RpZ2VzdD0iQzc1RDE3RTU3NEI1NkVGNURCQkUzOTk0QzBFOTc5NUMiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIGRjOmZvcm1hdD0iaW1hZ2UvanBlZyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkYxNUYwMEI2OTM5OUUxMTFBQjkxQ0RBNzRBRTNEOTJDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjUyNDgxODhENjQyRjExRTFBNTEzQkE1QkE5RTU1MzBEIi8+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjAzMENCMjk1RDRBNEUxMTFBOTlGOTRFMTVENTY4RjcxIiBzdEV2dDp3aGVuPSIyMDEyLTA1LTIzVDE4OjMwOjQ2KzA1OjMwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6QTJFQTRGRUM3OEE1RTExMUIxREU5RTY2NjM3QzZENUIiIHN0RXZ0OndoZW49IjIwMTItMDUtMjRUMTM6NDc6MzcrMDU6MzAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUuMSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpBNEVBNEZFQzc4QTVFMTExQjFERTlFNjY2MzdDNkQ1QiIgc3RFdnQ6d2hlbj0iMjAxMi0wNS0yNFQxMzo1MjowNiswNTozMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDw/eHBhY2tldCBlbmQ9InciPz7/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAQECAQEBAgICAgICAgICAQICAgICAgICAgL/2wBDAQEBAQEBAQEBAQECAQEBAgICAgICAgICAgIC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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The items match!\n", - "The black shirt and the white sneakers with red and beige accents can work well together. Black is a versatile color that pairs well with many shoe options, and the white sneakers can add a sporty and casual touch to the outfit.\n" - ] - }, - { - "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQEASABIAAD/7SJuUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAA8cAVoAAxslRxwCAAACbLYAOEJJTQQlAAAAAAAQyGtLl86hDGcpRzULVQTTCjhCSU0EOgAAAAAAkwAAABAAAAABAAAAAAALcHJpbnRPdXRwdXQAAAAFAAAAAENsclNlbnVtAAAAAENsclMAAAAAUkdCQwAAAABJbnRlZW51bQAAAABJbnRlAAAAAENscm0AAAAATXBCbGJvb2wBAAAAD3ByaW50U2l4dGVlbkJpdGJvb2wAAAAAC3ByaW50ZXJOYW1lVEVYVAAAAAEAAAA4QklNBDsAAAAAAbIAAAAQAAAAAQAAAAAAEnByaW50T3V0cHV0T3B0aW9ucwAAABIAAAAAQ3B0bmJvb2wAAAAAAENsYnJib29sAAAAAABSZ3NNYm9vbAAAAAAAQ3JuQ2Jvb2wAAAAAAENudENib29sAAAAAABMYmxzYm9vbAAAAAAATmd0dmJvb2wAAAAAAEVtbERib29sAAAAAABJbnRyYm9vbAAAAAAAQmNrZ09iamMAAAABAAAAAAAAUkdCQwAAAAMAAAAAUmQgIGRvdWJAb+AAAAAAAAAAAABHcm4gZG91YkBv4AAAAAAAAAAAAEJsICBkb3ViQG/gAAAAAAAAAAAAQnJkVFVudEYjUmx0AAAAAAAAAAAAAAAAQmxkIFVudEYjUmx0AAAAAAAAAAAAAAAAUnNsdFVudEYjUHhsQFIAAAAAAAAAAAAKdmVjdG9yRGF0YWJvb2wBAAAAAFBnUHNlbnVtAAAAAFBnUHMAAAAAUGdQQwAAAABMZWZ0VW50RiNSbHQAAAAAAAAAAAAAAABUb3AgVW50RiNSbHQAAAAAAAAAAAAAAABTY2wgVW50RiNQcmNAWQAAAAAAADhCSU0D7QAAAAAAEABIAAAAAQACAEgAAAABAAI4QklNBCYAAAAAAA4AAAAAAAAAAAAAP4AAADhCSU0EDQAAAAAABAAAAB44QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAAAAABADhCSU0nEAAAAAAACgABAAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEAMgAAAAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklNA/gAAAAAAHAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAOEJJTQQAAAAAAAACAAA4QklNBAIAAAAAAAQAAAAAOEJJTQQwAAAAAAACAQE4QklNBC0AAAAAAAYAAQAAAAE4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQQeAAAAAAAEAAAAADhCSU0EGgAAAAADNwAAAAYAAAAAAAAAAAAABaAAAAQ4AAAAAQAxAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAQ4AAAFoAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAAbnVsbAAAAAIAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAFoAAAAABSZ2h0bG9uZwAABDgAAAAGc2xpY2VzVmxMcwAAAAFPYmpjAAAAAQAAAAAABXNsaWNlAAAAEgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3JvdXBJRGxvbmcAAAAAAAAABm9yaWdpbmVudW0AAAAMRVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNlVHlwZQAAAABJbWcgAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAABaAAAAAAUmdodGxvbmcAAAQ4AAAAA3VybFRFWFQAAAABAAAAAAAAbnVsbFRFWFQAAAABAAAAAAAATXNnZVRFWFQAAAABAAAAAAAGYWx0VGFnVEVYVAAAAAEAAAAAAA5jZWxsVGV4dElzSFRNTGJvb2wBAAAACGNlbGxUZXh0VEVYVAAAAAEAAAAAAAlob3J6QWxpZ25lbnVtAAAAD0VTbGljZUhvcnpBbGlnbgAAAAdkZWZhdWx0AAAACXZl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YmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MSA2NC4xNDA5NDksIDIwMTAvMTIvMDctMTA6NTc6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpjcnM9Imh0dHA6Ly9ucy5hZG9iZS5jb20vY2FtZXJhLXJhdy1zZXR0aW5ncy8xLjAvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ1dWlkOjIxMUFENENBQUU0MEUwMTE5RjM3REQyRUYwNTgxM0RGIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjE5NzcxN0IyQTg4QzExRTE5OEU5RTZERDVFQjYyRTQyIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjg5NDdCNjhEOENBOEUxMTE5RjE2REI4OTBCNDY5MjcyIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzUuMSBXaW5kb3dzIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxMi0wNS0yOFQxMTozOCswNTozMCIgeG1wOk1vZGlmeURhdGU9IjIwMTItMDUtMjhUMTE6NDg6MzQrMDU6MzAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTItMDUtMjhUMTE6NDg6MzQrMDU6MzAiIGNyczpBbHJlYWR5QXBwbGllZD0iVHJ1ZSIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NUE1OTM3NjE0NkE2RTExMTlBOUZDNjg5QTgxNzlFOUIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NTI0ODE4OEQ2NDJGMTFFMUE1MTNCQTVCQTlFNTUzMEQiLz4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ODk0N0I2OEQ4Q0E4RTExMTlGMTZEQjg5MEI0NjkyNzIiIHN0RXZ0OndoZW49IjIwMTItMDUtMjhUMTE6NDg6MzQrMDU6MzAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUuMSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+/9sAQwABAQEBAQEBAQEBAQEBAgIDAgICAgIEAwMCAwUEBQUFBAQEBQYHBgUF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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The items match!\n", - "The black button-up shirt is casual and versatile, making it compatible with the white and red athletic shoes for a relaxed and sporty look.\n" - ] - }, - { - "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/7AARRHVja3kAAQAEAAAAWAAA/+EAGEV4aWYAAElJKgAIAAAAAAAAAAAAAAD/4QNvaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MSA2NC4xNDA5NDksIDIwMTAvMTIvMDctMTA6NTc6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OEEwOUUwRDBBMDdDRTExMTkwNzJCMkFERDI5ODUyODYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTFGOThGNUFCM0FDMTFFMTlFOUVBRDhEN0Q5NUZFODAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTFGOThGNTlCM0FDMTFFMTlFOUVBRDhEN0Q5NUZFODAiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4QTA5RTBEMEEwN0NFMTExOTA3MkIyQUREMjk4NTI4NiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4QTA5RTBEMEEwN0NFMTExOTA3MkIyQUREMjk4NTI4NiIvPiA8L3JkZjpEZXNjcmlwdGlv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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The items match!\n", - "The black shirt pairs well with the light blue jeans, creating a classic and balanced color combination that is casual and stylish.\n" - ] - }, - { - "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQEASABIAAD/7RRaUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAABccAVoAAxslRxwBWgADGyVHHAIAAALNmgA4QklNBCUAAAAAABBqZzHAmT3KQlQPgF7QDyIyOEJJTQQ6AAAAAACTAAAAEAAAAAEAAAAAAAtwcmludE91dHB1dAAAAAUAAAAAQ2xyU2VudW0AAAAAQ2xyUwAAAABSR0JDAAAAAEludGVlbnVtAAAAAEludGUAAAAAQ2xybQAAAABNcEJsYm9vbAEAAAAPcHJpbnRTaXh0ZWVuQml0Ym9vbAAAAAALcHJpbnRlck5hbWVURVhUAAAAAQAAADhCSU0EOwAAAAABsgAAABAAAAABAAAAAAAScHJpbnRPdXRwdXRPcHRpb25zAAAAEgAAAABDcHRuYm9vbAAAAAAAQ2xicmJvb2wAAAAAAFJnc01ib29sAAAAAABDcm5DYm9vbAAAAAAAQ250Q2Jvb2wAAAAAAExibHNib29sAAAAAABOZ3R2Ym9vbAAAAAAARW1sRGJvb2wAAAAAAEludHJib29sAAAAAABCY2tnT2JqYwAAAAEAAAAAAABSR0JDAAAAAwAAAABSZCAgZG91YkBv4AAAAAAAAAAAAEdybiBkb3ViQG/gAAAAAAAAAAAAQmwgIGRvdWJAb+AAAAAAAAAAAABCcmRUVW50RiNSbHQAAAAAAAAAAAAAAABCbGQgVW50RiNSbHQAAAAAAAAAAAAAAABSc2x0VW50RiNQeGxAUgAAAAAAAAAAAAp2ZWN0b3JEYXRhYm9vbAEAAAAAUGdQc2VudW0AAAAAUGdQcwAAAABQZ1BDAAAAAExlZnRVbnRGI1JsdAAAAAAAAAAAAAAAAFRvcCBVbnRGI1JsdAAAAAAAAAAAAAAAAFNjbCBVbnRGI1ByY0BZAAAAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAIASAAAAAEAAjhCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJTQPyAAAAAAAKAAD///////8AADhCSU0EDQAAAAAABAAAAB44QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAAAAABADhCSU0nEAAAAAAACgABAAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEAMgAAAAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklNA/gAAAAAAHAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAOEJJTQQIAAAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHgAAAAAABAAAAAA4QklNBBoAAAAAAzcAAAAGAAAAAAAAAAAAAAWgAAAEOAAAAAEAMQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAEOAAABaAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAG51bGwAAAACAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAABaAAAAAAUmdodGxvbmcAAAQ4AAAABnNsaWNlc1ZsTHMAAAABT2JqYwAAAAEAAAAAAAVzbGljZQAAABIAAAAHc2xpY2VJRGxvbmcAAAAAAAAAB2dyb3VwSURsb25nAAAAAAAAAAZvcmlnaW5lbnVtAAAADEVTbGljZU9yaWdpbgAAAA1hdXRvR2VuZXJhdGVkAAAAAFR5cGVlbnVtAAAACkVTbGljZVR5cGUAAAAASW1nIAAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAAWgAAAAAFJnaHRsb25nAAAEOAAAAAN1cmxURVhUAAAAAQAAAAAAAG51bGxURVhUAAAAAQAAAAAAAE1zZ2VURVhUAAAAAQAAAAAABmFsdFRhZ1RFWFQAAAABAAAAAAAOY2VsbFRleHRJc0hUTUxib29sAQAAAAhjZWxsVGV4dFRFWFQAAAABAAAAAAAJaG9yekFsaWduZW51bQAAAA9FU2xpY2VIb3J6QWxpZ24AAAAHZGVmYXVsdAAAAAl2ZXJ0QWxpZ25lbnVtAAAAD0VTbGljZVZlcnRBbGlnbgAA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cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6Y3JzPSJodHRwOi8vbnMuYWRvYmUuY29tL2NhbWVyYS1yYXctc2V0dGluZ3MvMS4wLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxNENGMEIzMjI1NjRFMTExODE0Mjg4QTlBRjEwQTA2QSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFQTdFRjgzQ0E5NjcxMUUxQjQzNzk1MDc3NTgwNEMxNyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0OThGN0RBQjZCQTlFMTExQTNFNEExRTZENDI2MjU2OSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyIgeG1wOkNyZWF0ZURhdGU9IjIwMTItMDUtMjlUMTM6NTU6NTcrMDU6MzAiIHhtcDpNb2RpZnlEYXRlPSIyMDEyLTA1LTI5VDE0OjQxOjIxKzA1OjMwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDEyLTA1LTI5VDE0OjQxOjIxKzA1OjMwIiBjcnM6QWxyZWFkeUFwcGxpZWQ9IlRydWUiIHBob3Rvc2hvcDpMZWdhY3lJUFRDRGlnZXN0PSIzOEI4NDdCNjUxMkVBNTVGMjk4ODcxODJBNEMyQTdFQSIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6OUIyMDFDQjlDNzk1RTExMTkyQjRFNzNBNjZCRjYyM0YiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDRjBCMzIyNTY0RTExMTgxNDI4OEE5QUYxMEEwNkEiLz4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MTdGNTM3RDc2MEE5RTExMUEzRTRBMUU2RDQyNjI1NjkiIHN0RXZ0OndoZW49IjIwMTItMDUtMjlUMTQ6MDk6MjIrMDU6MzAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUuMSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxOEY1MzdENzYwQTlFMTExQTNFNEExRTZENDI2MjU2OSIgc3RFdnQ6d2hlbj0iMjAxMi0wNS0yOVQxNDoxMjozOCswNTozMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjFERjUzN0Q3NjBBOUUxMTFBM0U0QTFFNkQ0MjYyNTY5IiBzdEV2dDp3aGVuPSIyMDEyLTA1LTI5VDE0OjIyOjIxKzA1OjMwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NDk4RjdEQUI2QkE5RTExMUEzRTRBMUU2RDQyNjI1NjkiIHN0RXZ0OndoZW49IjIwMTItMDUtMjlUMTQ6NDE6MjErMDU6MzAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUuMSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+/9sAQwABAQEBAQEBAQEBAQEBAgIDAgICAgIEAwMCAwUEBQUFBAQEBQYHBgUFBwYEBAYJBgcICAgICAUGCQoJCAoHCAgI/9sAQwEBAQECAgIEAgIECAUEBQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI/8AAEQgAUAA8AwERAAIRAQMRAf/EAB4AAAEEAgMBAAAAAAAAAAAAAAAHCQoLBggBAgUE/8QAPBAAAQMEAQMBBgIDEQAAAAAAAQIDBAUGBxEACBIhQQoTFCIxMglRYYHRFRYjJCZCRFJUcYKhpLGytMH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAQID/8QAIBEBAQACAgICAwAAAAAAAAAAAAECERIxIVEDQRNhgf/aAAwDAQACEQMRAD8An8cA4GqfWH1h4k6JcToy3l9ysu0d+os0iDDprbbkqdLcQtYQhK1oToIacWpRPgJ9fAJZNmp2faLejlTAcdx9mtt3R2gMQD/n8Rw1wpa+l38brpf6os42hgi3rXyLaNx191yNSpdUEQxnpCWXHfdLLbqlIKg0pKfB2ogeN8JcTzAIIBHkHhlzwDgHACQASfA4EEj2lrrDXknqks3pjtOrB21scU0v1f3Sh2O16chDi0Eg6JZipjI8/aqQ6Pz5qRvFGbkXTPZSU/ErHneu7m+LVZXibPN54fyjjzKl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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The items match!\n", - "Both the black shirt and the black watch have a sleek and coordinated look, making them suitable to be worn together as part of an outfit.\n" - ] - } - ], + "outputs": [], "source": [ "# Select the unique paths for the generated images\n", "paths = list(set(paths))\n", @@ -797,7 +593,7 @@ "source": [ "### Conclusion\n", "\n", - "In this Jupyter Notebook, we explored the application of GPT-4o and other machine learning techniques to the domain of fashion. We demonstrated how to analyze images of clothing items, extract relevant features, and use this information to find matching items that complement an original outfit. Through the implementation of guardrails and self-correction mechanisms, we refined the model's suggestions to ensure they are accurate and contextually relevant.\n", + "In this Jupyter Notebook, we explored the application of GPT-4o mini and other machine learning techniques to the domain of fashion. We demonstrated how to analyze images of clothing items, extract relevant features, and use this information to find matching items that complement an original outfit. Through the implementation of guardrails and self-correction mechanisms, we refined the model's suggestions to ensure they are accurate and contextually relevant.\n", "\n", "This approach has several practical uses in the real world, including:\n", "\n", @@ -805,7 +601,7 @@ "2. **Virtual Wardrobe Applications**: Users can upload images of their own clothing items to create a virtual wardrobe and receive suggestions for new items that match their existing pieces.\n", "3. **Fashion Design and Styling**: Fashion designers and stylists can use this tool to experiment with different combinations and styles, streamlining the creative process.\n", "\n", - "However, one of the considerations to keep in mind is **cost**. The use of LLMs and image analysis models can incur costs, especially if used extensively. It's important to consider the cost-effectiveness of implementing these technologies.\n", + "However, one of the considerations to keep in mind is **cost**. The use of LLMs and image analysis models can incur costs, especially if used extensively. It's important to consider the cost-effectiveness of implementing these technologies. `gpt-4o-mini` is priced at `$0.01` per 1000 tokens. This adds up to `$0.00255` for one 256px x 256px image.\n", "\n", "Overall, this notebook serves as a foundation for further exploration and development in the intersection of fashion and AI, opening doors to more personalized and intelligent fashion recommendation systems." ] @@ -813,7 +609,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -827,7 +623,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/How_to_stream_completions.ipynb b/examples/How_to_stream_completions.ipynb index a1d9098c..98ce1e2c 100644 --- a/examples/How_to_stream_completions.ipynb +++ b/examples/How_to_stream_completions.ipynb @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -62,16 +62,16 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Full response received 5.27 seconds after request\n", + "Full response received 1.88 seconds after request\n", "Full response received:\n", - "ChatCompletion(id='chatcmpl-8ZB8ywkV5DuuJO7xktqUcNYfG8j6I', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100.', role='assistant', function_call=None, tool_calls=None))], created=1703395008, model='gpt-3.5-turbo-0613', object='chat.completion', system_fingerprint=None, usage=CompletionUsage(completion_tokens=299, prompt_tokens=36, total_tokens=335))\n" + "ChatCompletion(id='chatcmpl-9lMgdoiMfxVHPDNVCtvXuTWcQ2GGb', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100', role='assistant', function_call=None, tool_calls=None))], created=1721075651, model='gpt-july-test', object='chat.completion', system_fingerprint='fp_e9b8ed65d2', usage=CompletionUsage(completion_tokens=298, prompt_tokens=36, total_tokens=334))\n" ] } ], @@ -84,7 +84,7 @@ "\n", "# send a ChatCompletion request to count to 100\n", "response = client.chat.completions.create(\n", - " model='gpt-3.5-turbo',\n", + " model='gpt-4o-mini',\n", " messages=[\n", " {'role': 'user', 'content': 'Count to 100, with a comma between each number and no newlines. E.g., 1, 2, 3, ...'}\n", " ],\n", @@ -110,7 +110,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -118,9 +118,9 @@ "output_type": "stream", "text": [ "Extracted reply: \n", - "ChatCompletionMessage(content='1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100.', role='assistant', function_call=None, tool_calls=None)\n", + "ChatCompletionMessage(content='1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100', role='assistant', function_call=None, tool_calls=None)\n", "Extracted content: \n", - "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100.\n" + "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100\n" ] } ], @@ -146,20 +146,23 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "ChatCompletionChunk(id='chatcmpl-8ZB9m2Ubv8FJs3CIb84WvYwqZCHST', choices=[Choice(delta=ChoiceDelta(content='', function_call=None, role='assistant', tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1703395058, model='gpt-3.5-turbo-0613', object='chat.completion.chunk', system_fingerprint=None)\n", + "ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content='', function_call=None, role='assistant', tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)\n", "\n", "****************\n", - "ChatCompletionChunk(id='chatcmpl-8ZB9m2Ubv8FJs3CIb84WvYwqZCHST', choices=[Choice(delta=ChoiceDelta(content='2', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1703395058, model='gpt-3.5-turbo-0613', object='chat.completion.chunk', system_fingerprint=None)\n", - "2\n", + "ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content='Two', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)\n", + "Two\n", "****************\n", - "ChatCompletionChunk(id='chatcmpl-8ZB9m2Ubv8FJs3CIb84WvYwqZCHST', choices=[Choice(delta=ChoiceDelta(content=None, function_call=None, role=None, tool_calls=None), finish_reason='stop', index=0, logprobs=None)], created=1703395058, model='gpt-3.5-turbo-0613', object='chat.completion.chunk', system_fingerprint=None)\n", + "ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content='.', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)\n", + ".\n", + "****************\n", + "ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content=None, function_call=None, role=None, tool_calls=None), finish_reason='stop', index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)\n", "None\n", "****************\n" ] @@ -171,7 +174,7 @@ "\n", "# a ChatCompletion request\n", "response = client.chat.completions.create(\n", - " model='gpt-3.5-turbo',\n", + " model='gpt-4o-mini',\n", " messages=[\n", " {'role': 'user', 'content': \"What's 1+1? Answer in one word.\"}\n", " ],\n", @@ -203,321 +206,320 @@ "source": [ "### 3. How much time is saved by streaming a chat completion\n", "\n", - "Now let's ask `gpt-3.5-turbo` to count to 100 again, and see how long it takes." + "Now let's ask `gpt-4o-mini` to count to 100 again, and see how long it takes." ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Message received 0.31 seconds after request: \n", - "Message received 0.31 seconds after request: 1\n", - "Message received 0.34 seconds after request: ,\n", - "Message received 0.34 seconds after request: \n", - "Message received 0.34 seconds after request: 2\n", - "Message received 0.39 seconds after request: ,\n", - "Message received 0.39 seconds after request: \n", - "Message received 0.39 seconds after request: 3\n", - "Message received 0.42 seconds after request: ,\n", - "Message received 0.42 seconds after request: \n", - "Message received 0.42 seconds after request: 4\n", - "Message received 0.47 seconds after request: ,\n", - "Message received 0.47 seconds after request: \n", - "Message received 0.47 seconds after request: 5\n", - "Message received 0.51 seconds after request: ,\n", - "Message received 0.51 seconds after request: \n", - "Message received 0.51 seconds after request: 6\n", - "Message received 0.55 seconds after request: ,\n", - "Message received 0.55 seconds after request: \n", - "Message received 0.55 seconds after request: 7\n", - "Message received 0.59 seconds after request: ,\n", - "Message received 0.59 seconds after request: \n", - "Message received 0.59 seconds after request: 8\n", - "Message received 0.63 seconds after request: ,\n", - "Message received 0.63 seconds after request: \n", - "Message received 0.63 seconds after request: 9\n", - "Message received 0.67 seconds after request: ,\n", - "Message received 0.67 seconds after request: \n", - "Message received 0.67 seconds after request: 10\n", - "Message received 0.71 seconds after request: ,\n", - "Message received 0.71 seconds after request: \n", - "Message received 0.71 seconds after request: 11\n", - "Message received 0.75 seconds after request: ,\n", - "Message received 0.75 seconds after request: \n", - "Message received 0.75 seconds after request: 12\n", - "Message received 0.98 seconds after request: ,\n", - "Message received 0.98 seconds after request: \n", - "Message received 0.98 seconds after request: 13\n", - "Message received 1.02 seconds after request: ,\n", - "Message received 1.02 seconds after request: \n", - "Message received 1.02 seconds after request: 14\n", - "Message received 1.04 seconds after request: ,\n", - "Message received 1.04 seconds after request: \n", - "Message received 1.04 seconds after request: 15\n", - "Message received 1.08 seconds after request: ,\n", - "Message received 1.08 seconds after request: \n", - "Message received 1.08 seconds after request: 16\n", - "Message received 1.12 seconds after request: ,\n", - "Message received 1.12 seconds after request: \n", - "Message received 1.12 seconds after request: 17\n", + "Message received 1.14 seconds after request: \n", + "Message received 1.14 seconds after request: 1\n", + "Message received 1.14 seconds after request: ,\n", + "Message received 1.14 seconds after request: \n", + "Message received 1.14 seconds after request: 2\n", "Message received 1.16 seconds after request: ,\n", "Message received 1.16 seconds after request: \n", - "Message received 1.16 seconds after request: 18\n", - "Message received 1.19 seconds after request: ,\n", - "Message received 1.19 seconds after request: \n", - "Message received 1.19 seconds after request: 19\n", - "Message received 1.23 seconds after request: ,\n", - "Message received 1.23 seconds after request: \n", - "Message received 1.23 seconds after request: 20\n", - "Message received 1.27 seconds after request: ,\n", - "Message received 1.27 seconds after request: \n", - "Message received 1.27 seconds after request: 21\n", - "Message received 1.31 seconds after request: ,\n", - "Message received 1.31 seconds after request: \n", - "Message received 1.31 seconds after request: 22\n", + "Message received 1.16 seconds after request: 3\n", "Message received 1.35 seconds after request: ,\n", "Message received 1.35 seconds after request: \n", - "Message received 1.35 seconds after request: 23\n", - "Message received 1.39 seconds after request: ,\n", - "Message received 1.39 seconds after request: \n", - "Message received 1.39 seconds after request: 24\n", - "Message received 1.43 seconds after request: ,\n", - "Message received 1.43 seconds after request: \n", - "Message received 1.43 seconds after request: 25\n", + "Message received 1.35 seconds after request: 4\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 5\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 6\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 7\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 8\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 9\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 10\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 11\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.36 seconds after request: 12\n", + "Message received 1.36 seconds after request: ,\n", + "Message received 1.36 seconds after request: \n", + "Message received 1.45 seconds after request: 13\n", + "Message received 1.45 seconds after request: ,\n", + "Message received 1.45 seconds after request: \n", + "Message received 1.45 seconds after request: 14\n", + "Message received 1.45 seconds after request: ,\n", + "Message received 1.45 seconds after request: \n", + "Message received 1.45 seconds after request: 15\n", + "Message received 1.45 seconds after request: ,\n", + "Message received 1.45 seconds after request: \n", + "Message received 1.46 seconds after request: 16\n", + "Message received 1.46 seconds after request: ,\n", + "Message received 1.46 seconds after request: \n", + "Message received 1.47 seconds after request: 17\n", "Message received 1.47 seconds after request: ,\n", "Message received 1.47 seconds after request: \n", - "Message received 1.47 seconds after request: 26\n", - "Message received 1.51 seconds after request: ,\n", - "Message received 1.51 seconds after request: \n", - "Message received 1.51 seconds after request: 27\n", + "Message received 1.49 seconds after request: 18\n", + "Message received 1.49 seconds after request: ,\n", + "Message received 1.49 seconds after request: \n", + "Message received 1.52 seconds after request: 19\n", + "Message received 1.52 seconds after request: ,\n", + "Message received 1.52 seconds after request: \n", + "Message received 1.53 seconds after request: 20\n", + "Message received 1.53 seconds after request: ,\n", + "Message received 1.53 seconds after request: \n", + "Message received 1.55 seconds after request: 21\n", "Message received 1.55 seconds after request: ,\n", "Message received 1.55 seconds after request: \n", - "Message received 1.55 seconds after request: 28\n", + "Message received 1.56 seconds after request: 22\n", + "Message received 1.56 seconds after request: ,\n", + "Message received 1.56 seconds after request: \n", + "Message received 1.58 seconds after request: 23\n", + "Message received 1.58 seconds after request: ,\n", + "Message received 1.58 seconds after request: \n", + "Message received 1.59 seconds after request: 24\n", "Message received 1.59 seconds after request: ,\n", "Message received 1.59 seconds after request: \n", - "Message received 1.59 seconds after request: 29\n", - "Message received 1.59 seconds after request: ,\n", - "Message received 1.59 seconds after request: \n", - "Message received 1.59 seconds after request: 30\n", - "Message received 1.59 seconds after request: ,\n", - "Message received 1.59 seconds after request: \n", - "Message received 1.59 seconds after request: 31\n", - "Message received 1.59 seconds after request: ,\n", - "Message received 1.59 seconds after request: \n", - "Message received 1.60 seconds after request: 32\n", - "Message received 1.60 seconds after request: ,\n", - "Message received 1.60 seconds after request: \n", - "Message received 1.60 seconds after request: 33\n", - "Message received 1.60 seconds after request: ,\n", - "Message received 1.60 seconds after request: \n", - "Message received 1.67 seconds after request: 34\n", + "Message received 1.62 seconds after request: 25\n", + "Message received 1.62 seconds after request: ,\n", + "Message received 1.62 seconds after request: \n", + "Message received 1.62 seconds after request: 26\n", + "Message received 1.62 seconds after request: ,\n", + "Message received 1.62 seconds after request: \n", + "Message received 1.65 seconds after request: 27\n", + "Message received 1.65 seconds after request: ,\n", + "Message received 1.65 seconds after request: \n", + "Message received 1.67 seconds after request: 28\n", "Message received 1.67 seconds after request: ,\n", "Message received 1.67 seconds after request: \n", - "Message received 1.68 seconds after request: 35\n", - "Message received 1.68 seconds after request: ,\n", - "Message received 1.68 seconds after request: \n", - "Message received 1.86 seconds after request: 36\n", - "Message received 1.86 seconds after request: ,\n", - "Message received 1.86 seconds after request: \n", - "Message received 1.90 seconds after request: 37\n", - "Message received 1.90 seconds after request: ,\n", - "Message received 1.90 seconds after request: \n", - "Message received 1.94 seconds after request: 38\n", - "Message received 1.94 seconds after request: ,\n", - "Message received 1.94 seconds after request: \n", - "Message received 1.98 seconds after request: 39\n", - "Message received 1.98 seconds after request: ,\n", - "Message received 1.98 seconds after request: \n", - "Message received 2.05 seconds after request: 40\n", - "Message received 2.05 seconds after request: ,\n", - "Message received 2.05 seconds after request: \n", - "Message received 2.09 seconds after request: 41\n", - "Message received 2.09 seconds after request: ,\n", - "Message received 2.09 seconds after request: \n", - "Message received 2.14 seconds after request: 42\n", - "Message received 2.14 seconds after request: ,\n", - "Message received 2.14 seconds after request: \n", - "Message received 2.14 seconds after request: 43\n", + "Message received 1.69 seconds after request: 29\n", + "Message received 1.69 seconds after request: ,\n", + "Message received 1.69 seconds after request: \n", + "Message received 1.80 seconds after request: 30\n", + "Message received 1.80 seconds after request: ,\n", + "Message received 1.80 seconds after request: \n", + "Message received 1.80 seconds after request: 31\n", + "Message received 1.80 seconds after request: ,\n", + "Message received 1.80 seconds after request: \n", + "Message received 1.80 seconds after request: 32\n", + "Message received 1.80 seconds after request: ,\n", + "Message received 1.80 seconds after request: \n", + "Message received 1.80 seconds after request: 33\n", + "Message received 1.80 seconds after request: ,\n", + "Message received 1.80 seconds after request: \n", + "Message received 1.80 seconds after request: 34\n", + "Message received 1.80 seconds after request: ,\n", + "Message received 1.80 seconds after request: \n", + "Message received 1.80 seconds after request: 35\n", + "Message received 1.80 seconds after request: ,\n", + "Message received 1.80 seconds after request: \n", + "Message received 1.80 seconds after request: 36\n", + "Message received 1.80 seconds after request: ,\n", + "Message received 1.80 seconds after request: \n", + "Message received 1.82 seconds after request: 37\n", + "Message received 1.82 seconds after request: ,\n", + "Message received 1.82 seconds after request: \n", + "Message received 1.83 seconds after request: 38\n", + "Message received 1.83 seconds after request: ,\n", + "Message received 1.83 seconds after request: \n", + "Message received 1.84 seconds after request: 39\n", + "Message received 1.84 seconds after request: ,\n", + "Message received 1.84 seconds after request: \n", + "Message received 1.87 seconds after request: 40\n", + "Message received 1.87 seconds after request: ,\n", + "Message received 1.87 seconds after request: \n", + "Message received 1.88 seconds after request: 41\n", + "Message received 1.88 seconds after request: ,\n", + "Message received 1.88 seconds after request: \n", + "Message received 1.91 seconds after request: 42\n", + "Message received 1.91 seconds after request: ,\n", + "Message received 1.91 seconds after request: \n", + "Message received 1.93 seconds after request: 43\n", + "Message received 1.93 seconds after request: ,\n", + "Message received 1.93 seconds after request: \n", + "Message received 1.93 seconds after request: 44\n", + "Message received 1.93 seconds after request: ,\n", + "Message received 1.93 seconds after request: \n", + "Message received 1.95 seconds after request: 45\n", + "Message received 1.95 seconds after request: ,\n", + "Message received 1.95 seconds after request: \n", + "Message received 2.00 seconds after request: 46\n", + "Message received 2.00 seconds after request: ,\n", + "Message received 2.00 seconds after request: \n", + "Message received 2.00 seconds after request: 47\n", + "Message received 2.00 seconds after request: ,\n", + "Message received 2.00 seconds after request: \n", + "Message received 2.00 seconds after request: 48\n", + "Message received 2.00 seconds after request: ,\n", + "Message received 2.00 seconds after request: \n", + "Message received 2.00 seconds after request: 49\n", + "Message received 2.00 seconds after request: ,\n", + "Message received 2.00 seconds after request: \n", + "Message received 2.00 seconds after request: 50\n", + "Message received 2.00 seconds after request: ,\n", + "Message received 2.00 seconds after request: \n", + "Message received 2.00 seconds after request: 51\n", + "Message received 2.00 seconds after request: ,\n", + "Message received 2.04 seconds after request: \n", + "Message received 2.04 seconds after request: 52\n", + "Message received 2.04 seconds after request: ,\n", + "Message received 2.04 seconds after request: \n", + "Message received 2.04 seconds after request: 53\n", + "Message received 2.04 seconds after request: ,\n", + "Message received 2.13 seconds after request: \n", + "Message received 2.13 seconds after request: 54\n", "Message received 2.14 seconds after request: ,\n", "Message received 2.14 seconds after request: \n", - "Message received 2.14 seconds after request: 44\n", + "Message received 2.14 seconds after request: 55\n", "Message received 2.14 seconds after request: ,\n", "Message received 2.14 seconds after request: \n", - "Message received 2.14 seconds after request: 45\n", + "Message received 2.14 seconds after request: 56\n", "Message received 2.14 seconds after request: ,\n", "Message received 2.14 seconds after request: \n", - "Message received 2.15 seconds after request: 46\n", - "Message received 2.15 seconds after request: ,\n", - "Message received 2.15 seconds after request: \n", - "Message received 2.30 seconds after request: 47\n", - "Message received 2.30 seconds after request: ,\n", - "Message received 2.30 seconds after request: \n", - "Message received 2.30 seconds after request: 48\n", - "Message received 2.30 seconds after request: ,\n", - "Message received 2.30 seconds after request: \n", - "Message received 2.30 seconds after request: 49\n", - "Message received 2.30 seconds after request: ,\n", - "Message received 2.30 seconds after request: \n", - "Message received 2.31 seconds after request: 50\n", - "Message received 2.31 seconds after request: ,\n", - "Message received 2.31 seconds after request: \n", - "Message received 2.39 seconds after request: 51\n", + "Message received 2.16 seconds after request: 57\n", + "Message received 2.16 seconds after request: ,\n", + "Message received 2.16 seconds after request: \n", + "Message received 2.17 seconds after request: 58\n", + "Message received 2.17 seconds after request: ,\n", + "Message received 2.17 seconds after request: \n", + "Message received 2.19 seconds after request: 59\n", + "Message received 2.19 seconds after request: ,\n", + "Message received 2.19 seconds after request: \n", + "Message received 2.21 seconds after request: 60\n", + "Message received 2.21 seconds after request: ,\n", + "Message received 2.21 seconds after request: \n", + "Message received 2.34 seconds after request: 61\n", + "Message received 2.34 seconds after request: ,\n", + "Message received 2.34 seconds after request: \n", + "Message received 2.34 seconds after request: 62\n", + "Message received 2.34 seconds after request: ,\n", + "Message received 2.34 seconds after request: \n", + "Message received 2.34 seconds after request: 63\n", + "Message received 2.34 seconds after request: ,\n", + "Message received 2.34 seconds after request: \n", + "Message received 2.34 seconds after request: 64\n", + "Message received 2.34 seconds after request: ,\n", + "Message received 2.34 seconds after request: \n", + "Message received 2.34 seconds after request: 65\n", + "Message received 2.34 seconds after request: ,\n", + "Message received 2.34 seconds after request: \n", + "Message received 2.34 seconds after request: 66\n", + "Message received 2.34 seconds after request: ,\n", + "Message received 2.34 seconds after request: \n", + "Message received 2.34 seconds after request: 67\n", + "Message received 2.34 seconds after request: ,\n", + "Message received 2.34 seconds after request: \n", + "Message received 2.36 seconds after request: 68\n", + "Message received 2.36 seconds after request: ,\n", + "Message received 2.36 seconds after request: \n", + "Message received 2.36 seconds after request: 69\n", + "Message received 2.36 seconds after request: ,\n", + "Message received 2.36 seconds after request: \n", + "Message received 2.38 seconds after request: 70\n", + "Message received 2.38 seconds after request: ,\n", + "Message received 2.38 seconds after request: \n", + "Message received 2.39 seconds after request: 71\n", "Message received 2.39 seconds after request: ,\n", "Message received 2.39 seconds after request: \n", - "Message received 2.40 seconds after request: 52\n", - "Message received 2.40 seconds after request: ,\n", + "Message received 2.39 seconds after request: 72\n", + "Message received 2.39 seconds after request: ,\n", + "Message received 2.39 seconds after request: \n", + "Message received 2.39 seconds after request: 73\n", + "Message received 2.39 seconds after request: ,\n", + "Message received 2.39 seconds after request: \n", + "Message received 2.39 seconds after request: 74\n", + "Message received 2.39 seconds after request: ,\n", + "Message received 2.39 seconds after request: \n", + "Message received 2.39 seconds after request: 75\n", + "Message received 2.39 seconds after request: ,\n", "Message received 2.40 seconds after request: \n", - "Message received 2.48 seconds after request: 53\n", - "Message received 2.48 seconds after request: ,\n", - "Message received 2.48 seconds after request: \n", - "Message received 2.49 seconds after request: 54\n", - "Message received 2.49 seconds after request: ,\n", - "Message received 2.49 seconds after request: \n", - "Message received 2.68 seconds after request: 55\n", + "Message received 2.40 seconds after request: 76\n", + "Message received 2.40 seconds after request: ,\n", + "Message received 2.42 seconds after request: \n", + "Message received 2.42 seconds after request: 77\n", + "Message received 2.42 seconds after request: ,\n", + "Message received 2.51 seconds after request: \n", + "Message received 2.51 seconds after request: 78\n", + "Message received 2.51 seconds after request: ,\n", + "Message received 2.52 seconds after request: \n", + "Message received 2.52 seconds after request: 79\n", + "Message received 2.52 seconds after request: ,\n", + "Message received 2.52 seconds after request: \n", + "Message received 2.52 seconds after request: 80\n", + "Message received 2.52 seconds after request: ,\n", + "Message received 2.52 seconds after request: \n", + "Message received 2.52 seconds after request: 81\n", + "Message received 2.52 seconds after request: ,\n", + "Message received 2.52 seconds after request: \n", + "Message received 2.52 seconds after request: 82\n", + "Message received 2.52 seconds after request: ,\n", + "Message received 2.60 seconds after request: \n", + "Message received 2.60 seconds after request: 83\n", + "Message received 2.60 seconds after request: ,\n", + "Message received 2.64 seconds after request: \n", + "Message received 2.64 seconds after request: 84\n", + "Message received 2.64 seconds after request: ,\n", + "Message received 2.64 seconds after request: \n", + "Message received 2.64 seconds after request: 85\n", + "Message received 2.64 seconds after request: ,\n", + "Message received 2.64 seconds after request: \n", + "Message received 2.66 seconds after request: 86\n", + "Message received 2.66 seconds after request: ,\n", + "Message received 2.66 seconds after request: \n", + "Message received 2.66 seconds after request: 87\n", + "Message received 2.66 seconds after request: ,\n", + "Message received 2.66 seconds after request: \n", + "Message received 2.68 seconds after request: 88\n", "Message received 2.68 seconds after request: ,\n", "Message received 2.68 seconds after request: \n", - "Message received 2.72 seconds after request: 56\n", + "Message received 2.69 seconds after request: 89\n", + "Message received 2.69 seconds after request: ,\n", + "Message received 2.69 seconds after request: \n", + "Message received 2.72 seconds after request: 90\n", "Message received 2.72 seconds after request: ,\n", "Message received 2.72 seconds after request: \n", - "Message received 2.77 seconds after request: 57\n", - "Message received 2.77 seconds after request: ,\n", - "Message received 2.77 seconds after request: \n", - "Message received 2.80 seconds after request: 58\n", - "Message received 2.80 seconds after request: ,\n", - "Message received 2.80 seconds after request: \n", - "Message received 2.85 seconds after request: 59\n", - "Message received 2.85 seconds after request: ,\n", - "Message received 2.85 seconds after request: \n", - "Message received 2.88 seconds after request: 60\n", - "Message received 2.88 seconds after request: ,\n", - "Message received 2.88 seconds after request: \n", - "Message received 2.88 seconds after request: 61\n", - "Message received 2.88 seconds after request: ,\n", - "Message received 2.88 seconds after request: \n", - "Message received 2.89 seconds after request: 62\n", - "Message received 2.89 seconds after request: ,\n", - "Message received 2.89 seconds after request: \n", - "Message received 2.89 seconds after request: 63\n", - "Message received 2.89 seconds after request: ,\n", - "Message received 2.89 seconds after request: \n", - "Message received 2.92 seconds after request: 64\n", - "Message received 2.92 seconds after request: ,\n", - "Message received 2.92 seconds after request: \n", - "Message received 3.37 seconds after request: 65\n", - "Message received 3.37 seconds after request: ,\n", - "Message received 3.37 seconds after request: \n", - "Message received 3.38 seconds after request: 66\n", - "Message received 3.38 seconds after request: ,\n", - "Message received 3.38 seconds after request: \n", - "Message received 3.38 seconds after request: 67\n", - "Message received 3.38 seconds after request: ,\n", - "Message received 3.38 seconds after request: \n", - "Message received 3.38 seconds after request: 68\n", - "Message received 3.38 seconds after request: ,\n", - "Message received 3.38 seconds after request: \n", - "Message received 3.42 seconds after request: 69\n", - "Message received 3.42 seconds after request: ,\n", - "Message received 3.42 seconds after request: \n", - "Message received 3.43 seconds after request: 70\n", - "Message received 3.43 seconds after request: ,\n", - "Message received 3.43 seconds after request: \n", - "Message received 3.46 seconds after request: 71\n", - "Message received 3.46 seconds after request: ,\n", - "Message received 3.46 seconds after request: \n", - "Message received 3.47 seconds after request: 72\n", - "Message received 3.47 seconds after request: ,\n", - "Message received 3.47 seconds after request: \n", - "Message received 3.50 seconds after request: 73\n", - "Message received 3.50 seconds after request: ,\n", - "Message received 3.50 seconds after request: \n", - "Message received 3.51 seconds after request: 74\n", - "Message received 3.51 seconds after request: ,\n", - "Message received 3.51 seconds after request: \n", - "Message received 3.52 seconds after request: 75\n", - "Message received 3.52 seconds after request: ,\n", - "Message received 3.52 seconds after request: \n", - "Message received 3.54 seconds after request: 76\n", - "Message received 3.54 seconds after request: ,\n", - "Message received 3.54 seconds after request: \n", - "Message received 3.56 seconds after request: 77\n", - "Message received 3.56 seconds after request: ,\n", - "Message received 3.56 seconds after request: \n", - "Message received 3.59 seconds after request: 78\n", - "Message received 3.59 seconds after request: ,\n", - "Message received 3.59 seconds after request: \n", - "Message received 3.59 seconds after request: 79\n", - "Message received 3.59 seconds after request: ,\n", - "Message received 3.59 seconds after request: \n", - "Message received 3.59 seconds after request: 80\n", - "Message received 3.59 seconds after request: ,\n", - "Message received 3.59 seconds after request: \n", - "Message received 3.61 seconds after request: 81\n", - "Message received 3.61 seconds after request: ,\n", - "Message received 3.61 seconds after request: \n", - "Message received 3.65 seconds after request: 82\n", - "Message received 3.65 seconds after request: ,\n", - "Message received 3.65 seconds after request: \n", - "Message received 3.85 seconds after request: 83\n", - "Message received 3.85 seconds after request: ,\n", - "Message received 3.85 seconds after request: \n", - "Message received 3.90 seconds after request: 84\n", - "Message received 3.90 seconds after request: ,\n", - "Message received 3.90 seconds after request: \n", - "Message received 3.95 seconds after request: 85\n", - "Message received 3.95 seconds after request: ,\n", - "Message received 3.95 seconds after request: \n", - "Message received 4.00 seconds after request: 86\n", - "Message received 4.00 seconds after request: ,\n", - "Message received 4.00 seconds after request: \n", - "Message received 4.04 seconds after request: 87\n", - "Message received 4.04 seconds after request: ,\n", - "Message received 4.04 seconds after request: \n", - "Message received 4.08 seconds after request: 88\n", - "Message received 4.08 seconds after request: ,\n", - "Message received 4.08 seconds after request: \n", - "Message received 4.12 seconds after request: 89\n", - "Message received 4.12 seconds after request: ,\n", - "Message received 4.12 seconds after request: \n", - "Message received 4.18 seconds after request: 90\n", - "Message received 4.18 seconds after request: ,\n", - "Message received 4.18 seconds after request: \n", - "Message received 4.18 seconds after request: 91\n", - "Message received 4.18 seconds after request: ,\n", - "Message received 4.18 seconds after request: \n", - "Message received 4.18 seconds after request: 92\n", - "Message received 4.18 seconds after request: ,\n", - "Message received 4.18 seconds after request: \n", - "Message received 4.19 seconds after request: 93\n", - "Message received 4.19 seconds after request: ,\n", - "Message received 4.19 seconds after request: \n", - "Message received 4.20 seconds after request: 94\n", - "Message received 4.20 seconds after request: ,\n", - "Message received 4.20 seconds after request: \n", - "Message received 4.23 seconds after request: 95\n", - "Message received 4.23 seconds after request: ,\n", - "Message received 4.23 seconds after request: \n", - "Message received 4.27 seconds after request: 96\n", - "Message received 4.27 seconds after request: ,\n", - "Message received 4.27 seconds after request: \n", - "Message received 4.39 seconds after request: 97\n", - "Message received 4.39 seconds after request: ,\n", - "Message received 4.39 seconds after request: \n", - "Message received 4.39 seconds after request: 98\n", - "Message received 4.39 seconds after request: ,\n", - "Message received 4.39 seconds after request: \n", - "Message received 4.41 seconds after request: 99\n", - "Message received 4.41 seconds after request: ,\n", - "Message received 4.41 seconds after request: \n", - "Message received 4.41 seconds after request: 100\n", - "Message received 4.41 seconds after request: .\n", - "Message received 4.41 seconds after request: None\n", - "Full response received 4.41 seconds after request\n", - "Full conversation received: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100.\n" + "Message received 2.82 seconds after request: 91\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 92\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 93\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 94\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 95\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 96\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 97\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 98\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 99\n", + "Message received 2.82 seconds after request: ,\n", + "Message received 2.82 seconds after request: \n", + "Message received 2.82 seconds after request: 100\n", + "Message received 2.82 seconds after request: None\n", + "Full response received 2.82 seconds after request\n", + "Full conversation received: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100\n" ] } ], @@ -530,7 +532,7 @@ "\n", "# send a ChatCompletion request to count to 100\n", "response = client.chat.completions.create(\n", - " model='gpt-3.5-turbo',\n", + " model='gpt-4o-mini',\n", " messages=[\n", " {'role': 'user', 'content': 'Count to 100, with a comma between each number and no newlines. E.g., 1, 2, 3, ...'}\n", " ],\n", @@ -584,7 +586,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -594,14 +596,17 @@ "choices: [Choice(delta=ChoiceDelta(content='', function_call=None, role='assistant', tool_calls=None), finish_reason=None, index=0, logprobs=None)]\n", "usage: None\n", "****************\n", - "choices: [Choice(delta=ChoiceDelta(content='2', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)]\n", + "choices: [Choice(delta=ChoiceDelta(content='Two', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)]\n", + "usage: None\n", + "****************\n", + "choices: [Choice(delta=ChoiceDelta(content='.', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)]\n", "usage: None\n", "****************\n", "choices: [Choice(delta=ChoiceDelta(content=None, function_call=None, role=None, tool_calls=None), finish_reason='stop', index=0, logprobs=None)]\n", "usage: None\n", "****************\n", "choices: []\n", - "usage: CompletionUsage(completion_tokens=1, prompt_tokens=19, total_tokens=20)\n", + "usage: CompletionUsage(completion_tokens=2, prompt_tokens=18, total_tokens=20)\n", "****************\n" ] } @@ -611,7 +616,7 @@ "\n", "# a ChatCompletion request\n", "response = client.chat.completions.create(\n", - " model='gpt-3.5-turbo',\n", + " model='gpt-4o-mini',\n", " messages=[\n", " {'role': 'user', 'content': \"What's 1+1? Answer in one word.\"}\n", " ],\n", @@ -624,13 +629,6 @@ " print(f\"choices: {chunk.choices}\\nusage: {chunk.usage}\")\n", " print(\"****************\")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -649,7 +647,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.3" + "version": "3.11.8" }, "orig_nbformat": 4, "vscode": { diff --git a/examples/How_to_use_guardrails.ipynb b/examples/How_to_use_guardrails.ipynb index 4915c181..dba07f0d 100644 --- a/examples/How_to_use_guardrails.ipynb +++ b/examples/How_to_use_guardrails.ipynb @@ -22,14 +22,14 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 20, "id": "ef059e71", "metadata": {}, "outputs": [], "source": [ "import openai\n", "\n", - "GPT_MODEL = 'gpt-3.5-turbo'" + "GPT_MODEL = 'gpt-4o-mini'" ] }, { @@ -50,8 +50,8 @@ "\n", "When designing guardrails it is important to consider the trade-off between **accuracy**, **latency** and **cost**, where you try to achieve maximum accuracy for the least impact to your bottom line and the user's experience. \n", "\n", - "We'll begin with a simple **topical guardrail** which aims to detect off-topic questions and prevent the LLM from answering if triggered. This guardrail consists of a simple prompt and uses `gpt-3.5-turbo`, maximising latency/cost over accuracy, but if we wanted to optimize further we could consider:\n", - "- **Accuracy:** You could consider using a fine-tuned model or few-shot examples to increase the accuracy. RAG can also be effective if you have a corpus of information that can help determine whether a piece of content is allowed or not.\n", + "We'll begin with a simple **topical guardrail** which aims to detect off-topic questions and prevent the LLM from answering if triggered. This guardrail consists of a simple prompt and uses `gpt-4o-mini`, maximising latency/cost holding a good enough accuracy, but if we wanted to optimize further we could consider:\n", + "- **Accuracy:** You could consider fine-tuning `gpt-4o-mini` or few-shot examples to increase the accuracy. RAG can also be effective if you have a corpus of information that can help determine whether a piece of content is allowed or not.\n", "- **Latency/Cost:** You could try fine-tuning smaller models, such as `babbage-002` or open-source offerings like Llama, which can perform quite well when given enough training examples. When using open-source offerings you can also tune the machines you are using for inference to maximize either cost or latency reduction.\n", "\n", "This simple guardrail aims to ensure the LLM only answers to a predefined set of topics, and responds to out-of-bounds queries with a canned message.\n", @@ -78,7 +78,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 21, "id": "e95efc89", "metadata": {}, "outputs": [], @@ -91,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 22, "id": "fee948e2", "metadata": {}, "outputs": [], @@ -153,7 +153,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 23, "id": "eba51754", "metadata": {}, "outputs": [ @@ -165,19 +165,29 @@ "Got guardrail response\n", "Getting LLM response\n", "Got LLM response\n", - "If you're a cat lover considering getting a dog, it's important to choose a breed that typically has a more cat-like temperament. Here are some dog breeds that are known to be more cat-friendly:\n", + "If you like cats and are considering getting a dog, there are several breeds known for their compatibility with feline friends. Here are some of the best dog breeds that tend to get along well with cats:\n", "\n", - "1. Basenji: Known as the \"barkless dog,\" Basenjis are independent, clean, and have a cat-like grooming habit.\n", + "1. **Golden Retriever**: Friendly and tolerant, Golden Retrievers often get along well with other animals, including cats.\n", "\n", - "2. Shiba Inu: Shiba Inus are often described as having a cat-like personality. They are independent, clean, and tend to be reserved with strangers.\n", + "2. **Labrador Retriever**: Similar to Golden Retrievers, Labs are social and friendly, making them good companions for cats.\n", "\n", - "3. Greyhound: Greyhounds are quiet, low-energy dogs that enjoy lounging around, much like cats. They are also known for their gentle and calm nature.\n", + "3. **Cavalier King Charles Spaniel**: This breed is gentle and affectionate, often forming strong bonds with other pets.\n", "\n", - "4. Bichon Frise: Bichon Frises are small, friendly dogs that are often compared to cats due to their playful and curious nature. They are also hypoallergenic, making them a good choice for those with allergies.\n", + "4. **Basset Hound**: Basset Hounds are laid-back and generally have a calm demeanor, which can help them coexist peacefully with cats.\n", "\n", - "5. Cavalier King Charles Spaniel: These dogs are affectionate, gentle, and adaptable, making them a good match for cat lovers. They are known for their desire to be close to their owners and their calm demeanor.\n", + "5. **Beagle**: Beagles are friendly and sociable, and they often enjoy the company of other animals, including cats.\n", "\n", - "Remember, individual dogs can have different personalities, so it's important to spend time with the specific dog you're considering to see if their temperament aligns with your preferences.\n" + "6. **Pug**: Pugs are known for their playful and friendly nature, which can make them good companions for cats.\n", + "\n", + "7. **Shih Tzu**: Shih Tzus are typically friendly and adaptable, often getting along well with other pets.\n", + "\n", + "8. **Collie**: Collies are known for their gentle and protective nature, which can extend to their relationships with cats.\n", + "\n", + "9. **Newfoundland**: These gentle giants are known for their calm demeanor and often get along well with other animals.\n", + "\n", + "10. **Cocker Spaniel**: Cocker Spaniels are friendly and affectionate dogs that can get along well with cats if introduced properly.\n", + "\n", + "When introducing a dog to a cat, it's important to do so gradually and supervise their interactions to ensure a positive relationship. Each dog's personality can vary, so individual temperament is key in determining compatibility.\n" ] } ], @@ -189,7 +199,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 24, "id": "c7d88b57", "metadata": {}, "outputs": [ @@ -254,7 +264,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 16, "id": "6c7b459f", "metadata": {}, "outputs": [], @@ -294,7 +304,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 17, "id": "43e3fd36", "metadata": {}, "outputs": [], @@ -347,7 +357,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 18, "id": "beea1305", "metadata": {}, "outputs": [], @@ -358,7 +368,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 19, "id": "1c582b4d", "metadata": {}, "outputs": [ @@ -392,30 +402,8 @@ "Got LLM response\n", "Checking moderation guardrail\n", "Got moderation response\n", - "Passed moderation\n", - "As a new dog owner, here are some helpful tips:\n", - "\n", - "1. Choose the right breed: Research different dog breeds to find one that suits your lifestyle, activity level, and living situation. Some breeds require more exercise and attention than others.\n", - "\n", - "2. Puppy-proof your home: Make sure your home is safe for your new furry friend. Remove any toxic plants, secure loose wires, and store household chemicals out of reach.\n", - "\n", - "3. Establish a routine: Dogs thrive on routine, so establish a consistent schedule for feeding, exercise, and bathroom breaks. This will help your dog feel secure and reduce any anxiety.\n", - "\n", - "4. Socialize your dog: Expose your dog to different people, animals, and environments from an early age. This will help them become well-adjusted and comfortable in various situations.\n", - "\n", - "5. Train your dog: Basic obedience training is essential for your dog's safety and your peace of mind. Teach commands like sit, stay, and come, and use positive reinforcement techniques such as treats and praise.\n", - "\n", - "6. Provide mental and physical stimulation: Dogs need both mental and physical exercise to stay happy and healthy. Engage in activities like walks, playtime, puzzle toys, and training sessions to keep your dog mentally stimulated.\n", - "\n", - "7. Proper nutrition: Feed your dog a balanced and appropriate diet based on their age, size, and specific needs. Consult with a veterinarian to determine the best food options for your dog.\n", - "\n", - "8. Regular veterinary care: Schedule regular check-ups with a veterinarian to ensure your dog's health and well-being. Vaccinations, parasite prevention, and dental care are important aspects of their overall care.\n", - "\n", - "9. Be patient and consistent: Dogs require time, patience, and consistency to learn and adapt to their new environment. Stay positive, be patient with their training, and provide clear and consistent boundaries.\n", - "\n", - "10. Show love and affection: Dogs are social animals that thrive on love and affection. Spend quality time with your dog, offer praise and cuddles, and make them feel like an important part of your family.\n", - "\n", - "Remember, being a responsible dog owner involves commitment, time, and effort. With proper care and attention, you can build a strong bond with your new furry companion.\n", + "Moderation guardrail flagged with a score of 3\n", + "Sorry, we're not permitted to give animal breed advice. I can help you with any general queries you might have.\n", "\n", "\n", "\n" @@ -447,13 +435,19 @@ "\n", "We look forward to seeing how you take this forward, and how thinking on guardrails evolves as the ecosystem matures. " ] + }, + { + "cell_type": "markdown", + "id": "5ed7b04d", + "metadata": {}, + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "openai_test", + "display_name": "Python 3", "language": "python", - "name": "openai_test" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -465,7 +459,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.8" } }, "nbformat": 4, diff --git a/examples/How_to_use_moderation.ipynb b/examples/How_to_use_moderation.ipynb index 39b8d264..6b25c9f1 100644 --- a/examples/How_to_use_moderation.ipynb +++ b/examples/How_to_use_moderation.ipynb @@ -26,7 +26,7 @@ "from openai import OpenAI\n", "client = OpenAI()\n", "\n", - "GPT_MODEL = 'gpt-3.5-turbo'" + "GPT_MODEL = 'gpt-4o-mini'" ] }, { @@ -339,7 +339,7 @@ "Custom moderation provides a tailored approach to content filtering, allowing for precise adherence to specific community standards or topics, making it an ideal choice for niche platforms or specialized content. Unlike the general categories covered by the moderation API, custom moderation offers a higher degree of control and requires more effort to set up and maintain. It shares the common goal of ensuring content safety with guardrails, focusing on setting criteria to filter and manage content, whether it's user input or output from language models. Custom moderation can be an alternative or an extension to the moderation API, that uses our completions endpoint. For those interested in exploring guardrails further, a cookbook with examples and guidance is available [here](https://cookbook.openai.com/examples/how_to_use_guardrails).\n", "\n", "#### Workflow\n", - "We will implement a small example to showcase custom moderation. We will use an extra call to gpt-4 to assess messages and decide if they should be moderated or not." + "We will implement a small example to showcase custom moderation. We will use an extra call to gpt-4o mini to assess messages and decide if they should be moderated or not." ] }, { @@ -349,7 +349,7 @@ "outputs": [], "source": [ "def custom_moderation(content, parameters):\n", - " # Define the prompt for GPT-4\n", + " # Define the prompt \n", " prompt = f\"\"\"Please assess the following content for any inappropriate material. You should base your assessment on the given parameters.\n", " Your answer should be in json format with the following fields: \n", " - flagged: a boolean indicating whether the content is flagged for any of the categories in the parameters\n", @@ -357,9 +357,9 @@ " - parameters: a dictionary of the parameters used for the assessment and their values\n", " Parameters: {parameters}\\n\\nContent:\\n{content}\\n\\nAssessment:\"\"\"\n", " \n", - " # Call GPT-4 with the prompt\n", + " # Call model with the prompt\n", " response = client.chat.completions.create(\n", - " model=\"gpt-4-turbo-preview\",\n", + " model=\"gpt-4o-mini\",\n", " response_format={ \"type\": \"json_object\" },\n", " messages=[\n", " {\"role\": \"system\", \"content\": \"You are a content moderation assistant.\"},\n", diff --git a/examples/SDG1.ipynb b/examples/SDG1.ipynb index 02fd5eb3..bdf22886 100644 --- a/examples/SDG1.ipynb +++ b/examples/SDG1.ipynb @@ -1,1276 +1,2166 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "I_IHQTO8xXBn" - }, - "source": [ - "# Synthetic Data generation (Part 1)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "VBoxtnxVdTWZ" - }, - "source": [ - "\n", - "Synthetic data generation using large language models (LLMs) offers a powerful solution to a commonly faced problem: the availability of high-quality, diverse, and privacy-compliant data. This could be used in a number of scenarios such as training a data science machine learning model (SVMs, decision trees, KNN's), finetuning a different GPT model on the data, as a solution to the coldstart problem, helping build compelling demos/apps with realistic data, scenario testing etc.\n", - "\n", - "There are a number of key drivers which may see you wanting to leverage synthetic data. \n", - "1. Human data may have privacy restrictions and/or identifiable data within it which we do not want to be used. \n", - "2. Synthetic data can be much more structured and therefore easier to manipulate than real data. \n", - "3. In domains where data is sparse or data of certain categories is sparse we may want to augment the data. \n", - "4. When dealing with imbalanced datasets or datasets which lack diversity, we may want to create data to improve the richness of our datasets.\n", - "\n", - "Unlike traditional data augmentation or manual data creation methods, using LLMs allows for the generation of rich, nuanced, and contextually relevant datasets that can significantly enhance it's usefulness to enterprises and developers.\n", - "\n", - "We split this tutorial into 2 parts. In this cookbook, we will have the following agenda:\n", - "1. CSV with a structured prompt\n", - "2. CSV with a Python program\n", - "3. Multitable CSV with a python program\n", - "4. Simply creating textual data\n", - "5. Dealing with imbalanced or non-diverse textual data\n", - "while in part 2, we will look at prompting strategies for getting better textual data.\n", - "\n", - "The last two in particular are useful for creating synthetic data to finetune another GPT model. For example using higher quality data produced by gpt-4 to finetune the cheaper and quicker gpt-3.5 for improved performance while reducing costs.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "NE9Rr29zlRsA" - }, - "source": [ - "### Getting setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "YGncxYrgQ8eb" - }, - "outputs": [], - "source": [ - "%pip install openai\n", - "%pip install pandas\n", - "%pip install scikit-learn\n", - "%pip install matplotlib" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "id": "8pzwvE-YQPtU" - }, - "outputs": [], - "source": [ - "from openai import OpenAI\n", - "import re\n", - "import numpy as np\n", - "import pandas as pd\n", - "from sklearn.cluster import KMeans\n", - "import matplotlib.pyplot as plt\n", - "import json\n", - "import matplotlib" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "B8eAx4-JxaZB" - }, - "source": [ - "### 1. CSV with a structure prompt\n", - "Here we create data in the simplest way. You can quickly generate data by addressing 3 key points: telling it the format of the data (CSV), the schema, and useful information regarding how columns relate (the LLM will be able to deduce this from the column names but a helping hand will improve performance)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "dqbvepd0n4vS", - "outputId": "8735cacc-baa5-463e-938c-783e6b508b00" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "```csv\n", - "id,house size,house price,location,number of bedrooms\n", - "1,100,220000,Suburbs,3\n", - "2,80,180000,Suburbs,2\n", - "3,120,320000,Suburbs,4\n", - "4,65,160000,Countryside,2\n", - "5,150,500000,City Center,4\n", - "6,90,200000,Countryside,3\n", - "7,200,700000,City Center,5\n", - "8,180,600000,Suburbs,5\n", - "9,70,140000,Countryside,2\n", - "10,130,400000,City Center,3\n", - "```\n" - ] - } - ], - "source": [ - "datagen_model = \"gpt-4-0125-preview\"\n", - "question = \"\"\"\n", - "Create a CSV file with 10 rows of housing data.\n", - "Each row should include the following fields:\n", - " - id (incrementing integer starting at 1)\n", - " - house size (m^2)\n", - " - house price\n", - " - location\n", - " - number of bedrooms\n", - "\n", - "Make sure that the numbers make sense (i.e. more rooms is usually bigger size, more expensive locations increase price. more size is usually higher price etc. make sure all the numbers make sense). Also only respond with the CSV.\n", - "\"\"\"\n", - "\n", - "response = client.chat.completions.create(\n", - " model=datagen_model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", - " {\"role\": \"user\", \"content\": question}\n", - " ]\n", - ")\n", - "res = response.choices[0].message.content\n", - "print(res)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "6ym0NiIyxiVj" - }, - "source": [ - "### 2. CSV with a Python program\n", - "The issue with generating data directly is we are limited in the amount of data we can generate because of the context. Instead what we can do is ask the LLM to generate a python program to generate the synthetic data. This allows us to scale to much more data while also providing us a view into how the data was generated by inspecting the python program.\n", - "\n", - "This would then let us edit the python program as we desire while giving us a good basis to start from.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "2yDuwB5ZxWS3", - "outputId": "dcbe1093-90f0-4f60-d9c6-34bf679bb092" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "To generate synthetic housing data and output it as a Pandas DataFrame, we can use Python with the `pandas` and `numpy` libraries. Below is a script that creates 100 rows of housing data considering the prescribed logic for house size, price, and number of bedrooms. It also takes into account the impact of location on house price.\n", - "\n", - "First, ensure you have pandas and numpy installed. You can install them via pip if you haven't already:\n", - "\n", - "```\n", - "pip install pandas numpy\n", - "```\n", - "\n", - "The script:\n", - "\n", - "```python\n", - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "# Seed for reproducibility\n", - "np.random.seed(42)\n", - "\n", - "# Initialize the lists\n", - "ids = list(range(1, 101))\n", - "sizes = np.random.normal(150, 50, 100).astype(int) # House sizes with a mean of 150 m^2 and a std of 50\n", - "bedrooms = np.random.choice([1, 2, 3, 4, 5], 100) # Number of bedrooms\n", - "locations = np.random.choice(['Downtown', 'Suburb', 'Countryside'], 100, p=[0.4, 0.4, 0.2]) # Location of houses with a preferential distribution\n", - "\n", - "# Prices will be influenced by location, size, and bedrooms. This part is simplistic and can be made more complex.\n", - "base_price = 100000 # Base price\n", - "price_per_m2 = 1000 # Base price per m^2\n", - "extra_per_bedroom = 5000 # Extra cost per additional bedroom\n", - "\n", - "prices = []\n", - "\n", - "for i in range(100):\n", - " base_location_multiplier = 1.5 if locations[i] == 'Downtown' else 1.2 if locations[i] == 'Suburb' else 1\n", - " location_multiplier = base_location_multiplier * (1 + (sizes[i] / 1000)) # More expensive if bigger, especially downtown\n", - " price = base_price + (sizes[i] * price_per_m2) + (bedrooms[i] * extra_per_bedroom)\n", - " prices.append(int(price * location_multiplier))\n", - "\n", - "# Create DataFrame\n", - "data = {\n", - " 'id': ids,\n", - " 'house size (m^2)': sizes,\n", - " 'number of bedrooms': bedrooms,\n", - " 'location': locations,\n", - " 'house price': prices\n", - "}\n", - "\n", - "df = pd.DataFrame(data)\n", - "\n", - "print(df)\n", - "```\n", - "\n", - "This program initializes with a seed for reproducibility while creating randomized but plausible data for housing. The sizes are normally distributed around a mean value, and bedrooms are chosen from a set number. The pricing logic uses base values plus increases according to size, bedroom count, and a location multiplier, with downtown locations inflating prices more than suburbs or countryside locations. Adjustments are simplistic for the purpose of example and can be refined for more nuanced simulations.\n" - ] - } - ], - "source": [ - "question = \"\"\"\n", - "Create a Python program to generate 100 rows of housing data.\n", - "I want you to at the end of it output a pandas dataframe with 100 rows of data.\n", - "Each row should include the following fields:\n", - " - id (incrementing integer starting at 1)\n", - " - house size (m^2)\n", - " - house price\n", - " - location\n", - " - number of bedrooms\n", - "\n", - "Make sure that the numbers make sense (i.e. more rooms is usually bigger size, more expensive locations increase price. more size is usually higher price etc. make sure all the numbers make sense).\n", - "\"\"\"\n", - "\n", - "response = client.chat.completions.create(\n", - " model=datagen_model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", - " {\"role\": \"user\", \"content\": question}\n", - " ]\n", - ")\n", - "res = response.choices[0].message.content\n", - "print(res)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We need to make sure to parse the output of this appropriately as often there may be surrounding text to the python code. We can also explicitly ask it to state all assumptions it made about the data it's generating, however in this circumstance it told us that automatically." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HZaJs7q8xm3L" - }, - "source": [ - "### 3. Multitable CSV with a python program\n", - "For more complex relationships however we need to make sure to specify a few more characteristics. \n", - "\n", - "To create multiple different datasets which relate to each other (for example housing, location, house type), as before we would need to specify the format, schema and useful information. However, the useful information required to get good performance is higher now. It's case-specific but a good amount of things to describe would be how the datasets relate to each other, addressing the size of the datasets in relation to one another, making sure foreign and primary keys are made appropriately and ideally using previously generated datasets to populate new ones so the actual data values match where necessary." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "3TWAhIYIxnbS", - "outputId": "8f766838-b2f0-419a-a4fb-543d029afce5" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "To create a Python program generating three Pandas DataFrames as described, I'll lay out a step-by-step process considering the relationships between the different types of data:\n", - "\n", - "1. Install pandas if you haven't yet: `pip install pandas`\n", - "2. Import pandas and generate each DataFrame. I'll make some assumptions for the synthetic data to keep it relatively simple.\n", - "\n", - "Let's start coding:\n", - "\n", - "```python\n", - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "# Generating Location DataFrame\n", - "np.random.seed(42) # For reproducibility\n", - "location_data = {\n", - " 'id': range(1, 11), # Assuming 10 unique locations\n", - " 'country': ['CountryA'] * 5 + ['CountryB'] * 5,\n", - " 'city': ['City' + str(i) for i in range(1, 11)],\n", - " 'population': np.random.randint(100000, 1000000, size=10),\n", - " 'area': np.random.randint(500, 20000, size=10),\n", - "}\n", - "locations_df = pd.DataFrame(location_data)\n", - "\n", - "# Generating House Types DataFrame\n", - "house_types_data = {\n", - " 'id': range(1, 5), # Assuming 4 unique house types\n", - " 'house type': ['Villa', 'Apartment', 'Townhouse', 'Bungalow'],\n", - " 'average house type price': [300000, 200000, 250000, 220000], # Just arbitrary prices\n", - " 'number of houses': [25, 50, 15, 10], # Total = 100 houses, matching the housing data requirement\n", - "}\n", - "house_types_df = pd.DataFrame(house_types_data)\n", - "\n", - "# Generating Housing Data\n", - "housing_data = {\n", - " 'id': range(1, 101),\n", - " 'house size': np.random.randint(50, 500, size=100),\n", - " 'house price': [], # To be calculated based on size, location, etc.\n", - " 'location_id': np.random.choice(locations_df['id'], size=100),\n", - " 'number of bedrooms': np.random.randint(1, 6, size=100),\n", - " 'house_type_id': np.random.choice(house_types_df['id'], size=100),\n", - "}\n", - "# Simple model to calculate house price based on size, type, and a base price from the location's median\n", - "base_prices = locations_df['population'] / 100000 # Simplified assumption: more populous => more expensive\n", - "housing_data['house price'] = [\n", - " (1200 * size) + (house_types_df.loc[type_id - 1, 'average house type price']) + (base_prices[loc_id - 1] * 1000)\n", - " for size, type_id, loc_id\n", - " in zip(housing_data['house size'], housing_data['house_type_id'], housing_data['location_id'])\n", - "]\n", - "\n", - "housing_df = pd.DataFrame(housing_data)\n", - "\n", - "# Display the first few rows of each DataFrame\n", - "print(locations_df.head())\n", - "print(house_types_df.head())\n", - "print(housing_df.head())\n", - "```\n", - "\n", - "Notes:\n", - "- This script assumes 10 unique locations and 4 house types for simplicity.\n", - "- House prices are arbitrarily calculated using the house size, type, and a base price influenced by the location's population. Reality would require a more complex model.\n", - "- `numpy.random.randint` is used to generate integer values. Similarly, `numpy.random.choice` is used to randomly assign locations and house types to each house, demonstrating a form of foreign key relationship.\n", - "- For simplicity, foreign keys are represented by corresponding ID fields (e.g., `location_id` in the housing data references the `id` in the location data).\n", - "\n", - "This simple synthetic data generation strategy illustrates creating related data sets with Python and pandas. The synthetic data should make general sense within the constraints provided, but keep in mind that for more complex or realistic data modeling, you'd need to incorporate more detailed rules and possibly real-world data.\n" - ] - } - ], - "source": [ - "question = \"\"\"\n", - "Create a Python program to generate 3 different pandas dataframes.\n", - "\n", - "1. Housing data\n", - "I want 100 rows. Each row should include the following fields:\n", - " - id (incrementing integer starting at 1)\n", - " - house size (m^2)\n", - " - house price\n", - " - location\n", - " - number of bedrooms\n", - " - house type\n", - " + any relevant foreign keys\n", - "\n", - "2. Location\n", - "Each row should include the following fields:\n", - " - id (incrementing integer starting at 1)\n", - " - country\n", - " - city\n", - " - population\n", - " - area (m^2)\n", - " + any relevant foreign keys\n", - "\n", - " 3. House types\n", - " - id (incrementing integer starting at 1)\n", - " - house type\n", - " - average house type price\n", - " - number of houses\n", - " + any relevant foreign keys\n", - "\n", - "Make sure that the numbers make sense (i.e. more rooms is usually bigger size, more expensive locations increase price. more size is usually higher price etc. make sure all the numbers make sense).\n", - "Make sure that the dataframe generally follow common sense checks, e.g. the size of the dataframes make sense in comparison with one another.\n", - "Make sure the foreign keys match up and you can use previously generated dataframes when creating each consecutive dataframes.\n", - "You can use the previously generated dataframe to generate the next dataframe.\n", - "\"\"\"\n", - "\n", - "response = client.chat.completions.create(\n", - " model=datagen_model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", - " {\"role\": \"user\", \"content\": question}\n", - " ]\n", - ")\n", - "res = response.choices[0].message.content\n", - "print(res)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Yv9XlRtauZYZ" - }, - "source": [ - "### 4. Simply creating textual data\n", - "Here we take a first look at creating textual data. This can be used to finetune another GPT model for example. In this case we imagine ourselves a retailer trying to streamline the process of creating descriptions for items they are selling. We again need to specify the format of the data, in particular in this case we want one which is easy to parse as an output." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The example we consider below is one in which we want to create input output training pairs for GPT model to finetune on. We will have the products' name and the category it belongs to as input and the output will be a description. \n", - "\n", - "Specifying the structure of the output explicitly and giving commands to not deviate from this help enforce the output structure. You can run this in a loop and append the data to generate more synthetic data. Again, as before we will need to parse the data well so that our code further downstream does not break." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "id": "2KJVwjV0upby" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.\n", - "Input: Northface Waterproof Jacket, Clothing\n", - "Output: Stay dry and stylish with the Northface Waterproof Jacket. Perfect for outdoor adventurers and city dwellers alike, this jacket combines cutting-edge waterproof technology with a sleek, modern design. Ideal for unpredictable weather, it ensures you're prepared for anything Mother Nature throws your way.\n", - "\n", - "2.\n", - "Input: Apple iPhone 12, Electronics\n", - "Output: Experience the next level of innovation with the Apple iPhone 12. Featuring a stunning Super Retina XDR display, a powerful A14 Bionic chip, and advanced dual-camera system, this phone is designed to push the boundaries of what's possible. With 5G capability for super-fast downloads and high-quality streaming, it's the perfect device for tech enthusiasts.\n", - "\n", - "3.\n", - "Input: Adidas Ultraboost Sneakers, Footwear\n", - "Output: Revolutionize your running experience with Adidas Ultraboost Sneakers. Engineered for long-lasting comfort and superior performance, these sneakers feature the innovative Boost \n" - ] - } - ], - "source": [ - "output_string = \"\"\n", - "for i in range(3):\n", - " question = f\"\"\"\n", - " I am creating input output training pairs to fine tune my gpt model. The usecase is a retailer generating a description for a product from a product catalogue. I want the input to be product name and category (to which the product belongs to) and output to be description.\n", - " The format should be of the form:\n", - " 1.\n", - " Input: product_name, category\n", - " Output: description\n", - " 2.\n", - " Input: product_name, category\n", - " Output: description\n", - "\n", - " Do not add any extra characters around that formatting as it will make the output parsing break.\n", - " Create as many training pairs as possible.\n", - " \"\"\"\n", - "\n", - " response = client.chat.completions.create(\n", - " model=datagen_model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", - " {\"role\": \"user\", \"content\": question}\n", - " ]\n", - " )\n", - " res = response.choices[0].message.content\n", - " output_string += res + \"\\n\" + \"\\n\"\n", - "print(output_string[:1000]) #displaying truncated response\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "K5EmKTEa7GlC" - }, - "source": [ - "Note: the above output is truncated. And now we can parse it as below to get a list of products, categories and their descriptions. For example, let's take a look at the products it's generated." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "owvoyJBh0o2n", - "outputId": "ee48bcc9-fd29-42bf-9beb-ef3800cdbcb2" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Northface Waterproof Jacket',\n", - " 'Apple iPhone 12',\n", - " 'Adidas Ultraboost Sneakers',\n", - " 'LEGO Star Wars Millennium Falcon',\n", - " 'Vitamix Professional Series 750 Blender',\n", - " 'Panasonic Lumix GH5 Camera',\n", - " 'Moleskine Classic Notebook',\n", - " 'Bodum French Press Coffee Maker',\n", - " 'Classic White Sneakers',\n", - " 'Multi-Purpose Blender',\n", - " 'Eco-Friendly Yoga Mat',\n", - " 'Organic Green Tea',\n", - " 'Smart LED Light Bulb',\n", - " 'Waterproof Hiking Boots',\n", - " 'Bamboo Toothbrush',\n", - " 'Modern Minimalist Floor Lamp',\n", - " 'Classic Leather Office Chair',\n", - " 'Stainless Steel French Press',\n", - " 'Eco-Friendly Bamboo Cutting Board',\n", - " 'Ultimate Gaming Laptop',\n", - " 'Waterproof Hiking Boots',\n", - " 'Compact Travel Umbrella',\n", - " \"Professional Chef's Knife\"]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#regex to parse data\n", - "pattern = re.compile(r'Input:\\s*(.+?),\\s*(.+?)\\nOutput:\\s*(.+?)(?=\\n\\n|\\Z)', re.DOTALL)\n", - "matches = pattern.findall(output_string)\n", - "products = []\n", - "categories = []\n", - "descriptions = []\n", - "\n", - "for match in matches:\n", - " product, category, description = match\n", - " products.append(product.strip())\n", - " categories.append(category.strip())\n", - " descriptions.append(description.strip())\n", - "products" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "bO3PgRwpyocn" - }, - "source": [ - "\n", - "### 5. Dealing with imbalanced or non-diverse textual data\n", - "Some of the most important aspects of generating high-quality synthetic data are accuracy (does the data make sense), consistency (are two separate data points for the same input roughly the same) and diversity (making sure our data distribution matches as much of the distribution that exists in production).\n", - "\n", - "\n", - "To increase the diversity of our data, we start first by clustering the data. This will provide us information about which clusters are underrepresented (imbalanced dataset) or which data is not addressed at all (widening the data distribution). Then, we will either suggest new clusters (using self-reflection type call from GPT) or ask the next iteration of our synthetic generation calls to explicitly target the underrepresented clusters. \n", - "\n", - "We can then recursively run this generation and analysis of cluster loop to automate generating diverse synthetic data." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ubdPEFYR-myU" - }, - "source": [ - "For demonstrative purposes, we explicitly prompt the LLM to generate information about 4 different topical areas: vehicle, clothing, toiletries, food. We will then cluster the data and see if it managed to find these 4 topic areas." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "m-yncn8s1hWZ", - "outputId": "35ae248d-4859-4d3f-ba29-94478aed7305" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2) toiletries\n", - "Input: \"Toothbrush X5+, Electronic toothbrush\"\n", - "Output: \"Experience a superior cleanse with the Toothbrush X5+. It comes equipped with an advanced sonic technology that guarantees a gentle yet effective clean every time.\"\n", - "\n", - "3) vehicle\n", - "Input: \"Pegasus Pro 300, Motorcycle\"\n", - "Output: \"Dominate the road with the stylish Pegasus Pro 300. This motorcycle guarantees a powerful, efficient, and thrilling performance on every ride.\"\n", - "\n", - "4) food\n", - "Input: \"Tasty Delight Instant Noodles, Instant food\"\n", - "Output: \"Tasty Delight Instant Noodles offer a quick, delicious meal ready in minutes. The perfect solution for those stepping up their cooking game.\"\n", - "\n", - "5) clothing\n", - "Input: \"UltraSport Men's Running Jacket, Sportswear\"\n", - "Output: \"UltraSport Men's Running Jacket combines functionality and style. The breathable material allows for comfortable workouts, even in colder weather.\"\n", - "\n", - "6) toiletries\n", - "Input: \"FreshBliss Shower Gel, Bath and body\"\n", - "Output: \"Indulge in luxury every morning with the FreshBliss Showe\n" - ] - } - ], - "source": [ - "output_string = \"\"\n", - "for i in range(3):\n", - " question = f\"\"\"\n", - " I am creating input output training pairs to fine tune my gpt model. I want the input to be product name and category and output to be description. the category should be things like: mobile phones, shoes, headphones, laptop, electronic toothbrush, etc. and also more importantly the categories should come under 4 main topics: vehicle, clothing, toiletries, food)\n", - " After the number of each example also state the topic area. The format should be of the form:\n", - " 1. topic_area\n", - " Input: product_name, category\n", - " Output: description\n", - "\n", - " Do not add any extra characters around that formatting as it will make the output parsing break.\n", - "\n", - " Here are some helpful examples so you get the style of output correct.\n", - "\n", - " 1) clothing\n", - " Input: \"Shoe Name, Shoes\"\n", - " Output: \"Experience unparalleled comfort. These shoes feature a blend of modern style and the traditional superior cushioning, perfect for those always on the move.\"\n", - " \"\"\"\n", - "\n", - " response = client.chat.completions.create(\n", - " model=\"gpt-4\",\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", - " {\"role\": \"user\", \"content\": question}\n", - " ]\n", - " )\n", - " res = response.choices[0].message.content\n", - " output_string += res + \"\\n\" + \"\\n\"\n", - "print(output_string[:1000]) #displaying truncated response" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note: The above output is truncated. In the example above, we would explicitly include the topic area as part of the response per example as it helps condition the proceeding output and tends to give better performance. We can also give it an actual example of what the output should look like so it gets the right idea of style of output but also to help enforce structure." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "id": "k7GAokEC1hUY" - }, - "outputs": [], - "source": [ - "pattern = re.compile(r'(\\d+)\\) (\\w+(?: \\w+)?)\\s*Input: \"(.+?), (.+?)\"\\s*Output: \"(.+?)\"', re.DOTALL)\n", - "matches = pattern.findall(output_string)\n", - "\n", - "\n", - "topics = []\n", - "products = []\n", - "categories = []\n", - "descriptions = []\n", - "\n", - "for match in matches:\n", - " number, topic, product, category, description = match\n", - " topics.append(topic)\n", - " products.append(product)\n", - " categories.append(category)\n", - " descriptions.append(description)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "Z49B3LrJ1hSG", - "outputId": "d76a9038-1879-44d9-f1db-dc933e066c54" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Toothbrush X5+',\n", - " 'Pegasus Pro 300',\n", - " 'Tasty Delight Instant Noodles',\n", - " \"UltraSport Men's Running Jacket\",\n", - " 'FreshBliss Shower Gel',\n", - " 'OceanBlue Yacht 700',\n", - " 'FarmFresh Organic Apples',\n", - " \"Elegance Women's Velvet Dress\",\n", - " \"GentleCare Men's Face Wash\",\n", - " 'AquaBreathe',\n", - " 'Lunar Ride',\n", - " 'Sunrise Juice',\n", - " 'TitanFlex',\n", - " 'GlowRadiant',\n", - " 'SolarSpeed',\n", - " 'HealthyBite',\n", - " 'Brushify',\n", - " 'Choco Crunchy',\n", - " 'Super X100',\n", - " 'Le Bliz',\n", - " 'Purely Lavender',\n", - " 'Cheesy Delight',\n", - " 'EcoSprint',\n", - " 'Denim Duo',\n", - " 'Fresh Dawn']" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "products" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "J1qKxLkAzKq0" - }, - "source": [ - "We will now cluster the data to analyze it. We will use K-means clustering to segregate the data. An important parameter of K-means to set is K, the number of clusters.\n", - "\n", - "We know that there should be 4 cluster (4 topics) since we specified this in prompt: vehicle, electronics, clothing, food. However in general for our data, we do not know the number of clusters that exist. Therefore we will use the elbow method to find the optimal number of clusters.\n", - "\n", - "In the elbow method, we iterate through a range of different K's, each time storing the inertia. The inertia measures the sum of the squared distances between each point in a cluster and the centroid of that cluster thus telling us how well-separated and dense each cluster is. If we plot K against the inertia, we are able to see how the inertia drops and where the drop in inertia is least rapid (often making an elbow shape) we can set our optimal number of clusters. You can read into more depth about the elbow method [here](https://en.wikipedia.org/wiki/Elbow_method_(clustering))." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "1BxwPTkpGzu8" - }, - "source": [ - "First let's store our data into a pandas dataframe for ease of analysis\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "id": "XcPBzORtKWv6" - }, - "outputs": [], - "source": [ - "data = {\n", - " 'Product': products,\n", - " 'Category': categories,\n", - " 'Description': descriptions\n", - "}\n", - "\n", - "df = pd.DataFrame(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HQbg6r37KjG0" - }, - "source": [ - "Next let us embed our data as the embeddings is what we will cluster since they should be close to each other in vector space if they are similar." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "id": "l8M7MX-1Jctr" - }, - "outputs": [], - "source": [ - "def get_embedding(text, model=\"text-embedding-3-small\"):\n", - " text = text.replace(\"\\n\", \" \")\n", - "\n", - " response = client.embeddings.create(input=[text], model=model)\n", - "\n", - " return response.data[0].embedding\n", - "\n", - "embedding_model = \"text-embedding-3-small\"\n", - "df[\"embedding\"] = df.Category.apply(lambda x: get_embedding(x, model=embedding_model))\n", - "\n", - "matrix = np.vstack(df.embedding.values)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ZcdZscBNKy0F" - }, - "source": [ - "Now we perform the elbow method. " - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 981 - }, - "id": "1Azw_xgVl_aY", - "outputId": "5b7076aa-a03c-4a40-f52c-08b09248cf18" - }, - "outputs": [], - "source": [ - "# Determine the optimal number of clusters using the elbow method\n", - "inertias = []\n", - "range_of_clusters = range(1, 13) # Adjust the range as necessary\n", - "\n", - "for n_clusters in range_of_clusters:\n", - " kmeans = KMeans(n_clusters=n_clusters, init=\"k-means++\", random_state=42, n_init=10)\n", - " kmeans.fit(matrix)\n", - " inertias.append(kmeans.inertia_)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This will output a chart for us in which we have to visually tell where the optimal cluster point is. We can see below that we see a gradual decrease of inertia rather than a sharp elbow but the point of steepest decrease appears to occur around 3, 4 or 5 clusters which lines up with our expectations given our prompt. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Plotting the elbow plot\n", - "plt.figure(figsize=(10, 6))\n", - "plt.plot(range_of_clusters, inertias, '-o')\n", - "plt.title('Elbow Method to Determine Optimal Number of Clusters')\n", - "plt.xlabel('Number of Clusters')\n", - "plt.ylabel('Inertia')\n", - "plt.xticks(range_of_clusters)\n", - "plt.show()" - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "I_IHQTO8xXBn" + }, + "source": [ + "# Synthetic Data generation (Part 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VBoxtnxVdTWZ" + }, + "source": [ + "\n", + "Synthetic data generation using large language models (LLMs) offers a powerful solution to a commonly faced problem: the availability of high-quality, diverse, and privacy-compliant data. This could be used in a number of scenarios such as training a data science machine learning model (SVMs, decision trees, KNN's), finetuning a different GPT model on the data, as a solution to the coldstart problem, helping build compelling demos/apps with realistic data, scenario testing etc.\n", + "\n", + "There are a number of key drivers which may see you wanting to leverage synthetic data. \n", + "1. Human data may have privacy restrictions and/or identifiable data within it which we do not want to be used. \n", + "2. Synthetic data can be much more structured and therefore easier to manipulate than real data. \n", + "3. In domains where data is sparse or data of certain categories is sparse we may want to augment the data. \n", + "4. When dealing with imbalanced datasets or datasets which lack diversity, we may want to create data to improve the richness of our datasets.\n", + "\n", + "Unlike traditional data augmentation or manual data creation methods, using LLMs allows for the generation of rich, nuanced, and contextually relevant datasets that can significantly enhance it's usefulness to enterprises and developers.\n", + "\n", + "We split this tutorial into 2 parts. In this cookbook, we will have the following agenda:\n", + "1. CSV with a structured prompt\n", + "2. CSV with a Python program\n", + "3. Multitable CSV with a python program\n", + "4. Simply creating textual data\n", + "5. Dealing with imbalanced or non-diverse textual data\n", + "while in part 2, we will look at prompting strategies for getting better textual data.\n", + "\n", + "The last two in particular are useful for creating synthetic data to finetune another GPT model. For example using higher quality data produced by `gpt-4o` to finetune the cheaper and quicker `gpt-3.5-turbo` for improved performance while reducing costs.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NE9Rr29zlRsA" + }, + "source": [ + "### Getting setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YGncxYrgQ8eb" + }, + "outputs": [], + "source": [ + "%pip install openai\n", + "%pip install pandas\n", + "%pip install scikit-learn\n", + "%pip install matplotlib" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "8pzwvE-YQPtU" + }, + "outputs": [], + "source": [ + "from openai import OpenAI\n", + "import os\n", + "import re\n", + "import numpy as np\n", + "import pandas as pd\n", + "from sklearn.cluster import KMeans\n", + "import matplotlib.pyplot as plt\n", + "import json\n", + "import matplotlib\n", + "\n", + "client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\", \"\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "B8eAx4-JxaZB" + }, + "source": [ + "### 1. CSV with a structure prompt\n", + "Here we create data in the simplest way. You can quickly generate data by addressing 3 key points: telling it the format of the data (CSV), the schema, and useful information regarding how columns relate (the LLM will be able to deduce this from the column names but a helping hand will improve performance)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "dqbvepd0n4vS", + "outputId": "8735cacc-baa5-463e-938c-783e6b508b00" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![elbow_chart](../images/elbow_chart.png)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "```csv\n", + "id,house_size_m2,house_price,location,number_of_bedrooms\n", + "1,50,150000,Suburban,2\n", + "2,75,250000,City Center,3\n", + "3,100,350000,Suburban,4\n", + "4,120,450000,Suburban,4\n", + "5,80,300000,City Center,3\n", + "6,90,400000,City Center,3\n", + "7,150,600000,Premium Area,5\n", + "8,200,750000,Premium Area,5\n", + "9,55,180000,Suburban,2\n", + "10,300,950000,Premium Area,6\n", + "```\n" + ] + } + ], + "source": [ + "datagen_model = \"gpt-4o-mini\"\n", + "question = \"\"\"\n", + "Create a CSV file with 10 rows of housing data.\n", + "Each row should include the following fields:\n", + " - id (incrementing integer starting at 1)\n", + " - house size (m^2)\n", + " - house price\n", + " - location\n", + " - number of bedrooms\n", + "\n", + "Make sure that the numbers make sense (i.e. more rooms is usually bigger size, more expensive locations increase price. more size is usually higher price etc. make sure all the numbers make sense). Also only respond with the CSV.\n", + "\"\"\"\n", + "\n", + "response = client.chat.completions.create(\n", + " model=datagen_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", + " {\"role\": \"user\", \"content\": question}\n", + " ]\n", + ")\n", + "res = response.choices[0].message.content\n", + "print(res)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6ym0NiIyxiVj" + }, + "source": [ + "### 2. CSV with a Python program\n", + "The issue with generating data directly is we are limited in the amount of data we can generate because of the context. Instead what we can do is ask the LLM to generate a python program to generate the synthetic data. This allows us to scale to much more data while also providing us a view into how the data was generated by inspecting the python program.\n", + "\n", + "This would then let us edit the python program as we desire while giving us a good basis to start from.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "2yDuwB5ZxWS3", + "outputId": "dcbe1093-90f0-4f60-d9c6-34bf679bb092" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "NN7NbTmiLe_-" - }, - "source": [ - "For demonstration purposes we will pick 5 as the optimal cluster number to show it doesn't matter exactly where we pick it as long as we are approximately right. There are numerous correct ways to categorize data. We also store which cluster each data point belongs to." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Certainly! Below is a Python program that generates synthetic housing data according to your specifications. We will create a pandas DataFrame with the defined fields and characteristics.\n", + "\n", + "```python\n", + "import pandas as pd\n", + "import random\n", + "\n", + "def generate_housing_data(num_rows):\n", + " data = []\n", + " \n", + " locations = [\n", + " ('City Center', 10000, 150), # (location name, base price per m², base size)\n", + " ('Suburban Area', 8000, 100),\n", + " ('Country Side', 5000, 80),\n", + " ('Coastal Region', 12000, 110),\n", + " ('Urban Neighborhood', 9000, 130)\n", + " ]\n", + " \n", + " for i in range(1, num_rows + 1):\n", + " # Randomly pick a location\n", + " location, base_price_per_m2, base_size = random.choice(locations)\n", + " \n", + " # Generate number of bedrooms (1 to 5)\n", + " number_of_bedrooms = random.randint(1, 5)\n", + " \n", + " # Calculate house size based on the number of bedrooms\n", + " house_size = base_size + (10 * number_of_bedrooms) + random.randint(-5, 15) # Adding some noise\n", + " \n", + " # Calculate house price based on house size and location\n", + " house_price = base_price_per_m2 * house_size + random.randint(-5000, 10000) # Adding some noise\n", + "\n", + " # Append the generated data to the list\n", + " data.append({\n", + " 'id': i,\n", + " 'house_size_m2': house_size,\n", + " 'house_price': house_price,\n", + " 'location': location,\n", + " 'number_of_bedrooms': number_of_bedrooms\n", + " })\n", + "\n", + " # Create a pandas DataFrame\n", + " df = pd.DataFrame(data)\n", + " return df\n", + "\n", + "# Generate 100 rows of housing data\n", + "housing_data_df = generate_housing_data(100)\n", + "\n", + "# Show the result\n", + "print(housing_data_df)\n", + "```\n", + "\n", + "### Explanation:\n", + "- The `generate_housing_data` function creates synthetic housing data for a specified number of rows (`num_rows`).\n", + "- We define different locations with corresponding base prices per square meter and average house sizes.\n", + "- For each house, we randomly select a location, number of bedrooms, and calculate house size and price to ensure a sensible correlation between the values.\n", + "- Finally, we create a pandas DataFrame from the generated data and return it.\n", + "\n", + "You can run this program in your Python environment, and it will output a DataFrame containing 100 rows of synthetic housing data.\n" + ] + } + ], + "source": [ + "question = \"\"\"\n", + "Create a Python program to generate 100 rows of housing data.\n", + "I want you to at the end of it output a pandas dataframe with 100 rows of data.\n", + "Each row should include the following fields:\n", + " - id (incrementing integer starting at 1)\n", + " - house size (m^2)\n", + " - house price\n", + " - location\n", + " - number of bedrooms\n", + "\n", + "Make sure that the numbers make sense (i.e. more rooms is usually bigger size, more expensive locations increase price. more size is usually higher price etc. make sure all the numbers make sense).\n", + "\"\"\"\n", + "\n", + "response = client.chat.completions.create(\n", + " model=datagen_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", + " {\"role\": \"user\", \"content\": question}\n", + " ]\n", + ")\n", + "res = response.choices[0].message.content\n", + "print(res)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need to make sure to parse the output of this appropriately as often there may be surrounding text to the python code. We can also explicitly ask it to state all assumptions it made about the data it's generating, however in this circumstance it told us that automatically." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HZaJs7q8xm3L" + }, + "source": [ + "### 3. Multitable CSV with a python program\n", + "For more complex relationships however we need to make sure to specify a few more characteristics. \n", + "\n", + "To create multiple different datasets which relate to each other (for example housing, location, house type), as before we would need to specify the format, schema and useful information. However, the useful information required to get good performance is higher now. It's case-specific but a good amount of things to describe would be how the datasets relate to each other, addressing the size of the datasets in relation to one another, making sure foreign and primary keys are made appropriately and ideally using previously generated datasets to populate new ones so the actual data values match where necessary." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "3TWAhIYIxnbS", + "outputId": "8f766838-b2f0-419a-a4fb-543d029afce5" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "KvrDe3WYKWgZ", - "outputId": "d0d95227-b9d2-4c52-a5f7-59159ba848d2" - }, - "outputs": [], - "source": [ - "n_clusters = 5\n", - "\n", - "kmeans = KMeans(n_clusters=n_clusters, init=\"k-means++\", random_state=42)\n", - "kmeans.fit(matrix)\n", - "labels = kmeans.labels_\n", - "df[\"Cluster\"] = labels" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Certainly! Below is a Python program that generates the three specified pandas DataFrames for housing data, location data, and house types. Each DataFrame will include the necessary fields, and the foreign keys will ensure proper relationships among them.\n", + "\n", + "```python\n", + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Set random seed for reproducibility\n", + "np.random.seed(0)\n", + "\n", + "# Function to generate location DataFrame\n", + "def generate_location_data(num_locations):\n", + " locations = {\n", + " \"id\": range(1, num_locations + 1),\n", + " \"country\": np.random.choice(['USA', 'Canada', 'UK'], num_locations),\n", + " \"city\": np.random.choice(['New York', 'Toronto', 'London', 'Vancouver', 'Manchester'], num_locations),\n", + " \"population\": np.random.randint(50000, 1000000, num_locations),\n", + " \"area\": np.random.randint(10000, 500000, num_locations)\n", + " }\n", + " return pd.DataFrame(locations)\n", + "\n", + "# Function to generate house types DataFrame\n", + "def generate_house_type_data(num_house_types):\n", + " house_types = {\n", + " \"id\": range(1, num_house_types + 1),\n", + " \"house_type\": np.random.choice(['Detached', 'Semi-Detached', 'Terraced', 'Flat'], num_house_types),\n", + " \"average_house_type_price\": np.random.randint(100000, 1000000, num_house_types),\n", + " \"number_of_houses\": np.random.randint(10, 1000, num_house_types)\n", + " }\n", + " return pd.DataFrame(house_types)\n", + "\n", + "# Function to generate housing data DataFrame\n", + "def generate_housing_data(num_houses, location_df, house_type_df):\n", + " house_sizes = np.random.randint(50, 300, num_houses) # size in m^2\n", + " location_ids = np.random.choice(location_df['id'], num_houses)\n", + " house_type_ids = np.random.choice(house_type_df['id'], num_houses)\n", + " \n", + " # Generate prices based on size, location, and house type\n", + " house_prices = (house_sizes * np.random.randint(2000, 5000, num_houses) // 10) + \\\n", + " (location_ids * 1000) + \\\n", + " (house_type_df.loc[house_type_ids - 1, 'average_house_type_price'].values // 4)\n", + " \n", + " housing_data = {\n", + " \"id\": range(1, num_houses + 1),\n", + " \"house_size\": house_sizes,\n", + " \"house_price\": house_prices,\n", + " \"location_id\": location_ids,\n", + " \"bedrooms\": np.random.randint(1, 6, num_houses),\n", + " \"house_type_id\": house_type_ids\n", + " }\n", + " \n", + " return pd.DataFrame(housing_data)\n", + "\n", + "# Generate DataFrames\n", + "num_locations = 10\n", + "num_house_types = 4\n", + "num_houses = 100\n", + "\n", + "location_df = generate_location_data(num_locations)\n", + "house_type_df = generate_house_type_data(num_house_types)\n", + "housing_df = generate_housing_data(num_houses, location_df, house_type_df)\n", + "\n", + "# Display the generated DataFrames\n", + "print(\"Location DataFrame:\")\n", + "print(location_df.head(), \"\\n\")\n", + "\n", + "print(\"House Types DataFrame:\")\n", + "print(house_type_df.head(), \"\\n\")\n", + "\n", + "print(\"Housing DataFrame:\")\n", + "print(housing_df.head(), \"\\n\")\n", + "\n", + "# Printing the DataFrame shapes\n", + "print(f\"Shapes: \\nLocation: {location_df.shape}, House Types: {house_type_df.shape}, Housing: {housing_df.shape}\")\n", + "```\n", + "\n", + "### Explanation of the Code:\n", + "1. **Location DataFrame:** \n", + " - Generates random locations with attributes such as country, city, population, and area.\n", + " \n", + "2. **House Types DataFrame:** \n", + " - Generates different types of houses along with average prices and quantity available.\n", + " \n", + "3. **Housing DataFrame:** \n", + " - Generates housing data with increments on price based on house size, location, and house type, while also ensuring foreign keys (IDs) for location and house type.\n", + "\n", + "### Output:\n", + "The three DataFrames generated will logically relate to one another with consistent data types and primary–foreign key relationships, resulting in a coherent representation of the housing dataset. The output displays heads of each DataFrame and their shapes for verification.\n" + ] + } + ], + "source": [ + "question = \"\"\"\n", + "Create a Python program to generate 3 different pandas dataframes.\n", + "\n", + "1. Housing data\n", + "I want 100 rows. Each row should include the following fields:\n", + " - id (incrementing integer starting at 1)\n", + " - house size (m^2)\n", + " - house price\n", + " - location\n", + " - number of bedrooms\n", + " - house type\n", + " + any relevant foreign keys\n", + "\n", + "2. Location\n", + "Each row should include the following fields:\n", + " - id (incrementing integer starting at 1)\n", + " - country\n", + " - city\n", + " - population\n", + " - area (m^2)\n", + " + any relevant foreign keys\n", + "\n", + " 3. House types\n", + " - id (incrementing integer starting at 1)\n", + " - house type\n", + " - average house type price\n", + " - number of houses\n", + " + any relevant foreign keys\n", + "\n", + "Make sure that the numbers make sense (i.e. more rooms is usually bigger size, more expensive locations increase price. more size is usually higher price etc. make sure all the numbers make sense).\n", + "Make sure that the dataframe generally follow common sense checks, e.g. the size of the dataframes make sense in comparison with one another.\n", + "Make sure the foreign keys match up and you can use previously generated dataframes when creating each consecutive dataframes.\n", + "You can use the previously generated dataframe to generate the next dataframe.\n", + "\"\"\"\n", + "\n", + "response = client.chat.completions.create(\n", + " model=datagen_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", + " {\"role\": \"user\", \"content\": question}\n", + " ]\n", + ")\n", + "res = response.choices[0].message.content\n", + "print(res)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Yv9XlRtauZYZ" + }, + "source": [ + "### 4. Simply creating textual data\n", + "Here we take a first look at creating textual data. This can be used to finetune another GPT model for example. In this case we imagine ourselves a retailer trying to streamline the process of creating descriptions for items they are selling. We again need to specify the format of the data, in particular in this case we want one which is easy to parse as an output." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The example we consider below is one in which we want to create input output training pairs for GPT model to finetune on. We will have the products' name and the category it belongs to as input and the output will be a description. \n", + "\n", + "Specifying the structure of the output explicitly and giving commands to not deviate from this help enforce the output structure. You can run this in a loop and append the data to generate more synthetic data. Again, as before we will need to parse the data well so that our code further downstream does not break." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "2KJVwjV0upby" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "tLvO4AISDM0J" - }, - "source": [ - "We will analyze the cluster data now. There are two separate things we will look to address. 1. imbalanced data, 2. Expanding the data distribution." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "1.\n", + "Input: Wireless Bluetooth Headphones, Electronics\n", + "Output: Immerse yourself in high-quality sound with these Wireless Bluetooth Headphones, featuring active noise cancellation and a comfortable over-ear design for extended listening sessions.\n", + "\n", + "2.\n", + "Input: Organic Green Tea, Beverages\n", + "Output: Enjoy a refreshing cup of Organic Green Tea, sourced from the finest leaves, packed with antioxidants, and perfect for a healthy, invigorating boost anytime.\n", + "\n", + "3.\n", + "Input: Stainless Steel Kitchen Knife, Kitchenware\n", + "Output: Cut with precision and ease using this Stainless Steel Kitchen Knife, designed with an ergonomic handle and a sharp blade for all your culinary tasks.\n", + "\n", + "4.\n", + "Input: Hiking Backpack, Outdoor Gear\n", + "Output: Explore the great outdoors with this durable Hiking Backpack, featuring multiple compartments for optimal organization and a breathable design for ultimate comfort on long treks.\n", + "\n", + "5.\n", + "Input: Air Fryer, Kitchen Appliances\n", + "Output: Cook your favorite meals with less oil using this Air Fryer\n" + ] + } + ], + "source": [ + "output_string = \"\"\n", + "for i in range(3):\n", + " question = f\"\"\"\n", + " I am creating input output training pairs to fine tune my gpt model. The usecase is a retailer generating a description for a product from a product catalogue. I want the input to be product name and category (to which the product belongs to) and output to be description.\n", + " The format should be of the form:\n", + " 1.\n", + " Input: product_name, category\n", + " Output: description\n", + " 2.\n", + " Input: product_name, category\n", + " Output: description\n", + "\n", + " Do not add any extra characters around that formatting as it will make the output parsing break.\n", + " Create as many training pairs as possible.\n", + " \"\"\"\n", + "\n", + " response = client.chat.completions.create(\n", + " model=datagen_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", + " {\"role\": \"user\", \"content\": question}\n", + " ]\n", + " )\n", + " res = response.choices[0].message.content\n", + " output_string += res + \"\\n\" + \"\\n\"\n", + "print(output_string[:1000]) #displaying truncated response\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K5EmKTEa7GlC" + }, + "source": [ + "Note: the above output is truncated. And now we can parse it as below to get a list of products, categories and their descriptions. For example, let's take a look at the products it's generated." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "owvoyJBh0o2n", + "outputId": "ee48bcc9-fd29-42bf-9beb-ef3800cdbcb2" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "zaQ_mdhpOJqs" - }, - "source": [ - "First for imbalanced data we count the number of examples in each cluster. Then we select a few examples from each cluster at random and ask the LLM what topics these map to. " + "data": { + "text/plain": [ + "['Wireless Bluetooth Headphones',\n", + " 'Organic Green Tea',\n", + " 'Stainless Steel Kitchen Knife',\n", + " 'Hiking Backpack',\n", + " 'Air Fryer',\n", + " \"Kids' Educational Tablet\",\n", + " 'Bluetooth Speaker',\n", + " 'Yoga Mat',\n", + " 'Memory Foam Mattress',\n", + " 'Smartwatch',\n", + " 'Leather Wallet',\n", + " 'Portable Phone Charger',\n", + " 'Non-Stick Cookware Set',\n", + " 'Pet Dog Bed',\n", + " 'Fitness Tracker',\n", + " 'Wireless Earbuds',\n", + " 'Organic Green Tea',\n", + " 'Reusable Water Bottle',\n", + " 'Yoga Mat',\n", + " 'Leather Wallet',\n", + " 'Air Fryer',\n", + " 'Gaming Mouse',\n", + " 'Crochet Kit',\n", + " 'Hiking Boots',\n", + " 'Scented Candles',\n", + " 'Bluetooth Speaker',\n", + " 'Stainless Steel Cookware Set',\n", + " 'Fitness Tracker',\n", + " 'Decorative Throw Pillows',\n", + " 'Eco-Friendly Cleaning Supplies',\n", + " 'Wireless Noise Cancelling Headphones',\n", + " 'Organic Green Tea',\n", + " 'Adjustable Yoga Mat',\n", + " 'Bluetooth Smart Scale',\n", + " 'Stainless Steel Water Bottle',\n", + " 'Soft Cotton Bedding Set',\n", + " 'Multi-Functional Kitchen Blender',\n", + " 'Eco-Friendly Reusable Bags',\n", + " 'Portable Phone Charger',\n", + " 'Classic Leather Wallet',\n", + " 'Suede Chelsea Boots',\n", + " 'Non-Stick Cookware Set',\n", + " 'Pet-Friendly Indoor Plants',\n", + " 'High-Protein Snack Bars',\n", + " 'LED Desk Lamp with USB Port']" ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#regex to parse data\n", + "pattern = re.compile(r'Input:\\s*(.+?),\\s*(.+?)\\nOutput:\\s*(.+?)(?=\\n\\n|\\Z)', re.DOTALL)\n", + "matches = pattern.findall(output_string)\n", + "products = []\n", + "categories = []\n", + "descriptions = []\n", + "\n", + "for match in matches:\n", + " product, category, description = match\n", + " products.append(product.strip())\n", + " categories.append(category.strip())\n", + " descriptions.append(description.strip())\n", + "products" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bO3PgRwpyocn" + }, + "source": [ + "\n", + "### 5. Dealing with imbalanced or non-diverse textual data\n", + "Some of the most important aspects of generating high-quality synthetic data are accuracy (does the data make sense), consistency (are two separate data points for the same input roughly the same) and diversity (making sure our data distribution matches as much of the distribution that exists in production).\n", + "\n", + "\n", + "To increase the diversity of our data, we start first by clustering the data. This will provide us information about which clusters are underrepresented (imbalanced dataset) or which data is not addressed at all (widening the data distribution). Then, we will either suggest new clusters (using self-reflection type call from GPT) or ask the next iteration of our synthetic generation calls to explicitly target the underrepresented clusters. \n", + "\n", + "We can then recursively run this generation and analysis of cluster loop to automate generating diverse synthetic data." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ubdPEFYR-myU" + }, + "source": [ + "For demonstrative purposes, we explicitly prompt the LLM to generate information about 4 different topical areas: vehicle, clothing, toiletries, food. We will then cluster the data and see if it managed to find these 4 topic areas." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "m-yncn8s1hWZ", + "outputId": "35ae248d-4859-4d3f-ba29-94478aed7305" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "crUT7OR7QcFD", - "outputId": "04f49ac2-1259-4622-bcf2-0686af93068c" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cluster\n", - "0 4\n", - "1 7\n", - "2 6\n", - "3 4\n", - "4 4\n", - "Name: count, dtype: int64\n" - ] - } - ], - "source": [ - "cluster_counts = df[\"Cluster\"].value_counts().sort_index()\n", - "print(cluster_counts)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "1. vehicle \n", + "Input: \"Tesla Model 3, Electric Car\" \n", + "Output: \"The Tesla Model 3 is a revolutionary electric car with impressive range and cutting-edge technology, designed to provide an exhilarating driving experience while minimizing environmental impact.\"\n", + "\n", + "2. clothing \n", + "Input: \"Nike Air Max, Shoes\" \n", + "Output: \"Elevate your sneaker game with Nike Air Max. Combining iconic style with superior comfort and support, these shoes are perfect for both workouts and casual outings.\"\n", + "\n", + "3. toiletries \n", + "Input: \"Oral-B Pro 1000, Electronic Toothbrush\" \n", + "Output: \"Achieve a superior clean with the Oral-B Pro 1000. This electronic toothbrush features 3D cleaning action that pulsates and oscillates to remove more plaque than a regular manual toothbrush.\"\n", + "\n", + "4. food \n", + "Input: \"Chobani Greek Yogurt, Yogurt\" \n", + "Output: \"Indulge in a nutritious snack with Chobani Greek Yogurt. Packed with protein and delicious flavors, it’s the perfect choice for a healthy breakfast or a satisfying treat anytime.\"\n", + "\n", + "5. vehicle \n", + "\n" + ] + } + ], + "source": [ + "output_string = \"\"\n", + "for i in range(3):\n", + " question = f\"\"\"\n", + " I am creating input output training pairs to fine tune my gpt model. I want the input to be product name and category and output to be description. the category should be things like: mobile phones, shoes, headphones, laptop, electronic toothbrush, etc. and also more importantly the categories should come under 4 main topics: vehicle, clothing, toiletries, food)\n", + " After the number of each example also state the topic area. The format should be of the form:\n", + " 1. topic_area\n", + " Input: product_name, category\n", + " Output: description\n", + "\n", + " Do not add any extra characters around that formatting as it will make the output parsing break.\n", + "\n", + " Here are some helpful examples so you get the style of output correct.\n", + "\n", + " 1) clothing\n", + " Input: \"Shoe Name, Shoes\"\n", + " Output: \"Experience unparalleled comfort. These shoes feature a blend of modern style and the traditional superior cushioning, perfect for those always on the move.\"\n", + " \"\"\"\n", + "\n", + " response = client.chat.completions.create(\n", + " model=\"gpt-4o-mini\",\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", + " {\"role\": \"user\", \"content\": question}\n", + " ]\n", + " )\n", + " res = response.choices[0].message.content\n", + " output_string += res + \"\\n\" + \"\\n\"\n", + "print(output_string[:1000]) #displaying truncated response" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: The above output is truncated. In the example above, we would explicitly include the topic area as part of the response per example as it helps condition the proceeding output and tends to give better performance. We can also give it an actual example of what the output should look like so it gets the right idea of style of output but also to help enforce structure." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "k7GAokEC1hUY" + }, + "outputs": [], + "source": [ + "pattern = re.compile(r'(\\d+)\\.\\s*(\\w+)\\s*Input:\\s*\"(.+?),\\s*(.+?)\"\\s*Output:\\s*\"(.*?)\"', re.DOTALL)\n", + "matches = pattern.findall(output_string)\n", + "\n", + "topics = []\n", + "products = []\n", + "categories = []\n", + "descriptions = []\n", + "\n", + "for match in matches:\n", + " number, topic, product, category, description = match\n", + " topics.append(topic)\n", + " products.append(product)\n", + " categories.append(category)\n", + " descriptions.append(description)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "Z49B3LrJ1hSG", + "outputId": "d76a9038-1879-44d9-f1db-dc933e066c54" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "8i1FGtM-Xx3k" - }, - "source": [ - "We can see the topics found here:\n", - "Eco-friendly Transportation, Luxury and Leisure Items, Personal Care Products, Electronic Toothbrushes and Clothing and Apparel\n", - "match well enough but not exactly to our initial prompt of:\n", - "vehicle, clothing, toiletries, food.\n", - "\n", - "As we chose 5 clusters, it split up toiletries into Skincare and Personal Care which doesn't affect us too much further downstream." + "data": { + "text/plain": [ + "['Tesla Model 3',\n", + " 'Nike Air Max',\n", + " 'Oral-B Pro 1000',\n", + " 'Chobani Greek Yogurt',\n", + " 'Ford F-150',\n", + " \"Levi's 511\",\n", + " 'Philips Sonicare',\n", + " 'Quaker Oatmeal',\n", + " 'Toyota Camry',\n", + " 'Adidas Ultraboost',\n", + " 'Toyota Camry',\n", + " 'Nike Air Max',\n", + " 'Colgate Electric Toothbrush',\n", + " 'Blue Diamond Almonds',\n", + " 'Harley Davidson Fat Boy',\n", + " 'Adidas UltraBoost',\n", + " \"Dove Men's Body Wash\",\n", + " 'Quaker Oats',\n", + " 'Ford F-150',\n", + " \"Levi's 501 Jeans\",\n", + " 'Tesla Model 3',\n", + " 'Nike Air Max',\n", + " 'Oral-B Pro 1000',\n", + " 'Organic Almond Butter',\n", + " 'Yamaha YZF-R3',\n", + " 'Adidas Ultraboost',\n", + " 'Philips Sonicare',\n", + " 'Organic Quinoa']" ] - }, + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "products" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "J1qKxLkAzKq0" + }, + "source": [ + "We will now cluster the data to analyze it. We will use K-means clustering to segregate the data. An important parameter of K-means to set is K, the number of clusters.\n", + "\n", + "We know that there should be 4 cluster (4 topics) since we specified this in prompt: vehicle, electronics, clothing, food. However in general for our data, we do not know the number of clusters that exist. Therefore we will use the elbow method to find the optimal number of clusters.\n", + "\n", + "In the elbow method, we iterate through a range of different K's, each time storing the inertia. The inertia measures the sum of the squared distances between each point in a cluster and the centroid of that cluster thus telling us how well-separated and dense each cluster is. If we plot K against the inertia, we are able to see how the inertia drops and where the drop in inertia is least rapid (often making an elbow shape) we can set our optimal number of clusters. You can read into more depth about the elbow method [here](https://en.wikipedia.org/wiki/Elbow_method_(clustering))." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1BxwPTkpGzu8" + }, + "source": [ + "First let's store our data into a pandas dataframe for ease of analysis\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "id": "XcPBzORtKWv6" + }, + "outputs": [], + "source": [ + "data = {\n", + " 'Product': products,\n", + " 'Category': categories,\n", + " 'Description': descriptions\n", + "}\n", + "\n", + "df = pd.DataFrame(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HQbg6r37KjG0" + }, + "source": [ + "Next let us embed our data as the embeddings is what we will cluster since they should be close to each other in vector space if they are similar." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "l8M7MX-1Jctr" + }, + "outputs": [], + "source": [ + "def get_embedding(text, model=\"text-embedding-3-small\"):\n", + " text = text.replace(\"\\n\", \" \")\n", + "\n", + " response = client.embeddings.create(input=[text], model=model)\n", + "\n", + " return response.data[0].embedding\n", + "\n", + "embedding_model = \"text-embedding-3-small\"\n", + "df[\"embedding\"] = df.Category.apply(lambda x: get_embedding(x, model=embedding_model))\n", + "\n", + "# Ensure there are embeddings to concatenate\n", + "if len(df.embedding.values) > 0:\n", + " matrix = np.vstack(df.embedding.values)\n", + "else:\n", + " matrix = np.array([]) # Handle the case where there are no embeddings\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "RRwIet9DUdKe", - "outputId": "8e7835c9-884a-4504-bbed-f556382dd9f5" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[\n", - " {\n", - " \"cluster\": 0,\n", - " \"topic\": \"Electronic Toothbrushes\"\n", - " },\n", - " {\n", - " \"cluster\": 1,\n", - " \"topic\": \"Clothing and Apparel\"\n", - " },\n", - " {\n", - " \"cluster\": 2,\n", - " \"topic\": \"Personal Care Products\"\n", - " },\n", - " {\n", - " \"cluster\": 3,\n", - " \"topic\": \"Eco-friendly Transportation\"\n", - " },\n", - " {\n", - " \"cluster\": 4,\n", - " \"topic\": \"Luxury and Leisure Items\"\n", - " }\n", - "]\n" - ] - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ProductCategoryDescriptionembedding
0Tesla Model 3Electric CarThe Tesla Model 3 is a revolutionary electric ...[0.003255360759794712, -0.039260633289813995, ...
1Nike Air MaxShoesElevate your sneaker game with Nike Air Max. C...[0.03943369910120964, 0.022045187652111053, -0...
2Oral-B Pro 1000Electronic ToothbrushAchieve a superior clean with the Oral-B Pro 1...[-0.003470012918114662, -0.01911414973437786, ...
3Chobani Greek YogurtYogurtIndulge in a nutritious snack with Chobani Gre...[0.0208318829536438, -0.02645781636238098, -0....
4Ford F-150Pickup TruckThe Ford F-150 is the ultimate pickup truck, d...[0.007467855699360371, -0.05288049206137657, -...
5Levi's 511JeansStep out in style with Levi's 511 jeans. Featu...[0.0037206460256129503, 0.022772302851080894, ...
6Philips SonicareElectric ToothbrushDiscover a new level of oral care with the Phi...[-0.00724813062697649, -0.011600878089666367, ...
7Quaker OatmealBreakfast CerealStart your day right with Quaker Oatmeal. This...[-0.006529285106807947, 0.007865572348237038, ...
8Toyota CamrySedanThe Toyota Camry stands out in the sedan categ...[-0.02088991366326809, -0.006191295105963945, ...
9Adidas UltraboostRunning ShoesRun like never before in the Adidas Ultraboost...[0.02679188922047615, 0.014639599248766899, 8....
10Toyota CamryCarThe Toyota Camry is a reliable midsize sedan k...[0.008056452497839928, -0.007912316359579563, ...
11Nike Air MaxShoesStep up your sneaker game with the Nike Air Ma...[0.03943241760134697, 0.02208484522998333, -0....
12Colgate Electric ToothbrushElectronic ToothbrushTransform your oral hygiene routine with the C...[-0.003470012918114662, -0.01911414973437786, ...
13Blue Diamond AlmondsNutsSnack healthy with Blue Diamond Almonds. These...[-0.013289917260408401, 0.036334190517663956, ...
14Harley Davidson Fat BoyMotorcycleExperience the thrill of the open road with th...[0.012365399859845638, 0.03552943095564842, -0...
15Adidas UltraBoostSneakersEnjoy a perfect blend of comfort and performan...[0.013107392005622387, 0.02963760495185852, -0...
16Dove Men's Body WashBody WashRefresh and hydrate your skin with Dove Men's ...[0.03760576993227005, -0.008475445210933685, -...
17Quaker OatsOatsStart your day right with Quaker Oats. Packed ...[-0.00903365109115839, 0.00896345917135477, 0....
18Ford F-150TruckThe Ford F-150 is a durable and dependable tru...[0.023461222648620605, -0.026651185005903244, ...
19Levi's 501 JeansJeansDiscover the timeless style of Levi's 501 Jean...[0.003762696636840701, 0.02275814116001129, -0...
20Tesla Model 3Mobile PhonesExplore the future of driving with the Tesla M...[0.03703858703374863, 0.03407958149909973, 0.0...
21Nike Air MaxShoesStep up your game with the Nike Air Max. Desig...[0.03943369910120964, 0.022045187652111053, -0...
22Oral-B Pro 1000Electronic ToothbrushAchieve a superior clean with the Oral-B Pro 1...[-0.003470012918114662, -0.01911414973437786, ...
23Organic Almond ButterFoodIndulge in the creamy goodness of Organic Almo...[-0.014613640494644642, -0.002179765608161688,...
24Yamaha YZF-R3Mobile PhonesIntroducing the Yamaha YZF-R3, the ultimate sp...[0.03703858703374863, 0.03407958149909973, 0.0...
25Adidas UltraboostShoesDiscover the Adidas Ultraboost, a shoe that of...[0.03944042697548866, 0.022062409669160843, -0...
26Philips SonicareElectronic ToothbrushExperience the dental care revolution with Phi...[-0.003470012918114662, -0.01911414973437786, ...
27Organic QuinoaFoodNourish your body with Organic Quinoa, a nutri...[-0.014613640494644642, -0.002179765608161688,...
\n", + "
" ], - "source": [ - "selected_examples = df.groupby('Cluster').apply(lambda x: x.sample(3)).reset_index(drop=True)\n", - "\n", - "# Format the selected examples\n", - "formatted_examples = \"\\n\".join(\n", - " f'Input: \"{row[\"Product\"]}, {row[\"Category\"]}\"\\nOutput: \"{row[\"Description\"]}\"\\nCluster: \"{row[\"Cluster\"]}\"'\n", - " for _, row in selected_examples.iterrows()\n", - ")\n", - "\n", - "topic_prompt = f\"\"\"\n", - " I previously generated some examples of input output trainings pairs and then I clustered them based on category. From each cluster I picked 3 example data point which you can find below.\n", - " I want you identify the broad topic areas these clusters belong to.\n", - " Previous examples:\n", - " {formatted_examples}\n", - "\n", - "\n", - " Your output should be strictly of the format:\n", - " Cluster: number, topic: topic\n", - " Cluster: number, topic: topic\n", - " Cluster: number, topic: topic\n", - "\n", - " Do not add any extra characters around that formatting as it will make the output parsing break.\n", - " \"\"\"\n", - "\n", - "response = client.chat.completions.create(\n", - " model=datagen_model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed analyze clustered data\"},\n", - " {\"role\": \"user\", \"content\": topic_prompt}\n", - " ]\n", - ")\n", - "res = response.choices[0].message.content\n", - "\n", - "pattern = r\"Cluster: (\\d+), topic: ([^\\n]+)\"\n", - "matches = re.findall(pattern, res)\n", - "clusters = [{\"cluster\": int(cluster), \"topic\": topic} for cluster, topic in matches]\n", - "json_output = json.dumps(clusters, indent=2)\n", - "print(json_output)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "x5hszl-SZVdi" - }, - "source": [ - "We now have the clusters and their counts so we could prompt the LLM to generate more examples within the topics we want. However for this example we won't take that further as they are well-split and you would just follow the procedure above for prompting the model to generate data while passing in the underrepresented topics." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "yVD_TPsHYvDb" - }, - "source": [ - "Next, we will try and deal with increasing the diversity of our data distribution. \n", - "\n", - "First we start in a similar way by finding a few examples from each cluster at random and ask the LLM what topics these map to. In addition to this in the same LLM call, we will ask it to generate more topics to increase the diversity of our data. We do this in one call to save time/cost." + "text/plain": [ + " Product Category \\\n", + "0 Tesla Model 3 Electric Car \n", + "1 Nike Air Max Shoes \n", + "2 Oral-B Pro 1000 Electronic Toothbrush \n", + "3 Chobani Greek Yogurt Yogurt \n", + "4 Ford F-150 Pickup Truck \n", + "5 Levi's 511 Jeans \n", + "6 Philips Sonicare Electric Toothbrush \n", + "7 Quaker Oatmeal Breakfast Cereal \n", + "8 Toyota Camry Sedan \n", + "9 Adidas Ultraboost Running Shoes \n", + "10 Toyota Camry Car \n", + "11 Nike Air Max Shoes \n", + "12 Colgate Electric Toothbrush Electronic Toothbrush \n", + "13 Blue Diamond Almonds Nuts \n", + "14 Harley Davidson Fat Boy Motorcycle \n", + "15 Adidas UltraBoost Sneakers \n", + "16 Dove Men's Body Wash Body Wash \n", + "17 Quaker Oats Oats \n", + "18 Ford F-150 Truck \n", + "19 Levi's 501 Jeans Jeans \n", + "20 Tesla Model 3 Mobile Phones \n", + "21 Nike Air Max Shoes \n", + "22 Oral-B Pro 1000 Electronic Toothbrush \n", + "23 Organic Almond Butter Food \n", + "24 Yamaha YZF-R3 Mobile Phones \n", + "25 Adidas Ultraboost Shoes \n", + "26 Philips Sonicare Electronic Toothbrush \n", + "27 Organic Quinoa Food \n", + "\n", + " Description \\\n", + "0 The Tesla Model 3 is a revolutionary electric ... \n", + "1 Elevate your sneaker game with Nike Air Max. C... \n", + "2 Achieve a superior clean with the Oral-B Pro 1... \n", + "3 Indulge in a nutritious snack with Chobani Gre... \n", + "4 The Ford F-150 is the ultimate pickup truck, d... \n", + "5 Step out in style with Levi's 511 jeans. Featu... \n", + "6 Discover a new level of oral care with the Phi... \n", + "7 Start your day right with Quaker Oatmeal. This... \n", + "8 The Toyota Camry stands out in the sedan categ... \n", + "9 Run like never before in the Adidas Ultraboost... \n", + "10 The Toyota Camry is a reliable midsize sedan k... \n", + "11 Step up your sneaker game with the Nike Air Ma... \n", + "12 Transform your oral hygiene routine with the C... \n", + "13 Snack healthy with Blue Diamond Almonds. These... \n", + "14 Experience the thrill of the open road with th... \n", + "15 Enjoy a perfect blend of comfort and performan... \n", + "16 Refresh and hydrate your skin with Dove Men's ... \n", + "17 Start your day right with Quaker Oats. Packed ... \n", + "18 The Ford F-150 is a durable and dependable tru... \n", + "19 Discover the timeless style of Levi's 501 Jean... \n", + "20 Explore the future of driving with the Tesla M... \n", + "21 Step up your game with the Nike Air Max. Desig... \n", + "22 Achieve a superior clean with the Oral-B Pro 1... \n", + "23 Indulge in the creamy goodness of Organic Almo... \n", + "24 Introducing the Yamaha YZF-R3, the ultimate sp... \n", + "25 Discover the Adidas Ultraboost, a shoe that of... \n", + "26 Experience the dental care revolution with Phi... \n", + "27 Nourish your body with Organic Quinoa, a nutri... \n", + "\n", + " embedding \n", + "0 [0.003255360759794712, -0.039260633289813995, ... \n", + "1 [0.03943369910120964, 0.022045187652111053, -0... \n", + "2 [-0.003470012918114662, -0.01911414973437786, ... \n", + "3 [0.0208318829536438, -0.02645781636238098, -0.... \n", + "4 [0.007467855699360371, -0.05288049206137657, -... \n", + "5 [0.0037206460256129503, 0.022772302851080894, ... \n", + "6 [-0.00724813062697649, -0.011600878089666367, ... \n", + "7 [-0.006529285106807947, 0.007865572348237038, ... \n", + "8 [-0.02088991366326809, -0.006191295105963945, ... \n", + "9 [0.02679188922047615, 0.014639599248766899, 8.... \n", + "10 [0.008056452497839928, -0.007912316359579563, ... \n", + "11 [0.03943241760134697, 0.02208484522998333, -0.... \n", + "12 [-0.003470012918114662, -0.01911414973437786, ... \n", + "13 [-0.013289917260408401, 0.036334190517663956, ... \n", + "14 [0.012365399859845638, 0.03552943095564842, -0... \n", + "15 [0.013107392005622387, 0.02963760495185852, -0... \n", + "16 [0.03760576993227005, -0.008475445210933685, -... \n", + "17 [-0.00903365109115839, 0.00896345917135477, 0.... \n", + "18 [0.023461222648620605, -0.026651185005903244, ... \n", + "19 [0.003762696636840701, 0.02275814116001129, -0... \n", + "20 [0.03703858703374863, 0.03407958149909973, 0.0... \n", + "21 [0.03943369910120964, 0.022045187652111053, -0... \n", + "22 [-0.003470012918114662, -0.01911414973437786, ... \n", + "23 [-0.014613640494644642, -0.002179765608161688,... \n", + "24 [0.03703858703374863, 0.03407958149909973, 0.0... \n", + "25 [0.03944042697548866, 0.022062409669160843, -0... \n", + "26 [-0.003470012918114662, -0.01911414973437786, ... \n", + "27 [-0.014613640494644642, -0.002179765608161688,... " ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZcdZscBNKy0F" + }, + "source": [ + "Now we perform the elbow method. " + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 981 }, + "id": "1Azw_xgVl_aY", + "outputId": "5b7076aa-a03c-4a40-f52c-08b09248cf18" + }, + "outputs": [], + "source": [ + "# Determine the optimal number of clusters using the elbow method\n", + "inertias = []\n", + "range_of_clusters = range(1, 13) # Adjust the range as necessary\n", + "\n", + "for n_clusters in range_of_clusters:\n", + " kmeans = KMeans(n_clusters=n_clusters, init=\"k-means++\", random_state=42, n_init=10)\n", + " kmeans.fit(matrix)\n", + " inertias.append(kmeans.inertia_)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This will output a chart for us in which we have to visually tell where the optimal cluster point is. We can see below that we see a gradual decrease of inertia rather than a sharp elbow but the point of steepest decrease appears to occur around 3, 4 or 5 clusters which lines up with our expectations given our prompt. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 53 - }, - "id": "mZjBbfFaZ3mn", - "outputId": "8864421a-e9d4-4ea6-f747-a76a3291a593" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1. Cluster topic mapping\n", - "Cluster: 0, topic: Electronic/Health Products\n", - "Cluster: 1, topic: Fashion and Food\n", - "Cluster: 2, topic: Personal Care/Wellness\n", - "Cluster: 3, topic: Eco-friendly Transportation\n", - "Cluster: 4, topic: Chocolate/Motorcycles\n", - "\n", - "2. New topics\n", - "1. Home Automation Gadgets\n", - "2. Educational Tools and Apps\n", - "3. Renewable Energy Solutions\n", - "4. Virtual Reality Experiences\n" - ] - } - ], - "source": [ - "selected_examples = df.groupby('Cluster').apply(lambda x: x.sample(3)).reset_index(drop=True)\n", - "\n", - "# Format the selected examples\n", - "formatted_examples = \"\\n\".join(\n", - " f'Input: \"{row[\"Product\"]}, {row[\"Category\"]}\"\\nOutput: \"{row[\"Description\"]}\"\\nCluster: \"{row[\"Cluster\"]}\"'\n", - " for _, row in selected_examples.iterrows()\n", - ")\n", - "\n", - "topic_prompt = f\"\"\"\n", - " I previously generated some examples of input output trainings pairs and then I clustered them based on category. From each cluster I picked 3 example data point which you can find below.\n", - " I want to promote diversity in my examples across categories so follow the procedure below:\n", - " 1. You must identify the broad topic areas these clusters belong to.\n", - " 2. You should generate further topic areas which don't exist so I can generate data within these topics to improve diversity.\n", - "\n", - "\n", - " Previous examples:\n", - " {formatted_examples}\n", - "\n", - "\n", - " Your output should be strictly of the format:\n", - "\n", - " 1. Cluster topic mapping\n", - " Cluster: number, topic: topic\n", - " Cluster: number, topic: topic\n", - " Cluster: number, topic: topic\n", - "\n", - " 2. New topics\n", - " 1. topic\n", - " 2. topic\n", - " 3. topic\n", - " 4. topic\n", - "\n", - " Do not add any extra characters around that formatting as it will make the output parsing break. It is very important you stick to that output format\n", - " \"\"\"\n", - "\n", - "response = client.chat.completions.create(\n", - " model=datagen_model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to analyze clustered data\"},\n", - " {\"role\": \"user\", \"content\": topic_prompt}\n", - " ]\n", - ")\n", - "res = response.choices[0].message.content\n", - "print(res)\n" + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0oAAAIjCAYAAAA9VuvLAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB/oElEQVR4nO3dd1yVdf/H8ffhMEWGoCxBxC0OcmQ5cue4TStT245um5qpaWn9Sm1oe95m2dD20NLUypFbMzfuLW4QFWWoIHCu3x/GiamgwMV4PR+P8yiucc7nOgcP532uz/X9WgzDMAQAAAAAsHMwuwAAAAAAKGkISgAAAACQDUEJAAAAALIhKAEAAABANgQlAAAAAMiGoAQAAAAA2RCUAAAAACAbghIAAAAAZENQAgAAAIBsCEqACSwWi8aPH2//efz48bJYLDp9+rR5RZVQ1atX12233Vbkj7Ns2TJZLBYtW7asyB8LWbVv317t27c3u4xic+jQIVksFk2fPr1cPXZhyTiGt956y+xS8iUpKUmDBw9WQECALBaLhg8fXij3O336dFksFh06dKhQ7g9ATgQloJBk/NHK6/b333+bXeI1q169uiwWizp37pzr+k8//dR+nBs2bCjw/e/cuVPjx48vFX/w//rrL40fP17nzp0r1PvNCMsZtwoVKqhatWrq2bOnpk2bppSUlGu+76Kquaw4c+aMRo8erbp168rV1VU+Pj7q2rWr5s2bd133+9133+m9994rnCKLWcYXBxaLRRs3bsyxfuDAgapYsaIJlZU+EydO1PTp0/X444/r66+/1oMPPnjF7dPT0zVt2jS1b99ePj4+cnFxUfXq1TVo0KBren+9Vr///nuWL/SA8sjR7AKAsuall15SWFhYjuW1atUyoZrC4+rqqqVLlyomJkYBAQFZ1n377bdydXVVcnLyNd33zp07NWHCBLVv317Vq1cvhGqLzl9//aUJEyZo4MCB8vb2LvT7nzJliipWrKiUlBQdP35cCxYs0EMPPaT33ntP8+bNU0hISImr+XotXLjQtMfes2ePOnXqpFOnTmnQoEFq3ry5zp07p2+//VY9e/bUqFGj9Oabb17TfX/33Xfavn17jjMIoaGhunjxopycnArhCIre+PHjNXfuXLPLKLWWLFmim2++WePGjbvqthcvXlTv3r01f/58tW3bVs8995x8fHx06NAh/fTTT/ryyy915MgRBQcHF3ndv//+uyZPnkxYQrlGUAIKWffu3dW8eXOzyyh0rVu31vr16/Xjjz/qqaeesi8/duyYVq5cqTvvvFM///yziRWWDX369FHlypXtP7/44ov69ttv1b9/f/Xt27dEnZm8cOGCKlSocN334+zsXAjVFFxqaqr69Omjs2fPasWKFbrpppvs60aMGKH7779fb731lpo3b66777670B7XYrHI1dW10O6vKN1www2aN2+eNm3apKZNm5pdTrE6f/683N3dr/t+YmNjFR4enq9tR48erfnz5+vdd9/NEbDHjRund99997rrMZNhGEpOTpabm5vZpQD5QusdUIKcPn1a/fr1k6enp3x9ffXUU0/lOEuTlpaml19+WTVr1rS3ZDz33HNZWrNGjhwpX19fGYZhX/bkk0/KYrHogw8+sC87efKkLBaLpkyZctXaXF1d1bt3b3333XdZln///feqVKmSunbtmut+u3fvVp8+feTj4yNXV1c1b95cc+bMsa+fPn26+vbtK0nq0KGDvd0n+7VCq1atUosWLeTq6qoaNWroq6++yvFYBw8eVN++feXj46MKFSro5ptv1m+//ZZju2PHjumOO+6Qu7u7/Pz8NGLEiHy1to0fP16jR4+WJIWFhdlrzWgZzM9rcy3uv/9+DR48WGvXrtWiRYuyrFu7dq26desmLy8vVahQQe3atdPq1avzXbMkffPNN2rWrJnc3Nzk4+Oje+65R0ePHs3yOO3bt1fDhg21ceNGtW3bVhUqVNBzzz2X5XqRyZMnq0aNGqpQoYK6dOmio0ePyjAMvfzyywoODpabm5tuv/12xcXF5bjvzNcoZbR9/fTTT3r11VcVHBwsV1dXderUSfv378/x/FztOcjLzz//rO3bt2vMmDFZQpIkWa1WffLJJ/L29s7yjXpGbT/++KOee+45BQQEyN3dXb169crynLVv316//fabDh8+bH/OM86W5nadUEYr25EjR3TbbbepYsWKqlq1qiZPnixJ2rZtmzp27Ch3d3eFhobm+HcYFxenUaNGqVGjRqpYsaI8PT3VvXt3bdmy5arPw5U8+eSTqlSpUr7OKmS/9jJD9erVNXDgQPvPGW3Kq1at0rBhw1SlShV5e3vr0Ucf1aVLl3Tu3Dn1799flSpVUqVKlfTMM89keS/L7N1331VoaKjc3NzUrl07bd++Pcc2V3sPylzT8uXL9cQTT8jPz++qZ21iY2P13//+V/7+/nJ1dVVERIS+/PJL+/qM35WoqCj99ttvuf7by+zYsWP65JNPdOutt+Z6HZPVatWoUaOuWFd+X4PU1FRNmDBBtWvXlqurq3x9fdWmTRv7+8vAgQPtv3uZW4Iz2Gw2vffee2rQoIFcXV3l7++vRx99VGfPns3xuLfddpsWLFig5s2by83NTZ988okkadGiRWrTpo28vb1VsWJF1a1bV88991yexwaYgTNKQCGLj4/PMSiDxWKRr6/vVfft16+fqlevrkmTJunvv//WBx98oLNnz2YJBYMHD9aXX36pPn366Omnn9batWs1adIk7dq1S7NmzZIk3XLLLXr33Xe1Y8cONWzYUJK0cuVKOTg4aOXKlRo2bJh9mSS1bds2X8d23333qUuXLjpw4IBq1qwp6XJ7UZ8+fXJtI9qxY4dat26tqlWrasyYMXJ3d9dPP/2kO+64Qz///LPuvPNOtW3bVsOGDdMHH3yg5557TvXr15ck+38laf/+/erTp4/++9//asCAAfriiy80cOBANWvWTA0aNJB0OfS1atVKFy5c0LBhw+Tr66svv/xSvXr10syZM3XnnXdKutza0qlTJx05ckTDhg1TUFCQvv76ay1ZsuSqx9+7d2/t3btX33//vd599137mZ8qVark+7W5Vg8++KCmTp2qhQsX6tZbb5V0uaWne/fuatasmcaNGycHBwdNmzZNHTt21MqVK9WiRYur1vzqq6/qhRdeUL9+/TR48GCdOnVKH374odq2bavNmzdnadU7c+aMunfvrnvuuUcPPPCA/P397eu+/fZbXbp0SU8++aTi4uL0xhtvqF+/furYsaOWLVumZ599Vvv379eHH36oUaNG6YsvvrjqMb/22mtycHDQqFGjFB8frzfeeEP333+/1q5da98mP89BXjLayfr375/rei8vL91+++368ssvtX///izts6+++qosFoueffZZxcbG6r333lPnzp0VGRkpNzc3Pf/884qPj9exY8fsZwGudk1Penq6unfvrrZt2+qNN97Qt99+q6FDh8rd3V3PP/+87r//fvXu3Vsff/yx+vfvr5YtW9rbfA8ePKjZs2erb9++CgsL08mTJ/XJJ5+oXbt22rlzp4KCgq76fOfG09NTI0aM0IsvvljoZ5WefPJJBQQEaMKECfr77781depUeXt766+//lK1atU0ceJE/f7773rzzTfVsGHDHK/TV199pcTERA0ZMkTJycl6//331bFjR23bts3+u5mf96DMnnjiCVWpUkUvvviizp8/n2ftFy9eVPv27bV//34NHTpUYWFhmjFjhgYOHKhz587pqaeeUv369fX1119rxIgRCg4O1tNPPy3p33972f3xxx9KS0u76jVMhWH8+PGaNGmSBg8erBYtWighIUEbNmzQpk2bdOutt+rRRx/ViRMntGjRIn399dc59n/00Uc1ffp0DRo0SMOGDVNUVJT+97//afPmzVq9enWWvwd79uzRvffeq0cffVQPP/yw6tatqx07dui2225T48aN9dJLL8nFxUX79+/P1xccQLEyABSKadOmGZJyvbm4uGTZVpIxbtw4+8/jxo0zJBm9evXKst0TTzxhSDK2bNliGIZhREZGGpKMwYMHZ9lu1KhRhiRjyZIlhmEYRmxsrCHJ+OijjwzDMIxz584ZDg4ORt++fQ1/f3/7fsOGDTN8fHwMm812xWMLDQ01evToYaSlpRkBAQHGyy+/bBiGYezcudOQZCxfvtx+/OvXr7fv16lTJ6NRo0ZGcnKyfZnNZjNatWpl1K5d275sxowZhiRj6dKluT62JGPFihX2ZbGxsYaLi4vx9NNP25cNHz7ckGSsXLnSviwxMdEICwszqlevbqSnpxuGYRjvvfeeIcn46aef7NudP3/eqFWrVp41ZPbmm28akoyoqKgsy/P72uQl43fg1KlTua4/e/asIcm48847DcO4/DzWrl3b6Nq1a5bX78KFC0ZYWJhx6623XrXmQ4cOGVar1Xj11VezLN+2bZvh6OiYZXm7du0MScbHH3+cZduoqChDklGlShXj3Llz9uVjx441JBkRERFGamqqffm9995rODs7Z/mdaNeundGuXTv7z0uXLjUkGfXr1zdSUlLsy99//31DkrFt27YCPwe5ueGGGwwvL68rbvPOO+8Ykow5c+Zkqa1q1apGQkKCfbuffvrJkGS8//779mU9evQwQkNDc9xnxnM2bdo0+7IBAwYYkoyJEyfal509e9Zwc3MzLBaL8cMPP9iX7969O8d7SHJysv13PPPjuLi4GC+99NIVHzs3Gcc5Y8YM49y5c0alSpWyvD8NGDDAcHd3z7JP9poyhIaGGgMGDLD/nPFekf11a9mypWGxWIzHHnvMviwtLc0IDg7O8vuRcQxubm7GsWPH7MvXrl1rSDJGjBhhX5bf96CMmtq0aWOkpaVd8bkxjH/fR7755hv7skuXLhktW7Y0KlasmOV3I+P982pGjBhhSDI2b9581W0z15z533V+X4OIiIir1jRkyBAjt4+JK1euNCQZ3377bZbl8+fPz7E84/17/vz5WbZ99913r/h+B5QUtN4BhWzy5MlatGhRltsff/yRr32HDBmS5ecnn3xS0uWLajP/d+TIkVm2y/imMqPNrEqVKqpXr55WrFghSVq9erWsVqtGjx6tkydPat++fZIun1Fq06ZNlpaKK7FarerXr5++//57SZfPIoSEhOiWW27JsW1cXJyWLFmifv36KTExUadPn9bp06d15swZde3aVfv27dPx48fz9bjh4eFZHqNKlSqqW7euDh48aF/2+++/q0WLFmrTpo19WcWKFfXII4/o0KFD2rlzp327wMBA9enTx75dhQoV9Mgjj+Srlrzk97W5VhlnIxITEyVJkZGR2rdvn+677z6dOXPG/vyeP39enTp10ooVK2Sz2a54n7/88otsNpv69etn3//06dMKCAhQ7dq1tXTp0izbu7i4aNCgQbneV9++feXl5WX/OaOV7YEHHpCjo2OW5ZcuXcrXaz9o0KAs1y9l/A5kvO7X+xwkJibKw8PjijVkrE9ISMiyvH///ln27dOnjwIDA+2/B9dq8ODB9v/39vZW3bp15e7urn79+tmX161bV97e3ll+/11cXOTgcPlPenp6us6cOWNvZ9q0adN11eTl5aXhw4drzpw52rx583XdV2b//e9/s7z33HTTTTIMQ//973/ty6xWq5o3b57lWDPccccdqlq1qv3nFi1a6KabbrK/BtfyHvTwww/LarVetfbff/9dAQEBuvfee+3LnJycNGzYMCUlJWn58uX5fyL+kfE7drXfycLg7e2tHTt22P8WFMSMGTPk5eWlW2+9Ncv7RrNmzVSxYsUc7xthYWE5WrMzzlT/+uuvV32fAsxE6x1QyFq0aHHNgznUrl07y881a9aUg4ODvaf98OHDcnBwyDGCXkBAgLy9vXX48GH7sltuucX+gWHlypVq3ry5mjdvLh8fH61cuVL+/v7asmWL7rvvvgLVeN999+mDDz7Qli1b9N133+mee+7J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AEA2BCUAAAAAyIagBAAAAADZEJQAAAAAIBuCUjFYsWKFevbsqaCgIFksFs2ePdvskorVpEmTdOONN8rDw0N+fn664447tGfPHrPLKjZTpkxR48aN7ZOstWzZUn/88YfZZZnmtddek8Vi0fDhw80upViMHz9eFosly61evXpml1Wsjh8/rgceeEC+vr5yc3NTo0aNtGHDBrPLKhbVq1fP8fpbLBYNGTLE7NKKRXp6ul544QWFhYXJzc1NNWvW1Msvv6zyNI5UYmKihg8frtDQULm5ualVq1Zav3692WUViat93jEMQy+++KICAwPl5uamzp07a9++feYUWwSudvy//PKLunTpIl9fX1ksFkVGRppSZ1G60nOQmpqqZ599Vo0aNZK7u7uCgoLUv39/nThxwryCr4KgVAzOnz+viIgITZ482exSTLF8+XINGTJEf//9txYtWqTU1FR16dJF58+fN7u0YhEcHKzXXntNGzdu1IYNG9SxY0fdfvvt2rFjh9mlFbv169frk08+UePGjc0upVg1aNBA0dHR9tuqVavMLqnYnD17Vq1bt5aTk5P++OMP7dy5U2+//bYqVapkdmnFYv369Vle+0WLFkmS+vbta3JlxeP111/XlClT9L///U+7du3S66+/rjfeeEMffvih2aUVm8GDB2vRokX6+uuvtW3bNnXp0kWdO3fW8ePHzS6t0F3t884bb7yhDz74QB9//LHWrl0rd3d3de3aVcnJycVcadG42vGfP39ebdq00euvv17MlRWfKz0HFy5c0KZNm/TCCy9o06ZN+uWXX7Rnzx716tXLhErzyUCxkmTMmjXL7DJMFRsba0gyli9fbnYppqlUqZLx2WefmV1GsUpMTDRq165tLFq0yGjXrp3x1FNPmV1SsRg3bpwRERFhdhmmefbZZ402bdqYXUaJ8dRTTxk1a9Y0bDab2aUUix49ehgPPfRQlmW9e/c27r//fpMqKl4XLlwwrFarMW/evCzLmzZtajz//PMmVVU8sn/esdlsRkBAgPHmm2/al507d85wcXExvv/+exMqLFpX+rwXFRVlSDI2b95crDUVt/x85l23bp0hyTh8+HDxFFVAnFFCsYuPj5ck+fj4mFxJ8UtPT9cPP/yg8+fPq2XLlmaXU6yGDBmiHj16qHPnzmaXUuz27dunoKAg1ahRQ/fff7+OHDlidknF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0jXve+DAAbVp00ahoaHy9fXNdZtDhw6pWbNmWrJkid58801t27ZN8+fPV4cOHTRkyJBrfuziYBiG0tLSzC4DAEo1ghIAlAOdO3dWQECAJk2alOc248ePz9GG9t5776l69er2nwcOHKg77rhDEydOlL+/v7y9vfXSSy8pLS1No0ePlo+Pj4KDgzVt2rQc97979261atVKrq6uatiwoZYvX55l/fbt29W9e3dVrFhR/v7+evDBB3X69Gn7+vbt22vo0KEaPny4KleurK5du+Z6HDabTS+99JKCg4Pl4uKiG264QfPnz7evt1gs2rhxo1566SVZLBaNHz8+1/t54oknZLFYtG7dOt11112qU6eOGjRooJEjR+rvv//OdZ/czghFRkbKYrHo0KFDkqTDhw+rZ8+eqlSpktzd3dWgQQP9/vvvOnTokDp06CBJqlSpkiwWiwYOHGg/pkmTJiksLExubm6KiIjQzJkzczzuH3/8oWbNmsnFxUWrVq3Sli1b1KFDB3l4eMjT01PNmjXThg0bcq0dAJAVQQkAygGr1aqJEyfqww8/1LFjx67rvpYsWaITJ05oxYoVeueddzRu3DjddtttqlSpktauXavHHntMjz76aI7HGT16tJ5++mlt3rxZLVu2VM+ePXXmzBlJ0rlz59SxY0c1adJEGzZs0Pz583Xy5En169cvy318+eWXcnZ21urVq/Xxxx/nWt/777+vt99+W2+99Za2bt2qrl27qlevXtq3b58kKTo6Wg0aNNDTTz+t6OhojRo1Ksd9xMXFaf78+RoyZIjc3d1zrPf29r6Wp06SNGTIEKWkpGjFihXatm2bXn/9dVWsWFEhISH6+eefJUl79uxRdHS03n//fUnSpEmT9NVXX+njjz/Wjh07NGLECD3wwAM5wuaYMWP02muvadeuXWrcuLHuv/9+BQcHa/369dq4caPGjBkjJyena64dAMoTR7MLAAAUjzvvvFM33HCDxo0bp88///ya78fHx0cffPCBHBwcVLduXb3xxhu6cOGCnnvuOUnS2LFj9dprr2nVqlW655577PsNHTpUd911lyRpypQpmj9/vj7//HM988wz+t///qcmTZpo4sSJ9u2/+OILhYSEaO/evapTp44kqXbt2nrjjTeuWN9bb72lZ5991v7Yr7/+upYuXar33ntPkydPVkBAgBwdHVWxYkUFBATkeh/79++XYRiqV6/eNT9PeTly5IjuuusuNWrUSJJUo0YN+zofHx9Jkp+fnz2MpaSkaOLEifrzzz/VsmVL+z6rVq3SJ598onbt2tn3f+mll3TrrbdmeazRo0fbj6N27dqFfjwAUFYRlACgHHn99dfVsWPHXM+i5FeDBg3k4PBvQ4K/v78aNmxo/9lqtcrX11exsbFZ9sv4kC9Jjo6Oat68uXbt2iVJ2rJli5YuXaqKFSvmeLwDBw7Yg1KzZs2uWFtCQoJOnDih1q1bZ1neunVrbdmyJZ9HePkan6IybNgwPf7441q4cKE6d+6su+66S40bN85z+/379+vChQtZApB0+RqtJk2aZFnWvHnzLD+PHDlSgwcP1tdff63OnTurb9++qlmzZuEdDACUYbTeAUA50rZtW3Xt2lVjx47Nsc7BwSFHQEhNTc2xXfbWLYvFkusym82W77qSkpLUs2dPRUZGZrnt27dPbdu2tW+XWxtcUahdu7YsFot2795doP0yAmTm5zH7czh48GAdPHhQDz74oLZt26bmzZvrww8/zPM+k5KSJEm//fZbludm586dWa5TknI+P+PHj9eOHTvUo0cPLVmyROHh4Zo1a1aBjgkAyiuCEgCUM6+99prmzp2rNWvWZFlepUoVxcTEZPmQX5hzH2UeACEtLU0bN25U/fr1JUlNmzbVjh07VL16ddWqVSvLrSDhyNPTU0FBQVq9enWW5atXr1Z4eHi+78fHx0ddu3bV5MmTdf78+Rzr8xq+u0qVKpIuXweVIbfnMCQkRI899ph++eUXPf300/r0008lSc7OzpKk9PR0+7bh4eFycXHRkSNHcjw3ISEhVz2WOnXqaMSIEVq4cKF69+6d60AbAICcCEoAUM40atRI999/vz744IMsy9u3b69Tp07pjTfe0IEDBzR58mT98ccfhfa4kydP1qxZs7R7924NGTJEZ8+e1UMPPSTp8gAHcXFxuvfee7V+/XodOHBACxYs0KBBg7KEhvwYPXq0Xn/9df3444/as2ePxowZo8jISD311FMFrjc9PV0tWrTQzz//rH379mnXrl364IMPsrQRZpYRXsaPH699+/bpt99+09tvv51lm+HDh2vBggWKiorSpk2btHTpUntgDA0NlcVi0bx583Tq1CklJSXJw8NDo0aN0ogRI/Tll1/qwIED2rRpkz788EN9+eWXedZ/8eJFDR06VMuWLdPhw4e1evVqrV+/3v5YAIArIygBQDn00ksv5WiNq1+/vj766CNNnjxZERERWrdu3XVdy5Tda6+9ptdee00RERFatWqV5syZo8qVK0uS/SxQenq6unTpokaNGmn48OHy9vbOcj1UfgwbNkwjR47U008/rUaNGmn+/PmaM2dOgQcyqFGjhjZt2qQOHTro6aefVsOGDXXrrbdq8eLFmjJlSq77ODk56fvvv9fu3bvVuHFjvf7663rllVeybJOenq4hQ4aofv366tatm+rUqaOPPvpIklS1alVNmDBBY8aMkb+/v4YOHSpJevnll/XCCy9o0qRJ9v1+++03hYWF5Vm/1WrVmTNn1L9/f9WpU0f9+vVT9+7dNWHChAI9DwBQXlmMorxiFQAAAABKIc4oAQAAAEA2BCUAAAAAyIagBAAAAADZEJQAAAAAIBuCEgAAAABkQ1ACAAAAgGwISgAAAACQDUEJAAAAALIhKAEAAABANgQlAAAAAMiGoAQAAAAA2fw/3VzJT9TMek4AAAAASUVORK5CYII=", + "text/plain": [ + "
" ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plotting the elbow plot\n", + "plt.figure(figsize=(10, 6))\n", + "plt.plot(range_of_clusters, inertias, '-o')\n", + "plt.title('Elbow Method to Determine Optimal Number of Clusters')\n", + "plt.xlabel('Number of Clusters')\n", + "plt.ylabel('Inertia')\n", + "plt.xticks(range_of_clusters)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![elbow_chart](../images/elbow_chart.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NN7NbTmiLe_-" + }, + "source": [ + "For demonstration purposes we will pick 5 as the optimal cluster number to show it doesn't matter exactly where we pick it as long as we are approximately right. There are numerous correct ways to categorize data. We also store which cluster each data point belongs to." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see here again that we explicitly prompt the output structure it should follow. I also tell it the purpose of generating topics (to promote diversity) so the model has full context." - ] + "id": "KvrDe3WYKWgZ", + "outputId": "d0d95227-b9d2-4c52-a5f7-59159ba848d2" + }, + "outputs": [], + "source": [ + "n_clusters = 5\n", + "\n", + "kmeans = KMeans(n_clusters=n_clusters, init=\"k-means++\", random_state=42)\n", + "kmeans.fit(matrix)\n", + "labels = kmeans.labels_\n", + "df[\"Cluster\"] = labels" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tLvO4AISDM0J" + }, + "source": [ + "We will analyze the cluster data now. There are two separate things we will look to address. 1. imbalanced data, 2. Expanding the data distribution." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zaQ_mdhpOJqs" + }, + "source": [ + "First for imbalanced data we count the number of examples in each cluster. Then we select a few examples from each cluster at random and ask the LLM what topics these map to. " + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "crUT7OR7QcFD", + "outputId": "04f49ac2-1259-4622-bcf2-0686af93068c" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "s254oJ-Ecka0" - }, - "source": [ - "We then parse the data into a list of cluster-mapping jsons and a list of topics" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Cluster\n", + "0 5\n", + "1 7\n", + "2 8\n", + "3 6\n", + "4 2\n", + "Name: count, dtype: int64\n" + ] + } + ], + "source": [ + "cluster_counts = df[\"Cluster\"].value_counts().sort_index()\n", + "print(cluster_counts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8i1FGtM-Xx3k" + }, + "source": [ + "We can see the topics found here:\n", + "Eco-friendly Transportation, Luxury and Leisure Items, Personal Care Products, Electronic Toothbrushes and Clothing and Apparel\n", + "match well enough but not exactly to our initial prompt of:\n", + "vehicle, clothing, toiletries, food.\n", + "\n", + "As we chose 5 clusters, it split up toiletries into Skincare and Personal Care which doesn't affect us too much further downstream." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "HTS4ybspcivw", - "outputId": "52ea363c-cbf5-420e-b81e-0d2710c50203" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "([{'cluster': 0, 'topic': 'Electronic/Health Products'},\n", - " {'cluster': 1, 'topic': 'Fashion and Food'},\n", - " {'cluster': 2, 'topic': 'Personal Care/Wellness'},\n", - " {'cluster': 3, 'topic': 'Eco-friendly Transportation'},\n", - " {'cluster': 4, 'topic': 'Chocolate/Motorcycles'}],\n", - " ['Home Automation Gadgets',\n", - " 'Educational Tools and Apps',\n", - " 'Renewable Energy Solutions',\n", - " 'Virtual Reality Experiences'])" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ProductCategoryDescriptionembeddingCluster
0Tesla Model 3Electric CarThe Tesla Model 3 is a revolutionary electric ...[0.003255360759794712, -0.039260633289813995, ...1
1Nike Air MaxShoesElevate your sneaker game with Nike Air Max. C...[0.03943369910120964, 0.022045187652111053, -0...2
2Oral-B Pro 1000Electronic ToothbrushAchieve a superior clean with the Oral-B Pro 1...[-0.003470012918114662, -0.01911414973437786, ...1
3Chobani Greek YogurtYogurtIndulge in a nutritious snack with Chobani Gre...[0.0208318829536438, -0.02645781636238098, -0....3
4Ford F-150Pickup TruckThe Ford F-150 is the ultimate pickup truck, d...[0.007467855699360371, -0.05288049206137657, -...0
5Levi's 511JeansStep out in style with Levi's 511 jeans. Featu...[0.0037206460256129503, 0.022772302851080894, ...2
6Philips SonicareElectric ToothbrushDiscover a new level of oral care with the Phi...[-0.00724813062697649, -0.011600878089666367, ...1
7Quaker OatmealBreakfast CerealStart your day right with Quaker Oatmeal. This...[-0.006529285106807947, 0.007865572348237038, ...3
8Toyota CamrySedanThe Toyota Camry stands out in the sedan categ...[-0.02088991366326809, -0.006191295105963945, ...0
9Adidas UltraboostRunning ShoesRun like never before in the Adidas Ultraboost...[0.02679188922047615, 0.014639599248766899, 8....2
10Toyota CamryCarThe Toyota Camry is a reliable midsize sedan k...[0.008056452497839928, -0.007912316359579563, ...0
11Nike Air MaxShoesStep up your sneaker game with the Nike Air Ma...[0.03943241760134697, 0.02208484522998333, -0....2
12Colgate Electric ToothbrushElectronic ToothbrushTransform your oral hygiene routine with the C...[-0.003470012918114662, -0.01911414973437786, ...1
13Blue Diamond AlmondsNutsSnack healthy with Blue Diamond Almonds. These...[-0.013289917260408401, 0.036334190517663956, ...3
14Harley Davidson Fat BoyMotorcycleExperience the thrill of the open road with th...[0.012365399859845638, 0.03552943095564842, -0...0
15Adidas UltraBoostSneakersEnjoy a perfect blend of comfort and performan...[0.013107392005622387, 0.02963760495185852, -0...2
16Dove Men's Body WashBody WashRefresh and hydrate your skin with Dove Men's ...[0.03760576993227005, -0.008475445210933685, -...1
17Quaker OatsOatsStart your day right with Quaker Oats. Packed ...[-0.00903365109115839, 0.00896345917135477, 0....3
18Ford F-150TruckThe Ford F-150 is a durable and dependable tru...[0.023461222648620605, -0.026651185005903244, ...0
19Levi's 501 JeansJeansDiscover the timeless style of Levi's 501 Jean...[0.003762696636840701, 0.02275814116001129, -0...2
20Tesla Model 3Mobile PhonesExplore the future of driving with the Tesla M...[0.03703858703374863, 0.03407958149909973, 0.0...4
21Nike Air MaxShoesStep up your game with the Nike Air Max. Desig...[0.03943369910120964, 0.022045187652111053, -0...2
22Oral-B Pro 1000Electronic ToothbrushAchieve a superior clean with the Oral-B Pro 1...[-0.003470012918114662, -0.01911414973437786, ...1
23Organic Almond ButterFoodIndulge in the creamy goodness of Organic Almo...[-0.014613640494644642, -0.002179765608161688,...3
24Yamaha YZF-R3Mobile PhonesIntroducing the Yamaha YZF-R3, the ultimate sp...[0.03703858703374863, 0.03407958149909973, 0.0...4
25Adidas UltraboostShoesDiscover the Adidas Ultraboost, a shoe that of...[0.03944042697548866, 0.022062409669160843, -0...2
26Philips SonicareElectronic ToothbrushExperience the dental care revolution with Phi...[-0.003470012918114662, -0.01911414973437786, ...1
27Organic QuinoaFoodNourish your body with Organic Quinoa, a nutri...[-0.014613640494644642, -0.002179765608161688,...3
\n", + "
" ], - "source": [ - "parts = res.split(\"\\n\\n\")\n", - "cluster_mapping_part = parts[0]\n", - "new_topics_part = parts[1]\n", - "\n", - "# Parse cluster topic mapping\n", - "cluster_topic_mapping_lines = cluster_mapping_part.split(\"\\n\")[1:] # Skip the first two lines\n", - "cluster_topic_mapping = [{\"cluster\": int(line.split(\",\")[0].split(\":\")[1].strip()), \"topic\": line.split(\":\")[2].strip()} for line in cluster_topic_mapping_lines]\n", - "\n", - "# Parse new topics\n", - "new_topics_lines = new_topics_part.split(\"\\n\")[1:] # Skip the first line\n", - "new_topics = [line.split(\". \")[1] for line in new_topics_lines]\n", - "\n", - "cluster_topic_mapping, new_topics" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "CX26-PGdcui0" - }, - "source": [ - "And finally we can use this information to further prompt a model to keep generating synthetic data. We do this by passing all the topics in the list of jsons to the prompt below." + "text/plain": [ + " Product Category \\\n", + "0 Tesla Model 3 Electric Car \n", + "1 Nike Air Max Shoes \n", + "2 Oral-B Pro 1000 Electronic Toothbrush \n", + "3 Chobani Greek Yogurt Yogurt \n", + "4 Ford F-150 Pickup Truck \n", + "5 Levi's 511 Jeans \n", + "6 Philips Sonicare Electric Toothbrush \n", + "7 Quaker Oatmeal Breakfast Cereal \n", + "8 Toyota Camry Sedan \n", + "9 Adidas Ultraboost Running Shoes \n", + "10 Toyota Camry Car \n", + "11 Nike Air Max Shoes \n", + "12 Colgate Electric Toothbrush Electronic Toothbrush \n", + "13 Blue Diamond Almonds Nuts \n", + "14 Harley Davidson Fat Boy Motorcycle \n", + "15 Adidas UltraBoost Sneakers \n", + "16 Dove Men's Body Wash Body Wash \n", + "17 Quaker Oats Oats \n", + "18 Ford F-150 Truck \n", + "19 Levi's 501 Jeans Jeans \n", + "20 Tesla Model 3 Mobile Phones \n", + "21 Nike Air Max Shoes \n", + "22 Oral-B Pro 1000 Electronic Toothbrush \n", + "23 Organic Almond Butter Food \n", + "24 Yamaha YZF-R3 Mobile Phones \n", + "25 Adidas Ultraboost Shoes \n", + "26 Philips Sonicare Electronic Toothbrush \n", + "27 Organic Quinoa Food \n", + "\n", + " Description \\\n", + "0 The Tesla Model 3 is a revolutionary electric ... \n", + "1 Elevate your sneaker game with Nike Air Max. C... \n", + "2 Achieve a superior clean with the Oral-B Pro 1... \n", + "3 Indulge in a nutritious snack with Chobani Gre... \n", + "4 The Ford F-150 is the ultimate pickup truck, d... \n", + "5 Step out in style with Levi's 511 jeans. Featu... \n", + "6 Discover a new level of oral care with the Phi... \n", + "7 Start your day right with Quaker Oatmeal. This... \n", + "8 The Toyota Camry stands out in the sedan categ... \n", + "9 Run like never before in the Adidas Ultraboost... \n", + "10 The Toyota Camry is a reliable midsize sedan k... \n", + "11 Step up your sneaker game with the Nike Air Ma... \n", + "12 Transform your oral hygiene routine with the C... \n", + "13 Snack healthy with Blue Diamond Almonds. These... \n", + "14 Experience the thrill of the open road with th... \n", + "15 Enjoy a perfect blend of comfort and performan... \n", + "16 Refresh and hydrate your skin with Dove Men's ... \n", + "17 Start your day right with Quaker Oats. Packed ... \n", + "18 The Ford F-150 is a durable and dependable tru... \n", + "19 Discover the timeless style of Levi's 501 Jean... \n", + "20 Explore the future of driving with the Tesla M... \n", + "21 Step up your game with the Nike Air Max. Desig... \n", + "22 Achieve a superior clean with the Oral-B Pro 1... \n", + "23 Indulge in the creamy goodness of Organic Almo... \n", + "24 Introducing the Yamaha YZF-R3, the ultimate sp... \n", + "25 Discover the Adidas Ultraboost, a shoe that of... \n", + "26 Experience the dental care revolution with Phi... \n", + "27 Nourish your body with Organic Quinoa, a nutri... \n", + "\n", + " embedding Cluster \n", + "0 [0.003255360759794712, -0.039260633289813995, ... 1 \n", + "1 [0.03943369910120964, 0.022045187652111053, -0... 2 \n", + "2 [-0.003470012918114662, -0.01911414973437786, ... 1 \n", + "3 [0.0208318829536438, -0.02645781636238098, -0.... 3 \n", + "4 [0.007467855699360371, -0.05288049206137657, -... 0 \n", + "5 [0.0037206460256129503, 0.022772302851080894, ... 2 \n", + "6 [-0.00724813062697649, -0.011600878089666367, ... 1 \n", + "7 [-0.006529285106807947, 0.007865572348237038, ... 3 \n", + "8 [-0.02088991366326809, -0.006191295105963945, ... 0 \n", + "9 [0.02679188922047615, 0.014639599248766899, 8.... 2 \n", + "10 [0.008056452497839928, -0.007912316359579563, ... 0 \n", + "11 [0.03943241760134697, 0.02208484522998333, -0.... 2 \n", + "12 [-0.003470012918114662, -0.01911414973437786, ... 1 \n", + "13 [-0.013289917260408401, 0.036334190517663956, ... 3 \n", + "14 [0.012365399859845638, 0.03552943095564842, -0... 0 \n", + "15 [0.013107392005622387, 0.02963760495185852, -0... 2 \n", + "16 [0.03760576993227005, -0.008475445210933685, -... 1 \n", + "17 [-0.00903365109115839, 0.00896345917135477, 0.... 3 \n", + "18 [0.023461222648620605, -0.026651185005903244, ... 0 \n", + "19 [0.003762696636840701, 0.02275814116001129, -0... 2 \n", + "20 [0.03703858703374863, 0.03407958149909973, 0.0... 4 \n", + "21 [0.03943369910120964, 0.022045187652111053, -0... 2 \n", + "22 [-0.003470012918114662, -0.01911414973437786, ... 1 \n", + "23 [-0.014613640494644642, -0.002179765608161688,... 3 \n", + "24 [0.03703858703374863, 0.03407958149909973, 0.0... 4 \n", + "25 [0.03944042697548866, 0.022062409669160843, -0... 2 \n", + "26 [-0.003470012918114662, -0.01911414973437786, ... 1 \n", + "27 [-0.014613640494644642, -0.002179765608161688,... 3 " ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "RRwIet9DUdKe", + "outputId": "8e7835c9-884a-4504-bbed-f556382dd9f5" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "zHf4LnVk0aHw" - }, - "outputs": [], - "source": [ - "output_string = \"\"\n", - "for i in range(3):\n", - " question = f\"\"\"\n", - " I am creating input output training pairs to fine tune my gpt model. I want the input to be product name and category and output to be description. the category should be things like: mobile phones, shoes, headphones, laptop, electronic toothbrush, etc. and also more importantly the categories should come under some main topics: {[entry['topic'] for entry in cluster_topic_mapping]})\n", - " After the number of each example also state the topic area. The format should be of the form:\n", - " 1. topic_area\n", - " Input: product_name, category\n", - " Output: description\n", - "\n", - " Do not add any extra characters around that formatting as it will make the output parsing break.\n", - "\n", - " Here are some helpful examples so you get the style of output correct.\n", - "\n", - " 1) clothing\n", - " Input: \"Shoe Name, Shoes\"\n", - " Output: \"Experience unparalleled comfort. These shoes feature a blend of modern style and the traditional superior cushioning, perfect for those always on the move.\"\n", - " \"\"\"\n", - "\n", - " response = client.chat.completions.create(\n", - " model=\"gpt-4\",\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", - " {\"role\": \"user\", \"content\": question}\n", - " ]\n", - " )\n", - " res = response.choices[0].message.content\n", - " output_string += res + \"\\n\" + \"\\n\"\n", - "print(output_string)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "[\n", + " {\n", + " \"cluster\": 0,\n", + " \"topic\": \"Automotive \"\n", + " },\n", + " {\n", + " \"cluster\": 1,\n", + " \"topic\": \"Personal Care \"\n", + " },\n", + " {\n", + " \"cluster\": 2,\n", + " \"topic\": \"Footwear \"\n", + " },\n", + " {\n", + " \"cluster\": 3,\n", + " \"topic\": \"Food \"\n", + " },\n", + " {\n", + " \"cluster\": 4,\n", + " \"topic\": \"Automotive \"\n", + " }\n", + "]\n" + ] + } + ], + "source": [ + "selected_examples = df.groupby('Cluster').apply(lambda x: x.sample(3, replace=True)).reset_index(drop=True)\n", + "\n", + "# Format the selected examples\n", + "formatted_examples = \"\\n\".join(\n", + " f'Input: \"{row[\"Product\"]}, {row[\"Category\"]}\"\\nOutput: \"{row[\"Description\"]}\"\\nCluster: \"{row[\"Cluster\"]}\"'\n", + " for _, row in selected_examples.iterrows()\n", + ")\n", + "\n", + "topic_prompt = f\"\"\"\n", + " I previously generated some examples of input output trainings pairs and then I clustered them based on category. From each cluster I picked 3 example data point which you can find below.\n", + " I want you identify the broad topic areas these clusters belong to.\n", + " Previous examples:\n", + " {formatted_examples}\n", + "\n", + "\n", + " Your output should be strictly of the format:\n", + " Cluster: number, topic: topic\n", + " Cluster: number, topic: topic\n", + " Cluster: number, topic: topic\n", + "\n", + " Do not add any extra characters around that formatting as it will make the output parsing break.\n", + " \"\"\"\n", + "\n", + "response = client.chat.completions.create(\n", + " model=datagen_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed analyze clustered data\"},\n", + " {\"role\": \"user\", \"content\": topic_prompt}\n", + " ]\n", + ")\n", + "res = response.choices[0].message.content\n", + "\n", + "pattern = r\"Cluster: (\\d+), topic: ([^\\n]+)\"\n", + "matches = re.findall(pattern, res)\n", + "clusters = [{\"cluster\": int(cluster), \"topic\": topic} for cluster, topic in matches]\n", + "json_output = json.dumps(clusters, indent=2)\n", + "print(json_output)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "x5hszl-SZVdi" + }, + "source": [ + "We now have the clusters and their counts so we could prompt the LLM to generate more examples within the topics we want. However for this example we won't take that further as they are well-split and you would just follow the procedure above for prompting the model to generate data while passing in the underrepresented topics." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yVD_TPsHYvDb" + }, + "source": [ + "Next, we will try and deal with increasing the diversity of our data distribution. \n", + "\n", + "First we start in a similar way by finding a few examples from each cluster at random and ask the LLM what topics these map to. In addition to this in the same LLM call, we will ask it to generate more topics to increase the diversity of our data. We do this in one call to save time/cost." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 53 }, + "id": "mZjBbfFaZ3mn", + "outputId": "8864421a-e9d4-4ea6-f747-a76a3291a593" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "RQMHQxnZdRug" - }, - "source": [ - "You can run this in a loop to append to your previous data and in this way you can keep generating more textual synthetic data to train another GPT model while making sure that we cater to imbalanced datasets and generating a diversity of data." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "1. Cluster topic mapping\n", + "Cluster: 0, topic: Automotive\n", + "Cluster: 1, topic: Personal Care\n", + "Cluster: 2, topic: Footwear\n", + "Cluster: 3, topic: Food\n", + "Cluster: 4, topic: Electric Vehicles\n", + "\n", + "2. New topics\n", + "1. topic: Home Appliances\n", + "2. topic: Outdoor Equipment\n", + "3. topic: Smart Home Technology\n", + "4. topic: Fitness Equipment\n" + ] + } + ], + "source": [ + "selected_examples = df.groupby('Cluster').apply(lambda x: x.sample(3, replace=True)).reset_index(drop=True)\n", + "\n", + "# Format the selected examples\n", + "formatted_examples = \"\\n\".join(\n", + " f'Input: \"{row[\"Product\"]}, {row[\"Category\"]}\"\\nOutput: \"{row[\"Description\"]}\"\\nCluster: \"{row[\"Cluster\"]}\"'\n", + " for _, row in selected_examples.iterrows()\n", + ")\n", + "\n", + "topic_prompt = f\"\"\"\n", + " I previously generated some examples of input output trainings pairs and then I clustered them based on category. From each cluster I picked 3 example data point which you can find below.\n", + " I want to promote diversity in my examples across categories so follow the procedure below:\n", + " 1. You must identify the broad topic areas these clusters belong to.\n", + " 2. You should generate further topic areas which don't exist so I can generate data within these topics to improve diversity.\n", + "\n", + "\n", + " Previous examples:\n", + " {formatted_examples}\n", + "\n", + "\n", + " Your output should be strictly of the format:\n", + "\n", + " 1. Cluster topic mapping\n", + " Cluster: number, topic: topic\n", + " Cluster: number, topic: topic\n", + " Cluster: number, topic: topic\n", + "\n", + " 2. New topics\n", + " 1. topic\n", + " 2. topic\n", + " 3. topic\n", + " 4. topic\n", + "\n", + " Do not add any extra characters around that formatting as it will make the output parsing break. It is very important you stick to that output format\n", + " \"\"\"\n", + "\n", + "response = client.chat.completions.create(\n", + " model=datagen_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to analyze clustered data\"},\n", + " {\"role\": \"user\", \"content\": topic_prompt}\n", + " ]\n", + ")\n", + "res = response.choices[0].message.content\n", + "print(res)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see here again that we explicitly prompt the output structure it should follow. I also tell it the purpose of generating topics (to promote diversity) so the model has full context." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s254oJ-Ecka0" + }, + "source": [ + "We then parse the data into a list of cluster-mapping jsons and a list of topics" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "HTS4ybspcivw", + "outputId": "52ea363c-cbf5-420e-b81e-0d2710c50203" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "Hiim8Xg5djGH" - }, - "source": [ - "You have now completed part 1 of the synthetic data generation tutorial where we have gone through:\n", - "* CSV with a structured prompt\n", - "* CSV with a Python program\n", - "* Multitable CSV with a python program\n", - "* Simply creating textual data\n", - "* Dealing with imbalanced or non-diverse textual data\n", - "\n", - "In part 2 you will find find out techniques for better prompting an LLM to enhance textual synthetic data generation." + "data": { + "text/plain": [ + "([{'cluster': 0, 'topic': 'Automotive'},\n", + " {'cluster': 1, 'topic': 'Personal Care'},\n", + " {'cluster': 2, 'topic': 'Footwear'},\n", + " {'cluster': 3, 'topic': 'Food'},\n", + " {'cluster': 4, 'topic': 'Electric Vehicles'}],\n", + " ['topic: Home Appliances',\n", + " 'topic: Outdoor Equipment',\n", + " 'topic: Smart Home Technology',\n", + " 'topic: Fitness Equipment'])" ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.14" + ], + "source": [ + "parts = res.split(\"\\n\\n\")\n", + "cluster_mapping_part = parts[0]\n", + "new_topics_part = parts[1]\n", + "\n", + "# Parse cluster topic mapping\n", + "cluster_topic_mapping_lines = cluster_mapping_part.split(\"\\n\")[1:] # Skip the first two lines\n", + "cluster_topic_mapping = [{\"cluster\": int(line.split(\",\")[0].split(\":\")[1].strip()), \"topic\": line.split(\":\")[2].strip()} for line in cluster_topic_mapping_lines]\n", + "\n", + "# Parse new topics\n", + "new_topics_lines = new_topics_part.split(\"\\n\")[1:] # Skip the first line\n", + "new_topics = [line.split(\". \")[1] for line in new_topics_lines]\n", + "\n", + "cluster_topic_mapping, new_topics" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CX26-PGdcui0" + }, + "source": [ + "And finally we can use this information to further prompt a model to keep generating synthetic data. We do this by passing all the topics in the list of jsons to the prompt below." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "id": "zHf4LnVk0aHw" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1. Automotive \n", + "Input: \"Tesla Model S, Electric Vehicles\" \n", + "Output: \"The Tesla Model S delivers exhilarating performance with advanced electric technology, offering a sleek design, impressive range, and an industry-leading infotainment system.\"\n", + "\n", + "2. Personal Care \n", + "Input: \"Oral-B Pro 1000, Electronic Toothbrush\" \n", + "Output: \"The Oral-B Pro 1000 features a 3D cleaning action that oscillates, rotates, and pulsates to remove plaque, ensuring a deeper clean for healthier gums.\"\n", + "\n", + "3. Footwear \n", + "Input: \"Nike Air Max 270, Shoes\" \n", + "Output: \"Step into comfort and style with Nike Air Max 270, designed with a large Max Air unit for superior cushioning and a breathable upper for a snug fit.\"\n", + "\n", + "4. Electronics \n", + "Input: \"Apple iPhone 12, Mobile Phones\" \n", + "Output: \"The Apple iPhone 12 combines powerful performance with stunning design, equipped with A14 Bionic chip and advanced camera systems for capturing every moment in stunning detail.\"\n", + "\n", + "5. Food \n", + "Input: \"Nature Valley Granola Bars, Snacks\" \n", + "Output: \"Nature Valley Granola Bars offer a wholesome crunch made from simple, delicious ingredients, providing a perfect snack that fuels your adventure.\"\n", + "\n", + "6. Automotive \n", + "Input: \"Ford F-150, Electric Vehicles\" \n", + "Output: \"The Ford F-150 stands at the forefront of durability and innovation, with its powerful electric version setting new standards for strength and sustainability in the truck category.\" \n", + "\n", + "7. Personal Care \n", + "Input: \"Philips Sonicare, Electronic Toothbrush\" \n", + "Output: \"Philips Sonicare delivers superior cleaning with dynamic technology that provides up to 31,000 strokes per minute for a healthier mouth and brighter smile.\"\n", + "\n", + "8. Footwear \n", + "Input: \"Adidas Ultraboost, Shoes\" \n", + "Output: \"The Adidas Ultraboost is a game-changer in running footwear, featuring responsive cushioning and a knit upper for a snug, supportive fit that adapts to any run.\"\n", + "\n", + "9. Electronics \n", + "Input: \"Dell XPS 13, Laptop\" \n", + "Output: \"The Dell XPS 13 is a remarkable laptop with an ultra-thin design, featuring a stunning InfinityEdge display and powerful performance to accommodate your multitasking needs.\"\n", + "\n", + "10. Food \n", + "Input: \"Kraft Macaroni & Cheese, Instant Food\" \n", + "Output: \"Kraft Macaroni & Cheese offers quick and convenient comfort food, combining creamy cheese sauce with perfectly cooked pasta for a simple meal that satisfies.\"\n", + "\n", + "1. Automotive \n", + "Input: \"Toyota Camry, Mobile Phones\" \n", + "Output: \"The Toyota Camry is a midsize sedan that combines efficiency with modern technology. It offers a spacious interior and the latest features for an enjoyable driving experience.\"\n", + "\n", + "2. Personal Care \n", + "Input: \"Oral-B Pro 1000, Electronic Toothbrush\" \n", + "Output: \"The Oral-B Pro 1000 not only provides powerful cleaning action but also enhances your oral hygiene routine with its smart pressure sensor and various cleaning modes.\"\n", + "\n", + "3. Footwear \n", + "Input: \"Nike Air Max, Shoes\" \n", + "Output: \"Step into comfort with the Nike Air Max. With cutting-edge technology and a sleek design, these shoes are perfect for athletes and casual wearers alike.\"\n", + "\n", + "4. Food \n", + "Input: \"Nature's Valley Granola Bar, Food\" \n", + "Output: \"Savor the wholesome goodness of Nature's Valley Granola Bar, crafted with real ingredients to fuel your day with delicious flavor and crunchy satisfaction.\"\n", + "\n", + "5. Electric Vehicles \n", + "Input: \"Tesla Model 3, Mobile Phones\" \n", + "Output: \"The Tesla Model 3 is a revolutionary electric vehicle that combines performance with sustainability, featuring an intuitive interface and cutting-edge technology for an exceptional driving experience.\"\n", + "\n", + "1. Automotive \n", + "Input: \"Tesla Model 3, Electric Vehicles\" \n", + "Output: \"The Tesla Model 3 combines cutting-edge technology with eco-friendly driving. Enjoy a sleek design, impressive range, and top-notch safety features, making it the perfect electric car for the modern driver.\"\n", + "\n", + "2. Personal Care \n", + "Input: \"Oral-B Pro 1000, Electronic Toothbrush\" \n", + "Output: \"Achieve a superior clean with the Oral-B Pro 1000. Featuring advanced 3D cleaning action, this electronic toothbrush ensures effective plaque removal while being gentle on gums, allowing you to maintain optimum oral health.\"\n", + "\n", + "3. Footwear \n", + "Input: \"Nike Air Max, Shoes\" \n", + "Output: \"Step up your game with Nike Air Max shoes. Combining iconic cushioning technology and bold style, these shoes provide ultimate comfort and support, perfect for both casual wear and athletic performance.\"\n", + "\n", + "4. Food \n", + "Input: \"Oreo Cookies, Snacks\" \n", + "Output: \"Indulge in the classic taste of Oreo Cookies. With their irresistible cream filling sandwiched between two crunchy chocolate wafers, these treats are perfect for satisfying your sweet tooth any time of the day.\"\n", + "\n", + "5. Personal Care \n", + "Input: \"Garnier Micellar Water, Skincare\" \n", + "Output: \"Garnier Micellar Water gently removes makeup and impurities while hydrating the skin. This soothing formula is suitable for all skin types, making it a must-have in your daily skincare routine.\"\n", + "\n", + "6. Automotive \n", + "Input: \"Ford F-150, Trucks\" \n", + "Output: \"The Ford F-150 is the quintessential pickup truck, combining power, reliability, and innovative technology. Equipped with advanced towing capabilities and a spacious interior, it's designed for both work and play.\"\n", + "\n", + "7. Electronics \n", + "Input: \"Samsung Galaxy S21, Mobile Phones\" \n", + "Output: \"Experience the future of mobile technology with the Samsung Galaxy S21. This smartphone features a stunning display, powerful processor, and multiple camera options, perfect for capturing life's moments in high definition.\"\n", + "\n", + "8. Footwear \n", + "Input: \"Adidas Ultraboost, Shoes\" \n", + "Output: \"Run in style with Adidas Ultraboost shoes. Known for their comfort and performance, these shoes utilize responsive cushioning to provide unmatched energy return with every step you take.\" \n", + "\n", + "9. Electronics \n", + "Input: \"Dell XPS 13, Laptops\" \n", + "Output: \"The Dell XPS 13 redefines the laptop experience with its stunning InfinityEdge display, powerful performance, and sleek design. Ideal for both professionals and students looking for portability and functionality.\"\n", + "\n", + "10. Personal Care \n", + "Input: \"Philips Sonicare, Electronic Toothbrush\" \n", + "Output: \"Philips Sonicare's electronic toothbrush guarantees a superior cleaning experience with its advanced sonic technology. This toothbrush not only helps remove plaque but also promotes healthier gums for a brighter smile.\"\n", + "\n", + "\n" + ] } + ], + "source": [ + "output_string = \"\"\n", + "for i in range(3):\n", + " question = f\"\"\"\n", + " I am creating input output training pairs to fine tune my gpt model. I want the input to be product name and category and output to be description. the category should be things like: mobile phones, shoes, headphones, laptop, electronic toothbrush, etc. and also more importantly the categories should come under some main topics: {[entry['topic'] for entry in cluster_topic_mapping]})\n", + " After the number of each example also state the topic area. The format should be of the form:\n", + " 1. topic_area\n", + " Input: product_name, category\n", + " Output: description\n", + "\n", + " Do not add any extra characters around that formatting as it will make the output parsing break.\n", + "\n", + " Here are some helpful examples so you get the style of output correct.\n", + "\n", + " 1) clothing\n", + " Input: \"Shoe Name, Shoes\"\n", + " Output: \"Experience unparalleled comfort. These shoes feature a blend of modern style and the traditional superior cushioning, perfect for those always on the move.\"\n", + " \"\"\"\n", + "\n", + " response = client.chat.completions.create(\n", + " model=\"gpt-4o-mini\",\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful assistant designed to generate synthetic data.\"},\n", + " {\"role\": \"user\", \"content\": question}\n", + " ]\n", + " )\n", + " res = response.choices[0].message.content\n", + " output_string += res + \"\\n\" + \"\\n\"\n", + "print(output_string)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RQMHQxnZdRug" + }, + "source": [ + "You can run this in a loop to append to your previous data and in this way you can keep generating more textual synthetic data to train another GPT model while making sure that we cater to imbalanced datasets and generating a diversity of data." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Hiim8Xg5djGH" + }, + "source": [ + "You have now completed part 1 of the synthetic data generation tutorial where we have gone through:\n", + "* CSV with a structured prompt\n", + "* CSV with a Python program\n", + "* Multitable CSV with a python program\n", + "* Simply creating textual data\n", + "* Dealing with imbalanced or non-diverse textual data\n", + "\n", + "In part 2 you will find find out techniques for better prompting an LLM to enhance textual synthetic data generation." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 0 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 1 } diff --git a/examples/Tag_caption_images_with_GPT4V.ipynb b/examples/Tag_caption_images_with_GPT4V.ipynb index 5e6f1ca8..03d3e2c0 100644 --- a/examples/Tag_caption_images_with_GPT4V.ipynb +++ b/examples/Tag_caption_images_with_GPT4V.ipynb @@ -1,15 +1,16 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", "id": "fd7e6164", "metadata": {}, "source": [ - "# Using GPT-4V to tag & caption images\n", + "# Using GPT-4o mini to tag & caption images\n", "\n", - "This notebook explores how to leverage GPT-4V to tag & caption images. \n", + "This notebook explores how to leverage the vision capabilities of the GPT-4* models (for example `gpt-4o`, `gpt-4o-mini` or `gpt-4-turbo`) to tag & caption images. \n", "\n", - "We can leverage the multimodal capabilities of GPT-4V to provide input images along with additional context on what they represent, and prompt the model to output tags or image descriptions. The image descriptions can then be further refined with a language model (in this notebook, we'll use GPT-4-turbo) to generate captions. \n", + "We can leverage the multimodal capabilities of these models to provide input images along with additional context on what they represent, and prompt the model to output tags or image descriptions. The image descriptions can then be further refined with a language model (in this notebook, we'll use `gpt-4o-mini`) to generate captions. \n", "\n", "Generating text content from images can be useful for multiple use cases, especially use cases involving search. \n", "We will illustrate a search use case in this notebook by using generated keywords and product captions to search for products - both from a text input and an image input.\n", @@ -39,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "5b4c63de", "metadata": {}, "outputs": [], @@ -56,7 +57,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 2, "id": "1b0fa62d", "metadata": {}, "outputs": [ @@ -318,7 +319,7 @@ "[5 rows x 25 columns]" ] }, - "execution_count": 14, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -337,7 +338,7 @@ "source": [ "## Tag images\n", "\n", - "In this section, we'll use GPT-4V to generate relevant tags for our products.\n", + "In this section, we'll use GPT-4o mini to generate relevant tags for our products.\n", "\n", "We'll use a simple zero-shot approach to extract keywords, and deduplicate those keywords using embeddings to avoid having multiple keywords that are too similar.\n", "\n", @@ -354,7 +355,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 32, "id": "752118c4", "metadata": {}, "outputs": [], @@ -381,7 +382,7 @@ "\n", "def analyze_image(img_url, title):\n", " response = client.chat.completions.create(\n", - " model=\"gpt-4-vision-preview\",\n", + " model=\"gpt-4o-mini\",\n", " messages=[\n", " {\n", " \"role\": \"system\",\n", @@ -392,7 +393,9 @@ " \"content\": [\n", " {\n", " \"type\": \"image_url\",\n", - " \"image_url\": img_url,\n", + " \"image_url\": {\n", + " \"url\": img_url,\n", + " }\n", " },\n", " ],\n", " },\n", @@ -418,7 +421,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 33, "id": "eb6a8159", "metadata": {}, "outputs": [], @@ -428,7 +431,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 34, "id": "b729129b", "metadata": {}, "outputs": [ @@ -448,7 +451,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "['shoe rack', 'free standing', 'multi-layer', 'metal', 'white']\n", + "['shoe rack', 'metal', 'white', 'multi-layer', 'hooks']\n", "\n", "\n", "\n" @@ -470,7 +473,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "['dining chairs', 'set of 2', 'leather', 'black']\n", + "['dining chair', 'leather', 'black']\n", "\n", "\n", "\n" @@ -492,7 +495,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "['plant repotting mat', 'waterproof', 'portable', 'foldable', 'easy to clean', 'green']\n", + "['repotting mat', 'waterproof', 'portable', 'foldable', 'green']\n", "\n", "\n", "\n" @@ -514,7 +517,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "['doormat', 'absorbent', 'non-slip', 'brown']\n", + "['doormat', 'absorbent', 'non-slip', 'coconut fiber', 'welcome', 'pickleball', 'outdoor']\n", "\n", "\n", "\n" @@ -536,7 +539,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "['tv tray table set', 'foldable', 'iron', 'grey']\n", + "['tv tray', 'foldable', 'metal', 'grey']\n", "\n", "\n", "\n" @@ -565,7 +568,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 35, "id": "f73d1b59", "metadata": {}, "outputs": [], @@ -590,7 +593,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 36, "id": "f0262f03", "metadata": {}, "outputs": [], @@ -601,7 +604,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 37, "id": "afc489d4", "metadata": {}, "outputs": [ @@ -639,17 +642,17 @@ " \n", " 1\n", " metal\n", - " [-0.020530997, 0.004478126, -0.011049379, -0.0...\n", + " [-0.020492474, 0.0044436487, -0.0110632675, -0...\n", " \n", " \n", " 2\n", " wood\n", - " [0.013877833, 0.02955235, 0.0006239023, -0.035...\n", + " [0.013840097, 0.029538965, 0.00064718135, -0.0...\n", " \n", " \n", " 3\n", " vintage\n", - " [-0.05235507, 0.008213689, -0.015532949, 0.002...\n", + " [-0.052348174, 0.008181616, -0.015513194, 0.00...\n", " \n", " \n", " 4\n", @@ -663,13 +666,13 @@ "text/plain": [ " keyword embedding\n", "0 industrial [-0.026137426, 0.021297162, -0.007273361, -0.0...\n", - "1 metal [-0.020530997, 0.004478126, -0.011049379, -0.0...\n", - "2 wood [0.013877833, 0.02955235, 0.0006239023, -0.035...\n", - "3 vintage [-0.05235507, 0.008213689, -0.015532949, 0.002...\n", + "1 metal [-0.020492474, 0.0044436487, -0.0110632675, -0...\n", + "2 wood [0.013840097, 0.029538965, 0.00064718135, -0.0...\n", + "3 vintage [-0.052348174, 0.008181616, -0.015513194, 0.00...\n", "4 bed [-0.011677503, 0.023275835, 0.0026937425, -0.0..." ] }, - "execution_count": 12, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -682,7 +685,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 38, "id": "f549e537", "metadata": {}, "outputs": [], @@ -703,7 +706,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 39, "id": "08c0ec9c", "metadata": {}, "outputs": [ @@ -717,7 +720,7 @@ "Replacing 'metal' with existing keyword: 'metal'\n", "Replacing 'metallic' with existing keyword: 'metal'\n", "Replacing 'woody' with existing keyword: 'wood'\n", - "Final keywords: {'table', 'desk', 'bed', 'old', 'vintage', 'metal', 'wood', 'old school'}\n" + "Final keywords: {'vintage', 'desk', 'wood', 'table', 'old', 'bed', 'metal', 'old school'}\n" ] } ], @@ -740,14 +743,14 @@ "source": [ "## Generate captions\n", "\n", - "In this section, we'll use GPT-4V to generate an image description and then use a few-shot examples approach with GPT-4-turbo to generate captions from the images.\n", + "In this section, we'll use GPT-4o mini to generate an image description and then use a few-shot examples approach with GPT-4-turbo to generate captions from the images.\n", "\n", "If few-shot examples are not enough for your use case, consider fine-tuning a model to get the generated captions to match the style & tone you are targeting. " ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 40, "id": "c67a434b", "metadata": {}, "outputs": [ @@ -853,7 +856,7 @@ "4 Iron Grey Set of 4 https://www.amazon.com/dp/B0CG1N9QRC " ] }, - "execution_count": 19, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -870,12 +873,12 @@ "id": "9bb5c4fa", "metadata": {}, "source": [ - "### Describing images with GPT-4V" + "### Describing images with GPT-4o mini" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 41, "id": "561912fc", "metadata": {}, "outputs": [], @@ -889,7 +892,7 @@ "\n", "def describe_image(img_url, title):\n", " response = client.chat.completions.create(\n", - " model=\"gpt-4-vision-preview\",\n", + " model=\"gpt-4o-mini\",\n", " temperature=0.2,\n", " messages=[\n", " {\n", @@ -901,7 +904,9 @@ " \"content\": [\n", " {\n", " \"type\": \"image_url\",\n", - " \"image_url\": img_url,\n", + " \"image_url\": {\n", + " \"url\": img_url,\n", + " }\n", " },\n", " ],\n", " },\n", @@ -926,7 +931,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 42, "id": "a0351489", "metadata": {}, "outputs": [ @@ -936,31 +941,27 @@ "text": [ "GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me... - https://www.amazon.com/dp/B0CJHKVG6P :\n", "\n", - "This is a free-standing shoe rack featuring a multi-layer design, constructed from metal for durability. The rack is finished in a clean white color, which gives it a modern and versatile look, suitable for various home decor styles. It includes several horizontal shelves dedicated to organizing shoes, providing ample space for multiple pairs.\n", - "\n", - "Additionally, the rack is equipped with 8 double hooks, which are integrated into the frame above the shoe shelves. These hooks offer extra functionality, allowing for the hanging of accessories such as hats, scarves, or bags. The design is space-efficient and ideal for placement in living rooms, bathrooms, hallways, or entryways, where it can serve as a practical storage solution while contributing to the tidiness and aesthetic of the space.\n", + "The item is a free-standing shoe rack designed for versatile use in living rooms, bathrooms, or hallways. It features a multi-layer metal structure with a sleek white finish. The rack includes eight double hooks at the top for hanging accessories like hats, bags, or scarves. Below, there are multiple shelves that provide ample space for organizing shoes, making it both functional and stylish for entryway storage.\n", "--------------------------\n", "\n", "subrtex Leather ding Room, Dining Chairs Set of 2,... - https://www.amazon.com/dp/B0B66QHB23 :\n", "\n", - "This image showcases a set of two dining chairs. The chairs are upholstered in black leather, featuring a sleek and modern design. They have a high back with subtle stitching details that create vertical lines, adding an element of elegance to the overall appearance. The legs of the chairs are also black, maintaining a consistent color scheme and enhancing the sophisticated look. These chairs would make a stylish addition to any contemporary dining room setting.\n", + "The Subrtex Leather Dining Chairs come in a set of two, featuring a sleek black design. Each chair is upholstered in durable faux leather, offering a modern and stylish look. The high backrest is accentuated with subtle vertical stitching, while the sturdy wooden legs provide stability and support. These chairs are ideal for enhancing the aesthetic of any dining room.\n", "--------------------------\n", "\n", "Plant Repotting Mat MUYETOL Waterproof Transplanti... - https://www.amazon.com/dp/B0BXRTWLYK :\n", "\n", - "This is a square plant repotting mat designed for indoor gardening activities such as transplanting or changing soil for plants. The mat measures 26.8 inches by 26.8 inches, providing ample space for gardening tasks. It is made from a waterproof material, which is likely a durable, easy-to-clean fabric, in a vibrant green color. The edges of the mat are raised with corner fastenings to keep soil and water contained, making the workspace tidy and preventing messes. The mat is also foldable, which allows for convenient storage when not in use. This mat is suitable for a variety of gardening tasks, including working with succulents and other small plants, and it can be a practical gift for garden enthusiasts.\n", + "The Plant Repotting Mat is a portable and foldable gardening accessory, measuring 26.8\" x 26.8\". It features a vibrant green color with black edges, designed to be waterproof for easy cleanup during soil changes. The mat provides a spacious area for repotting plants and comes with tools for transplanting. Ideal for indoor gardening, it helps keep your workspace tidy while you care for your succulents and other plants.\n", "--------------------------\n", "\n", "Pickleball Doormat, Welcome Doormat Absorbent Non-... - https://www.amazon.com/dp/B0C1MRB2M8 :\n", "\n", - "This is a rectangular doormat featuring a playful design that caters to pickleball enthusiasts. The mat's background is a natural coir color, which is a fibrous material made from coconut husks, known for its durability and excellent scraping properties. Emblazoned across the mat in bold, black letters is the phrase \"it's a good day to play PICKLEBALL,\" with the word \"PICKLEBALL\" being prominently displayed in larger font size. Below the text, there are two crossed pickleball paddles in black, symbolizing the sport.\n", - "\n", - "The doormat measures approximately 16x24 inches, making it a suitable size for a variety of entryways. Its design suggests that it has an absorbent quality, which would be useful for wiping shoes and preventing dirt from entering the home. Additionally, the description implies that the doormat has a non-slip feature, which is likely due to a backing material that helps keep the mat in place on various floor surfaces. This mat would be a welcoming addition to the home of any pickleball player or sports enthusiast, offering both functionality and a touch of personal interest.\n", + "The Pickleball Doormat features a natural coir material with a rectangular shape, measuring 16x24 inches. It showcases a playful design with the phrase \"It's a good day to play PICKLEBALL\" in bold black lettering, accompanied by graphic illustrations of pickleball paddles. The mat is designed to be absorbent and non-slip, making it suitable for entryways or bathrooms. Its light brown color adds a warm touch to any space.\n", "--------------------------\n", "\n", "JOIN IRON Foldable TV Trays for Eating Set of 4 wi... - https://www.amazon.com/dp/B0CG1N9QRC :\n", "\n", - "This image features a set of four foldable TV trays with a stand, designed for eating or as snack tables. The tables are presented in a sleek grey finish, which gives them a modern and versatile look, suitable for a variety of home decor styles. Each tray table has a rectangular top with a wood grain texture, supported by a sturdy black iron frame that folds easily for compact storage. The accompanying stand allows for neat organization and easy access when the tables are not in use. These tables are ideal for small spaces where multifunctional furniture is essential, offering a convenient surface for meals, work, or leisure activities.\n", + "The JOIN IRON Foldable TV Trays set includes four sleek, grey snack tables designed for convenience and space-saving. Each tray features a sturdy, flat surface supported by a durable metal frame, allowing for easy folding and storage. The minimalist design makes them ideal for small spaces, perfect for enjoying meals or snacks while watching TV. The set also comes with a stand for organized storage when not in use.\n", "--------------------------\n", "\n" ] @@ -984,7 +985,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 43, "id": "66b5bc53", "metadata": {}, "outputs": [], @@ -1027,12 +1028,12 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 44, "id": "b5ac5262", "metadata": {}, "outputs": [], "source": [ - "def caption_image(description, model=\"gpt-4-turbo-preview\"):\n", + "def caption_image(description, model=\"gpt-4o-mini\"):\n", " messages = formatted_examples\n", " messages.insert(0, \n", " {\n", @@ -1063,7 +1064,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 45, "id": "2d8f3427", "metadata": {}, "outputs": [], @@ -1073,7 +1074,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 46, "id": "b426d22d", "metadata": {}, "outputs": [ @@ -1083,34 +1084,26 @@ "text": [ "LOVMOR 30'' Bathroom Vanity Sink Base Cabine, Stor... - https://www.amazon.com/dp/B0C9WYYFLB :\n", "\n", - "This is a LOVMOR 30'' Bathroom Vanity Sink Base Cabinet featuring a classic design with a rich brown finish. The cabinet is designed to provide ample storage with three drawers on the left side, offering organized space for bathroom essentials. The drawers are likely to have smooth glides for easy operation. Below the drawers, there is a large cabinet door that opens to reveal additional storage space, suitable for larger items. The paneling on the drawers and door features a raised, framed design, adding a touch of elegance to the overall appearance. This vanity base is versatile and can be used not only in bathrooms but also in kitchens, laundry rooms, and other areas where extra storage is needed. The construction material is not specified, but it appears to be made of wood or a wood-like composite. Please note that the countertop and sink are not included and would need to be purchased separately.\n", + "The LOVMOR 30'' Bathroom Vanity Sink Base Cabinet features a classic design with a rich brown finish. It includes three drawers on the left side for ample storage, complemented by a spacious cabinet door on the right. The cabinet is constructed with detailed paneling, adding a touch of elegance, making it suitable for bathrooms, kitchens, laundry rooms, and more. Its versatile style allows it to blend seamlessly into various decor themes.\n", "--------------------------\n", "\n", - "LOVMOR 30'' classic brown bathroom vanity base cabinet with three drawers and additional storage space.\n", + "Classic 30'' brown bathroom vanity sink base cabinet with storage drawers.\n", "--------------------------\n", "\n", "Folews Bathroom Organizer Over The Toilet Storage,... - https://www.amazon.com/dp/B09NZY3R1T :\n", "\n", - "This is a 4-tier bathroom organizer designed to fit over a standard toilet, providing a space-saving storage solution. The unit is constructed with a sturdy metal frame in a black finish, which offers both durability and a sleek, modern look. The design includes four shelves that offer ample space for bathroom essentials, towels, and decorative items. Two of the shelves are designed with a metal grid pattern, while the other two feature a solid metal surface for stable storage.\n", - "\n", - "Additionally, the organizer includes adjustable baskets, which can be positioned according to your storage needs, allowing for customization and flexibility. The freestanding structure is engineered to maximize the unused vertical space above the toilet, making it an ideal choice for small bathrooms or for those looking to declutter countertops and cabinets.\n", - "\n", - "The overall design is minimalist and functional, with clean lines that can complement a variety of bathroom decors. The open shelving concept ensures that items are easily accessible and visible. Installation is typically straightforward, with no need for wall mounting, making it a convenient option for renters or those who prefer not to drill into walls.\n", + "The Folews Bathroom Organizer is a freestanding, 4-tier storage rack designed to fit over a toilet. It features a sleek black metal frame with adjustable shelves, allowing for customizable storage options. The shelves are made of wire, providing a modern look while ensuring durability. This organizer includes baskets for additional storage and is ideal for maximizing bathroom space by holding toiletries, towels, and other essentials. Its design is both functional and stylish, making it a great addition to any bathroom.\n", "--------------------------\n", "\n", - "Modern 4-tier black metal bathroom organizer with adjustable shelves and baskets, designed to fit over a standard toilet for space-saving storage.\n", + "Freestanding 4-tier black metal bathroom organizer with adjustable wire shelves and baskets.\n", "--------------------------\n", "\n", "GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me... - https://www.amazon.com/dp/B0CJHKVG6P :\n", "\n", - "This is a multi-functional free-standing shoe rack featuring a sturdy metal construction with a white finish. It is designed with multiple layers, providing ample space to organize and store shoes. The rack includes four tiers dedicated to shoe storage, each tier capable of holding several pairs of shoes.\n", - "\n", - "Above the shoe storage area, there is an additional shelf that can be used for placing bags, small decorative items, or other accessories. At the top, the rack is equipped with 8 double hooks, which are ideal for hanging hats, scarves, coats, or umbrellas, making it a versatile piece for an entryway, living room, bathroom, or hallway.\n", - "\n", - "The overall design is sleek and modern, with clean lines that would complement a variety of home decor styles. The vertical structure of the rack makes it a space-saving solution for keeping footwear and accessories organized in areas with limited floor space.\n", + "The GOYMFK Free Standing Shoe Rack is a versatile storage solution designed for various spaces like living rooms, bathrooms, or hallways. It features a multi-layer metal construction with a sleek white finish. The rack includes eight double hooks at the top for hanging items such as hats, bags, or scarves. Below, there are multiple shelves for organizing shoes, accommodating various styles and sizes. Its modern design combines functionality with a clean aesthetic, making it a practical addition to any home.\n", "--------------------------\n", "\n", - "Multi-layer white metal shoe rack with additional shelf and 8 double hooks for versatile storage in entryways or hallways.\n", + "Versatile white metal free-standing shoe rack with hooks and multiple shelves.\n", "--------------------------\n", "\n" ] @@ -1139,7 +1132,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 47, "id": "302d251d", "metadata": {}, "outputs": [], @@ -1153,7 +1146,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 48, "id": "9285bb14", "metadata": {}, "outputs": [], @@ -1186,7 +1179,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 49, "id": "297bbc45", "metadata": {}, "outputs": [], @@ -1212,7 +1205,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 50, "id": "e62b8708", "metadata": {}, "outputs": [ @@ -1222,7 +1215,7 @@ "(312, 9)" ] }, - "execution_count": 36, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } @@ -1243,12 +1236,69 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 51, "id": "43ec629b", "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 - GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me...\n", + "1 - subrtex Leather ding Room, Dining Chairs Set of 2,...\n", + "2 - Plant Repotting Mat MUYETOL Waterproof Transplanti...\n", + "3 - Pickleball Doormat, Welcome Doormat Absorbent Non-...\n", + "4 - JOIN IRON Foldable TV Trays for Eating Set of 4 wi...\n", + "5 - LOVMOR 30'' Bathroom Vanity Sink Base Cabine, Stor...\n", + "6 - Folews Bathroom Organizer Over The Toilet Storage,...\n", + "7 - GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me...\n", + "8 - subrtex Leather ding Room, Dining Chairs Set of 2,...\n", + "9 - Plant Repotting Mat MUYETOL Waterproof Transplanti...\n", + "10 - Pickleball Doormat, Welcome Doormat Absorbent Non-...\n", + "11 - JOIN IRON Foldable TV Trays for Eating Set of 4 wi...\n", + "12 - LOVMOR 30'' Bathroom Vanity Sink Base Cabine, Stor...\n", + "13 - Folews Bathroom Organizer Over The Toilet Storage,...\n", + "14 - Lerliuo Nightstand, Side Table, Industrial Bedside...\n", + "15 - Boss Office Products Any Task Mid-Back Task Chair ...\n", + "16 - Kingston Brass BA1752BB Heritage 18-Inch Towel-Bar...\n", + "17 - Chief Mfg.Swing-Arm Wall Mount Hardware Mount Blac...\n", + "18 - DOMYDEVM Black End Table, Nightstand with Charging...\n", + "19 - LASCO 35-5019 Hallmack Style 24-Inch Towel Bar Acc...\n", + "20 - Table-Mate II PRO TV Tray Table - Folding Table wi...\n", + "21 - EGFheal White Dress Up Storage\n", + "22 - Caroline's Treasures PPD3013JMAT Enchanted Garden ...\n", + "23 - Leick Home 70007-WTGD Mixed Metal and Wood Stepped...\n", + "24 - Caroline's Treasures CK3435MAT Bichon Frise Doorma...\n", + "25 - Wildkin Kids Canvas Sling Bookshelf with Storage f...\n", + "26 - Gbuzozie 38L Round Laundry Hamper Cute Mermaid Gir...\n", + "27 - Tiita Comfy Saucer Chair, Soft Faux Fur Oversized ...\n", + "28 - Summer Desk Decor,Welcome Summer Wood Block Sign D...\n", + "29 - Homebeez 39.1\" Length Bedroom Storage Bench, End B...\n", + "30 - Flash Furniture Webb Commercial Grade 24\" Round Bl...\n", + "31 - Mellow 2 Inch Ventilated Memory Foam Mattress Topp...\n", + "32 - CangLong Mid Century Modern Side Chair with Wood L...\n", + "33 - HomePop Metal Accent Table Triangle Base Round Mir...\n", + "34 - MAEPA RV Shoe Storage for Bedside - 8 Extra Large ...\n", + "35 - NearMoon Hand Towel Holder/Towel Ring - Bathroom T...\n", + "36 - FLYJOE Narrow Side Table with PU Leather Magazine ...\n", + "37 - HomePop Home Decor | K2380-YDQY-2 | Luxury Large F...\n", + "38 - Moroccan Leather Pouf Ottoman for Living Room - Ro...\n", + "39 - AnyDesign Christmas Welcome Doormat Decorative Xma...\n", + "40 - GXFC ZHAO Welcome Funny Door Mat Shoes and Bras Of...\n", + "41 - LEASYLIFE Black Metal Trash can,10L/2.6GAL,Open To...\n", + "42 - Solid Wood Wine Cabinet, bar Rack - Home Wood Furn...\n", + "43 - Black Leather Office Chair Mid Back Leather Desk C...\n", + "44 - Convenience Concepts Tucson Flip Top End Table wit...\n", + "45 - 3-Tier Kitchen Storage Cart with Handle, Multifunc...\n", + "46 - Mimoglad Office Chair, High Back Ergonomic Desk Ch...\n", + "47 - Let the Adventure Begin Door Mat 17\"x30\" Decorativ...\n", + "48 - 1 Pack Adjustable Height Center Support Leg for Be...\n", + "49 - Stylo Culture Traditional Cotton Patchwork Embroid...\n" + ] + } + ], "source": [ "# Running on first 50 lines\n", "for index, row in df[:50].iterrows():\n", @@ -1259,7 +1309,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 52, "id": "85febcd2", "metadata": {}, "outputs": [ @@ -1304,9 +1354,9 @@ " Metal\n", " White\n", " https://www.amazon.com/dp/B0CJHKVG6P\n", - " [shoe rack, free standing, multi-layer, metal,...\n", - " This is a free-standing shoe rack featuring a ...\n", - " White metal free-standing shoe rack with multi...\n", + " [shoe rack, metal, white, multi-layer, hooks]\n", + " The GOYMFK Free Standing Shoe Rack is a versat...\n", + " Sleek white multi-layer metal free-standing sh...\n", " \n", " \n", " 1\n", @@ -1316,9 +1366,9 @@ " Sponge\n", " Black\n", " https://www.amazon.com/dp/B0B66QHB23\n", - " [dining chairs, set of 2, leather, black]\n", - " This image features a set of two black dining ...\n", - " Set of 2 sleek black faux leather dining chair...\n", + " [dining chair, leather, black]\n", + " The Subrtex Leather Dining Chairs come in a se...\n", + " Set of 2 modern black faux leather dining chai...\n", " \n", " \n", " 2\n", @@ -1328,9 +1378,9 @@ " Polyethylene\n", " Green\n", " https://www.amazon.com/dp/B0BXRTWLYK\n", - " [plant repotting mat, waterproof, portable, fo...\n", - " This is a square plant repotting mat designed ...\n", - " Waterproof green square plant repotting mat\n", + " [repotting mat, waterproof, portable, foldable...\n", + " The Plant Repotting Mat is a portable and fold...\n", + " Vibrant green waterproof plant repotting mat\n", " \n", " \n", " 3\n", @@ -1340,9 +1390,9 @@ " Rubber\n", " A5589\n", " https://www.amazon.com/dp/B0C1MRB2M8\n", - " [doormat, absorbent, non-slip, brown]\n", - " This is a rectangular doormat featuring a play...\n", - " Pickleball-themed coir doormat with playful de...\n", + " [doormat, absorbent, non-slip, coconut fiber, ...\n", + " The Pickleball Doormat is a charming welcome m...\n", + " Coir welcome mat featuring a playful \"It's a g...\n", " \n", " \n", " 4\n", @@ -1352,9 +1402,9 @@ " Iron\n", " Grey Set of 4\n", " https://www.amazon.com/dp/B0CG1N9QRC\n", - " [tv tray table set, foldable, iron, grey]\n", - " This image showcases a set of two foldable TV ...\n", - " Set of two foldable TV trays with grey wood gr...\n", + " [tv tray, foldable, metal, grey]\n", + " The JOIN IRON Foldable TV Tray Set includes fo...\n", + " Set of 4 foldable grey TV trays with durable b...\n", " \n", " \n", "\n", @@ -1383,28 +1433,28 @@ "4 Iron Grey Set of 4 https://www.amazon.com/dp/B0CG1N9QRC \n", "\n", " keywords \\\n", - "0 [shoe rack, free standing, multi-layer, metal,... \n", - "1 [dining chairs, set of 2, leather, black] \n", - "2 [plant repotting mat, waterproof, portable, fo... \n", - "3 [doormat, absorbent, non-slip, brown] \n", - "4 [tv tray table set, foldable, iron, grey] \n", + "0 [shoe rack, metal, white, multi-layer, hooks] \n", + "1 [dining chair, leather, black] \n", + "2 [repotting mat, waterproof, portable, foldable... \n", + "3 [doormat, absorbent, non-slip, coconut fiber, ... \n", + "4 [tv tray, foldable, metal, grey] \n", "\n", " img_description \\\n", - "0 This is a free-standing shoe rack featuring a ... \n", - "1 This image features a set of two black dining ... \n", - "2 This is a square plant repotting mat designed ... \n", - "3 This is a rectangular doormat featuring a play... \n", - "4 This image showcases a set of two foldable TV ... \n", + "0 The GOYMFK Free Standing Shoe Rack is a versat... \n", + "1 The Subrtex Leather Dining Chairs come in a se... \n", + "2 The Plant Repotting Mat is a portable and fold... \n", + "3 The Pickleball Doormat is a charming welcome m... \n", + "4 The JOIN IRON Foldable TV Tray Set includes fo... \n", "\n", " caption \n", - "0 White metal free-standing shoe rack with multi... \n", - "1 Set of 2 sleek black faux leather dining chair... \n", - "2 Waterproof green square plant repotting mat \n", - "3 Pickleball-themed coir doormat with playful de... \n", - "4 Set of two foldable TV trays with grey wood gr... " + "0 Sleek white multi-layer metal free-standing sh... \n", + "1 Set of 2 modern black faux leather dining chai... \n", + "2 Vibrant green waterproof plant repotting mat \n", + "3 Coir welcome mat featuring a playful \"It's a g... \n", + "4 Set of 4 foldable grey TV trays with durable b... " ] }, - "execution_count": 40, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } @@ -1415,24 +1465,33 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 53, + "id": "c36d3320", + "metadata": {}, + "outputs": [], + "source": [ + "data_path = \"data/items_tagged_and_captioned.csv\"" + ] + }, + { + "cell_type": "code", + "execution_count": 54, "id": "b98b0ec8", "metadata": {}, "outputs": [], "source": [ - "# Saving locally for later\n", - "data_path = \"data/items_tagged_and_captioned.csv\"\n", + "# Saving locally for later - optional: do not execute if you prefer to use the provided file\n", "df.to_csv(data_path, index=False)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "id": "a9f0de2f", "metadata": {}, "outputs": [], "source": [ - "# Optional: load data from saved file\n", + "# Optional: load data from saved file if you haven't processed the whole dataset\n", "df = pd.read_csv(data_path)" ] }, @@ -1449,7 +1508,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 56, "id": "9cc54beb", "metadata": {}, "outputs": [], @@ -1459,34 +1518,2664 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 57, "id": "d9810f84", "metadata": {}, "outputs": [], "source": [ "def embed_tags_caption(x):\n", " if x['caption'] != '':\n", - " keywords_string = \",\".join(k for k in x['keywords']) + '\\n'\n", - " content = keywords_string + x['caption']\n", - " embedding = get_embedding(content)\n", - " return embedding" + " try:\n", + " keywords_string = \",\".join(k for k in x['keywords']) + '\\n'\n", + " content = keywords_string + x['caption']\n", + " embedding = get_embedding(content)\n", + " return embedding\n", + " except Exception as e:\n", + " print(f\"Error creating embedding for {x}: {e}\")" ] }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 58, "id": "6780488b", "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Error creating embedding for title Suptsifira Shoe storage box, 24 Packs Shoe Box...\n", + "primary_image https://m.media-amazon.com/images/I/51enKGSxK8...\n", + "style NaN\n", + "material Porcelain\n", + "color White\n", + "url https://www.amazon.com/dp/B0BZ85JVBN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 50, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Wellynap Computer Desk,31.5 inches Folding Tab...\n", + "primary_image https://m.media-amazon.com/images/I/51pO-N48te...\n", + "style Modern\n", + "material Wood\n", + "color Teak & Black\n", + "url https://www.amazon.com/dp/B0CFL2G31X\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 51, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Smlttel Gold Clothing Rack With Shelves, Gold ...\n", + "primary_image https://m.media-amazon.com/images/I/41aRwocdfA...\n", + "style Modern\n", + "material Metal\n", + "color C gold\n", + "url https://www.amazon.com/dp/B0B93TC1Z8\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 52, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Franklin Sports NFL Storage Ottoman + Containe...\n", + "primary_image https://m.media-amazon.com/images/I/31ptZB+wS-...\n", + "style Team Licensed Storage Ottoman with Detachable Lid\n", + "material Fabric\n", + "color Team Color\n", + "url https://www.amazon.com/dp/B0787KRJ8S\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 53, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Honey-Can-Do 3-Tier Nesting Bamboo Shoe Rack S...\n", + "primary_image https://m.media-amazon.com/images/I/51GnnjKaVs...\n", + "style Shoe\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B08WRLKR7T\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 54, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Furnistar 15.9 inch Modern Round Velvet Storag...\n", + "primary_image https://m.media-amazon.com/images/I/31IBS5mzYS...\n", + "style Modern\n", + "material Wood\n", + "color Grey\n", + "url https://www.amazon.com/dp/B0C4NT8N8C\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 55, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title AMHANCIBLE C Shaped Side Table, End Tables Set...\n", + "primary_image https://m.media-amazon.com/images/I/41qDAGoNCr...\n", + "style Straight Leg\n", + "material Engineered Wood\n", + "color Black\n", + "url https://www.amazon.com/dp/B0BT9SVN1V\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 56, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title LONGWIN Black Hanging Wall Round Mirror Decor ...\n", + "primary_image https://m.media-amazon.com/images/I/41kC6cU5HX...\n", + "style Modern\n", + "material Glass, Metal\n", + "color Black\n", + "url https://www.amazon.com/dp/B094F897P3\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 57, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Need Fold Wall Mounted Workbench Folding Wall ...\n", + "primary_image https://m.media-amazon.com/images/I/31SqvdFCut...\n", + "style Modern\n", + "material Metal\n", + "color Teak Color Desktop & Warm White Folding Brackets\n", + "url https://www.amazon.com/dp/B00UV7B29A\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 58, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Big Joe Fuf XL Cover Only Machine Washable, Gr...\n", + "primary_image https://m.media-amazon.com/images/I/21ysztDdCY...\n", + "style Plush\n", + "material NaN\n", + "color Grey\n", + "url https://www.amazon.com/dp/B08T7JP8ZN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 59, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Plymor Rectangle 5mm Beveled Glass Mirror, 6 i...\n", + "primary_image https://m.media-amazon.com/images/I/31wigA5chu...\n", + "style NaN\n", + "material Glass\n", + "color Silver\n", + "url https://www.amazon.com/dp/B09F3SGZ8Y\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 60, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title TIMCORR CD Case DVD Holder Storage: 144 Capaci...\n", + "primary_image https://m.media-amazon.com/images/I/411Q2ETwel...\n", + "style Portable\n", + "material EVA + PVC + PP + Non-woven fabric\n", + "color Black\n", + "url https://www.amazon.com/dp/B0B19ZGGXC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 61, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Ginger Cayden Closed Towel Ring - 4905/SN - Sa...\n", + "primary_image https://m.media-amazon.com/images/I/31LNv7QILd...\n", + "style NaN\n", + "material Brass\n", + "color Satin Nickel\n", + "url https://www.amazon.com/dp/B00U0ECLG2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 62, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Brightify Black Bathroom Mirrors for Wall, 24 ...\n", + "primary_image https://m.media-amazon.com/images/I/510A0nIdGZ...\n", + "style Modern\n", + "material Aluminum\n", + "color Black\n", + "url https://www.amazon.com/dp/B0C2HNGCRX\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 63, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title SogesHome Wood Corner Cabinet Wall Corner Stor...\n", + "primary_image https://m.media-amazon.com/images/I/41BTUFVwm+...\n", + "style Open Frame\n", + "material NaN\n", + "color White&teak\n", + "url https://www.amazon.com/dp/B0C3B4D4RH\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 64, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Toy Storage for Lego Play Mat Bag - Duplo Toy ...\n", + "primary_image https://m.media-amazon.com/images/I/51KKvmDCqB...\n", + "style NaN\n", + "material Nylon\n", + "color Orange\n", + "url https://www.amazon.com/dp/B0B4CL1M1M\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 65, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Flash Furniture Jefferson 2 Pk. Contemporary B...\n", + "primary_image https://m.media-amazon.com/images/I/41GYYVLfGj...\n", + "style Contemporary\n", + "material NaN\n", + "color Brown\n", + "url https://www.amazon.com/dp/B00FEAN1SY\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 66, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Hong Art- Metal Mirror-Matt Black,Glass Panel ...\n", + "primary_image https://m.media-amazon.com/images/I/31XytAHobH...\n", + "style Classic\n", + "material Metal\n", + "color Black\n", + "url https://www.amazon.com/dp/B08GSH4KVM\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 67, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Convenience Concepts American Heritage Round E...\n", + "primary_image https://m.media-amazon.com/images/I/311rmB9BDW...\n", + "style Round End Table\n", + "material Solid + Manufactured Wood,Particle Board/Chipb...\n", + "color Pink\n", + "url https://www.amazon.com/dp/B01B65BYYI\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 68, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Flash Furniture Diamond Black Vinyl Luxurious ...\n", + "primary_image https://m.media-amazon.com/images/I/41LYsAMww6...\n", + "style Fixed\n", + "material Foam\n", + "color Black Vinyl\n", + "url https://www.amazon.com/dp/B000TMHWGO\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 69, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Gatco 1918, Modern Rectangle Waste Basket, Mat...\n", + "primary_image https://m.media-amazon.com/images/I/31dnAVaEmv...\n", + "style Rectangle\n", + "material Stainless Steel\n", + "color Matte Black\n", + "url https://www.amazon.com/dp/B07TXMJ5FQ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 70, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Winrise Office Chair Ergonomic Desk Chair, Hig...\n", + "primary_image https://m.media-amazon.com/images/I/41hCFaVIC+...\n", + "style Straight\n", + "material Sponge\n", + "color S-black\n", + "url https://www.amazon.com/dp/B0CGQZBCZP\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 71, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Adeco Euro Style Fabric Arm Bench Chair Footst...\n", + "primary_image https://m.media-amazon.com/images/I/41hUc8c+DC...\n", + "style Modern\n", + "material Engineered Wood\n", + "color Brown\n", + "url https://www.amazon.com/dp/B017TNJR72\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 72, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Motiv 0202/PC Sine 18-In Towel Bar, Polished C...\n", + "primary_image https://m.media-amazon.com/images/I/31a6GfenW0...\n", + "style NaN\n", + "material Brass\n", + "color 18\" Towel Bar\n", + "url https://www.amazon.com/dp/B001AS8D82\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 73, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Imports Décor PVC Backed Coir Doormat, Eighth ...\n", + "primary_image https://m.media-amazon.com/images/I/51H9lDOICr...\n", + "style Art Deco\n", + "material Vinyl\n", + "color Black and Beige\n", + "url https://www.amazon.com/dp/B08WF83LMF\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 74, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Croydex Chester Square Flexi-Fix Wall Mounted ...\n", + "primary_image https://m.media-amazon.com/images/I/41sDO1HW2c...\n", + "style NaN\n", + "material NaN\n", + "color Silver\n", + "url https://www.amazon.com/dp/B09DGFRM4B\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 75, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title itbe Easy Fit Ready-to-Assemble Multipurpose O...\n", + "primary_image https://m.media-amazon.com/images/I/21NWASZgUV...\n", + "style Flat Panel\n", + "material Alloy Steel\n", + "color Blue\n", + "url https://www.amazon.com/dp/B09FR4XSCT\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 76, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Delta ARV18-DN Arvo 18-in Wall Mount Towel Bar...\n", + "primary_image https://m.media-amazon.com/images/I/11zzs81fXB...\n", + "style 18\" Towel Bar with 6\" Extender\n", + "material Multiple Base Materials\n", + "color Spotshield Brushed Nickel\n", + "url https://www.amazon.com/dp/B09LVSZRZS\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 77, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Bamboo Waste Basket | Waste Basket for Bathroo...\n", + "primary_image https://m.media-amazon.com/images/I/318RY00VlI...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B08VWTB8CH\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 78, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Way Basics Vinyl Record Storage - 2 Tier Book ...\n", + "primary_image https://m.media-amazon.com/images/I/41YMttt7a5...\n", + "style Modern\n", + "material Recycled Material\n", + "color White\n", + "url https://www.amazon.com/dp/B075M1PKSW\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 79, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title TocTen Double Bath Towel Bar - Thicken SUS304 ...\n", + "primary_image https://m.media-amazon.com/images/I/41cFJKXyA5...\n", + "style NaN\n", + "material Stainless Steel\n", + "color Matte Black\n", + "url https://www.amazon.com/dp/B0BWRVGQRM\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 80, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MoNiBloom Adjustable Bar Stools Set of 2, 360°...\n", + "primary_image https://m.media-amazon.com/images/I/41jD28iN4b...\n", + "style Straight\n", + "material NaN\n", + "color Dark Grey\n", + "url https://www.amazon.com/dp/B0CB7SG59J\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 81, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title LANTEFUL Shoe Rack Organizer Shoe Storage Cabi...\n", + "primary_image https://m.media-amazon.com/images/I/51e8SrHHW3...\n", + "style free standing shoe racks\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0C3QDL2XW\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 82, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ANDY STAR 24x32 INCH Brushed Nickel Mirror, Ro...\n", + "primary_image https://m.media-amazon.com/images/I/41MQWfATgg...\n", + "style NaN\n", + "material Stainless Steel\n", + "color Brushed Nickel\n", + "url https://www.amazon.com/dp/B0CBRGS5D7\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 83, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MJL Furniture Designs Upholstered Cubed/Square...\n", + "primary_image https://m.media-amazon.com/images/I/410tv-zDYX...\n", + "style Contemporary\n", + "material Wood\n", + "color Smoke Grey\n", + "url https://www.amazon.com/dp/B01D378FYE\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 84, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Cpintltr Small Foot Stool Ottoman Modern Accen...\n", + "primary_image https://m.media-amazon.com/images/I/51CjfUJVuL...\n", + "style NaN\n", + "material Pine\n", + "color Green\n", + "url https://www.amazon.com/dp/B0CKPFKDZY\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 85, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title YuiHome Extendable Round, Farmhouse 16\" Leaf T...\n", + "primary_image https://m.media-amazon.com/images/I/5175Qzg03L...\n", + "style Farmhouse\n", + "material Rubber Wood, Engineered Wood\n", + "color Natural Wood Wash\n", + "url https://www.amazon.com/dp/B0CHVQ6BC5\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 86, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Ergonomic Office Chair,Office Chair, with Lumb...\n", + "primary_image https://m.media-amazon.com/images/I/51vnoZERmP...\n", + "style With arms\n", + "material Foam\n", + "color All Black\n", + "url https://www.amazon.com/dp/B0CBBV4S1P\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 87, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kate and Laurel Celia Round Metal Foldable Acc...\n", + "primary_image https://m.media-amazon.com/images/I/31ZMqrgDD8...\n", + "style Modern\n", + "material Iron\n", + "color Black\n", + "url https://www.amazon.com/dp/B084WLY61H\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 88, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Lizipai Floating Bedside Table, No Assembly Re...\n", + "primary_image https://m.media-amazon.com/images/I/41HBX6be98...\n", + "style no\n", + "material Wood\n", + "color White\n", + "url https://www.amazon.com/dp/B09NBWCTDS\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 89, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title CordaRoy's Chenille Bean Bag Ottoman Footstool...\n", + "primary_image https://m.media-amazon.com/images/I/51HpCirQNA...\n", + "style Modern\n", + "material Engineered Wood\n", + "color Rainforest\n", + "url https://www.amazon.com/dp/B0BSZ96YG7\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 90, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Plebs Home Solid Desktop Store Cart, with Rubb...\n", + "primary_image https://m.media-amazon.com/images/I/51WFQwBEqj...\n", + "style Slab\n", + "material Wood\n", + "color Dark Blue\n", + "url https://www.amazon.com/dp/B0CD7FSWMK\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 91, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ErGear Ergonomic Desk Chair, Office Chair with...\n", + "primary_image https://m.media-amazon.com/images/I/41C4FUmS-h...\n", + "style With arms\n", + "material Memory Foam\n", + "color Black\n", + "url https://www.amazon.com/dp/B0C99D3V15\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 92, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kingston Brass Millennium Towel-Ring, 7.63\", O...\n", + "primary_image https://m.media-amazon.com/images/I/31+kzwXTjx...\n", + "style NaN\n", + "material Brass\n", + "color Oil Rubbed Bronze\n", + "url https://www.amazon.com/dp/B00FM0WG7I\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 93, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Homebeez 18.9\" Round Velvet Storage Ottoman Mu...\n", + "primary_image https://m.media-amazon.com/images/I/51vTxE-9lH...\n", + "style Modern\n", + "material Wood\n", + "color Orange\n", + "url https://www.amazon.com/dp/B09DKG6JDN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 94, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Mickey and Friends Collapsible Nylon Basket Bu...\n", + "primary_image https://m.media-amazon.com/images/I/410mEc5bbl...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0B7Q5LB2C\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 95, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Homepop Home Decor | Backless Nailhead Trim Co...\n", + "primary_image https://m.media-amazon.com/images/I/41HPIScA4s...\n", + "style Contemporary\n", + "material NaN\n", + "color Blue\n", + "url https://www.amazon.com/dp/B01LWPSVUW\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 96, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Camco Life Is Better at The Campsite Outdoor &...\n", + "primary_image https://m.media-amazon.com/images/I/51DN2is3Zj...\n", + "style Outdoor & Indoor\n", + "material Rubber\n", + "color Blue\n", + "url https://www.amazon.com/dp/B07D7RQNJV\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 97, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MoNiBloom Round Folding Faux Fur Saucer Chair ...\n", + "primary_image https://m.media-amazon.com/images/I/41eoFKL3gK...\n", + "style Modern\n", + "material Polyester\n", + "color Burgundy\n", + "url https://www.amazon.com/dp/B0CD7TH3BF\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 98, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title YMYNY Vanity Stool Chair with Storage, Square ...\n", + "primary_image https://m.media-amazon.com/images/I/519Am3LPMv...\n", + "style Modern\n", + "material NaN\n", + "color Dusty Blue\n", + "url https://www.amazon.com/dp/B0C1NSNDW2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 99, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Casual Home 5 Piece Tray Table Set, Espresso\n", + "primary_image https://m.media-amazon.com/images/I/41WweDJqgZ...\n", + "style Tray Table Set\n", + "material Wood\n", + "color Espresso\n", + "url https://www.amazon.com/dp/B0069H9BYO\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 100, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Simplify Hanging Grey 20-Pocket Shoe Boho Clos...\n", + "primary_image https://m.media-amazon.com/images/I/41eYiOqsld...\n", + "style NaN\n", + "material 80% Linen printed nonwoven +20% solid nonwoven...\n", + "color Grey\n", + "url https://www.amazon.com/dp/B09J1RM23P\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 101, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Get Set Style Black Glass Side Table, Square G...\n", + "primary_image https://m.media-amazon.com/images/I/51gG6ukN1n...\n", + "style Modern and Elegant\n", + "material Tempered Glass\n", + "color Shiny Black\n", + "url https://www.amazon.com/dp/B0C5DH6ZY6\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 102, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Watson & Whitely Swivel Bar Stools Set of 2, F...\n", + "primary_image https://m.media-amazon.com/images/I/41nDc6aFKo...\n", + "style Modern\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CKQTTZ5V\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 103, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Sweet Jojo Designs Boho Rainbow Girl Ottoman P...\n", + "primary_image https://m.media-amazon.com/images/I/31nn4NwuKf...\n", + "style Shabby Chic\n", + "material Engineered Wood\n", + "color Multi Color\n", + "url https://www.amazon.com/dp/B0BZJYM4Q6\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 104, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Pekokavo Sofa Arm Clip Tray, Side Table for Re...\n", + "primary_image https://m.media-amazon.com/images/I/51yz-83kj+...\n", + "style Modern\n", + "material Bamboo\n", + "color Bamboo\n", + "url https://www.amazon.com/dp/B08SL4GH7G\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 105, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Caroline's Treasures JMA2013HRM2858 Seaweed Sa...\n", + "primary_image https://m.media-amazon.com/images/I/514qJ5aPtb...\n", + "style Modern\n", + "material Rubber\n", + "color Multicolored\n", + "url https://www.amazon.com/dp/B07SPYM4M5\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 106, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Xchouxer Side Tables Natural Bamboo Sofa Armre...\n", + "primary_image https://m.media-amazon.com/images/I/511LXRAxI+...\n", + "style Modern\n", + "material Bamboo\n", + "color Beige\n", + "url https://www.amazon.com/dp/B08FC5HPBS\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 107, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Montessori Learning Toddler Tower, Foldable To...\n", + "primary_image https://m.media-amazon.com/images/I/51n9ojprZE...\n", + "style Modern\n", + "material Wood\n", + "color Wood\n", + "url https://www.amazon.com/dp/B0CKMRJ1H9\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 108, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title PAK HOME Set of 2 High Gloss Brown Marble Look...\n", + "primary_image https://m.media-amazon.com/images/I/51u3oxvEiS...\n", + "style Tripod\n", + "material Wood\n", + "color Brown Marble High Gloss / Gold Legs\n", + "url https://www.amazon.com/dp/B09K3MYL91\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 109, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title kukli kitchen Spring Door Mat 30 X 17 Inch - S...\n", + "primary_image https://m.media-amazon.com/images/I/61rRHgR+aE...\n", + "style Classic\n", + "material Rubber\n", + "color Color-33\n", + "url https://www.amazon.com/dp/B0BNL8CC5X\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 110, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Dewhut Oversized Pumpkin Couch Accent Chair, M...\n", + "primary_image https://m.media-amazon.com/images/I/519KoH2aW4...\n", + "style Modern\n", + "material Sponge\n", + "color Navy\n", + "url https://www.amazon.com/dp/B0CF8HTCS4\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 111, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Toland Home Garden 800009 Gypsy Garden Flower ...\n", + "primary_image https://m.media-amazon.com/images/I/61gTdPHg5Q...\n", + "style Outdoor & Indoor\n", + "material Rubber\n", + "color NaN\n", + "url https://www.amazon.com/dp/B00PNJAACG\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 112, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Sintosin Vintage Oval Mirrors for Wall Decor 1...\n", + "primary_image https://m.media-amazon.com/images/I/41NiOP0+4j...\n", + "style Shabby Chic\n", + "material Wood\n", + "color Oval\n", + "url https://www.amazon.com/dp/B0BWJLZF5G\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 113, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title BEWISHOME Vanity Stool, Bedroom Vanity Chair w...\n", + "primary_image https://m.media-amazon.com/images/I/410emoPl2k...\n", + "style Modern\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0B6FML1VS\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 114, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Children's Factory School Age High Back Lounge...\n", + "primary_image https://m.media-amazon.com/images/I/51ORnRyifR...\n", + "style Single Seat\n", + "material NaN\n", + "color Blue-red\n", + "url https://www.amazon.com/dp/B00740P05Y\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 115, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title FLYJOE Shoe Rack Bench, 3-Tier Freestanding Wo...\n", + "primary_image https://m.media-amazon.com/images/I/51WQiiIyuS...\n", + "style NaN\n", + "material NaN\n", + "color Rustic Walnut\n", + "url https://www.amazon.com/dp/B0CN8NXR1Q\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 116, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title FLYZC Counter Height Bar Stools Set of 4, Stoo...\n", + "primary_image https://m.media-amazon.com/images/I/51jw0SXQMW...\n", + "style Straight\n", + "material NaN\n", + "color Grey & Black\n", + "url https://www.amazon.com/dp/B0CH862BV2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 117, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title SITMOD Gaming Chairs for Adults with Footrest-...\n", + "primary_image https://m.media-amazon.com/images/I/41bntfm39U...\n", + "style With arms\n", + "material Memory Foam\n", + "color Grey\n", + "url https://www.amazon.com/dp/B0B3HM3FTZ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 118, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title CM Cosmos Stuffed Animal Storage Bean Bag Chai...\n", + "primary_image https://m.media-amazon.com/images/I/41XEtwrKqo...\n", + "style NaN\n", + "material NaN\n", + "color Grey & White\n", + "url https://www.amazon.com/dp/B07JCPZDSL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 119, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Cionyce 4 Pcs Sectional Couch Connectors, Pin ...\n", + "primary_image https://m.media-amazon.com/images/I/41sejv2mO6...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B09V6RSWSR\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 120, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Tiita Saucer Chair with Ottoman, Soft Faux Fur...\n", + "primary_image https://m.media-amazon.com/images/I/51C5YkDdUy...\n", + "style Garden\n", + "material NaN\n", + "color Beige With Ottoman\n", + "url https://www.amazon.com/dp/B0BWDJ8NSM\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 121, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Grandmother Birthday Gifts Compact Makeup Mirr...\n", + "primary_image https://m.media-amazon.com/images/I/417J95lDDa...\n", + "style NaN\n", + "material Stainless Steel\n", + "color For Grandmother\n", + "url https://www.amazon.com/dp/B0C289KQNK\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 122, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title GIA 24-Inch Counter Height Square Backless Met...\n", + "primary_image https://m.media-amazon.com/images/I/414M2Vz5Yj...\n", + "style Straight\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0B75Z1T2H\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 123, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Vintage Desktop Apothecary Cabinet with 3 Draw...\n", + "primary_image https://m.media-amazon.com/images/I/41yz4PMNd0...\n", + "style drawer,wood\n", + "material Wood\n", + "color Mahogany Wood Brown\n", + "url https://www.amazon.com/dp/B0B24KQJS9\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 124, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title WAYTRIM Dresser Storage Tower, 4 Fabric Organi...\n", + "primary_image https://m.media-amazon.com/images/I/41DfHAtQUK...\n", + "style Modern\n", + "material NaN\n", + "color Camel\n", + "url https://www.amazon.com/dp/B07W56HHX5\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 125, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Power Recliner Power Supply Kit-4-Piece Univer...\n", + "primary_image https://m.media-amazon.com/images/I/51N6Zq4kxx...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0BHVLGGYL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 126, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Anna Stay Wine Rack Wall Mounted - Decorative ...\n", + "primary_image https://m.media-amazon.com/images/I/51K1wX04DX...\n", + "style Modern\n", + "material NaN\n", + "color Wine Gold\n", + "url https://www.amazon.com/dp/B09ZQM2FX3\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 127, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Lufeiya Small Computer Desk with 2 Drawers for...\n", + "primary_image https://m.media-amazon.com/images/I/41zNNJV-QU...\n", + "style Country Rustic\n", + "material Engineered Wood\n", + "color Rustic Brown\n", + "url https://www.amazon.com/dp/B0CB5G1BHX\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 128, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Watson & Whitely Swivel Bar Stools Set of 2, F...\n", + "primary_image https://m.media-amazon.com/images/I/41IWqaJGuW...\n", + "style Modern\n", + "material NaN\n", + "color White (Multi-colored)\n", + "url https://www.amazon.com/dp/B0BV6KR1T7\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 129, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Adeco Large Square Storage Ottoman Bench, Tuft...\n", + "primary_image https://m.media-amazon.com/images/I/31HEdjZpCb...\n", + "style Mid-Century Modern\n", + "material Wood\n", + "color Orange Brown\n", + "url https://www.amazon.com/dp/B0C6XNNL9M\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 130, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title New Classic Furniture Evander Wood End Table w...\n", + "primary_image https://m.media-amazon.com/images/I/51TJVV3sRq...\n", + "style Contemporary\n", + "material Wood\n", + "color Two Tone Cream/Brown\n", + "url https://www.amazon.com/dp/B0B6YR22H1\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 131, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Lipper International Wooden Storage Crate, whi...\n", + "primary_image https://m.media-amazon.com/images/I/31MZPtCF0R...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B07MZRYQ2X\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 132, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Amazon Basics Kids Adjustable Mesh Low-Back Sw...\n", + "primary_image https://m.media-amazon.com/images/I/41bsjzUI6N...\n", + "style Mesh\n", + "material NaN\n", + "color Red\n", + "url https://www.amazon.com/dp/B0BHF9PPJC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 133, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Joovy Coo Bassinet, Portable Bassinet with Sto...\n", + "primary_image https://m.media-amazon.com/images/I/41UOfS3Jmk...\n", + "style NaN\n", + "material fabric\n", + "color NaN\n", + "url https://www.amazon.com/dp/B07NFSLLCG\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 134, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Halatua 6ftlarge Fur Bean Bag Cover Lazy Sofa ...\n", + "primary_image https://m.media-amazon.com/images/I/51-utQ4pnb...\n", + "style NaN\n", + "material Polyester\n", + "color Snowblue\n", + "url https://www.amazon.com/dp/B0C7L8GGJF\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 135, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Flash Furniture Walker Small Rustic Natural Ho...\n", + "primary_image https://m.media-amazon.com/images/I/31QOFqtaHJ...\n", + "style Sled\n", + "material Engineered Wood\n", + "color Rustic\n", + "url https://www.amazon.com/dp/B08JWJTZ1Y\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 136, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title BOKKOLIK Vintage Bar Stools Swivel PU Seat 29-...\n", + "primary_image https://m.media-amazon.com/images/I/41PjcPoHTL...\n", + "style Soft PU Seat\n", + "material NaN\n", + "color Dark Brown\n", + "url https://www.amazon.com/dp/B0BG7MX77T\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 137, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Nalupatio Storage Ottoman, Bedroom End Bench,U...\n", + "primary_image https://m.media-amazon.com/images/I/31+6K0Tbdp...\n", + "style Modern\n", + "material Wood\n", + "color Light Green\n", + "url https://www.amazon.com/dp/B0C48X7JQB\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 138, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Homevany Bamboo Wine Rack,4 Tier, Wine Bottle ...\n", + "primary_image https://m.media-amazon.com/images/I/51DO5hfgdK...\n", + "style Modern\n", + "material NaN\n", + "color Brown\n", + "url https://www.amazon.com/dp/B08T8ZRZ1F\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 139, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Armen Living Julius 30\" Cream Faux Leather and...\n", + "primary_image https://m.media-amazon.com/images/I/31v34T0kgn...\n", + "style Straight\n", + "material NaN\n", + "color Cream/Walnut\n", + "url https://www.amazon.com/dp/B0961N94SZ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 140, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title WONSTART Vanity Mirror with Lights, 50 x 41cm ...\n", + "primary_image https://m.media-amazon.com/images/I/41k7g8oo6b...\n", + "style Modern\n", + "material Aluminum, Glass\n", + "color Silver\n", + "url https://www.amazon.com/dp/B0C2VF2S6R\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 141, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Cpintltr Velvet Foot Rest Stool Multipurpose D...\n", + "primary_image https://m.media-amazon.com/images/I/51K84REZCG...\n", + "style Modern\n", + "material Wood\n", + "color Dusty Pink\n", + "url https://www.amazon.com/dp/B0CH34CCLV\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 142, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title uxcell Shredded Memory Foam Filling, 10 Pounds...\n", + "primary_image https://m.media-amazon.com/images/I/51i6LeHlc9...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0C4DWRF3M\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 143, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title FAMSINGO Ergonomic Mesh Office Chair, High Bac...\n", + "primary_image https://m.media-amazon.com/images/I/41Jm-GtY+5...\n", + "style With arms\n", + "material Memory Foam\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CBBMQPVC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 144, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Serta Style Hannah II Office Chair, Harvard Pi...\n", + "primary_image https://m.media-amazon.com/images/I/41XQ7R6j7l...\n", + "style with-arms\n", + "material Foam\n", + "color Harvard Pink\n", + "url https://www.amazon.com/dp/B07667648L\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 145, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Christmas 3D Illusion Doormat, Non-Slip Visual...\n", + "primary_image https://m.media-amazon.com/images/I/51uOa02x4H...\n", + "style Classic\n", + "material 棉质\n", + "color Red\n", + "url https://www.amazon.com/dp/B0CC28VDSV\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 146, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Narrow Console Table with Power Strips, Sofa T...\n", + "primary_image https://m.media-amazon.com/images/I/51FRxl-qgF...\n", + "style Sofa Table with Outlets\n", + "material MDF Board and Metal\n", + "color Black\n", + "url https://www.amazon.com/dp/B0BSHFVY3J\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 147, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title AnRui Folding Floor Chair with Adjustable Back...\n", + "primary_image https://m.media-amazon.com/images/I/51iuIrMVq+...\n", + "style Solid Back\n", + "material Foam\n", + "color Stripe\n", + "url https://www.amazon.com/dp/B08QRF4TTL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 148, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title sogesfurniture 5 Tier Free Standing Wooden Sho...\n", + "primary_image https://m.media-amazon.com/images/I/51j2v3ij2u...\n", + "style Modern\n", + "material Engineered Wood\n", + "color NaN\n", + "url https://www.amazon.com/dp/B07WLK9TNS\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 149, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title fengxiaomin-Plastic Bed Slat End Caps Holders ...\n", + "primary_image https://m.media-amazon.com/images/I/41gvi7RjrZ...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CNVJ24YF\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 150, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MoNiBloom Massage Gaming Recliner Chair with S...\n", + "primary_image https://m.media-amazon.com/images/I/41Md8gR4YY...\n", + "style Modern\n", + "material NaN\n", + "color Green\n", + "url https://www.amazon.com/dp/B0BZKMYST2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 151, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title SUNSLASH Wall Mounted Mirror, Arched Wall Mirr...\n", + "primary_image https://m.media-amazon.com/images/I/41nGiqXS+5...\n", + "style NaN\n", + "material Aluminum\n", + "color Black(arched)\n", + "url https://www.amazon.com/dp/B0BP9QYFTL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 152, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Allied Brass Carolina Crystal Collection Frame...\n", + "primary_image https://m.media-amazon.com/images/I/21+UCtQ6p9...\n", + "style Antique\n", + "material Brass\n", + "color Antique Brass\n", + "url https://www.amazon.com/dp/B07ZSF42WD\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 153, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Home Source 40.7' Elegance Bar Server and Wine...\n", + "primary_image https://m.media-amazon.com/images/I/41nYPK8Xbr...\n", + "style Fluted shape\n", + "material Walnut Wood\n", + "color Walnut\n", + "url https://www.amazon.com/dp/B0CN1LGXNP\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 154, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Shintenchi 60\" Small Loveseat, 3 in 1 Cute Con...\n", + "primary_image https://m.media-amazon.com/images/I/41SkpIbGdQ...\n", + "style Pillow-Top\n", + "material Wood\n", + "color Dark Gray\n", + "url https://www.amazon.com/dp/B0CMTHD198\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 155, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title King Mattresses Bag for Moving Storage Protect...\n", + "primary_image https://m.media-amazon.com/images/I/41ye8pFDZ9...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CN44TTFJ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 156, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title sawsile Asymmetrical Wall Mirror,Unique Gold V...\n", + "primary_image https://m.media-amazon.com/images/I/41G-NEOXwf...\n", + "style NaN\n", + "material Wood, Iron\n", + "color Gold\n", + "url https://www.amazon.com/dp/B0CDWH5PQP\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 157, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Leather At Home, Decorative 13 Inch Rounded Pi...\n", + "primary_image https://m.media-amazon.com/images/I/51ePbFDPNR...\n", + "style Classic\n", + "material Leather\n", + "color Bourbon Brown\n", + "url https://www.amazon.com/dp/B0BBKQ3XW9\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 158, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Hzuaneri Blanket Ladder Shelf for Living Room,...\n", + "primary_image https://m.media-amazon.com/images/I/31XETwaX0W...\n", + "style Farmhouse\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0BSKY28M7\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 159, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title 9 Inch lighted magnifying mirror with Adjustab...\n", + "primary_image https://m.media-amazon.com/images/I/41j2FBzCCJ...\n", + "style Modern\n", + "material Alloy Steel\n", + "color Brushed Nickel\n", + "url https://www.amazon.com/dp/B0CMJCCT9C\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 160, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title shopperals Large Black Fogless Handheld Shavin...\n", + "primary_image https://m.media-amazon.com/images/I/413+UE2HxQ...\n", + "style NaN\n", + "material Plastic\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CJCRFZCG\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 161, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Convenience Concepts French Country Desk, Drif...\n", + "primary_image https://m.media-amazon.com/images/I/21Xa4sH6hP...\n", + "style French Country\n", + "material Engineered Wood\n", + "color Driftwood/White\n", + "url https://www.amazon.com/dp/B07D6TS5MR\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 162, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title FurnitureR 27''H Round Drawer 2 Tiers Endtable...\n", + "primary_image https://m.media-amazon.com/images/I/51VXthftc3...\n", + "style Mid-Century Modern\n", + "material Engineered Wood\n", + "color Green and Brown\n", + "url https://www.amazon.com/dp/B0BVYQTMNX\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 163, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Flash Furniture Contemporary Red Vinyl Rounded...\n", + "primary_image https://m.media-amazon.com/images/I/41OOyTZhTz...\n", + "style Contemporary\n", + "material NaN\n", + "color Red\n", + "url https://www.amazon.com/dp/B00EAY2HTY\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 164, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Stylish Camping Ming's Mark RC4 Reversible Cla...\n", + "primary_image https://m.media-amazon.com/images/I/515xhjtnk0...\n", + "style Modern\n", + "material Polypropylene\n", + "color Green/Beige\n", + "url https://www.amazon.com/dp/B0044G9M2S\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 165, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Christopher Knight Home Adelina Fabric Occaisi...\n", + "primary_image https://m.media-amazon.com/images/I/41FESwmeXb...\n", + "style Wing Back\n", + "material NaN\n", + "color Light Lavender\n", + "url https://www.amazon.com/dp/B073GLR1DG\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 166, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ODK Small Computer Desk, 27.5 inch Desk for Sm...\n", + "primary_image https://m.media-amazon.com/images/I/41meqsf8aq...\n", + "style Modern\n", + "material Engineered Wood\n", + "color Pure White\n", + "url https://www.amazon.com/dp/B092HVNQQ4\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 167, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title GOmaize Cute Wall Mirror with 4 Layers of Colo...\n", + "primary_image https://m.media-amazon.com/images/I/417WwDOB5X...\n", + "style Bohemian\n", + "material Plastic\n", + "color Blue\n", + "url https://www.amazon.com/dp/B0CB6HZR7Z\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 168, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title huester What are You Doing in My Swamp Door Ma...\n", + "primary_image https://m.media-amazon.com/images/I/51L59TyllJ...\n", + "style Farmhouse\n", + "material Rubber\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0C8SGN73S\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 169, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Bedstory 3 Inch Queen Size Memory Foam Mattres...\n", + "primary_image https://m.media-amazon.com/images/I/516PONoRDr...\n", + "style NaN\n", + "material Memory Foam\n", + "color White\n", + "url https://www.amazon.com/dp/B0B31DB3LN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 170, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Toland Home Garden 800252 Birthday Bash Party ...\n", + "primary_image https://m.media-amazon.com/images/I/51rfyHppFm...\n", + "style Modern\n", + "material Rubber\n", + "color Balloon Outdoor Doormat for Entryway Indoor En...\n", + "url https://www.amazon.com/dp/B01AA0SO7A\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 171, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Asense Small Footstool Ottoman Set of 2, Faux ...\n", + "primary_image https://m.media-amazon.com/images/I/31mK9NtBNH...\n", + "style Modern\n", + "material NaN\n", + "color 2 Pack Faux Leather Celadon\n", + "url https://www.amazon.com/dp/B0CPLSTFW5\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 172, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title PINGEUI 2 Packs 13 Inches Bamboo Step Stool, N...\n", + "primary_image https://m.media-amazon.com/images/I/41Y0vrrtp7...\n", + "style Modern\n", + "material Bamboo\n", + "color Brown\n", + "url https://www.amazon.com/dp/B099VZPTWT\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 173, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Poundex Y1553 Two Piece PU Round Shape Barstoo...\n", + "primary_image https://m.media-amazon.com/images/I/31XVd1lG-z...\n", + "style Modern\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0183K9SMO\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 174, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title SP-AU-Era Mirror cabinet storage box, cosmetic...\n", + "primary_image https://m.media-amazon.com/images/I/61zDAVHDAf...\n", + "style Wall-mounted Perforated Home Bathroom Sink, Co...\n", + "material PET\n", + "color blackish green\n", + "url https://www.amazon.com/dp/B0C99SY5W2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 175, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kavonty Storage Chest, Storage Bench, Retro To...\n", + "primary_image https://m.media-amazon.com/images/I/41YpXf+0X2...\n", + "style NaN\n", + "material NaN\n", + "color Rustic Brown\n", + "url https://www.amazon.com/dp/B0BB9RZ19N\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 176, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Barkan TV Wall Mount, 32-70 inch Full Motion A...\n", + "primary_image https://m.media-amazon.com/images/I/41NgcrmTA7...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B01L0YHBB0\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 177, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title danpinera Side Table Round Metal, Outdoor Side...\n", + "primary_image https://m.media-amazon.com/images/I/41fuboxDT3...\n", + "style Modern\n", + "material Iron\n", + "color Light Green\n", + "url https://www.amazon.com/dp/B09FXM34DV\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 178, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Dscabomlg Foldable Shoe Storage Plastic Vertic...\n", + "primary_image https://m.media-amazon.com/images/I/41bq4r8uj5...\n", + "style Modern\n", + "material NaN\n", + "color Grey&white\n", + "url https://www.amazon.com/dp/B0CG5SJN86\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 179, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ACCHAR Ergonomic Office Chair, Reclining Mesh ...\n", + "primary_image https://m.media-amazon.com/images/I/413qdlao4p...\n", + "style With arms\n", + "material Foam\n", + "color White\n", + "url https://www.amazon.com/dp/B0C2C9S1R6\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 180, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ODK Small Computer Desk, 27.5 Inch, Compact Ti...\n", + "primary_image https://m.media-amazon.com/images/I/41NmfAngKl...\n", + "style Modern\n", + "material Engineered Wood\n", + "color Black\n", + "url https://www.amazon.com/dp/B08CB925CT\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 181, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Front Door Mats by ZULINE,Entry and Back Yard ...\n", + "primary_image https://m.media-amazon.com/images/I/51+qRIvl1F...\n", + "style Outdoor & Indoor\n", + "material Rubber\n", + "color Brown-diamond\n", + "url https://www.amazon.com/dp/B09PBH963M\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 182, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MyGift Modern Over The Door Towel Rack in Shab...\n", + "primary_image https://m.media-amazon.com/images/I/515aoZQHoA...\n", + "style NaN\n", + "material Metal\n", + "color Whitewashed Wood & Black Metal\n", + "url https://www.amazon.com/dp/B0C5BBYRDN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 183, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title WEENFON Storage Cabinet with Doors and Shelves...\n", + "primary_image https://m.media-amazon.com/images/I/51F9Edov14...\n", + "style Shaker\n", + "material Engineered Wood\n", + "color Grey\n", + "url https://www.amazon.com/dp/B0BF8KWBR2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 184, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title SOOWERY End Tables with Charging Station, Set ...\n", + "primary_image https://m.media-amazon.com/images/I/41x2Yzpw5a...\n", + "style Retro\n", + "material Iron\n", + "color Brown\n", + "url https://www.amazon.com/dp/B0BRFX55TJ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 185, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Bednowitz Twin Box Spring,5 Inch Low Profile M...\n", + "primary_image https://m.media-amazon.com/images/I/51rTEhx3EA...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CJR8KM2D\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 186, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title BOKKOLIK Industrial Bar Stools (Set of 2) Coun...\n", + "primary_image https://m.media-amazon.com/images/I/41r1PM96rV...\n", + "style industrial/retro/rustic/vintage/farmhouse/chic\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0BJZPV117\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 187, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title HOOBRO Over The Toilet Storage Cabinet, Mass-S...\n", + "primary_image https://m.media-amazon.com/images/I/41i8ryTI4h...\n", + "style louver\n", + "material Engineered Wood, Metal\n", + "color Rustic Brown\n", + "url https://www.amazon.com/dp/B0B31G7LBC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 188, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Hanover Swivel Counter Height Bar Stool, White...\n", + "primary_image https://m.media-amazon.com/images/I/31039iD-Mp...\n", + "style Classic\n", + "material NaN\n", + "color White and Gray\n", + "url https://www.amazon.com/dp/B0B97PJ94P\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 189, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title VECELO Modern Industrial Style 3-Piece Dining ...\n", + "primary_image https://m.media-amazon.com/images/I/41rj5r2UFS...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B09MS5RJTT\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 190, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Tenkovic Metal Coat Rack Stand with Quartz Bas...\n", + "primary_image https://m.media-amazon.com/images/I/31N5mQxbhB...\n", + "style NaN\n", + "material Metal, Wood\n", + "color tree gold\n", + "url https://www.amazon.com/dp/B0BZCMCJDY\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 191, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title FANYE Oversized 6 Seaters Modular Storage Sect...\n", + "primary_image https://m.media-amazon.com/images/I/41MTr4ynO3...\n", + "style Track\n", + "material Wood\n", + "color Navy Blue\n", + "url https://www.amazon.com/dp/B0CP7YFXD2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 192, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title HOMSHO 2-Tier Storage Bench,Shoe Bench with Pa...\n", + "primary_image https://m.media-amazon.com/images/I/41Sq7pT7XM...\n", + "style NaN\n", + "material NaN\n", + "color White\n", + "url https://www.amazon.com/dp/B0BY23W1J9\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 193, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Realhotan 18 Inch Twin Bed Frame 3500 Pounds H...\n", + "primary_image https://m.media-amazon.com/images/I/51+pTJO13K...\n", + "style NaN\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CCCS3RB9\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 194, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kwikset BTBNC1C Pfister Bath Hardware, 18\", Po...\n", + "primary_image https://m.media-amazon.com/images/I/31A+awsgcP...\n", + "style Contemporary\n", + "material Zinc\n", + "color Polished Chrome\n", + "url https://www.amazon.com/dp/B00JMTNK0W\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 195, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MAHANCRIS End Table Set of 2, Side Table with ...\n", + "primary_image https://m.media-amazon.com/images/I/41wsItqcjU...\n", + "style Straight Leg\n", + "material Engineered Wood\n", + "color Rustic Brown + Black\n", + "url https://www.amazon.com/dp/B0CJNJMY5H\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 196, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Moen MY3786CH Idora Single Post Bathroom Hand ...\n", + "primary_image https://m.media-amazon.com/images/I/41LVA3Tody...\n", + "style NaN\n", + "material Zinc\n", + "color Chrome\n", + "url https://www.amazon.com/dp/B0882HQRJX\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 197, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Roundhill Furniture Swivel Black Bonded Leathe...\n", + "primary_image https://m.media-amazon.com/images/I/31VM2JhRDZ...\n", + "style Modern\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B00D93AT24\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 198, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title PINPLUS Storage Ottoman Bench, Linen Coffee Ta...\n", + "primary_image https://m.media-amazon.com/images/I/41gj8mVGFG...\n", + "style Modern\n", + "material Engineered Wood\n", + "color White\n", + "url https://www.amazon.com/dp/B0BZ3RYRNY\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 199, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Red Co. 14 x 18 inch Large Decorative Frameles...\n", + "primary_image https://m.media-amazon.com/images/I/21M6+MAnWp...\n", + "style Modern\n", + "material Glass\n", + "color Silver\n", + "url https://www.amazon.com/dp/B087Z3RXLN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 200, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title PONTMENT Foot Stool Leather Footstool Solid Wo...\n", + "primary_image https://m.media-amazon.com/images/I/51ElPbhgU7...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0C38VPJ15\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 201, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kingston Brass BA2714C Milano Towel-Ring, 6-In...\n", + "primary_image https://m.media-amazon.com/images/I/41X7yXWQ+P...\n", + "style Contemporary\n", + "material Brass\n", + "color Polished Chrome\n", + "url https://www.amazon.com/dp/B0003SDM18\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 202, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Lazy Chair with Ottoman, Modern Lounge Accent ...\n", + "primary_image https://m.media-amazon.com/images/I/415U1ul6gp...\n", + "style NaN\n", + "material NaN\n", + "color Grey\n", + "url https://www.amazon.com/dp/B0CCRXWDF1\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 203, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title latifolia Shoe Cabinet, Vintage Shoe Storage C...\n", + "primary_image https://m.media-amazon.com/images/I/41Mst-29Zd...\n", + "style Modern\n", + "material Bamboo\n", + "color Brown\n", + "url https://www.amazon.com/dp/B0CGX7Y9HQ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 204, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Jumweo Towel Racks for Bathroom, Metal Towel R...\n", + "primary_image https://m.media-amazon.com/images/I/411VfNriJE...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CM6PR2ZB\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 205, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Christopher Knight Home Gentry Bonded Leather ...\n", + "primary_image https://m.media-amazon.com/images/I/412PrvRCw-...\n", + "style Leather\n", + "material Foam\n", + "color Black\n", + "url https://www.amazon.com/dp/B005FFA3LQ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 206, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title BokWin 4 Sets No Mortise Bed Rail Fittings Woo...\n", + "primary_image https://m.media-amazon.com/images/I/41ocbpXWJg...\n", + "style NaN\n", + "material Iron\n", + "color NaN\n", + "url https://www.amazon.com/dp/B09CGPQT1L\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 207, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Simple Deluxe Gaming Chair, Big and Tall Gamer...\n", + "primary_image https://m.media-amazon.com/images/I/41ZTMbqu1J...\n", + "style With arms\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0B51LYB8T\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 208, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title OIGUMR Shield Wall Mirror Mirror Wall Decor Vi...\n", + "primary_image https://m.media-amazon.com/images/I/41LSP7xb2q...\n", + "style NaN\n", + "material Resin\n", + "color Gold\n", + "url https://www.amazon.com/dp/B0BMXD3D6J\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 209, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ChooChoo Farmhouse End Table, Modern End Table...\n", + "primary_image https://m.media-amazon.com/images/I/41P7V9O6ga...\n", + "style Modern\n", + "material Engineered Wood\n", + "color White and Brown\n", + "url https://www.amazon.com/dp/B0CJHT9KH6\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 210, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ZIYOO Twin Bed Frame 14 Inch High 3 Inches Wid...\n", + "primary_image https://m.media-amazon.com/images/I/31dZ6tsbHO...\n", + "style NaN\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B07RY46G23\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 211, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MoNiBloom Set of 2 Plastic Barstools with PU C...\n", + "primary_image https://m.media-amazon.com/images/I/31fCq+IIEu...\n", + "style Modern\n", + "material NaN\n", + "color White\n", + "url https://www.amazon.com/dp/B0CB7SM7MM\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 212, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title KingCamp Stable Folding Camping Table Bamboo O...\n", + "primary_image https://m.media-amazon.com/images/I/41Sc-GGZBe...\n", + "style YELLOW\n", + "material Aluminum,Bamboo\n", + "color Yellow-27.6\"d X 47.2\"w X 27.56\"h\n", + "url https://www.amazon.com/dp/B08ZHPDZX5\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 213, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Artistic Weavers Berma Knitted Jute Round Pouf...\n", + "primary_image https://m.media-amazon.com/images/I/51wZvzlzMD...\n", + "style Natural\n", + "material Engineered Wood\n", + "color Slate\n", + "url https://www.amazon.com/dp/B00JVZEZE2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 214, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Dwellicity Hello Welcome Mat Black and Gray St...\n", + "primary_image https://m.media-amazon.com/images/I/51nGbm-6b-...\n", + "style Modern\n", + "material Polyvinyl Chloride\n", + "color NaN\n", + "url https://www.amazon.com/dp/B099NTP2SZ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 215, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Lifewit 70.9\" Narrow Long Console Sofa Table w...\n", + "primary_image https://m.media-amazon.com/images/I/417XCOhUDg...\n", + "style Modern\n", + "material Engineered Wood\n", + "color Rustic Brown\n", + "url https://www.amazon.com/dp/B0BZYWTH2D\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 216, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Henn&Hart 20\" Wide Round Side Table with Mirro...\n", + "primary_image https://m.media-amazon.com/images/I/41+Mg7qmpY...\n", + "style Side Table\n", + "material Glass\n", + "color Antique Brass/Mirror\n", + "url https://www.amazon.com/dp/B07WK22XDX\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 217, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title klotski Kids Table and 2 Chair Set, Wood Activ...\n", + "primary_image https://m.media-amazon.com/images/I/41QhFgJUCg...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CGZW945K\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 218, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kraftware Grant Signature Home San Remo Pineco...\n", + "primary_image https://m.media-amazon.com/images/I/419nFYjmvG...\n", + "style NaN\n", + "material Vinyl\n", + "color Brown\n", + "url https://www.amazon.com/dp/B0751KYGV4\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 219, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Alise Bath 3 Towel Bars,Towel Holder Towel Rac...\n", + "primary_image https://m.media-amazon.com/images/I/41frWw+ttR...\n", + "style NaN\n", + "material Stainless Steel, Metal\n", + "color Matte Black\n", + "url https://www.amazon.com/dp/B0BGN333H4\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 220, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Round Mirror, Black Round Mirror 24 Inch, Roun...\n", + "primary_image https://m.media-amazon.com/images/I/41igYIRb2f...\n", + "style Modern\n", + "material Metal\n", + "color Black\n", + "url https://www.amazon.com/dp/B08TTKV6LY\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 221, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Gexpusm Wood Coffee Table, Natural Wood Coffee...\n", + "primary_image https://m.media-amazon.com/images/I/51xwMLJtrt...\n", + "style 4 independent iron legs\n", + "material Wood\n", + "color Octagonal Coffee Table\n", + "url https://www.amazon.com/dp/B0BWXB7C1B\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 222, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Karl home Accent Chair Mid-Century Modern Chai...\n", + "primary_image https://m.media-amazon.com/images/I/51+a05Mxh+...\n", + "style Mid-Century Modern\n", + "material NaN\n", + "color Beige\n", + "url https://www.amazon.com/dp/B0BLP4W97Y\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 223, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kottova Vanity Mirror with Lights,Makeup Mirro...\n", + "primary_image https://m.media-amazon.com/images/I/41Z2VFHxc2...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0BJ1Y5TDN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 224, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title L.R. Resources Corcovado Metallic Braided Pouf...\n", + "primary_image https://m.media-amazon.com/images/I/51QokReEa1...\n", + "style Bohemian\n", + "material Cotton\n", + "color Grey / White\n", + "url https://www.amazon.com/dp/B078YDGBM8\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 225, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title GREENSTELL Coat Rack, Wooden Coat Rack Freesta...\n", + "primary_image https://m.media-amazon.com/images/I/31lWN-XSfC...\n", + "style Rustic\n", + "material Wood\n", + "color Black\n", + "url https://www.amazon.com/dp/B09M8M4P9L\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 226, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title COLLECTIVE HOME Mail Organizer with Mirror, Wa...\n", + "primary_image https://m.media-amazon.com/images/I/510ciQYiY4...\n", + "style Rustic\n", + "material Black\n", + "color White\n", + "url https://www.amazon.com/dp/B0BWY1HPMB\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 227, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Nightstand with Charging Station and LED Light...\n", + "primary_image https://m.media-amazon.com/images/I/41Co0zmXyy...\n", + "style With power outlet\n", + "material Glass, Engineered Wood\n", + "color Black\n", + "url https://www.amazon.com/dp/B0C6K8LMG8\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 228, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kmitmuk 2 Pack Cabinet Towel Holder, White Kit...\n", + "primary_image https://m.media-amazon.com/images/I/21b4+99Ox0...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CGXJ3VR7\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 229, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title GIA Toolix Backless Stool with Metal Seat, Gun...\n", + "primary_image https://m.media-amazon.com/images/I/41mgAYeNEx...\n", + "style Tapered\n", + "material NaN\n", + "color Gunmetal\n", + "url https://www.amazon.com/dp/B01FL46UD0\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 230, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title It's_Organized Gaming Desk 55 inch PC Computer...\n", + "primary_image https://m.media-amazon.com/images/I/41oiXo1q4w...\n", + "style Gaming\n", + "material Alloy Steel\n", + "color Black\n", + "url https://www.amazon.com/dp/B08CR34X1X\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 231, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Serta Executive Office Padded Arms, Adjustable...\n", + "primary_image https://m.media-amazon.com/images/I/41ZBS1hvHz...\n", + "style with-arms\n", + "material Foam\n", + "color Black/Blue\n", + "url https://www.amazon.com/dp/B07644FZVS\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 232, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title KoiHome Wooden Daybed with 2 Storage Drawers, ...\n", + "primary_image https://m.media-amazon.com/images/I/511irNkgaw...\n", + "style NaN\n", + "material NaN\n", + "color Espresso\n", + "url https://www.amazon.com/dp/B0CHMQC63H\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 233, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Soerreo Shoe Slot Storage Box Adjustable Shoe ...\n", + "primary_image https://m.media-amazon.com/images/I/4127YVIANk...\n", + "style Modern\n", + "material Plastic\n", + "color 10 Piece Set\n", + "url https://www.amazon.com/dp/B07X5VSLV1\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 234, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Arch Window Wall Mirror for Living Room,White ...\n", + "primary_image https://m.media-amazon.com/images/I/419YPa-PWh...\n", + "style French Country\n", + "material Wood\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CJV7SF48\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 235, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Jennifer Taylor Home Jacob 18\" Storage Cube Ot...\n", + "primary_image https://m.media-amazon.com/images/I/51KOhS-ZWZ...\n", + "style Contemporary\n", + "material Engineered Wood\n", + "color Tan Floral Jacquard\n", + "url https://www.amazon.com/dp/B0C9FWFGRP\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 236, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title C COMFORTLAND Unstuffed Faux Leather Ottoman P...\n", + "primary_image https://m.media-amazon.com/images/I/51qAukZMUD...\n", + "style Modern\n", + "material This is an empty shell that you have to stuff.\n", + "color Grey3\n", + "url https://www.amazon.com/dp/B0BWY5RPD1\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 237, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ZZQXTC Over Toilet Storage Cabinet, Bathroom S...\n", + "primary_image https://m.media-amazon.com/images/I/31cXPz4r76...\n", + "style wood\n", + "material Wood\n", + "color Over the Toilet Storage Cabinet White\n", + "url https://www.amazon.com/dp/B0CBDLJ32L\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 238, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title 40ft Upholstery Elastic Webbing,Two Inch (2\") ...\n", + "primary_image https://m.media-amazon.com/images/I/51oKu+lxwz...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CG9CDKQ7\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 239, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kujielan Oval Wall Mirror with Leaf Decorative...\n", + "primary_image https://m.media-amazon.com/images/I/419muJNV1J...\n", + "style Contemporary\n", + "material Metal\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CF9W6WW2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 240, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title RRG Coat Rack Stand, Metal Coat Tree with Heav...\n", + "primary_image https://m.media-amazon.com/images/I/214BED2RP6...\n", + "style 8 T-shaped Hooks\n", + "material Metal\n", + "color Gold - T 67\"/170cm\n", + "url https://www.amazon.com/dp/B09VBPNY7P\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 241, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Mirrors for Wall Decor, Golden Hanging Mirror ...\n", + "primary_image https://m.media-amazon.com/images/I/31TgX2crLU...\n", + "style NaN\n", + "material Iron\n", + "color Gold\n", + "url https://www.amazon.com/dp/B097R4M5Y5\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 242, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Mokoze Wavy Mirror Irregular Border 10.24\"x6.3...\n", + "primary_image https://m.media-amazon.com/images/I/319OzJXVrx...\n", + "style NaN\n", + "material Plastic\n", + "color White\n", + "url https://www.amazon.com/dp/B0C9QHJ611\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 243, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title (100) 12\" Record Outer Sleeves - Outer Reseala...\n", + "primary_image https://m.media-amazon.com/images/I/41uJZW57cB...\n", + "style NaN\n", + "material Vinyl, Plastic, Polypropylene (PP)\n", + "color NaN\n", + "url https://www.amazon.com/dp/B07B8VT4DC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 244, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Christopher Knight Home Munro Recliner, Navy B...\n", + "primary_image https://m.media-amazon.com/images/I/31exiSJMk8...\n", + "style Contemporary\n", + "material Foam\n", + "color Navy Blue + Teak\n", + "url https://www.amazon.com/dp/B09DS1VPFS\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 245, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title 3-Tier Side Table,Narrow End Table with Storag...\n", + "primary_image https://m.media-amazon.com/images/I/41tzKL1XIP...\n", + "style Modern\n", + "material Engineered Wood\n", + "color White\n", + "url https://www.amazon.com/dp/B0CP732ZN8\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 246, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title DBTHTSK Sofa Latch,Bed Replacement Parts,Heavy...\n", + "primary_image https://m.media-amazon.com/images/I/41gQlYHLvc...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0C2GQK6ZD\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 247, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Boraam Sonoma Bench, Storm Gray Wire-Brush\n", + "primary_image https://m.media-amazon.com/images/I/316Y4ewyCL...\n", + "style NaN\n", + "material NaN\n", + "color Storm Gray Wire-brush\n", + "url https://www.amazon.com/dp/B07T9M8Y88\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 248, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kwikset BTBCB2Y, Tuscan Bronze\n", + "primary_image https://m.media-amazon.com/images/I/21lfjygKja...\n", + "style Transitional\n", + "material Metal\n", + "color Tuscan Bronze\n", + "url https://www.amazon.com/dp/B001AHXWQ6\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 249, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Ilyapa 2-Tier Gold Metal Record Player Stand w...\n", + "primary_image https://m.media-amazon.com/images/I/4107MgspWh...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0BT6FF83T\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 250, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title GZsenwo (2 Pieces) 3-5/8\" Stainless Steel Repl...\n", + "primary_image https://m.media-amazon.com/images/I/41GvGSllzM...\n", + "style NaN\n", + "material Stainless Steel\n", + "color 2pcs\n", + "url https://www.amazon.com/dp/B0C6SYFYZN\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 251, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title HomePop by Kinfine Fabric Upholstered Round St...\n", + "primary_image https://m.media-amazon.com/images/I/51x3kXXPgx...\n", + "style Glam,Farmhouse,Traditional\n", + "material Engineered Wood\n", + "color Tan Woven\n", + "url https://www.amazon.com/dp/B0BG6BJ3DL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 252, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title EFTILE HOME 2 Foot Stool Handmade Wooden 3 Leg...\n", + "primary_image https://m.media-amazon.com/images/I/41-mDeiQw+...\n", + "style NaN\n", + "material Wood\n", + "color Kiwi\n", + "url https://www.amazon.com/dp/B0CKJ4YZC9\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 253, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Soft Foot Stool Ottoman Footrest Vanity Stool ...\n", + "primary_image https://m.media-amazon.com/images/I/41oTGNme97...\n", + "style NaN\n", + "material Iron\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CKW44X29\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 254, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title GAOMON Black 4 Drawer Dresser for Bedroom, Woo...\n", + "primary_image https://m.media-amazon.com/images/I/41GkzVqoNy...\n", + "style NaN\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CM1B86CJ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 255, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Alise 24-Inch Bathroom Lavatory Towel Rack Tow...\n", + "primary_image https://m.media-amazon.com/images/I/51FqMNM3yY...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0B6HXHQSW\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 256, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Seventable Nightstand with Charging Station an...\n", + "primary_image https://m.media-amazon.com/images/I/41Wn14U8Ll...\n", + "style Modern\n", + "material Engineered Wood\n", + "color Black\n", + "url https://www.amazon.com/dp/B09DLBNY6W\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 257, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Furinno Coffee Table with Bins, Espresso/Brown...\n", + "primary_image https://m.media-amazon.com/images/I/31CY4VJNyx...\n", + "style Modern\n", + "material Beech,Particle Board\n", + "color Espresso/Brown\n", + "url https://www.amazon.com/dp/B08C7Y4RB3\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 258, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Mod Made Mid Century Modern Chrome Wire Counte...\n", + "primary_image https://m.media-amazon.com/images/I/41BxXleMgG...\n", + "style Straight\n", + "material NaN\n", + "color Black Pad\n", + "url https://www.amazon.com/dp/B09Q1ZHQFR\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 259, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Bloomingville 15 Inches Mango Wood and Metal O...\n", + "primary_image https://m.media-amazon.com/images/I/21-b0yTRSN...\n", + "style Rustic\n", + "material Metal\n", + "color Black\n", + "url https://www.amazon.com/dp/B0CFSPXPYF\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 260, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Gnyonat Accent Chair with Ottoman,Living Room ...\n", + "primary_image https://m.media-amazon.com/images/I/41Gau9oSdR...\n", + "style NaN\n", + "material NaN\n", + "color Blue\n", + "url https://www.amazon.com/dp/B0C3TYNRJC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 261, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title SLLFLY Water Bottle Organizer,Stackable Water ...\n", + "primary_image https://m.media-amazon.com/images/I/51EAJVwOuL...\n", + "style Clear\n", + "material NaN\n", + "color Clear\n", + "url https://www.amazon.com/dp/B0BZNKKCC3\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 262, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title jela Kids Couch Large, Floor Sofa Modular Funi...\n", + "primary_image https://m.media-amazon.com/images/I/41Zury7vcH...\n", + "style Padded\n", + "material Suede\n", + "color Charcoal\n", + "url https://www.amazon.com/dp/B0BL9CDX29\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 263, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Flexson TV Mount Attachment for Sonos Beam - B...\n", + "primary_image https://m.media-amazon.com/images/I/31vbAI-UxE...\n", + "style NaN\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B07DQ6GPK6\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 264, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Small Collapsible Kids Hamper Fold Office Wast...\n", + "primary_image https://m.media-amazon.com/images/I/41v-ozvbCq...\n", + "style 现代\n", + "material Polyester\n", + "color 11.8\"*19.7\" Pink\n", + "url https://www.amazon.com/dp/B07K2Q2NRC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 265, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Diyalor 2.6 Gallon Small Trash Can with Handle...\n", + "primary_image https://m.media-amazon.com/images/I/219EPmkeeJ...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B09QCMCPYC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 266, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title DAYTOYS C Shaped End Table-Movable Sofa Table ...\n", + "primary_image https://m.media-amazon.com/images/I/41pgntXmHr...\n", + "style Classic\n", + "material Wood\n", + "color Black\n", + "url https://www.amazon.com/dp/B0C32RWCV7\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 267, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Phantoscope Storage Ottoman Round15 Inch, Velv...\n", + "primary_image https://m.media-amazon.com/images/I/31V7JNrxMg...\n", + "style Modern\n", + "material Engineered Wood\n", + "color Coffee\n", + "url https://www.amazon.com/dp/B095HPZ7DD\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 268, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Casual Home Night Owl Nightstand with USB Port...\n", + "primary_image https://m.media-amazon.com/images/I/3142Zp+eYu...\n", + "style Night Owl\n", + "material Walnut,Solid Wood,MDF\n", + "color Espresso\n", + "url https://www.amazon.com/dp/B019C4PPTU\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 269, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title NOVICA 302212 Handmade Wood and Reverse Painte...\n", + "primary_image https://m.media-amazon.com/images/I/51bKwT153n...\n", + "style Colonial\n", + "material Wood, Glass\n", + "color Burgundy\n", + "url https://www.amazon.com/dp/B07N41BVDG\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 270, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Toy Storage Basket and Play Mat for Building B...\n", + "primary_image https://m.media-amazon.com/images/I/61f83XRzyg...\n", + "style NaN\n", + "material fabric\n", + "color Grey\n", + "url https://www.amazon.com/dp/B08PMH8F89\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 271, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title RICOO SQ4965 No-Gap Wall Mount for Samsung® Q7...\n", + "primary_image https://m.media-amazon.com/images/I/41VNr1xTfE...\n", + "style NaN\n", + "material NaN\n", + "color black\n", + "url https://www.amazon.com/dp/B083WKFRRR\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 272, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Hosley Wooden Frame Mirror 20 Inch High. Ideal...\n", + "primary_image https://m.media-amazon.com/images/I/410lp8Rwjv...\n", + "style Contemporary\n", + "material Wood\n", + "color Brown\n", + "url https://www.amazon.com/dp/B07BQHWWRW\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 273, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title BRIAN & DANY Foldable Storage Ottoman Footrest...\n", + "primary_image https://m.media-amazon.com/images/I/413YS7nQBn...\n", + "style Modern\n", + "material Wood\n", + "color Khaki\n", + "url https://www.amazon.com/dp/B08BNDNGHJ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 274, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ReplacementScrews Bed Frame Rail Screws Compat...\n", + "primary_image https://m.media-amazon.com/images/I/31-vY+TuWO...\n", + "style Flat\n", + "material Metal\n", + "color Multicolored\n", + "url https://www.amazon.com/dp/B0CMXYMDH4\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 275, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title mDesign Round Metal in-Lay Accent Table with H...\n", + "primary_image https://m.media-amazon.com/images/I/413u0H2o1I...\n", + "style Modern\n", + "material Steel/Mirror\n", + "color Soft Brass/Mirror\n", + "url https://www.amazon.com/dp/B08XPR7662\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 276, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title NSFRCLHO Round End Table, Tempered Glass End T...\n", + "primary_image https://m.media-amazon.com/images/I/41z8YktAkG...\n", + "style Classic\n", + "material Tempered Glass\n", + "color Black\n", + "url https://www.amazon.com/dp/B089YWCTN2\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 277, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title pranovo Metal Sofa Handle Cable Recliner Chair...\n", + "primary_image https://m.media-amazon.com/images/I/3144eTNpeE...\n", + "style NaN\n", + "material Aluminum\n", + "color Black\n", + "url https://www.amazon.com/dp/B00R5VYYIG\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 278, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Stuffed Animal Storage Bean Bag Chair Cover fo...\n", + "primary_image https://m.media-amazon.com/images/I/41dBlMhHTh...\n", + "style NaN\n", + "material velvet\n", + "color Cover Only\n", + "url https://www.amazon.com/dp/B08JLH2PVH\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 279, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Pinkpum Shoe Ogranizer for Closet, 12 Pack Sho...\n", + "primary_image https://m.media-amazon.com/images/I/41huFJxt+F...\n", + "style NaN\n", + "material Acrylonitrile Butadiene Styrene\n", + "color Clear\n", + "url https://www.amazon.com/dp/B0B6P65LGH\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 280, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title BOOSDEN Padded Folding Chair 2 Pack, Foldable ...\n", + "primary_image https://m.media-amazon.com/images/I/41H64LdIQ8...\n", + "style NaN\n", + "material NaN\n", + "color 2 Pack Thick Chair | Red\n", + "url https://www.amazon.com/dp/B0CC4SZBQ9\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 281, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Kingston Brass SCC8247 Edenscape Pedestal Stee...\n", + "primary_image https://m.media-amazon.com/images/I/31FOa-k+Et...\n", + "style Modern\n", + "material Alloy Steel\n", + "color Brushed Brass\n", + "url https://www.amazon.com/dp/B0B5VJNZHL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 282, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Industrial Rolling Bar 3-Tier Kitchen Serving ...\n", + "primary_image https://m.media-amazon.com/images/I/51rjiq645t...\n", + "style NaN\n", + "material Solid Wood,Iron\n", + "color Brown+black\n", + "url https://www.amazon.com/dp/B07RGDWW5C\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 283, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Chill Sack Bean Bag Chair: Giant 5' Memory Foa...\n", + "primary_image https://m.media-amazon.com/images/I/51fQFu92ts...\n", + "style Furniture Foam\n", + "material NaN\n", + "color Microsuede - Lime\n", + "url https://www.amazon.com/dp/B00P21TM2O\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 284, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Caroline's Treasures BB5130JMAT Day of The Dea...\n", + "primary_image https://m.media-amazon.com/images/I/41Q15C0DMD...\n", + "style Day of the Dead Red Flowers Skull\n", + "material Rubber\n", + "color Day of the Dead Red Flowers Skull\n", + "url https://www.amazon.com/dp/B01MR9GSZE\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 285, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title glitzhome Adjustable Bar Stool Set of 2 Swivel...\n", + "primary_image https://m.media-amazon.com/images/I/51OPfpn9ov...\n", + "style Mid-Century\n", + "material NaN\n", + "color Begin\n", + "url https://www.amazon.com/dp/B08ZC5CYXG\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 286, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Symmons 673TR-STN Identity Wall-Mounted Towel ...\n", + "primary_image https://m.media-amazon.com/images/I/31cLgr4MIB...\n", + "style Contemporary\n", + "material Brass\n", + "color Satin Nickel\n", + "url https://www.amazon.com/dp/B01LYD3YB1\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 287, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title glitzhome Kitchen Island with Storage Kitchen ...\n", + "primary_image https://m.media-amazon.com/images/I/51wSfraUuh...\n", + "style Shaker\n", + "material Mdf,Metal,Plastic\n", + "color Red\n", + "url https://www.amazon.com/dp/B09D2T4GP4\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 288, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Lipper International Child's Toy Chest, 33.25\"...\n", + "primary_image https://m.media-amazon.com/images/I/41IWlgQ25-...\n", + "style NaN\n", + "material Engineered Wood, Beechwood, Metal\n", + "color Walnut Finish\n", + "url https://www.amazon.com/dp/B005H05TWC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 289, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title dnbss LED Nightstand with Charging Station, Sw...\n", + "primary_image https://m.media-amazon.com/images/I/41CANS+MiT...\n", + "style Modern\n", + "material Wood\n", + "color 1-black\n", + "url https://www.amazon.com/dp/B0BNWVLYV1\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 290, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Remote Control Holder,TV Remote Caddy/Box with...\n", + "primary_image https://m.media-amazon.com/images/I/41p58Tdmyo...\n", + "style NaN\n", + "material Leather\n", + "color Orange\n", + "url https://www.amazon.com/dp/B0C2GZNDXF\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 291, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MoNiBloom Foldable Storage Free Standing Shoes...\n", + "primary_image https://m.media-amazon.com/images/I/41SpDKbBsl...\n", + "style Modern\n", + "material Bamboo\n", + "color NaN\n", + "url https://www.amazon.com/dp/B09JSR3CYZ\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 292, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Walker Edison Furniture Modern Round Nesting C...\n", + "primary_image https://m.media-amazon.com/images/I/51U3y0LRMe...\n", + "style Coffee Table\n", + "material Manufactured Wood\n", + "color Walnut/Gold\n", + "url https://www.amazon.com/dp/B072P27BTW\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 293, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Way Basics Book Shelf 4 Cubby Storage (Tool-fr...\n", + "primary_image https://m.media-amazon.com/images/I/31eEZQKN+r...\n", + "style Modern\n", + "material Recycled Material\n", + "color NaN\n", + "url https://www.amazon.com/dp/B071HWKHQL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 294, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Mind Reader Trash Can and Toilet Brush Set, Ba...\n", + "primary_image https://m.media-amazon.com/images/I/31ktspfOC9...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0BJ7PQ9XH\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 295, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title #4203 Adjustable 1/4\" Threaded Non-Skid Leveli...\n", + "primary_image https://m.media-amazon.com/images/I/31Oas3rE7s...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B01M0S28J1\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 296, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Funny Welcome Doormat for Entryway Front Porch...\n", + "primary_image https://m.media-amazon.com/images/I/415x2v3cW5...\n", + "style Farmhouse\n", + "material Rubber\n", + "color Colorful,Funny,Novelty,Personalized\n", + "url https://www.amazon.com/dp/B09VFPFBND\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 297, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title KINGYES Folding Adjustable Backrest Adirondack...\n", + "primary_image https://m.media-amazon.com/images/I/41RnRNOgDD...\n", + "style With arms\n", + "material NaN\n", + "color Grey\n", + "url https://www.amazon.com/dp/B0B2JRSBL3\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 298, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Leick Home 10109-GR Oval Condo/Apartment Coffe...\n", + "primary_image https://m.media-amazon.com/images/I/31hgF2KPIJ...\n", + "style Oval Coffee Table\n", + "material Wood\n", + "color Smoke Gray\n", + "url https://www.amazon.com/dp/B08KLBTL5R\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 299, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Carter's by DaVinci Colby 3-Drawer Dresser in ...\n", + "primary_image https://m.media-amazon.com/images/I/31eTOoDK36...\n", + "style NaN\n", + "material pine, Wood\n", + "color Grey\n", + "url https://www.amazon.com/dp/B071DZG655\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 300, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Modway Baronet Button-Tufted Vegan Leather Par...\n", + "primary_image https://m.media-amazon.com/images/I/31Um2-NPw3...\n", + "style Contemporary\n", + "material Foam\n", + "color Grey\n", + "url https://www.amazon.com/dp/B0BR8NVGDL\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 301, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title MOOACE Small Side Table, Round End Table Night...\n", + "primary_image https://m.media-amazon.com/images/I/419Yb6N5yy...\n", + "style Modern\n", + "material Wood\n", + "color Brown\n", + "url https://www.amazon.com/dp/B0BGL3QXKR\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 302, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title BYOOTIQUE Makeup Chair Folding Camping Stool C...\n", + "primary_image https://m.media-amazon.com/images/I/511N0PuE9E...\n", + "style NaN\n", + "material NaN\n", + "color NaN\n", + "url https://www.amazon.com/dp/B0CC4X9SS3\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 303, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title nimboo Kids Couch - Modular Kids Play Couch Se...\n", + "primary_image https://m.media-amazon.com/images/I/51He1KLeOs...\n", + "style NaN\n", + "material High Density Comfort Foam\n", + "color Rainbow Unicorn\n", + "url https://www.amazon.com/dp/B0CLC3XWR6\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 304, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title LOKKHAN Industrial Bar Table 38.6\"-48.4\" Heigh...\n", + "primary_image https://m.media-amazon.com/images/I/31uVNZMOnX...\n", + "style NaN\n", + "material Wood Tabletop,Wooden Tabletop\n", + "color Copper\n", + "url https://www.amazon.com/dp/B0BVT748HV\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 305, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title UTONE Gaming Chair Computer Chair Breathable F...\n", + "primary_image https://m.media-amazon.com/images/I/31dCSKQ14Y...\n", + "style Solid Back\n", + "material Textile\n", + "color Pink\n", + "url https://www.amazon.com/dp/B0CF9F4TQD\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 306, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Lexicon Victoria Saddle Wood Bar Stools (Set o...\n", + "primary_image https://m.media-amazon.com/images/I/41CPL03Y-W...\n", + "style Contemporary\n", + "material Wood\n", + "color Black Sand\n", + "url https://www.amazon.com/dp/B08SLPBC36\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 307, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title ANZORG Behind Door Hanging Kids Shoes Organize...\n", + "primary_image https://m.media-amazon.com/images/I/31qQ2tZPv-...\n", + "style NaN\n", + "material Non Woven Fabric\n", + "color 12 Pockets\n", + "url https://www.amazon.com/dp/B09KN5ZTXC\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 308, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Pipishell Full-Motion TV Wall Mount for Most 3...\n", + "primary_image https://m.media-amazon.com/images/I/41TkLI3K2-...\n", + "style NaN\n", + "material NaN\n", + "color Black\n", + "url https://www.amazon.com/dp/B0BN7T57NK\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 309, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Noori Rug Home - Lux Collection Modern Ava Rou...\n", + "primary_image https://m.media-amazon.com/images/I/21Uq9uJEE5...\n", + "style Glam\n", + "material Engineered Wood\n", + "color Ivory/Gold Ava\n", + "url https://www.amazon.com/dp/B097FC9C27\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 310, dtype: object: 'float' object is not iterable\n", + "Error creating embedding for title Modway Parcel Upholstered Fabric Parsons Dinin...\n", + "primary_image https://m.media-amazon.com/images/I/41f8WNXejU...\n", + "style Modern\n", + "material Foam\n", + "color Beige\n", + "url https://www.amazon.com/dp/B00SMM4H98\n", + "keywords NaN\n", + "img_description NaN\n", + "caption NaN\n", + "Name: 311, dtype: object: 'float' object is not iterable\n" + ] + } + ], "source": [ "df_search['embedding'] = df_search.apply(lambda x: embed_tags_caption(x), axis=1)" ] }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 59, "id": "52241091", "metadata": {}, "outputs": [ @@ -1532,10 +4221,10 @@ " Metal\n", " White\n", " https://www.amazon.com/dp/B0CJHKVG6P\n", - " ['shoe rack', 'free standing', 'multi-layer', ...\n", - " This is a free-standing shoe rack featuring a ...\n", - " White metal free-standing shoe rack with multi...\n", - " [-0.06596625, -0.026769113, -0.013789515, -0.0...\n", + " ['shoe rack', 'metal', 'white', 'multi-layer',...\n", + " The GOYMFK Free Standing Shoe Rack is a versat...\n", + " Sleek white multi-layer metal free-standing sh...\n", + " [-0.06301482, -0.038354326, -0.0108071, -0.015...\n", " \n", " \n", " 1\n", @@ -1545,10 +4234,10 @@ " Sponge\n", " Black\n", " https://www.amazon.com/dp/B0B66QHB23\n", - " ['dining chairs', 'set of 2', 'leather', 'black']\n", - " This image features a set of two black dining ...\n", - " Set of 2 sleek black faux leather dining chair...\n", - " [-0.0077859573, -0.010376813, -0.01928079, -0....\n", + " ['dining chair', 'leather', 'black']\n", + " The Subrtex Leather Dining Chairs come in a se...\n", + " Set of 2 modern black faux leather dining chai...\n", + " [-0.018292552, -0.006216094, -0.009373649, -0....\n", " \n", " \n", " 2\n", @@ -1558,10 +4247,10 @@ " Polyethylene\n", " Green\n", " https://www.amazon.com/dp/B0BXRTWLYK\n", - " ['plant repotting mat', 'waterproof', 'portabl...\n", - " This is a square plant repotting mat designed ...\n", - " Waterproof green square plant repotting mat\n", - " [-0.023248248, 0.005370147, -0.0048999498, -0....\n", + " ['repotting mat', 'waterproof', 'portable', 'f...\n", + " The Plant Repotting Mat is a portable and fold...\n", + " Vibrant green waterproof plant repotting mat\n", + " [-0.010247701, 0.0074028056, -0.00037697714, -...\n", " \n", " \n", " 3\n", @@ -1571,10 +4260,10 @@ " Rubber\n", " A5589\n", " https://www.amazon.com/dp/B0C1MRB2M8\n", - " ['doormat', 'absorbent', 'non-slip', 'brown']\n", - " This is a rectangular doormat featuring a play...\n", - " Pickleball-themed coir doormat with playful de...\n", - " [-0.028953036, -0.026369056, -0.011363288, 0.0...\n", + " ['doormat', 'absorbent', 'non-slip', 'coconut ...\n", + " The Pickleball Doormat is a charming welcome m...\n", + " Coir welcome mat featuring a playful \"It's a g...\n", + " [-0.0033125042, -0.02689817, -0.009523449, 0.0...\n", " \n", " \n", " 4\n", @@ -1584,10 +4273,10 @@ " Iron\n", " Grey Set of 4\n", " https://www.amazon.com/dp/B0CG1N9QRC\n", - " ['tv tray table set', 'foldable', 'iron', 'grey']\n", - " This image showcases a set of two foldable TV ...\n", - " Set of two foldable TV trays with grey wood gr...\n", - " [-0.030723095, -0.0051356032, -0.027088132, 0....\n", + " ['tv tray', 'foldable', 'metal', 'grey']\n", + " The JOIN IRON Foldable TV Tray Set includes fo...\n", + " Set of 4 foldable grey TV trays with durable b...\n", + " [-0.020860892, -0.0053859027, -0.019131333, -0...\n", " \n", " \n", "\n", @@ -1616,35 +4305,35 @@ "4 Iron Grey Set of 4 https://www.amazon.com/dp/B0CG1N9QRC \n", "\n", " keywords \\\n", - "0 ['shoe rack', 'free standing', 'multi-layer', ... \n", - "1 ['dining chairs', 'set of 2', 'leather', 'black'] \n", - "2 ['plant repotting mat', 'waterproof', 'portabl... \n", - "3 ['doormat', 'absorbent', 'non-slip', 'brown'] \n", - "4 ['tv tray table set', 'foldable', 'iron', 'grey'] \n", + "0 ['shoe rack', 'metal', 'white', 'multi-layer',... \n", + "1 ['dining chair', 'leather', 'black'] \n", + "2 ['repotting mat', 'waterproof', 'portable', 'f... \n", + "3 ['doormat', 'absorbent', 'non-slip', 'coconut ... \n", + "4 ['tv tray', 'foldable', 'metal', 'grey'] \n", "\n", " img_description \\\n", - "0 This is a free-standing shoe rack featuring a ... \n", - "1 This image features a set of two black dining ... \n", - "2 This is a square plant repotting mat designed ... \n", - "3 This is a rectangular doormat featuring a play... \n", - "4 This image showcases a set of two foldable TV ... \n", + "0 The GOYMFK Free Standing Shoe Rack is a versat... \n", + "1 The Subrtex Leather Dining Chairs come in a se... \n", + "2 The Plant Repotting Mat is a portable and fold... \n", + "3 The Pickleball Doormat is a charming welcome m... \n", + "4 The JOIN IRON Foldable TV Tray Set includes fo... \n", "\n", " caption \\\n", - "0 White metal free-standing shoe rack with multi... \n", - "1 Set of 2 sleek black faux leather dining chair... \n", - "2 Waterproof green square plant repotting mat \n", - "3 Pickleball-themed coir doormat with playful de... \n", - "4 Set of two foldable TV trays with grey wood gr... \n", + "0 Sleek white multi-layer metal free-standing sh... \n", + "1 Set of 2 modern black faux leather dining chai... \n", + "2 Vibrant green waterproof plant repotting mat \n", + "3 Coir welcome mat featuring a playful \"It's a g... \n", + "4 Set of 4 foldable grey TV trays with durable b... \n", "\n", " embedding \n", - "0 [-0.06596625, -0.026769113, -0.013789515, -0.0... \n", - "1 [-0.0077859573, -0.010376813, -0.01928079, -0.... \n", - "2 [-0.023248248, 0.005370147, -0.0048999498, -0.... \n", - "3 [-0.028953036, -0.026369056, -0.011363288, 0.0... \n", - "4 [-0.030723095, -0.0051356032, -0.027088132, 0.... " + "0 [-0.06301482, -0.038354326, -0.0108071, -0.015... \n", + "1 [-0.018292552, -0.006216094, -0.009373649, -0.... \n", + "2 [-0.010247701, 0.0074028056, -0.00037697714, -... \n", + "3 [-0.0033125042, -0.02689817, -0.009523449, 0.0... \n", + "4 [-0.020860892, -0.0053859027, -0.019131333, -0... " ] }, - "execution_count": 63, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -1663,7 +4352,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "(49, 10)\n" + "(50, 10)\n" ] } ], @@ -1676,23 +4365,32 @@ { "cell_type": "code", "execution_count": 61, + "id": "5cc4352b", + "metadata": {}, + "outputs": [], + "source": [ + "data_embeddings_path = \"data/items_tagged_and_captioned_embeddings.csv\"" + ] + }, + { + "cell_type": "code", + "execution_count": 62, "id": "5d0bc2df", "metadata": {}, "outputs": [], "source": [ - "# Saving locally for later\n", - "data_embeddings_path = \"data/items_tagged_and_captioned_embeddings.csv\"\n", + "# Saving locally for later - optional: do not execute if you prefer to use the provided file\n", "df_search.to_csv(data_embeddings_path, index=False)" ] }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 63, "id": "1794c6fb", "metadata": {}, "outputs": [], "source": [ - "# Optional: load data from saved file\n", + "# Optional: load data from saved file if you haven't processed the whole dataset\n", "from ast import literal_eval\n", "df_search = pd.read_csv(data_embeddings_path)\n", "df_search[\"embedding\"] = df_search.embedding.apply(literal_eval).apply(np.array)" @@ -1710,7 +4408,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 64, "id": "1c957f85", "metadata": {}, "outputs": [], @@ -1725,7 +4423,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 65, "id": "94d48746", "metadata": {}, "outputs": [], @@ -1735,7 +4433,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 66, "id": "828e6adf", "metadata": {}, "outputs": [ @@ -1745,7 +4443,7 @@ "text": [ "Input: shoe storage\n", "\n", - "GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me... (https://www.amazon.com/dp/B0CJHKVG6P) - Similarity: 0.62\n" + "GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me... (https://www.amazon.com/dp/B0CJHKVG6P) - Similarity: 0.57\n" ] }, { @@ -1767,13 +4465,13 @@ "\n", "\n", "\n", - "GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me... (https://www.amazon.com/dp/B0CJHKVG6P) - Similarity: 0.57\n" + "MAEPA RV Shoe Storage for Bedside - 8 Extra Large ... (https://www.amazon.com/dp/B0C4PL1R3F) - Similarity: 0.55\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1791,7 +4489,7 @@ "\n", "Input: black metal side table\n", "\n", - "FLYJOE Narrow Side Table with PU Leather Magazine ... (https://www.amazon.com/dp/B0CHYDTQKN) - Similarity: 0.59\n" + "FLYJOE Narrow Side Table with PU Leather Magazine ... (https://www.amazon.com/dp/B0CHYDTQKN) - Similarity: 0.58\n" ] }, { @@ -1837,13 +4535,13 @@ "\n", "Input: doormat\n", "\n", - "Pickleball Doormat, Welcome Doormat Absorbent Non-... (https://www.amazon.com/dp/B0C1MRB2M8) - Similarity: 0.59\n" + "GXFC ZHAO Welcome Funny Door Mat Shoes and Bras Of... (https://www.amazon.com/dp/B07X61R7N8) - Similarity: 0.52\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1859,13 +4557,13 @@ "\n", "\n", "\n", - "Caroline's Treasures PPD3013JMAT Enchanted Garden ... (https://www.amazon.com/dp/B08Q5KDSQK) - Similarity: 0.57\n" + "Pickleball Doormat, Welcome Doormat Absorbent Non-... (https://www.amazon.com/dp/B0C1MRB2M8) - Similarity: 0.49\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1883,7 +4581,7 @@ "\n", "Input: step bookshelf\n", "\n", - "Leick Home 70007-WTGD Mixed Metal and Wood Stepped... (https://www.amazon.com/dp/B098KNRNLQ) - Similarity: 0.61\n" + "Leick Home 70007-WTGD Mixed Metal and Wood Stepped... (https://www.amazon.com/dp/B098KNRNLQ) - Similarity: 0.57\n" ] }, { @@ -1905,7 +4603,7 @@ "\n", "\n", "\n", - "Wildkin Kids Canvas Sling Bookshelf with Storage f... (https://www.amazon.com/dp/B07GBVFZ1Y) - Similarity: 0.47\n" + "Wildkin Kids Canvas Sling Bookshelf with Storage f... (https://www.amazon.com/dp/B07GBVFZ1Y) - Similarity: 0.46\n" ] }, { @@ -1929,13 +4627,13 @@ "\n", "Input: ottoman\n", "\n", - "HomePop Home Decor | K2380-YDQY-2 | Luxury Large F... (https://www.amazon.com/dp/B0B94T1TZ1) - Similarity: 0.53\n" + "Moroccan Leather Pouf Ottoman for Living Room - Ro... (https://www.amazon.com/dp/B0CP45784G) - Similarity: 0.49\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1951,13 +4649,13 @@ "\n", "\n", "\n", - "Moroccan Leather Pouf Ottoman for Living Room - Ro... (https://www.amazon.com/dp/B0CP45784G) - Similarity: 0.51\n" + "HomePop Home Decor | K2380-YDQY-2 | Luxury Large F... (https://www.amazon.com/dp/B0B94T1TZ1) - Similarity: 0.46\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2002,7 +4700,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 67, "id": "bdae7409", "metadata": {}, "outputs": [], @@ -2013,7 +4711,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 68, "id": "78845a30", "metadata": { "scrolled": false @@ -2043,13 +4741,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "Mimoglad Office Chair, High Back Ergonomic Desk Ch... (https://www.amazon.com/dp/B0C2YQZS69) - Similarity: 0.63\n" + "Black Leather Office Chair Mid Back Leather Desk C... (https://www.amazon.com/dp/B0BVQSPCCF) - Similarity: 0.54\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2085,13 +4783,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "CangLong Mid Century Modern Side Chair with Wood L... (https://www.amazon.com/dp/B08RTLBD1T) - Similarity: 0.51\n" + "subrtex Leather ding Room, Dining Chairs Set of 2,... (https://www.amazon.com/dp/B0B66QHB23) - Similarity: 0.52\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2127,7 +4825,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "MAEPA RV Shoe Storage for Bedside - 8 Extra Large ... (https://www.amazon.com/dp/B0C4PL1R3F) - Similarity: 0.61\n" + "MAEPA RV Shoe Storage for Bedside - 8 Extra Large ... (https://www.amazon.com/dp/B0C4PL1R3F) - Similarity: 0.65\n" ] }, { @@ -2169,7 +4867,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Chief Mfg.Swing-Arm Wall Mount Hardware Mount Blac... (https://www.amazon.com/dp/B007E40Z5K) - Similarity: 0.63\n" + "Chief Mfg.Swing-Arm Wall Mount Hardware Mount Blac... (https://www.amazon.com/dp/B007E40Z5K) - Similarity: 0.66\n" ] }, { @@ -2211,13 +4909,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "HomePop Home Decor | K2380-YDQY-2 | Luxury Large F... (https://www.amazon.com/dp/B0B94T1TZ1) - Similarity: 0.63\n" + "Homebeez 39.1\" Length Bedroom Storage Bench, End B... (https://www.amazon.com/dp/B0BWQ8M4Q3) - Similarity: 0.52\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2253,13 +4951,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "CangLong Mid Century Modern Side Chair with Wood L... (https://www.amazon.com/dp/B08RTLBD1T) - Similarity: 0.58\n" + "subrtex Leather ding Room, Dining Chairs Set of 2,... (https://www.amazon.com/dp/B0B66QHB23) - Similarity: 0.51\n" ] }, { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2295,7 +4993,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "LOVMOR 30'' Bathroom Vanity Sink Base Cabine, Stor... (https://www.amazon.com/dp/B0C9WYYFLB) - Similarity: 0.69\n" + "LOVMOR 30'' Bathroom Vanity Sink Base Cabine, Stor... (https://www.amazon.com/dp/B0C9WYYFLB) - Similarity: 0.58\n" ] }, { @@ -2337,7 +5035,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Folews Bathroom Organizer Over The Toilet Storage,... (https://www.amazon.com/dp/B09NZY3R1T) - Similarity: 0.82\n" + "Folews Bathroom Organizer Over The Toilet Storage,... (https://www.amazon.com/dp/B09NZY3R1T) - Similarity: 0.73\n" ] }, { @@ -2379,7 +5077,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me... (https://www.amazon.com/dp/B0CJHKVG6P) - Similarity: 0.69\n" + "GOYMFK 1pc Free Standing Shoe Rack, Multi-layer Me... (https://www.amazon.com/dp/B0CJHKVG6P) - Similarity: 0.72\n" ] }, { @@ -2421,7 +5119,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "subrtex Leather ding Room, Dining Chairs Set of 2,... (https://www.amazon.com/dp/B0B66QHB23) - Similarity: 0.87\n" + "subrtex Leather ding Room, Dining Chairs Set of 2,... (https://www.amazon.com/dp/B0B66QHB23) - Similarity: 0.77\n" ] }, { @@ -2463,7 +5161,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Plant Repotting Mat MUYETOL Waterproof Transplanti... (https://www.amazon.com/dp/B0BXRTWLYK) - Similarity: 0.69\n" + "Plant Repotting Mat MUYETOL Waterproof Transplanti... (https://www.amazon.com/dp/B0BXRTWLYK) - Similarity: 0.64\n" ] }, { @@ -2514,7 +5212,7 @@ "## Wrapping up\n", "\n", "\n", - "In this notebook, we explored how to leverage the multimodal capabilities of GPT-4V to tag and caption images. By providing images along with contextual information to the model, we were able to generate tags and descriptions that can be further refined using a language model like GPT-4-turbo to create captions. This process has practical applications in various scenarios, particularly in enhancing search functionalities.\n", + "In this notebook, we explored how to leverage the multimodal capabilities of `gpt-4o-mini` to tag and caption images. By providing images along with contextual information to the model, we were able to generate tags and descriptions that can be further refined to create captions. This process has practical applications in various scenarios, particularly in enhancing search functionalities.\n", "\n", "The search use case illustrated can be directly applied to applications such as recommendation systems, but the techniques covered in this notebook can be extended beyond items search and used in multiple use cases, for example RAG applications leveraging unstructured image data.\n", "\n", @@ -2538,7 +5236,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/batch_processing.ipynb b/examples/batch_processing.ipynb index 2fcf562c..69cf2b80 100644 --- a/examples/batch_processing.ipynb +++ b/examples/batch_processing.ipynb @@ -22,7 +22,7 @@ "\n", "This cookbook will walk you through how to use the Batch API with a couple of practical examples.\n", "\n", - "We will start with an example to categorize movies using `gpt-3.5-turbo`, and then cover how we can use the vision capabilities of `gpt-4-turbo` to caption images.\n", + "We will start with an example to categorize movies using `gpt-4o-mini`, and then cover how we can use the vision capabilities of this model to caption images.\n", "\n", "Please note that multiple models are available through the Batch API, and that you can use the same parameters in your Batch API calls as with the Chat Completions endpoint." ] @@ -77,7 +77,7 @@ "source": [ "## First example: Categorizing movies\n", "\n", - "In this example, we will use `gpt-3.5-turbo` to extract movie categories from a description of the movie. We will also extract a 1-sentence summary from this description. \n", + "In this example, we will use `gpt-4o-mini` to extract movie categories from a description of the movie. We will also extract a 1-sentence summary from this description. \n", "\n", "We will use [JSON mode](https://platform.openai.com/docs/guides/text-generation/json-mode) to extract categories as an array of strings and the 1-sentence summary in a structured format. \n", "\n", @@ -338,7 +338,7 @@ "\n", "def get_categories(description):\n", " response = client.chat.completions.create(\n", - " model=\"gpt-3.5-turbo\",\n", + " model=\"gpt-4o-mini\",\n", " temperature=0.1,\n", " # This is to enable JSON mode, making sure responses are valid json objects\n", " response_format={ \n", @@ -374,7 +374,7 @@ "\n", "RESULT: {\n", " \"categories\": [\"drama\"],\n", - " \"summary\": \"Two imprisoned men bond over the years and find redemption through acts of common decency.\"\n", + " \"summary\": \"Two imprisoned men develop a deep bond over the years, ultimately finding redemption through their shared acts of kindness.\"\n", "}\n", "\n", "\n", @@ -386,7 +386,7 @@ "\n", "RESULT: {\n", " \"categories\": [\"crime\", \"drama\"],\n", - " \"summary\": \"A crime drama about an aging patriarch passing on his empire to his son.\"\n", + " \"summary\": \"An aging crime lord hands over his empire to his hesitant son.\"\n", "}\n", "\n", "\n", @@ -397,8 +397,8 @@ "OVERVIEW: When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, Batman must accept one of the greatest psychological and physical tests of his ability to fight injustice.\n", "\n", "RESULT: {\n", - " \"categories\": [\"action\", \"thriller\"],\n", - " \"summary\": \"A thrilling action movie where Batman faces the chaotic Joker in a battle of justice.\"\n", + " \"categories\": [\"action\", \"thriller\", \"superhero\"],\n", + " \"summary\": \"Batman faces a formidable challenge as the Joker unleashes chaos on Gotham City.\"\n", "}\n", "\n", "\n", @@ -410,7 +410,7 @@ "\n", "RESULT: {\n", " \"categories\": [\"crime\", \"drama\"],\n", - " \"summary\": \"A portrayal of Vito Corleone's early life and career in 1920s New York City, as his son Michael expands the family crime syndicate.\"\n", + " \"summary\": \"The film depicts the early life of Vito Corleone and the rise of his son Michael within the family crime syndicate in 1920s New York City.\"\n", "}\n", "\n", "\n", @@ -421,8 +421,8 @@ "OVERVIEW: A jury holdout attempts to prevent a miscarriage of justice by forcing his colleagues to reconsider the evidence.\n", "\n", "RESULT: {\n", - " \"categories\": [\"drama\"],\n", - " \"summary\": \"A gripping drama about a jury holdout trying to prevent a miscarriage of justice by challenging his colleagues to reconsider the evidence.\"\n", + " \"categories\": [\"drama\", \"thriller\"],\n", + " \"summary\": \"A jury holdout fights to ensure justice is served by challenging his fellow jurors to reevaluate the evidence.\"\n", "}\n", "\n", "\n", @@ -489,7 +489,7 @@ " \"url\": \"/v1/chat/completions\",\n", " \"body\": {\n", " # This is what you would have in your Chat Completions API call\n", - " \"model\": \"gpt-3.5-turbo\",\n", + " \"model\": \"gpt-4o-mini\",\n", " \"temperature\": 0.1,\n", " \"response_format\": { \n", " \"type\": \"json_object\"\n", @@ -557,7 +557,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "FileObject(id='file-nG1JDPSMRMinN8FOdaL30kVD', bytes=1127310, created_at=1714045723, filename='batch_tasks_movies.jsonl', object='file', purpose='batch', status='processed', status_details=None)\n" + "FileObject(id='file-lx16f1KyIxQ2UHVvkG3HLfNR', bytes=1127310, created_at=1721144107, filename='batch_tasks_movies.jsonl', object='file', purpose='batch', status='processed', status_details=None)\n" ] } ], @@ -601,18 +601,10 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": null, "id": "6105d809", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Batch(id='batch_xU74ytOBYUpaUQE3Cwi8SCbA', completion_window='24h', created_at=1714049780, endpoint='/v1/chat/completions', input_file_id='file-6y0JPmkHU42qtaEK8x8ZYzkp', object='batch', status='completed', cancelled_at=None, cancelling_at=None, completed_at=1714049914, error_file_id=None, errors=None, expired_at=None, expires_at=1714136180, failed_at=None, finalizing_at=1714049896, in_progress_at=1714049821, metadata=None, output_file_id='file-XPfkEFZSaM4Avps7mcD3i8BY', request_counts=BatchRequestCounts(completed=312, failed=0, total=312))\n" - ] - } - ], + "outputs": [], "source": [ "batch_job = client.batches.retrieve(batch_job.id)\n", "print(batch_job)" @@ -787,7 +779,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 12, "id": "079d21e7", "metadata": {}, "outputs": [ @@ -1049,7 +1041,7 @@ "[5 rows x 25 columns]" ] }, - "execution_count": 17, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -1072,7 +1064,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 13, "id": "918fd79f", "metadata": {}, "outputs": [], @@ -1088,7 +1080,7 @@ "\n", "def get_caption(img_url, title):\n", " response = client.chat.completions.create(\n", - " model=\"gpt-4-turbo\",\n", + " model=\"gpt-4o-mini\",\n", " temperature=0.2,\n", " max_tokens=300,\n", " messages=[\n", @@ -1120,7 +1112,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 14, "id": "1daac93d", "metadata": {}, "outputs": [ @@ -1140,7 +1132,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "CAPTION: White multi-layer metal shoe rack featuring eight double hooks for hanging accessories, ideal for organizing footwear and small items in living spaces.\n", + "CAPTION: A stylish white free-standing shoe rack featuring multiple layers and eight double hooks, perfect for organizing shoes and accessories in living rooms, bathrooms, or hallways.\n", "\n", "\n" ] @@ -1161,7 +1153,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "CAPTION: A set of two elegant black leather dining chairs with a sleek design and vertical stitching detail on the backrest.\n", + "CAPTION: Set of 2 black leather dining chairs featuring a sleek design with vertical stitching and sturdy wooden legs.\n", "\n", "\n" ] @@ -1182,7 +1174,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "CAPTION: A green, waterproof, square, foldable repotting mat designed for indoor gardening, featuring raised edges and displayed with gardening tools and small potted plants.\n", + "CAPTION: The MUYETOL Plant Repotting Mat is a waterproof, portable, and foldable gardening work mat measuring 26.8\" x 26.8\", designed for easy soil changing and indoor transplanting.\n", "\n", "\n" ] @@ -1203,7 +1195,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "CAPTION: A brown, absorbent non-slip doormat featuring the phrase \"It's a good day to play PICKLEBALL\" with a pickleball paddle graphic, ideal for sports enthusiasts.\n", + "CAPTION: Absorbent non-slip doormat featuring the phrase \"It's a good day to play PICKLEBALL\" with paddle graphics, measuring 16x24 inches.\n", "\n", "\n" ] @@ -1224,7 +1216,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "CAPTION: Set of four foldable grey TV trays with a stand, featuring a sleek, space-saving design suitable for small areas.\n", + "CAPTION: Set of 4 foldable TV trays in grey, featuring a compact design with a stand for easy storage, perfect for small spaces.\n", "\n", "\n" ] @@ -1252,7 +1244,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 16, "id": "48e59bb1", "metadata": {}, "outputs": [], @@ -1272,7 +1264,7 @@ " \"url\": \"/v1/chat/completions\",\n", " \"body\": {\n", " # This is what you would have in your Chat Completions API call\n", - " \"model\": \"gpt-4-turbo\",\n", + " \"model\": \"gpt-4o-mini\",\n", " \"temperature\": 0.2,\n", " \"max_tokens\": 300,\n", " \"messages\": [\n", @@ -1304,7 +1296,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 17, "id": "e75193f2", "metadata": {}, "outputs": [], @@ -1320,7 +1312,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 18, "id": "f2bc166a", "metadata": {}, "outputs": [], @@ -1335,7 +1327,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 19, "id": "0d7d7ec9", "metadata": {}, "outputs": [], @@ -1351,20 +1343,12 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": null, "id": "53456a08", "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Batch(id='batch_xU74ytOBYUpaUQE3Cwi8SCbA', completion_window='24h', created_at=1714049780, endpoint='/v1/chat/completions', input_file_id='file-6y0JPmkHU42qtaEK8x8ZYzkp', object='batch', status='completed', cancelled_at=None, cancelling_at=None, completed_at=1714049914, error_file_id=None, errors=None, expired_at=None, expires_at=1714136180, failed_at=None, finalizing_at=1714049896, in_progress_at=1714049821, metadata=None, output_file_id='file-XPfkEFZSaM4Avps7mcD3i8BY', request_counts=BatchRequestCounts(completed=312, failed=0, total=312))\n" - ] - } - ], + "outputs": [], "source": [ "batch_job = client.batches.retrieve(batch_job.id)\n", "print(batch_job)" @@ -1559,7 +1543,7 @@ "source": [ "## Wrapping up\n", "\n", - "In this cookbook, we have seen two examples of how to use the new Batch API, but keep in mind that the Batch API works the same way as the Chat Completions endpoint, supporting the same parameters and most of the recent models (gpt-3.5-turbo, gpt-4, gpt-4-vision-preview, gpt-4-turbo...).\n", + "In this cookbook, we have seen two examples of how to use the new Batch API, but keep in mind that the Batch API works the same way as the Chat Completions endpoint, supporting the same parameters and most of the recent models (gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo...).\n", "\n", "By using this API, you can significantly reduce costs, so we recommend switching every workload that can happen async to a batch job with this new API." ] @@ -1581,7 +1565,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/gpt4o/introduction_to_gpt4o.ipynb b/examples/gpt4o/introduction_to_gpt4o.ipynb index c5dae8f7..6a16a8ee 100644 --- a/examples/gpt4o/introduction_to_gpt4o.ipynb +++ b/examples/gpt4o/introduction_to_gpt4o.ipynb @@ -4,14 +4,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Introduction to GPT-4o\n", - "GPT-4o (\"o\" for \"omni\") is designed to handle a combination of text, audio, and video inputs, and can generate outputs in text, audio, and image formats.\n", + "# Introduction to GPT-4o and GPT-4o mini\n", + "\n", + "GPT-4o (\"o\" for \"omni\") and GPT-4o mini are natively multimodal models designed to handle a combination of text, audio, and video inputs, and can generate outputs in text, audio, and image formats. GPT-4o mini is the lightweight version of GPT-4o.\n", "\n", "### Background\n", - "Before GPT-4o, users could interact with ChatGPT using Voice Mode, which operated with three separate models. GPT-4o will integrate these capabilities into a single model that's trained across text, vision, and audio. This unified approach ensures that all inputs—whether text, visual, or auditory—are processed cohesively by the same neural network.\n", + "\n", + "Before GPT-4o, users could interact with ChatGPT using Voice Mode, which operated with three separate models. GPT-4o integrates these capabilities into a single model that's trained across text, vision, and audio. This unified approach ensures that all inputs — whether text, visual, or auditory — are processed cohesively by the same neural network.\n", + "\n", + "GPT-4o mini is the next iteration of this omni model family, available in a smaller and cheaper version. This model offers higher accuracy than GPT-3.5 Turbo while being just as fast and supporting multimodal inputs and outputs.\n", "\n", "### Current API Capabilities\n", - "Currently, the API supports `{text, image}` inputs only, with `{text}` outputs, the same modalities as `gpt-4-turbo`. Additional modalities, including audio, will be introduced soon. This guide will help you get started with using GPT-4o for text, image, and video understanding.\n" + "\n", + "Currently, the API supports `{text, image}` inputs only, with `{text}` outputs, the same modalities as `gpt-4-turbo`.\n", + "\n", + "Additional modalities, including audio, will be introduced soon. This guide will help you get started with using GPT-4o mini for text, image, and video understanding." ] }, { @@ -35,7 +42,7 @@ "metadata": {}, "outputs": [], "source": [ - "%pip install --upgrade openai --quiet" + "%pip install --upgrade openai" ] }, { @@ -55,7 +62,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -63,24 +70,20 @@ "import os\n", "\n", "## Set the API key and model name\n", - "MODEL=\"gpt-4o\"\n", + "MODEL=\"gpt-4o-mini\"\n", "client = OpenAI(api_key=os.environ.get(\"OPENAI_API_KEY\", \"\"))" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Assistant: Of course! \n", - "\n", - "\\[ 2 + 2 = 4 \\]\n", - "\n", - "If you have any other questions, feel free to ask!\n" + "Assistant: Of course! \\( 2 + 2 = 4 \\).\n" ] } ], @@ -101,7 +104,7 @@ "metadata": {}, "source": [ "## Image Processing\n", - "GPT-4o can directly process images and take intelligent actions based on the image. We can provide images in two formats:\n", + "GPT-4o mini can directly process images and take intelligent actions based on the image. We can provide images in two formats:\n", "1. Base64 Encoded\n", "2. URL\n", "\n", @@ -110,7 +113,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -143,31 +146,43 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "To find the area of the triangle, we can use Heron's formula. First, we need to find the semi-perimeter of the triangle.\n", - "\n", - "The sides of the triangle are 6, 5, and 9.\n", - "\n", - "1. Calculate the semi-perimeter \\( s \\):\n", - "\\[ s = \\frac{a + b + c}{2} = \\frac{6 + 5 + 9}{2} = 10 \\]\n", - "\n", - "2. Use Heron's formula to find the area \\( A \\):\n", - "\\[ A = \\sqrt{s(s-a)(s-b)(s-c)} \\]\n", - "\n", - "Substitute the values:\n", - "\\[ A = \\sqrt{10(10-6)(10-5)(10-9)} \\]\n", - "\\[ A = \\sqrt{10 \\cdot 4 \\cdot 5 \\cdot 1} \\]\n", - "\\[ A = \\sqrt{200} \\]\n", - "\\[ A = 10\\sqrt{2} \\]\n", - "\n", - "So, the area of the triangle is \\( 10\\sqrt{2} \\) square units.\n" - ] + "data": { + "text/markdown": [ + "To find the area of the triangle, you can use the formula:\n", + "\n", + "\\[\n", + "\\text{Area} = \\frac{1}{2} \\times \\text{base} \\times \\text{height}\n", + "\\]\n", + "\n", + "In the triangle you provided:\n", + "\n", + "- The base is \\(9\\) (the length at the bottom).\n", + "- The height is \\(5\\) (the vertical line from the top vertex to the base).\n", + "\n", + "Now, plug in the values:\n", + "\n", + "\\[\n", + "\\text{Area} = \\frac{1}{2} \\times 9 \\times 5\n", + "\\]\n", + "\n", + "Calculating this gives:\n", + "\n", + "\\[\n", + "\\text{Area} = \\frac{1}{2} \\times 45 = 22.5\n", + "\\]\n", + "\n", + "So, the area of the triangle is **22.5 square units**." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -192,7 +207,7 @@ " temperature=0.0,\n", ")\n", "\n", - "print(response.choices[0].message.content)" + "display(Markdown(response.choices[0].message.content))" ] }, { @@ -204,36 +219,37 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 5, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "To find the area of the triangle, we can use Heron's formula. Heron's formula states that the area of a triangle with sides of length \\(a\\), \\(b\\), and \\(c\\) is:\n", - "\n", - "\\[ \\text{Area} = \\sqrt{s(s-a)(s-b)(s-c)} \\]\n", - "\n", - "where \\(s\\) is the semi-perimeter of the triangle:\n", - "\n", - "\\[ s = \\frac{a + b + c}{2} \\]\n", - "\n", - "For the given triangle, the side lengths are \\(a = 5\\), \\(b = 6\\), and \\(c = 9\\).\n", - "\n", - "First, calculate the semi-perimeter \\(s\\):\n", - "\n", - "\\[ s = \\frac{5 + 6 + 9}{2} = \\frac{20}{2} = 10 \\]\n", - "\n", - "Now, apply Heron's formula:\n", - "\n", - "\\[ \\text{Area} = \\sqrt{10(10-5)(10-6)(10-9)} \\]\n", - "\\[ \\text{Area} = \\sqrt{10 \\cdot 5 \\cdot 4 \\cdot 1} \\]\n", - "\\[ \\text{Area} = \\sqrt{200} \\]\n", - "\\[ \\text{Area} = 10\\sqrt{2} \\]\n", - "\n", - "So, the area of the triangle is \\(10\\sqrt{2}\\) square units.\n" - ] + "data": { + "text/markdown": [ + "It seems there was an error processing the image, so I can't see the triangle or its dimensions. However, I can help you calculate the area of a triangle if you provide the base and height or the lengths of the sides.\n", + "\n", + "The area \\( A \\) of a triangle can be calculated using the formula:\n", + "\n", + "1. **Using base and height**:\n", + " \\[\n", + " A = \\frac{1}{2} \\times \\text{base} \\times \\text{height}\n", + " \\]\n", + "\n", + "2. **Using Heron's formula** (if you know the lengths of all three sides \\( a, b, c \\)):\n", + " \\[\n", + " s = \\frac{a + b + c}{2} \\quad \\text{(semi-perimeter)}\n", + " \\]\n", + " \\[\n", + " A = \\sqrt{s(s-a)(s-b)(s-c)}\n", + " \\]\n", + "\n", + "Please provide the necessary dimensions, and I'll help you calculate the area!" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -251,7 +267,7 @@ " temperature=0.0,\n", ")\n", "\n", - "print(response.choices[0].message.content)" + "display(Markdown(response.choices[0].message.content))" ] }, { @@ -259,9 +275,9 @@ "metadata": {}, "source": [ "## Video Processing\n", - "While it's not possible to directly send a video to the API, GPT-4o can understand videos if you sample frames and then provide them as images. It performs better at this task than GPT-4 Turbo.\n", + "While it's not possible to directly send a video to the API, GPT-4o can understand videos if you sample frames and then provide them as images. \n", "\n", - "Since GPT-4o in the API does not yet support audio-in (as of May 2024), we'll use a combination of GPT-4o and Whisper to process both the audio and visual for a provided video, and showcase two usecases:\n", + "Since GPT-4o mini in the API does not yet support audio-in (as of July 2024), we'll use a combination of GPT-4o mini and Whisper to process both the audio and visual for a provided video, and showcase two usecases:\n", "1. Summarization\n", "2. Question and Answering\n", "\n" @@ -283,8 +299,8 @@ "metadata": {}, "outputs": [], "source": [ - "%pip install opencv-python --quiet\n", - "%pip install moviepy --quiet" + "%pip install opencv-python\n", + "%pip install moviepy" ] }, { @@ -296,7 +312,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -311,7 +327,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -384,7 +400,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -406,7 +422,7 @@ "text/html": [ "\n", " \n", " " @@ -415,7 +431,7 @@ "" ] }, - "execution_count": 11, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -447,49 +463,54 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "## Video Summary: OpenAI DevDay Keynote Recap\n", - "\n", - "The video appears to be a keynote recap from OpenAI's DevDay event. Here are the key points covered in the video:\n", - "\n", - "1. **Introduction and Event Overview**:\n", - " - The video starts with the title \"OpenAI DevDay\" and transitions to \"Keynote Recap.\"\n", - " - The event venue is shown, with attendees gathering and the stage set up.\n", - "\n", - "2. **Keynote Presentation**:\n", - " - A speaker, presumably from OpenAI, takes the stage to present.\n", - " - The presentation covers various topics related to OpenAI's latest developments and announcements.\n", - "\n", - "3. **Announcements**:\n", - " - **GPT-4 Turbo**: Introduction of GPT-4 Turbo, highlighting its enhanced capabilities and performance.\n", - " - **JSON Mode**: A new feature that allows for structured data output in JSON format.\n", - " - **Function Calling**: Demonstration of improved function calling capabilities, making interactions more efficient.\n", - " - **Context Length and Control**: Enhancements in context length and user control over the model's responses.\n", - " - **Better Knowledge Integration**: Improvements in the model's knowledge base and retrieval capabilities.\n", - "\n", - "4. **Product Demonstrations**:\n", - " - **DALL-E 3**: Introduction of DALL-E 3 for advanced image generation.\n", - " - **Custom Models**: Announcement of custom models, allowing users to tailor models to specific needs.\n", - " - **API Enhancements**: Updates to the API, including threading, retrieval, and code interpreter functionalities.\n", - "\n", - "5. **Pricing and Token Efficiency**:\n", - " - Discussion on GPT-4 Turbo pricing, emphasizing cost efficiency with reduced input and output tokens.\n", - "\n", - "6. **New Features and Tools**:\n", - " - Introduction of new tools and features for developers, including a variety of GPT-powered applications.\n", - " - Emphasis on building with natural language and the ease of creating custom applications.\n", - "\n", - "7. **Closing Remarks**:\n", - " - The speaker concludes the presentation, thanking the audience and highlighting the future of OpenAI's developments.\n", - "\n", - "The video ends with the OpenAI logo and the event title \"OpenAI DevDay.\"\n" - ] + "data": { + "text/markdown": [ + "# OpenAI Dev Day Summary\n", + "\n", + "## Overview\n", + "The video captures highlights from OpenAI's Dev Day, showcasing new advancements and features in AI technology, particularly focusing on the latest updates to their models and tools.\n", + "\n", + "## Key Highlights\n", + "\n", + "### Event Introduction\n", + "- The event is branded as \"OpenAI Dev Day,\" setting the stage for discussions on AI advancements.\n", + "\n", + "### Keynote Recap\n", + "- The keynote features a recap of significant updates and innovations in OpenAI's offerings.\n", + "\n", + "### New Features and Models\n", + "- Introduction of **GPT-4 Turbo** and **DALL-E 3**, emphasizing improvements in performance and capabilities.\n", + "- Discussion on **JSON Mode** and **Function Calling**, showcasing how these features enhance user interaction with AI.\n", + "\n", + "### Enhanced User Experience\n", + "- Presentation of new functionalities that allow for better control and expanded knowledge in AI interactions.\n", + "- Emphasis on **context length** and **more control** over AI responses.\n", + "\n", + "### Pricing and Efficiency\n", + "- Announcement of pricing structures for GPT-4 Turbo, highlighting cost-effectiveness with reduced token usage.\n", + "\n", + "### Custom Models\n", + "- Introduction of custom models that allow developers to tailor AI functionalities to specific needs.\n", + "\n", + "### Community Engagement\n", + "- Encouragement for developers to build applications using natural language, fostering a collaborative environment.\n", + "\n", + "### Closing Remarks\n", + "- The event concludes with a call to action for developers to engage with OpenAI's tools and contribute to the AI ecosystem.\n", + "\n", + "## Conclusion\n", + "OpenAI Dev Day serves as a platform for unveiling new technologies and fostering community engagement, aiming to empower developers with advanced AI tools and capabilities." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -506,7 +527,7 @@ " ],\n", " temperature=0,\n", ")\n", - "print(response.choices[0].message.content)" + "display(Markdown(response.choices[0].message.content))" ] }, { @@ -523,27 +544,57 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 11, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "### Summary\n", - "\n", - "Welcome to OpenAI's first-ever Dev Day. Key announcements include:\n", - "\n", - "- **GPT-4 Turbo**: A new model supporting up to 128,000 tokens of context, featuring JSON mode for valid JSON responses, improved instruction following, and better knowledge retrieval from external documents or databases. It is also significantly cheaper than GPT-4.\n", - "- **New Features**: \n", - " - **Dolly 3**, **GPT-4 Turbo with Vision**, and a new **Text-to-Speech model** are now available in the API.\n", - " - **Custom Models**: A program where OpenAI researchers help companies create custom models tailored to their specific use cases.\n", - " - **Increased Rate Limits**: Doubling tokens per minute for established GPT-4 customers and allowing requests for further rate limit changes.\n", - "- **GPTs**: Tailored versions of ChatGPT for specific purposes, programmable through conversation, with options for private or public sharing, and a forthcoming GPT Store.\n", - "- **Assistance API**: Includes persistent threads, built-in retrieval, a code interpreter, and improved function calling.\n", - "\n", - "OpenAI is excited about the future of AI integration and looks forward to seeing what users will create with these new tools. The event concludes with an invitation to return next year for more advancements.\n" - ] + "data": { + "text/markdown": [ + "# OpenAI Dev Day Summary\n", + "\n", + "Welcome to the inaugural OpenAI Dev Day, where several exciting updates and features were announced:\n", + "\n", + "## Key Announcements\n", + "\n", + "- **Launch of GPT-4 Turbo**: \n", + " - Supports up to **128,000 tokens** of context.\n", + " - Introduces **JSON mode** for valid JSON responses.\n", + " - Improved function calling capabilities.\n", + "\n", + "- **Knowledge Retrieval**: \n", + " - New feature allowing models to access external documents and databases for enhanced knowledge.\n", + "\n", + "- **Dolly 3 and Vision Models**: \n", + " - Integration of Dolly 3, GPT-4 Turbo with Vision, and a new Text-to-Speech model into the API.\n", + "\n", + "- **Custom Models Program**: \n", + " - Collaboration with companies to create tailored models for specific use cases.\n", + "\n", + "- **Increased Rate Limits**: \n", + " - Doubling of tokens per minute for established GPT-4 customers, with options for further adjustments in API settings.\n", + "\n", + "- **Cost Efficiency**: \n", + " - GPT-4 Turbo is **3x cheaper** for prompt tokens and **2x cheaper** for completion tokens compared to GPT-4.\n", + "\n", + "- **Introduction of GPTs**: \n", + " - Tailored versions of ChatGPT for specific purposes, allowing users to create private or public GPTs easily through conversation.\n", + "\n", + "- **Upcoming GPT Store**: \n", + " - Launching later this month for sharing GPT creations.\n", + "\n", + "- **Assistance API Enhancements**: \n", + " - Features include persistent threads, built-in retrieval, a code interpreter, and improved function calling.\n", + "\n", + "## Conclusion\n", + "\n", + "OpenAI is excited about the future of AI integration and the potential for users to leverage these new tools. The team looks forward to seeing the innovative applications that will emerge from these advancements. Thank you for participating in this event!" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -566,7 +617,7 @@ " ],\n", " temperature=0,\n", ")\n", - "print(response.choices[0].message.content)" + "display(Markdown(response.choices[0].message.content))" ] }, { @@ -581,64 +632,55 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 12, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "## Video Summary: OpenAI Dev Day\n", - "\n", - "### Introduction\n", - "- The video begins with the title \"OpenAI Dev Day\" and transitions to a keynote recap.\n", - "\n", - "### Event Overview\n", - "- The event is held at a venue with a sign reading \"OpenAI Dev Day.\"\n", - "- Attendees are seen entering and gathering in a large hall.\n", - "\n", - "### Keynote Presentation\n", - "- The keynote speaker introduces the event and announces the launch of GPT-4 Turbo.\n", - "- **GPT-4 Turbo**:\n", - " - Supports up to 128,000 tokens of context.\n", - " - Introduces a new feature called JSON mode for valid JSON responses.\n", - " - Improved function calling capabilities.\n", - " - Enhanced instruction-following and knowledge retrieval from external documents or databases.\n", - " - Knowledge updated up to April 2023.\n", - " - Available in the API along with DALL-E 3, GPT-4 Turbo with Vision, and a new Text-to-Speech model.\n", - "\n", - "### Custom Models\n", - "- Launch of a new program called Custom Models.\n", - " - Researchers will collaborate with companies to create custom models tailored to specific use cases.\n", - " - Higher rate limits and the ability to request changes to rate limits and quotas directly in API settings.\n", - "\n", - "### Pricing and Performance\n", - "- **GPT-4 Turbo**:\n", - " - 3x cheaper for prompt tokens and 2x cheaper for completion tokens compared to GPT-4.\n", - " - Doubling the tokens per minute for established GPT-4 customers.\n", - "\n", - "### Introduction of GPTs\n", - "- **GPTs**:\n", - " - Tailored versions of ChatGPT for specific purposes.\n", - " - Combine instructions, expanded knowledge, and actions for better performance and control.\n", - " - Can be created without coding, through conversation.\n", - " - Options to make GPTs private, share publicly, or create for company use in ChatGPT Enterprise.\n", - " - Announcement of the upcoming GPT Store.\n", - "\n", - "### Assistance API\n", - "- **Assistance API**:\n", - " - Includes persistent threads for handling long conversation history.\n", - " - Built-in retrieval and code interpreter with a working Python interpreter in a sandbox environment.\n", - " - Improved function calling.\n", - "\n", - "### Conclusion\n", - "- The speaker emphasizes the potential of integrating intelligence everywhere, providing \"superpowers on demand.\"\n", - "- Encourages attendees to return next year, hinting at even more advanced developments.\n", - "- The event concludes with thanks to the attendees.\n", - "\n", - "### Closing\n", - "- The video ends with the OpenAI logo and a final thank you message.\n" - ] + "data": { + "text/markdown": [ + "# OpenAI Dev Day Summary\n", + "\n", + "## Overview\n", + "The first-ever OpenAI Dev Day introduced several exciting updates and features, primarily focusing on the launch of **GPT-4 Turbo**. This new model enhances capabilities and expands the potential for developers.\n", + "\n", + "## Key Announcements\n", + "\n", + "### 1. **GPT-4 Turbo**\n", + "- Supports up to **128,000 tokens** of context.\n", + "- Offers improved performance in following instructions and handling multiple function calls.\n", + "\n", + "### 2. **JSON Mode**\n", + "- A new feature that ensures responses are formatted in valid JSON, enhancing data handling.\n", + "\n", + "### 3. **Retrieval Feature**\n", + "- Allows models to access external knowledge from documents or databases, improving the accuracy and relevance of responses.\n", + "\n", + "### 4. **DALL·E 3 and Vision Capabilities**\n", + "- Introduction of **DALL·E 3**, **GPT-4 Turbo with Vision**, and a new **Text-to-Speech** model, all available in the API.\n", + "\n", + "### 5. **Custom Models Program**\n", + "- A new initiative where OpenAI researchers collaborate with companies to create tailored models for specific use cases.\n", + "\n", + "### 6. **Rate Limits and Pricing**\n", + "- Doubling of tokens per minute for established GPT-4 customers.\n", + "- **GPT-4 Turbo** is significantly cheaper, with a **3x reduction** in prompt tokens and **2x reduction** in completion tokens.\n", + "\n", + "### 7. **Introduction of GPTs**\n", + "- Tailored versions of ChatGPT designed for specific purposes, combining instructions, expanded knowledge, and actions.\n", + "- Users can create private or public GPTs without needing coding skills.\n", + "\n", + "### 8. **Assistance API**\n", + "- Features persistent threads, built-in retrieval, a code interpreter, and improved function calling, making it easier for developers to manage conversations and data.\n", + "\n", + "## Conclusion\n", + "The event highlighted OpenAI's commitment to enhancing AI capabilities and accessibility for developers. The advancements presented are expected to empower users to create innovative applications and solutions. OpenAI looks forward to future developments and encourages ongoing collaboration with the developer community." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -657,7 +699,7 @@ "],\n", " temperature=0,\n", ")\n", - "print(response.choices[0].message.content)" + "display(Markdown(response.choices[0].message.content))" ] }, { @@ -675,7 +717,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -684,16 +726,20 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 14, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Visual QA: \n", - "Sam Altman used the example about raising windows and turning the radio on to demonstrate the function calling capability of GPT-4 Turbo. The example illustrated how the model can interpret and execute multiple commands in a more structured and efficient manner. The \"before\" and \"after\" comparison showed how the model can now directly call functions like `raise_windows()` and `radio_on()` based on natural language instructions, showcasing improved control and functionality.\n" - ] + "data": { + "text/markdown": [ + "Visual QA:Sam Altman used the example of raising windows and turning the radio on to illustrate the concept of function calling in AI. This example demonstrates how AI can interpret natural language commands and translate them into specific functions or actions, making interactions more intuitive and user-friendly. By showing a relatable scenario, he highlighted the advancements in AI's ability to understand and execute complex instructions seamlessly." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -710,21 +756,26 @@ " ],\n", " temperature=0,\n", ")\n", - "print(\"Visual QA:\\n\" + qa_visual_response.choices[0].message.content)" + "display(Markdown(\"Visual QA:\" + qa_visual_response.choices[0].message.content))" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 15, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Audio QA:\n", - "The provided transcription does not include any mention of Sam Altman or an example about raising windows and turning the radio on. Therefore, I cannot provide an answer based on the given transcription.\n" - ] + "data": { + "text/markdown": [ + "Audio QA:\n", + "The transcription provided does not include any mention of Sam Altman discussing raising windows or turning the radio on. Therefore, I cannot provide an answer to that specific question based on the given transcription. If you have more context or another transcription that includes that example, please share it, and I would be happy to help!" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -736,21 +787,26 @@ " ],\n", " temperature=0,\n", ")\n", - "print(\"Audio QA:\\n\" + qa_audio_response.choices[0].message.content)" + "display(Markdown(\"Audio QA:\\n\" + qa_audio_response.choices[0].message.content))" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 16, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Both QA:\n", - "Sam Altman used the example of raising windows and turning the radio on to demonstrate the improved function calling capabilities of GPT-4 Turbo. The example illustrated how the model can now handle multiple function calls more effectively and follow instructions better. In the \"before\" scenario, the model had to be prompted separately for each action, whereas in the \"after\" scenario, the model could handle both actions in a single prompt, showcasing its enhanced ability to manage and execute multiple tasks simultaneously.\n" - ] + "data": { + "text/markdown": [ + "Both QA:\n", + "Sam Altman used the example of raising windows and turning the radio on to illustrate the new function calling feature in the GPT-4 Turbo model. This example demonstrates how the model can interpret natural language commands and translate them into specific function calls, making it easier for users to interact with the system in a more intuitive way. It highlights the model's ability to understand context and execute multiple actions based on user instructions." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -769,7 +825,7 @@ " ],\n", " temperature=0,\n", ")\n", - "print(\"Both QA:\\n\" + qa_both_response.choices[0].message.content)" + "display(Markdown(\"Both QA:\\n\" + qa_both_response.choices[0].message.content))" ] }, { @@ -779,15 +835,16 @@ "Comparing the three answers, the most accurate answer is generated by using both the audio and visual from the video. Sam Altman did not discuss the raising windows or radio on during the Keynote, but referenced an improved capability for the model to execute multiple functions in a single request while the examples were shown behind him.\n", "\n", "## Conclusion\n", + "\n", "Integrating many input modalities such as audio, visual, and textual, significantly enhances the performance of the model on a diverse range of tasks. This multimodal approach allows for more comprehensive understanding and interaction, mirroring more closely how humans perceive and process information. \n", "\n", - "Currently, GPT-4o in the API supports text and image inputs, with audio capabilities coming soon." + "Currently, GPT-4o and GPT-4o mini in the API support text and image inputs, with audio capabilities coming soon." ] } ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -801,7 +858,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/registry.yaml b/registry.yaml index 9fe9652d..982e9c93 100644 --- a/registry.yaml +++ b/registry.yaml @@ -1214,9 +1214,9 @@ tags: - guardrails -- title: How to combine GPT4 with Vision with RAG to create a clothing matchmaker app +- title: How to combine GPT4o mini with RAG to create a clothing matchmaker app path: examples/How_to_combine_GPT4o_with_RAG_Outfit_Assistant.ipynb - date: 2024-02-16 + date: 2024-07-18 authors: - teomusatoiu tags: @@ -1234,9 +1234,9 @@ - embeddings -- title: Using GPT4 with Vision to tag and caption images +- title: Using GPT4o mini to tag and caption images path: examples/Tag_caption_images_with_GPT4V.ipynb - date: 2024-02-28 + date: 2024-07-18 authors: - katiagg tags: @@ -1306,9 +1306,9 @@ - completions - functions -- title: Introduction to gpt-4o +- title: Introduction to GPT-4o and GPT-4o mini path: examples/gpt4o/introduction_to_gpt4o.ipynb - date: 2024-05-13 + date: 2024-07-18 authors: - justonf tags: