demo-python/code/conference-demos/ignite-2024/azure-ai-search-multimodal-build-demo.ipynb (896 lines of code) (raw):

{ "cells": [ { "cell_type": "markdown", "metadata": { "redirect_from": ["https://github.com/azure/azure-search-vector-samples/blob/main/demo-python/code/e2e-demos/azure-ai-search-multimodal-build-demo.ipynb"] }, "source": [ "# Azure AI Search Multimodal Retrieval Demo\n", "\n", "## Introduction\n", "In this demo, we will show you how to create a multimodal (text + images) vector index in Azure AI Search.\n", "\n", "**This unofficial code sample was created for an Ignite 2024 demo. It's offered \"as-is\" and might not work for all customers and all scenarios.**\n", "\n", "## Prerequisites\n", "- 🐍 Python 3.9 or higher\n", "- ☁️ Azure Blob Storage\n", "- 🔗 Azure AI Vision Service or Azure AI Multi-Service Account\n", "- 🔗 Azure AI Search Service\n", "\n", "## Features Covered\n", "This demo covers the following features:\n", "- ✅ Stored=False\n", "- ✅ Scalar Quantization to int8\n", "- ✅ Reranking w/full precision vectors\n", "- ✅ Oversampling\n", "- ✅ Integrated Vectorization\n", "- ✅ Multi-Vector Search\n", "- ✅ Generate Dense Captions with AI Vision Image Analysis API\n", "- ✅ **[NEW]** Azure AI Vision Embedding Skill\n", "- ✅ **[NEW]** Azure AI Vision Vectorizer\n", "- ✅ **[NEW]** Azure AI Vision Latest Multilingual Model\n", "- ✅ **[NEW]** Vector Weighting\n", "\n", "Let's get started!" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "! pip install azure-search-documents --pre --quiet\n", "! pip install openai python-dotenv azure-identity cohere azure-ai-vision-imageanalysis --quiet" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generate JSON with text and images via Azure AI Vision Studio\n", "https://portal.vision.cognitive.azure.com/demo/image-captioning" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "import json\n", "import os\n", "from uuid import uuid4\n", "\n", "from azure.ai.vision.imageanalysis import ImageAnalysisClient\n", "from azure.ai.vision.imageanalysis.models import VisualFeatures\n", "from azure.core.credentials import AzureKeyCredential\n", "from azure.storage.blob import BlobServiceClient\n", "\n", "# Get environment variables for Azure AI Vision\n", "try:\n", " endpoint = os.getenv(\"AZURE_AI_VISION_ENDPOINT\")\n", " key = os.getenv(\"AZURE_AI_VISION_API_KEY\")\n", " connection_string = os.getenv(\"BLOB_CONNECTION_STRING\")\n", " # container_name = os.getenv(\"BLOB_CONTAINER_NAME\")\n", " container_name = \"vector-sandbox\"\n", "except KeyError as e:\n", " print(f\"Missing environment variable: {str(e)}\")\n", " print(\"Set them before running this sample.\")\n", " exit()\n", "\n", "# Create an Image Analysis client\n", "client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key))\n", "\n", "# Setup for Azure Blob Storage\n", "blob_service_client = BlobServiceClient.from_connection_string(connection_string)\n", "container_client = blob_service_client.get_container_client(container_name)\n", "\n", "def get_caption(image_url):\n", " \"\"\"\n", " Get a caption for the image using Azure AI Vision.\n", " \"\"\"\n", " try:\n", " result = client.analyze_from_url(\n", " image_url=image_url,\n", " visual_features=[VisualFeatures.CAPTION, VisualFeatures.READ],\n", " gender_neutral_caption=False\n", " )\n", " if result.caption is not None:\n", " return result.caption.text\n", " else:\n", " return \"No caption available\"\n", " except Exception as e:\n", " print(f\"An error occurred: {e}\")\n", " return \"Error generating caption\"\n", "\n", "def generate_json_objects():\n", " json_objects = []\n", "\n", " # Iterate over the blobs in the container\n", " for blob in container_client.list_blobs():\n", " image_url = f\"https://{blob_service_client.account_name}.blob.core.windows.net/{container_name}/{blob.name}\"\n", " caption = get_caption(image_url)\n", "\n", " json_object = {\"id\": str(uuid4()), \"imageUrl\": image_url, \"caption\": caption}\n", " json_objects.append(json_object)\n", "\n", " return json_objects\n", "\n", "def write_to_file(json_objects):\n", " # Write the updated JSON to a file\n", " with open(\"build-demo.json\", \"w\") as json_file:\n", " json.dump(json_objects, json_file, indent=4)\n", "\n", "json_objects = generate_json_objects()\n", "write_to_file(json_objects)" ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [], "source": [ "import os\n", "\n", "from azure.core.credentials import AzureKeyCredential\n", "from azure.identity import DefaultAzureCredential, get_bearer_token_provider\n", "from azure.search.documents import SearchClient\n", "from azure.search.documents.indexes import SearchIndexClient, SearchIndexerClient\n", "from azure.search.documents.indexes.models import (\n", " AIServicesVisionParameters,\n", " AIServicesVisionVectorizer,\n", " AIStudioModelCatalogName,\n", " AzureMachineLearningVectorizer,\n", " AzureOpenAIVectorizer,\n", " AzureOpenAIModelName,\n", " AzureOpenAIParameters,\n", " BlobIndexerDataToExtract,\n", " BlobIndexerParsingMode,\n", " CognitiveServicesAccountKey,\n", " DefaultCognitiveServicesAccount,\n", " ExhaustiveKnnAlgorithmConfiguration,\n", " ExhaustiveKnnParameters,\n", " FieldMapping,\n", " HnswAlgorithmConfiguration,\n", " HnswParameters,\n", " IndexerExecutionStatus,\n", " IndexingParameters,\n", " IndexingParametersConfiguration,\n", " InputFieldMappingEntry,\n", " OutputFieldMappingEntry,\n", " ScalarQuantizationCompressionConfiguration,\n", " ScalarQuantizationParameters,\n", " SearchField,\n", " SearchFieldDataType,\n", " SearchIndex,\n", " SearchIndexer,\n", " SearchIndexerDataContainer,\n", " SearchIndexerDataIdentity,\n", " SearchIndexerDataSourceConnection,\n", " SearchIndexerSkillset,\n", " SemanticConfiguration,\n", " SemanticField,\n", " SemanticPrioritizedFields,\n", " SemanticSearch,\n", " SimpleField,\n", " VectorSearch,\n", " VectorSearchAlgorithmKind,\n", " VectorSearchAlgorithmMetric,\n", " VectorSearchProfile,\n", " VisionVectorizeSkill\n", ")\n", "from azure.search.documents.models import (\n", " HybridCountAndFacetMode,\n", " HybridSearch,\n", " SearchScoreThreshold,\n", " VectorizableTextQuery,\n", " VectorizableImageBinaryQuery,\n", " VectorizableImageUrlQuery,\n", " VectorSimilarityThreshold,\n", ")\n", "from azure.storage.blob import BlobServiceClient\n", "from dotenv import load_dotenv\n", "from IPython.display import Image, display, HTML\n", "from openai import AzureOpenAI" ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [], "source": [ "# Load environment variables\n", "load_dotenv()\n", "\n", "# Configuration\n", "AZURE_AI_VISION_API_KEY = os.getenv(\"AZURE_AI_VISION_API_KEY\")\n", "AZURE_AI_VISION_ENDPOINT = os.getenv(\"AZURE_AI_VISION_ENDPOINT\")\n", "AZURE_OPENAI_ENDPOINT = os.getenv(\"AZURE_OPENAI_ENDPOINT\")\n", "BLOB_CONNECTION_STRING = os.getenv(\"BLOB_CONNECTION_STRING\")\n", "BLOB_CONTAINER_NAME = os.getenv(\"BLOB_CONTAINER_NAME\")\n", "INDEX_NAME = \"build-multimodal-demo\"\n", "SEARCH_SERVICE_API_KEY = os.getenv(\"AZURE_SEARCH_ADMIN_KEY\")\n", "SEARCH_SERVICE_ENDPOINT = os.getenv(\"AZURE_SEARCH_SERVICE_ENDPOINT\")" ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using AAD for authentication.\n" ] } ], "source": [ "# User-specified parameter\n", "USE_AAD_FOR_SEARCH = True # Set this to False to use API key for authentication\n", "\n", "def authenticate_azure_search(api_key=None, use_aad_for_search=False):\n", " if use_aad_for_search:\n", " print(\"Using AAD for authentication.\")\n", " credential = DefaultAzureCredential()\n", " else:\n", " print(\"Using API keys for authentication.\")\n", " if api_key is None:\n", " raise ValueError(\"API key must be provided if not using AAD for authentication.\")\n", " credential = AzureKeyCredential(api_key)\n", " return credential\n", "\n", "azure_search_credential = authenticate_azure_search(api_key=SEARCH_SERVICE_API_KEY, use_aad_for_search=USE_AAD_FOR_SEARCH)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a blob data source connector on Azure AI Search" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Data source 'build-multimodal-demo-blob' created or updated successfully.\n" ] } ], "source": [ "def create_or_update_data_source(indexer_client, container_name, connection_string, index_name):\n", " \"\"\"\n", " Create or update a data source connection for Azure AI Search.\n", " \"\"\"\n", " container = SearchIndexerDataContainer(name=container_name)\n", " data_source_connection = SearchIndexerDataSourceConnection(\n", " name=f\"{index_name}-blob\",\n", " type=\"azureblob\",\n", " connection_string=connection_string,\n", " container=container\n", " )\n", " try:\n", " indexer_client.create_or_update_data_source_connection(data_source_connection)\n", " print(f\"Data source '{index_name}-blob' created or updated successfully.\")\n", " except Exception as e:\n", " raise Exception(f\"Failed to create or update data source due to error: {e}\")\n", "\n", "# Create a SearchIndexerClient instance\n", "indexer_client = SearchIndexerClient(SEARCH_SERVICE_ENDPOINT, azure_search_credential)\n", "\n", "# Call the function to create or update the data source\n", "create_or_update_data_source(indexer_client, BLOB_CONTAINER_NAME, BLOB_CONNECTION_STRING, INDEX_NAME)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a search index" ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created index: build-multimodal-demo\n" ] } ], "source": [ "def create_fields():\n", " \"\"\"Creates the fields for the search index based on the specified schema.\"\"\"\n", " return [\n", " SimpleField(\n", " name=\"id\", type=SearchFieldDataType.String, key=True, filterable=True\n", " ),\n", " SearchField(name=\"caption\", type=SearchFieldDataType.String, searchable=True),\n", " SearchField(name=\"imageUrl\", type=SearchFieldDataType.String, searchable=True),\n", " SearchField(\n", " name=\"captionVector\",\n", " type=SearchFieldDataType.Collection(SearchFieldDataType.Single),\n", " vector_search_dimensions=1024,\n", " vector_search_profile_name=\"myHnswProfile\",\n", " stored=False,\n", " ),\n", " SearchField(\n", " name=\"imageVector\",\n", " type=SearchFieldDataType.Collection(SearchFieldDataType.Single),\n", " vector_search_dimensions=1024,\n", " vector_search_profile_name=\"myHnswProfile\",\n", " stored=False,\n", " ),\n", " ]\n", "\n", "\n", "def create_vector_search_configuration():\n", " \"\"\"Creates the vector search configuration.\"\"\"\n", " return VectorSearch(\n", " algorithms=[\n", " HnswAlgorithmConfiguration(\n", " name=\"myHnsw\",\n", " parameters=HnswParameters(\n", " m=4,\n", " ef_construction=400,\n", " ef_search=500,\n", " metric=VectorSearchAlgorithmMetric.COSINE,\n", " ),\n", " )\n", " ],\n", " compressions=[\n", " ScalarQuantizationCompressionConfiguration(\n", " name=\"myScalarQuantization\",\n", " rerank_with_original_vectors=True,\n", " default_oversampling=10,\n", " parameters=ScalarQuantizationParameters(quantized_data_type=\"int8\"),\n", " )\n", " ],\n", " vectorizers=[\n", " AIServicesVisionVectorizer(\n", " name=\"myAIServicesVectorizer\",\n", " kind=\"aiServicesVision\",\n", " ai_services_vision_parameters=AIServicesVisionParameters(\n", " model_version=\"2023-04-15\",\n", " resource_uri=AZURE_AI_VISION_ENDPOINT,\n", " api_key=AZURE_AI_VISION_API_KEY,\n", " ),\n", " )\n", " ],\n", " profiles=[\n", " VectorSearchProfile(\n", " name=\"myHnswProfile\",\n", " algorithm_configuration_name=\"myHnsw\",\n", " compression_configuration_name=\"myScalarQuantization\",\n", " vectorizer=\"myAIServicesVectorizer\",\n", " )\n", " ],\n", " )\n", "\n", "\n", "def create_search_index(index_client, index_name, fields, vector_search):\n", " \"\"\"Creates or updates a search index.\"\"\"\n", " index = SearchIndex(\n", " name=index_name,\n", " fields=fields,\n", " vector_search=vector_search,\n", " )\n", " index_client.create_or_update_index(index=index)\n", "\n", "\n", "index_client = SearchIndexClient(\n", " endpoint=SEARCH_SERVICE_ENDPOINT, credential=azure_search_credential\n", ")\n", "fields = create_fields()\n", "vector_search = create_vector_search_configuration()\n", "\n", "# Create the search index with the adjusted schema\n", "create_search_index(index_client, INDEX_NAME, fields, vector_search)\n", "print(f\"Created index: {INDEX_NAME}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a Skillset " ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created skillset: build-multimodal-demo-skillset\n" ] } ], "source": [ "def create_text_embedding_skill():\n", " return VisionVectorizeSkill(\n", " name=\"text-embedding-skill\",\n", " description=\"Skill to generate embeddings for text via Azure AI Vision\",\n", " context=\"/document\",\n", " model_version=\"2023-04-15\",\n", " inputs=[InputFieldMappingEntry(name=\"text\", source=\"/document/caption\")],\n", " outputs=[OutputFieldMappingEntry(name=\"vector\", target_name=\"captionVector\")],\n", " )\n", "\n", "def create_image_embedding_skill():\n", " return VisionVectorizeSkill(\n", " name=\"image-embedding-skill\",\n", " description=\"Skill to generate embeddings for image via Azure AI Vision\",\n", " context=\"/document\",\n", " model_version=\"2023-04-15\",\n", " inputs=[InputFieldMappingEntry(name=\"url\", source=\"/document/imageUrl\")],\n", " outputs=[OutputFieldMappingEntry(name=\"vector\", target_name=\"imageVector\")],\n", " )\n", "\n", "def create_skillset(client, skillset_name, text_embedding_skill, image_embedding_skill):\n", " skillset = SearchIndexerSkillset(\n", " name=skillset_name,\n", " description=\"Skillset for generating embeddings\",\n", " skills=[text_embedding_skill, image_embedding_skill],\n", " cognitive_services_account=CognitiveServicesAccountKey(\n", " key=AZURE_AI_VISION_API_KEY,\n", " description=\"AI Vision Multi Service Account in West US\",\n", " ),\n", " )\n", " client.create_or_update_skillset(skillset)\n", "\n", "client = SearchIndexerClient(\n", " endpoint=SEARCH_SERVICE_ENDPOINT, credential=azure_search_credential\n", ")\n", "skillset_name = f\"{INDEX_NAME}-skillset\"\n", "text_embedding_skill = create_text_embedding_skill()\n", "image_embedding_skill = create_image_embedding_skill()\n", "\n", "create_skillset(client, skillset_name, text_embedding_skill, image_embedding_skill)\n", "print(f\"Created skillset: {skillset_name}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run Indexer" ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "build-multimodal-demo-indexer created or updated.\n", "build-multimodal-demo-indexer is running. If queries return no results, please wait a bit and try again.\n" ] } ], "source": [ "def create_and_run_indexer(indexer_client, indexer_name, skillset_name, index_name, data_source_name):\n", " indexer = SearchIndexer(\n", " name=indexer_name,\n", " description=\"Indexer to index documents and generate embeddings\",\n", " skillset_name=skillset_name,\n", " target_index_name=index_name,\n", " data_source_name=data_source_name,\n", " parameters=IndexingParameters(\n", " configuration=IndexingParametersConfiguration(\n", " parsing_mode=BlobIndexerParsingMode.JSON_ARRAY,\n", " query_timeout=None,\n", " ),\n", " ),\n", " field_mappings=[FieldMapping(source_field_name=\"id\", target_field_name=\"id\")],\n", " output_field_mappings=[\n", " FieldMapping(source_field_name=\"/document/captionVector\", target_field_name=\"captionVector\"),\n", " FieldMapping(source_field_name=\"/document/imageVector\", target_field_name=\"imageVector\"),\n", " ],\n", " )\n", "\n", " indexer_client.create_or_update_indexer(indexer)\n", " print(f\"{indexer_name} created or updated.\")\n", "\n", " indexer_client.run_indexer(indexer_name)\n", " print(f\"{indexer_name} is running. If queries return no results, please wait a bit and try again.\")\n", "\n", "indexer_client = SearchIndexerClient(\n", " endpoint=SEARCH_SERVICE_ENDPOINT, credential=azure_search_credential\n", ")\n", "data_source_name = f\"{INDEX_NAME}-blob\"\n", "indexer_name = f\"{INDEX_NAME}-indexer\"\n", "\n", "create_and_run_indexer(indexer_client, indexer_name, skillset_name, INDEX_NAME, data_source_name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simple vector search (text to text)" ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Caption: a woman in a red dress\n", "Score: 0.9404777\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture286.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n", "Caption: a red handbag with a strap\n", "Score: 0.90242684\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture526.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n", "Caption: a woman in a dress\n", "Score: 0.8996681\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture300.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n" ] } ], "source": [ "# Initialize the SearchClient\n", "search_client = SearchClient(\n", " SEARCH_SERVICE_ENDPOINT,\n", " index_name=INDEX_NAME,\n", " credential=azure_search_credential,\n", ")\n", "\n", "# Define the query\n", "# query = \"sunglasses for holiday\"\n", "# query = \"休日のサングラス\" # Japanese query\n", "query = \"female red dresses\" # Spanish query\n", "\n", "vector_query = VectorizableTextQuery(\n", " text=query,\n", " k_nearest_neighbors=3,\n", " fields=\"captionVector\",\n", " # fields=\"imageVector\",\n", ")\n", "\n", "# Perform the search\n", "results = search_client.search(\n", " search_text=None,\n", " vector_queries=[vector_query],\n", " top=3\n", ")\n", "\n", "\n", "# Print the results\n", "for result in results:\n", " print(f\"Caption: {result['caption']}\")\n", " print(f\"Score: {result['@search.score']}\")\n", " display(HTML(f'<img src=\"{result[\"imageUrl\"]}\" style=\"width:200px;\"/>'))\n", " print(\"-\" * 50) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simple Vector Search (text to image)" ] }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Caption: a group of high heels\n", "Score: 0.032522473484277725\n", "URL: https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture504.jpg\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture504.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n", "Caption: a group of clothes and shoes\n", "Score: 0.01666666753590107\n", "URL: https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture477.jpg\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture477.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n", "Caption: a group of shoes on a wood surface\n", "Score: 0.01666666753590107\n", "URL: https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture496.jpg\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture496.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n" ] } ], "source": [ "# Define the text query\n", "query = \"shoes for running\"\n", "text_vector_query = VectorizableTextQuery(\n", " text=query,\n", " k_nearest_neighbors=10,\n", " fields=\"captionVector\",\n", ")\n", "# Define the image query\n", "image_vector_query = VectorizableImageUrlQuery( # Alternatively, use VectorizableImageBinaryQuery\n", " url=\"https://images.unsplash.com/photo-1542291026-7eec264c27ff?q=80&w=1770&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D\", # Image of a Red Nike Running Shoe\n", " k_nearest_neighbors=10,\n", " fields=\"imageVector\",\n", ")\n", "\n", "# Perform the search\n", "results = search_client.search(\n", " search_text=None, vector_queries=[text_vector_query, image_vector_query], top=3\n", ")\n", "\n", "# Print the results\n", "for result in results:\n", " print(f\"Caption: {result['caption']}\")\n", " print(f\"Score: {result['@search.score']}\")\n", " print(f\"URL: {result['imageUrl']}\")\n", " display(HTML(f'<img src=\"{result[\"imageUrl\"]}\" style=\"width:200px;\"/>'))\n", " print(\"-\" * 50) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Multi-modal vector search with weighting images 100x more than captions" ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Caption: a group of shoes on a wood surface\n", "Score: 1.6666667461395264\n", "URL: https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture496.jpg\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture496.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n", "Caption: a woman in blue running\n", "Score: 1.6393442153930664\n", "URL: https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture654.jpg\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture654.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n", "Caption: a group of high heels\n", "Score: 1.6292965412139893\n", "URL: https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture504.jpg\n" ] }, { "data": { "text/html": [ "<img src=\"https://fsunavalastorage.blob.core.windows.net/vector-sandbox/Picture504.jpg\" style=\"width:200px;\"/>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n" ] } ], "source": [ "# Define the text query\n", "query = \"shoes for running\"\n", "text_vector_query = VectorizableTextQuery(\n", " text=query,\n", " k_nearest_neighbors=5,\n", " fields=\"captionVector\",\n", ")\n", "# Define the image query\n", "image_vector_query = VectorizableImageUrlQuery( # Alternatively, use VectorizableImageBinaryQuery\n", " url=\"https://images.unsplash.com/photo-1542291026-7eec264c27ff?q=80&w=1770&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D\", # Image of a Red Nike Running Shoe\n", " k_nearest_neighbors=5,\n", " fields=\"imageVector\",\n", " weight=100,\n", ")\n", "\n", "# Perform the search\n", "results = search_client.search(\n", " search_text=None, vector_queries=[text_vector_query, image_vector_query], top=3\n", ")\n", "\n", "# Print the results\n", "for result in results:\n", " print(f\"Caption: {result['caption']}\")\n", " print(f\"Score: {result['@search.score']}\")\n", " print(f\"URL: {result['imageUrl']}\")\n", " display(HTML(f'<img src=\"{result[\"imageUrl\"]}\" style=\"width:200px;\"/>'))\n", " print(\"-\" * 50) " ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 2 }