diff --git a/docs/tutorials/aws/DeepSeek_demo_notebook_for_RAG.ipynb b/docs/tutorials/aws/DeepSeek_demo_notebook_for_RAG.ipynb new file mode 100644 index 0000000000..9746765979 --- /dev/null +++ b/docs/tutorials/aws/DeepSeek_demo_notebook_for_RAG.ipynb @@ -0,0 +1,1939 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "772cdd8e-44b9-44e4-b159-a71cd87724dc", + "metadata": {}, + "source": [ + "# 0. Create helper" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1def63f4-cf68-4076-bc5b-43502ea897a8", + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "from botocore.exceptions import BotoCoreError\n", + "import json\n", + "import requests\n", + "from requests.auth import HTTPBasicAuth\n", + "from requests_aws4auth import AWS4Auth\n", + "import time\n", + "from getpass import getpass\n", + "import urllib.parse\n", + "\n", + "# This Python code is compatible with AWS OpenSearch versions 2.9 and higher.\n", + "class AIConnectorHelper:\n", + " \n", + " def __init__(self,\n", + " opensearch_domain_region, \n", + " opensearch_domain_name,\n", + " opensearch_domain_username,\n", + " opensearch_domain_password,\n", + " aws_user_arn,\n", + " aws_role_arn,\n", + " aws_access_key_id,\n", + " aws_secret_access_key,\n", + " aws_session_token):\n", + " self.opensearch_domain_region = opensearch_domain_region\n", + " self.opensearch_domain_username = opensearch_domain_username\n", + " self.opensearch_domain_opensearch_domain_password = opensearch_domain_password\n", + " self.aws_user_arn = aws_user_arn\n", + " self.aws_role_arn = aws_role_arn\n", + " self.aws_access_key_id = aws_access_key_id\n", + " self.aws_secret_access_key = aws_secret_access_key\n", + " self.aws_session_token = aws_session_token\n", + " \n", + " # Create the session and clients\n", + " self.session = boto3.Session(\n", + " aws_access_key_id=aws_access_key_id,\n", + " aws_secret_access_key=aws_secret_access_key,\n", + " aws_session_token=aws_session_token,\n", + " region_name=opensearch_domain_region\n", + " )\n", + " self.opensearch_client = self.session.client('es')\n", + " self.iam_client = self.session.client('iam')\n", + " self.secretsmanager_client = self.session.client('secretsmanager')\n", + " self.sts_client = self.session.client('sts')\n", + " # Get the OpenSearch domain info\n", + " self.opensearch_domain_url, self.opensearch_domain_arn = self.get_opensearch_domain_info(opensearch_domain_name)\n", + " \n", + " def get_opensearch_domain_info(self, domain_name):\n", + " try:\n", + " response = self.opensearch_client.describe_elasticsearch_domain(DomainName=domain_name)\n", + " domain_info = response['DomainStatus']\n", + " domain_url = domain_info['Endpoint']\n", + " domain_arn = domain_info['ARN']\n", + " return f'https://{domain_url}', domain_arn\n", + " except self.opensearch_client.exceptions.ResourceNotFoundException:\n", + " print(f\"Domain '{domain_name}' not found.\")\n", + " return None, None\n", + " \n", + " def get_user_arn(self, username):\n", + " if not username:\n", + " return None\n", + " try:\n", + " # Get information about the IAM user\n", + " response = self.iam_client.get_user(UserName=username)\n", + " user_arn = response['User']['Arn']\n", + " return user_arn\n", + " except self.iam_client.exceptions.NoSuchEntityException:\n", + " print(f\"IAM user '{username}' not found.\")\n", + " return None\n", + "\n", + " def secret_exists(self, secret_name):\n", + " try:\n", + " self.secretsmanager_client.get_secret_value(SecretId=secret_name)\n", + " return True\n", + " except self.secretsmanager_client.exceptions.ResourceNotFoundException:\n", + " # If a ResourceNotFoundException was raised, the secret does not exist\n", + " return False\n", + "\n", + " def get_secret_arn(self, secret_name):\n", + " try:\n", + " response = self.secretsmanager_client.describe_secret(SecretId=secret_name)\n", + " return response['ARN']\n", + " except self.secretsmanager_client.exceptions.ResourceNotFoundException:\n", + " print(f\"The requested secret {secret_name} was not found\")\n", + " return None\n", + " except Exception as e:\n", + " print(f\"An error occurred: {e}\")\n", + " return None\n", + "\n", + " def create_secret(self, secret_name, secret_value):\n", + " try:\n", + " response = self.secretsmanager_client.create_secret(\n", + " Name=secret_name,\n", + " SecretString=json.dumps(secret_value),\n", + " )\n", + " print(f'Secret {secret_name} created successfully.')\n", + " return response['ARN'] # Return the ARN of the created secret\n", + " except BotoCoreError as e:\n", + " print(f'Error creating secret: {e}')\n", + " return None\n", + "\n", + " def role_exists(self, role_name):\n", + " try:\n", + " self.iam_client.get_role(RoleName=role_name)\n", + " return True\n", + " except self.iam_client.exceptions.NoSuchEntityException:\n", + " return False\n", + "\n", + " def create_iam_role(self, role_name, trust_policy_json, inline_policy_json):\n", + " try:\n", + " # Create the role with the trust policy\n", + " create_role_response = self.iam_client.create_role(\n", + " RoleName=role_name,\n", + " AssumeRolePolicyDocument=json.dumps(trust_policy_json),\n", + " Description='Role with custom trust and inline policies',\n", + " )\n", + "\n", + " # Get the ARN of the newly created role\n", + " role_arn = create_role_response['Role']['Arn']\n", + "\n", + " # Attach the inline policy to the role\n", + " self.iam_client.put_role_policy(\n", + " RoleName=role_name,\n", + " PolicyName='InlinePolicy', # you can replace this with your preferred policy name\n", + " PolicyDocument=json.dumps(inline_policy_json)\n", + " )\n", + "\n", + " print(f'Created role: {role_name}')\n", + " return role_arn\n", + "\n", + " except Exception as e:\n", + " print(f\"Error creating the role: {e}\")\n", + " return None\n", + "\n", + " def get_role_arn(self, role_name):\n", + " if not role_name:\n", + " return None\n", + " try:\n", + " response = self.iam_client.get_role(RoleName=role_name)\n", + " # Return ARN of the role\n", + " return response['Role']['Arn']\n", + " except self.iam_client.exceptions.NoSuchEntityException:\n", + " print(f\"The requested role {role_name} does not exist\")\n", + " return None\n", + " except Exception as e:\n", + " print(f\"An error occurred: {e}\")\n", + " return None\n", + "\n", + " def map_iam_role_to_backend_role(self, role_arn, os_security_role='ml_full_access'):\n", + " url = f'{self.opensearch_domain_url}/_plugins/_security/api/rolesmapping/{os_security_role}'\n", + " r=requests.get(url, auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password))\n", + " role_mapping = json.loads(r.text)\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + " if 'status' in role_mapping and role_mapping['status'] == 'NOT_FOUND':\n", + " data = {'backend_roles': [ role_arn ] }\n", + " response = requests.put(url, headers=headers, data=json.dumps(data), auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password))\n", + " print(response.text)\n", + " else:\n", + " role_mapping = role_mapping[os_security_role]\n", + " role_mapping['backend_roles'].append(role_arn)\n", + " data = [\n", + " {\n", + " \"op\": \"replace\", \"path\": \"/backend_roles\", \"value\": list(set(role_mapping['backend_roles']))\n", + " }\n", + " ]\n", + " response = requests.patch(url, headers=headers, data=json.dumps(data), auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password))\n", + " print(response.text)\n", + "\n", + " def assume_role(self, create_connector_role_arn, role_session_name=\"your_session_name\"):\n", + " assumed_role_object = self.sts_client.assume_role(\n", + " RoleArn=create_connector_role_arn,\n", + " RoleSessionName=role_session_name,\n", + " )\n", + "\n", + " # Obtain the temporary credentials from the assumed role \n", + " temp_credentials = assumed_role_object[\"Credentials\"]\n", + "\n", + " return temp_credentials\n", + "\n", + " def create_connector(self, create_connector_role_name, payload):\n", + " create_connector_role_arn = self.get_role_arn(create_connector_role_name)\n", + " temp_credentials = self.assume_role(create_connector_role_arn)\n", + " awsauth = AWS4Auth(\n", + " temp_credentials[\"AccessKeyId\"],\n", + " temp_credentials[\"SecretAccessKey\"],\n", + " self.opensearch_domain_region,\n", + " 'es',\n", + " session_token=temp_credentials[\"SessionToken\"],\n", + " )\n", + "\n", + " path = '/_plugins/_ml/connectors/_create'\n", + " url = self.opensearch_domain_url + path\n", + "\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + "\n", + " r = requests.post(url, auth=awsauth, json=payload, headers=headers)\n", + " print(r.text)\n", + " connector_id = json.loads(r.text)['connector_id']\n", + " return connector_id\n", + " \n", + " def get_task(self, task_id):\n", + " return requests.get(f'{self.opensearch_domain_url}/_plugins/_ml/tasks/{task_id}',\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password))\n", + " \n", + " def create_model(self, model_name, description, connector_id, deploy=True):\n", + " payload = {\n", + " \"name\": model_name,\n", + " \"function_name\": \"remote\",\n", + " \"description\": description,\n", + " \"connector_id\": connector_id\n", + " }\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + " deploy_str = str(deploy).lower()\n", + " r = requests.post(f'{self.opensearch_domain_url}/_plugins/_ml/models/_register?deploy={deploy_str}',\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " json=payload,\n", + " headers=headers)\n", + " print(r.text)\n", + " response = json.loads(r.text)\n", + " if 'model_id' in response:\n", + " return response['model_id']\n", + " else:\n", + " time.sleep(2) # sleep two seconds for task complete\n", + " r = self.get_task(response['task_id'])\n", + " print(r.text)\n", + " return json.loads(r.text)['model_id']\n", + " \n", + " def deploy_model(self, model_id):\n", + " return requests.post(f'{self.opensearch_domain_url}/_plugins/_ml/models/{model_id}/_deploy',\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " headers=headers)\n", + " \n", + " def predict(self, model_id, payload):\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + "\n", + " r = requests.post(f'{self.opensearch_domain_url}/_plugins/_ml/models/{model_id}/_predict',\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " json=payload,\n", + " headers=headers)\n", + " return r.text\n", + "\n", + " def create_index(self, index_name, payload):\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + "\n", + " r = requests.put(f'{self.opensearch_domain_url}/{index_name}',\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " json=payload,\n", + " headers=headers)\n", + " return r.text\n", + "\n", + " def search(self, index_name, query, search_pipeline=None):\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + "\n", + " search_url = f'{self.opensearch_domain_url}/{index_name}/_search'\n", + " if search_pipeline:\n", + " search_url = f'{self.opensearch_domain_url}/{index_name}/_search?search_pipeline={search_pipeline}'\n", + "\n", + " r = requests.get(search_url,\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " json=query,\n", + " headers=headers)\n", + " return r.text\n", + "\n", + " def bulk_ingest(self, index_name, data):\n", + " # Prepare the bulk request body\n", + " bulk_data = []\n", + " for i, item in enumerate(data, start=1):\n", + " # Add the action line\n", + " bulk_data.append(json.dumps({\"index\": {\"_index\": index_name}}))\n", + " # Add the document data\n", + " bulk_data.append(json.dumps(item))\n", + " \n", + " # Join the bulk data with newlines\n", + " bulk_body = \"\\n\".join(bulk_data) + \"\\n\"\n", + " \n", + " # Set the headers\n", + " headers = {\"Content-Type\": \"application/x-ndjson\"}\n", + " \n", + " # Send the bulk request with Basic Auth\n", + " response = requests.post(f\"{self.opensearch_domain_url}/_bulk\",\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " headers=headers,\n", + " data=bulk_body)\n", + " \n", + " # Check the response\n", + " if response.status_code == 200:\n", + " print(\"Bulk insert successful\")\n", + " print(json.dumps(response.json(), indent=2))\n", + " else:\n", + " print(f\"Error: {response.status_code}\")\n", + " print(response.text)\n", + "\n", + " def create_ingest_pipeline(self, pipeline_name, payload):\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + "\n", + " r = requests.put(f'{self.opensearch_domain_url}/_ingest/pipeline/{pipeline_name}',\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " json=payload,\n", + " headers=headers)\n", + " return r.text\n", + " \n", + " def create_search_pipeline(self, pipeline_name, payload):\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + "\n", + " r = requests.put(f'{self.opensearch_domain_url}/_search/pipeline/{pipeline_name}',\n", + " auth=HTTPBasicAuth(self.opensearch_domain_username, self.opensearch_domain_opensearch_domain_password),\n", + " json=payload,\n", + " headers=headers)\n", + " return r.text\n", + " \n", + " def create_connector_with_secret(self, secret_name, secret_value, connector_role_name, create_connector_role_name, create_connector_input, sleep_time_in_seconds=10):\n", + " # Step1: Create Secret\n", + " print('Step1: Create Secret')\n", + " if not self.secret_exists(secret_name):\n", + " secret_arn = self.create_secret(secret_name, secret_value)\n", + " else:\n", + " print('secret exists, skip creating')\n", + " secret_arn = self.get_secret_arn(secret_name)\n", + " print('----------')\n", + " \n", + " # Step2: Create IAM role configued in connector\n", + " trust_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"Service\": \"es.amazonaws.com\"\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + " }\n", + " ]\n", + " }\n", + "\n", + " inline_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Action\": [\n", + " \"secretsmanager:GetSecretValue\",\n", + " \"secretsmanager:DescribeSecret\"\n", + " ],\n", + " \"Effect\": \"Allow\",\n", + " \"Resource\": secret_arn\n", + " }\n", + " ]\n", + " }\n", + "\n", + " print('Step2: Create IAM role configued in connector')\n", + " if not self.role_exists(connector_role_name):\n", + " connector_role_arn = self.create_iam_role(connector_role_name, trust_policy, inline_policy)\n", + " else:\n", + " print('role exists, skip creating')\n", + " connector_role_arn = self.get_role_arn(connector_role_name)\n", + " print('----------', connector_role_arn)\n", + " \n", + " # Step 3: Configure IAM role in OpenSearch\n", + " # 3.1 Create IAM role for Signing create connector request\n", + " statements = []\n", + " if self.aws_user_arn:\n", + " statements.append({\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"AWS\": self.aws_user_arn\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + " })\n", + " if self.aws_role_arn:\n", + " statements.append({\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"AWS\": self.aws_role_arn\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + " })\n", + " trust_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": statements\n", + " }\n", + "\n", + " inline_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": \"iam:PassRole\",\n", + " \"Resource\": connector_role_arn\n", + " },\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": \"es:ESHttpPost\",\n", + " \"Resource\": self.opensearch_domain_arn\n", + " }\n", + " ]\n", + " }\n", + "\n", + " print('Step 3: Configure IAM role in OpenSearch')\n", + " print('Step 3.1: Create IAM role for Signing create connector request')\n", + " if not self.role_exists(create_connector_role_name):\n", + " create_connector_role_arn = self.create_iam_role(create_connector_role_name, trust_policy, inline_policy)\n", + " else:\n", + " print('role exists, skip creating')\n", + " create_connector_role_arn = self.get_role_arn(create_connector_role_name)\n", + " print('----------')\n", + " \n", + " # 3.2 Map backend role\n", + " print(f'Step 3.2: Map IAM role {create_connector_role_name} to OpenSearch permission role')\n", + " self.map_iam_role_to_backend_role(create_connector_role_arn)\n", + " print('----------')\n", + " \n", + " # 4. Create connector\n", + " print('Step 4: Create connector in OpenSearch')\n", + " # When you create an IAM role, it can take some time for the changes to propagate across AWS systems.\n", + " # During this time, some services might not immediately recognize the new role or its permissions.\n", + " # So we wait for some time before creating connector.\n", + " # If you see such error: ClientError: An error occurred (AccessDenied) when calling the AssumeRole operation\n", + " # you can rerun this function.\n", + " \n", + " # Wait for some time\n", + " time.sleep(sleep_time_in_seconds)\n", + " payload = create_connector_input\n", + " payload['credential'] = {\n", + " \"secretArn\": secret_arn,\n", + " \"roleArn\": connector_role_arn\n", + " }\n", + " connector_id = self.create_connector(create_connector_role_name, payload)\n", + " print('----------')\n", + " return connector_id\n", + " \n", + " def create_connector_with_role(self, connector_role_inline_policy, connector_role_name, create_connector_role_name, create_connector_input, sleep_time_in_seconds=10):\n", + " # Step1: Create IAM role configued in connector\n", + " trust_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"Service\": \"es.amazonaws.com\"\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + " }\n", + " ]\n", + " }\n", + "\n", + " print('Step1: Create IAM role configued in connector')\n", + " if not self.role_exists(connector_role_name):\n", + " connector_role_arn = self.create_iam_role(connector_role_name, trust_policy, connector_role_inline_policy)\n", + " else:\n", + " print('role exists, skip creating')\n", + " connector_role_arn = self.get_role_arn(connector_role_name)\n", + " print('----------')\n", + "\n", + " # Step 2: Configure IAM role in OpenSearch\n", + " # 2.1 Create IAM role for Signing create connector request\n", + " statements = []\n", + " if self.aws_user_arn:\n", + " statements.append({\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"AWS\": self.aws_user_arn\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + " })\n", + " if self.aws_role_arn:\n", + " statements.append({\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"AWS\": self.aws_role_arn\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + " })\n", + " trust_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": statements\n", + " }\n", + "\n", + " inline_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": \"iam:PassRole\",\n", + " \"Resource\": connector_role_arn\n", + " },\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": \"es:ESHttpPost\",\n", + " \"Resource\": self.opensearch_domain_arn\n", + " }\n", + " ]\n", + " }\n", + "\n", + " print('Step 2: Configure IAM role in OpenSearch')\n", + " print('Step 2.1: Create IAM role for Signing create connector request')\n", + " if not self.role_exists(create_connector_role_name):\n", + " create_connector_role_arn = self.create_iam_role(create_connector_role_name, trust_policy, inline_policy)\n", + " else:\n", + " print('role exists, skip creating')\n", + " create_connector_role_arn = self.get_role_arn(create_connector_role_name)\n", + " print('----------')\n", + "\n", + " # 2.2 Map backend role\n", + " print(f'Step 2.2: Map IAM role {create_connector_role_name} to OpenSearch permission role')\n", + " self.map_iam_role_to_backend_role(create_connector_role_arn)\n", + " print('----------')\n", + "\n", + " # 3. Create connector\n", + " print('Step 3: Create connector in OpenSearch')\n", + " # When you create an IAM role, it can take some time for the changes to propagate across AWS systems.\n", + " # During this time, some services might not immediately recognize the new role or its permissions.\n", + " # So we wait for some time before creating connector.\n", + " # If you see such error: ClientError: An error occurred (AccessDenied) when calling the AssumeRole operation\n", + " # you can rerun this function.\n", + "\n", + " # Wait for some time\n", + " time.sleep(sleep_time_in_seconds)\n", + " payload = create_connector_input\n", + " payload['credential'] = {\n", + " \"roleArn\": connector_role_arn\n", + " }\n", + " connector_id = self.create_connector(create_connector_role_name, payload)\n", + " print('----------')\n", + " return connector_id" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2fe3038d-38d9-4a0d-8aeb-8272039e109a", + "metadata": {}, + "outputs": [], + "source": [ + "def pretty_print_json(json_string):\n", + " # Parse the JSON string\n", + " parsed = json.loads(json_string)\n", + " \n", + " # Pretty print with indentation\n", + " pretty_json = json.dumps(parsed, indent=4, sort_keys=True)\n", + " \n", + " print(pretty_json)" + ] + }, + { + "cell_type": "markdown", + "id": "f35e337e-bc27-4582-bb20-beaf7bd101be", + "metadata": {}, + "source": [ + "# 1. Set up configurations" + ] + }, + { + "cell_type": "markdown", + "id": "1b72f8ff-963c-494c-a0d4-7ccc29cf1957", + "metadata": {}, + "source": [ + "## 1.1 OpenSearch configuration" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "a28c771d-d2b5-4a6c-b23a-7051c5ca52cb", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your AWS OpenSearch region, default us-east-1 \n", + "Enter your AWS OpenSearch domain name ········\n", + "Enter your AWS OpenSearch domain admin username ········\n", + "Enter your AWS OpenSearch domain password ········\n" + ] + } + ], + "source": [ + "opensearch_domain_region = input('Enter your AWS OpenSearch region, default us-east-1') or 'us-east-1'\n", + "opensearch_domain_name = getpass('Enter your AWS OpenSearch domain name') or None\n", + "opensearch_domain_username = getpass('Enter your AWS OpenSearch domain admin username') or None\n", + "opensearch_domain_password = getpass('Enter your AWS OpenSearch domain password') or None" + ] + }, + { + "cell_type": "markdown", + "id": "7c1db0b1-2afe-466c-b7e1-2c2b58c8ab76", + "metadata": {}, + "source": [ + "## 1.2 AWS Credential configuration\n", + "\n", + "**You must set either `aws_user_arn` or `aws_role_arn`.**\n", + "\n", + "### 1. `aws_user_arn` :\n", + "\n", + "Use AWS IAM user ARN.\n", + "To avoid permission issue and quick start, you can use user with `AdministratorAccess` policy.\n", + "\n", + "### 2. `aws_role_arn`\n", + "\n", + "Use AWS IAM role ARN.\n", + "\n", + "If you use AWS role, you can use this AWS CLI to get AWS role temporary credential\n", + "\n", + "`aws sts assume-role --role-arn --role-session-name `\n", + "\n", + "This AWS role must have such least permission:\n", + "1. Required Trust Relationship Policy:\n", + "```\n", + "{\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"Service\": \"es.amazonaws.com\"\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + " }\n", + " ]\n", + "}\n", + "```\n", + "\n", + "Note: Additional trust relationship configuration is needed as you need to use other entities to assume this role for temporary credentials.\n", + "For example, if you want an IAM user to assume this role, add the following statement to the trust relationship policy:\n", + "```\n", + "{\n", + " \"Effect\": \"Allow\",\n", + " \"Principal\": {\n", + " \"AWS\": \"arn:aws:iam:::user/\"\n", + " },\n", + " \"Action\": \"sts:AssumeRole\"\n", + "}\n", + "```\n", + "2. Required Permission Policy:\n", + "```\n", + "{\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"es:DescribeElasticsearchDomain\",\n", + " \"es:DescribeDomain\"\n", + " ],\n", + " \"Resource\": \"\"\n", + " },\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"iam:CreateRole\",\n", + " \"iam:GetRole\",\n", + " \"iam:PutRolePolicy\",\n", + " \"iam:AttachRolePolicy\",\n", + " \"iam:TagRole\",\n", + " \"iam:PassRole\"\n", + " ],\n", + " \"Resource\": \"arn:aws:iam:::role/*\"\n", + " }\n", + " ]\n", + "}\n", + "```\n", + "If you need to store API key in AWS SecretManger, you need to add following statement to the permission policy:\n", + "```\n", + "{\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"secretsmanager:CreateSecret\",\n", + " \"secretsmanager:GetSecretValue\",\n", + " \"secretsmanager:DescribeSecret\"\n", + " ],\n", + " \"Resource\": \"arn:aws:secretsmanager:::secret:*\"\n", + "}\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "1088316a-b778-4a69-8d74-b9e47bd77a1e", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your connector role prefix my_test_role\n" + ] + } + ], + "source": [ + "connector_role_prefix = input('Enter your connector role prefix') or None \n", + "if not connector_role_prefix:\n", + " raise ValueError(\"You must provide connector_role_prefix\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "84379cf6-33d8-4a49-b21c-a2e6d69027f1", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your secret prefix my_test_secret\n" + ] + } + ], + "source": [ + "secret_prefix = input('Enter your secret prefix') or None \n", + "if not connector_role_prefix:\n", + " raise ValueError(\"You must provide secret_prefix\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6aceed83-5824-41a5-b327-c046c5db02d4", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your AWS IAM user RN ········\n", + "Enter your AWS IAM role ARN ········\n" + ] + } + ], + "source": [ + "aws_user_arn = getpass('Enter your AWS IAM user RN') or None\n", + "aws_role_arn = getpass('Enter your AWS IAM role ARN') or None \n", + "# You must set either aws_user_arn or aws_role_arn. \n", + "if not bool(aws_user_arn) ^ bool(aws_role_arn): # XOR operation\n", + " raise ValueError(\"You must provide exactly one of aws_user_arn or aws_role_arn\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5a0b2fe9-ccd7-4f0b-bcd3-3478b5c1d5e1", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your AWS Access Key ID: ········\n", + "Enter your AWS Secret Access Key: ········\n", + "Enter your AWS Session Token: ········\n" + ] + } + ], + "source": [ + "aws_access_key_id = getpass(\"Enter your AWS Access Key ID: \")\n", + "aws_secret_access_key = getpass(\"Enter your AWS Secret Access Key: \")\n", + "aws_session_token = getpass(\"Enter your AWS Session Token: \")" + ] + }, + { + "cell_type": "markdown", + "id": "200218d7-900c-4e0c-bfe3-4c2b8e29ee78", + "metadata": {}, + "source": [ + "## 1.3 Initialize Connector Helper" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c03f2281-85dc-4493-a946-5c466d990e56", + "metadata": {}, + "outputs": [], + "source": [ + "helper = AIConnectorHelper(opensearch_domain_region, \n", + " opensearch_domain_name, \n", + " opensearch_domain_username, \n", + " opensearch_domain_password, \n", + " aws_user_arn,\n", + " aws_role_arn,\n", + " aws_access_key_id,\n", + " aws_secret_access_key,\n", + " aws_session_token\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "9d37327c-bc8f-44c7-968b-397548101b62", + "metadata": {}, + "source": [ + "## 2. Create Connector and Model\n", + "\n", + "This demo notebook provides three options\n", + "- 2.1 Use DeepSeek Chat service API\n", + "- 2.2 Use DeepSeek R1 model on Bedrock\n", + "- 2.3 Use DeepSeek R1 model on SageMaker" + ] + }, + { + "cell_type": "markdown", + "id": "0d21df38-1ef7-4d6d-9f32-4016e7e6e23d", + "metadata": {}, + "source": [ + "## 2.1 Use DeepSeek Chat service API\n", + "\n", + "Refer to this [tutorial](https://github.com/opensearch-project/ml-commons/blob/main/docs/tutorials/aws/RAG_with_DeepSeek_Chat_model.md) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "9e6e0125-9e50-47af-b2df-63fbe871c130", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your DeepSeek API Key: ········\n" + ] + } + ], + "source": [ + "deepseek_api_key = getpass(\"Enter your DeepSeek API Key: \")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f3a1ed8d-c2a3-4737-8067-ad3dcc017ae0", + "metadata": {}, + "outputs": [], + "source": [ + "secret_name = f'{secret_prefix}_deepseek_api_secret'\n", + "secret_key = f'{secret_prefix}_deepseek_api_key'\n", + "secret_value = { secret_key : deepseek_api_key }" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "479b349a-6fe0-4515-bb27-c6bc899f2d20", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Step1: Create Secret\n", + "Secret my_test_secret_deepseek_api_secret created successfully.\n", + "----------\n", + "Step2: Create IAM role configued in connector\n", + "Created role: my_test_role_deepseek_chat_model\n", + "---------- arn:aws:iam::419213735998:role/my_test_role_deepseek_chat_model\n", + "Step 3: Configure IAM role in OpenSearch\n", + "Step 3.1: Create IAM role for Signing create connector request\n", + "Created role: my_test_role_deepseek_chat_model_create\n", + "----------\n", + "Step 3.2: Map IAM role my_test_role_deepseek_chat_model_create to OpenSearch permission role\n", + "{\"status\":\"OK\",\"message\":\"'ml_full_access' updated.\"}\n", + "----------\n", + "Step 4: Create connector in OpenSearch\n", + "{\"connector_id\":\"qeRFvpQBFSAM-WczLLLu\"}\n", + "----------\n" + ] + } + ], + "source": [ + "# You can use existing role if the role permission and trust relationship are correct.\n", + "# But highly suggest to specify new role names. AIConnectorHelper will create role automatically with correct permission.\n", + "# If you see permission issue, always try to create new roles.\n", + "connector_role_name = f'{connector_role_prefix}_deepseek_chat_model'\n", + "create_connector_role_name = f'{connector_role_prefix}_deepseek_chat_model_create'\n", + "\n", + "create_connector_input = {\n", + " \"name\": \"DeepSeek Chat\",\n", + " \"description\": \"Test connector for DeepSeek Chat\",\n", + " \"version\": \"1\",\n", + " \"protocol\": \"http\",\n", + " \"parameters\": {\n", + " \"endpoint\": \"api.deepseek.com\",\n", + " \"model\": \"deepseek-chat\"\n", + " },\n", + " \"actions\": [\n", + " {\n", + " \"action_type\": \"predict\",\n", + " \"method\": \"POST\",\n", + " \"url\": \"https://${parameters.endpoint}/v1/chat/completions\",\n", + " \"headers\": {\n", + " \"Content-Type\": \"application/json\",\n", + " \"Authorization\": f\"Bearer ${{credential.secretArn.{secret_key}}}\"\n", + " },\n", + " \"request_body\": \"{ \\\"model\\\": \\\"${parameters.model}\\\", \\\"messages\\\": ${parameters.messages} }\"\n", + " }\n", + " ]\n", + "}\n", + "\n", + "deepseek_connector_id = helper.create_connector_with_secret(secret_name,\n", + " secret_value, \n", + " connector_role_name, \n", + " create_connector_role_name, \n", + " create_connector_input,\n", + " sleep_time_in_seconds=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "4ef4c9d5-1b5e-4e42-a0e1-ca380afcbc39", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"task_id\":\"kylFvpQBts7fa6byLx2Q\",\"status\":\"CREATED\",\"model_id\":\"lClFvpQBts7fa6byLx2p\"}\n" + ] + }, + { + "data": { + "text/plain": [ + "'lClFvpQBts7fa6byLx2p'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_name='DeepSeek Chat Model'\n", + "description='DeepSeek Chat Model'\n", + "deepseek_model_id = helper.create_model(model_name, description, deepseek_connector_id)\n", + "deepseek_model_id" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e2b1c45e-c45b-4ea1-b05e-1789716b041b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"inference_results\": [\n", + " {\n", + " \"output\": [\n", + " {\n", + " \"dataAsMap\": {\n", + " \"choices\": [\n", + " {\n", + " \"finish_reason\": \"stop\",\n", + " \"index\": 0.0,\n", + " \"message\": {\n", + " \"content\": \"Hello! How can I assist you today? \\ud83d\\ude0a\",\n", + " \"role\": \"assistant\"\n", + " }\n", + " }\n", + " ],\n", + " \"created\": 1738359001.0,\n", + " \"id\": \"2ba6a5be-905e-4814-9460-7c4e8035f029\",\n", + " \"model\": \"deepseek-chat\",\n", + " \"object\": \"chat.completion\",\n", + " \"system_fingerprint\": \"fp_3a5770e1b4\",\n", + " \"usage\": {\n", + " \"completion_tokens\": 11.0,\n", + " \"prompt_cache_hit_tokens\": 0.0,\n", + " \"prompt_cache_miss_tokens\": 11.0,\n", + " \"prompt_tokens\": 11.0,\n", + " \"prompt_tokens_details\": {\n", + " \"cached_tokens\": 0.0\n", + " },\n", + " \"total_tokens\": 22.0\n", + " }\n", + " },\n", + " \"name\": \"response\"\n", + " }\n", + " ],\n", + " \"status_code\": 200\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "request_data = {\n", + " \"parameters\": {\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a helpful assistant.\"\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Hello!\"\n", + " }\n", + " ]\n", + " }\n", + "}\n", + "response = helper.predict(deepseek_model_id, request_data)\n", + "pretty_print_json(response)" + ] + }, + { + "cell_type": "markdown", + "id": "a6c2bda1-5579-4428-bfb0-6dedde4b092b", + "metadata": {}, + "source": [ + "## 2.2 Use DeepSeek R1 model on Bedrock\n", + "\n", + "Refer to this [tutorial](https://github.com/opensearch-project/ml-commons/blob/main/docs/tutorials/aws/RAG_with_DeepSeek_R1_model_on_Bedrock.md) for more details.\n", + "\n", + "Make sure you already have DeepSeek R1 model running on Bedrock before running next step." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "28fcaf63-643f-49e8-a332-b34c8ffb6f14", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your DeepSeek Model Bedrock ARN: ········\n" + ] + } + ], + "source": [ + "deepseek_model_bedrock_arn = getpass(\"Enter your DeepSeek Model Bedrock ARN: \")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "f8da1167-4785-42b0-b997-20c67a7c462a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Step1: Create IAM role configued in connector\n", + "Created role: my_test_role_deepseek_r1_bedrock\n", + "----------\n", + "Step 2: Configure IAM role in OpenSearch\n", + "Step 2.1: Create IAM role for Signing create connector request\n", + "Created role: my_test_role_deepseek_r1_bedrock_create\n", + "----------\n", + "Step 2.2: Map IAM role my_test_role_deepseek_r1_bedrock_create to OpenSearch permission role\n", + "{\"status\":\"OK\",\"message\":\"'ml_full_access' updated.\"}\n", + "----------\n", + "Step 3: Create connector in OpenSearch\n", + "{\"connector_id\":\"quRGvpQBFSAM-WczVLIM\"}\n", + "----------\n" + ] + } + ], + "source": [ + "# You can use existing role if the role permission and trust relationship are correct.\n", + "# But highly suggest to specify new role names. AIConnectorHelper will create role automatically with correct permission.\n", + "# If you see permission issue, always try to create new roles.\n", + "connector_role_name = f'{connector_role_prefix}_deepseek_r1_bedrock'\n", + "create_connector_role_name = f'{connector_role_prefix}_deepseek_r1_bedrock_create'\n", + "\n", + "bedrock_region = 'us-east-1' # bedrock region could be different with OpenSearch domain region\n", + "\n", + "connector_role_inline_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Action\": [\n", + " \"bedrock:InvokeModel\"\n", + " ],\n", + " \"Effect\": \"Allow\",\n", + " \"Resource\": deepseek_model_bedrock_arn\n", + " }\n", + " ]\n", + "}\n", + "create_connector_input = {\n", + " \"name\": \"DeepSeek R1 model connector\",\n", + " \"description\": \"Connector for my Bedrock DeepSeek model\",\n", + " \"version\": \"1.0\",\n", + " \"protocol\": \"aws_sigv4\",\n", + " \"parameters\": {\n", + " \"service_name\": \"bedrock\",\n", + " \"region\": bedrock_region,\n", + " \"model_id\": urllib.parse.quote_plus(deepseek_model_bedrock_arn),\n", + " \"temperature\": 0,\n", + " \"max_gen_len\": 4000\n", + " },\n", + " \"actions\": [\n", + " {\n", + " \"action_type\": \"PREDICT\",\n", + " \"method\": \"POST\",\n", + " \"url\": f\"https://bedrock-runtime.{bedrock_region}.amazonaws.com/model/${{parameters.model_id}}/invoke\",\n", + " \"headers\": {\n", + " \"content-type\": \"application/json\"\n", + " },\n", + " \"request_body\": \"{ \\\"prompt\\\": \\\"<|begin▁of▁sentence|><|User|>${parameters.inputs}<|Assistant|>\\\", \\\"temperature\\\": ${parameters.temperature}, \\\"max_gen_len\\\": ${parameters.max_gen_len} }\",\n", + " \"post_process_function\": \"\\n return '{' +\\n '\\\"name\\\": \\\"response\\\",'+\\n '\\\"dataAsMap\\\": {' +\\n '\\\"completion\\\":\\\"' + escape(params.generation) + '\\\"}' +\\n '}';\\n \"\n", + " }\n", + " ]\n", + "}\n", + "\n", + "deepseek_connector_id = helper.create_connector_with_role(connector_role_inline_policy,\n", + " connector_role_name,\n", + " create_connector_role_name,\n", + " create_connector_input,\n", + " sleep_time_in_seconds=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "82c2073a-aa9a-41b2-86fe-7f46d5e44c56", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"task_id\":\"lilGvpQBts7fa6byWx0I\",\"status\":\"CREATED\",\"model_id\":\"lylGvpQBts7fa6byWx0x\"}\n" + ] + }, + { + "data": { + "text/plain": [ + "'lylGvpQBts7fa6byWx0x'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_name='DeepSeek R1 Model on Bedrock'\n", + "description='DeepSeek R1 Model on Bedrock'\n", + "deepseek_model_id = helper.create_model(model_name, description, deepseek_connector_id)\n", + "deepseek_model_id" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "b5d17481-08cd-4cdf-bba1-961edcfe62dc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"inference_results\": [\n", + " {\n", + " \"output\": [\n", + " {\n", + " \"dataAsMap\": {\n", + " \"completion\": \"\\n\\n\\n\\nHello! How can I assist you today? \\ud83d\\ude0a\"\n", + " },\n", + " \"name\": \"response\"\n", + " }\n", + " ],\n", + " \"status_code\": 200\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "request_data={\n", + " \"parameters\": {\n", + " \"inputs\": \"hello\"\n", + " }\n", + "}\n", + "response = helper.predict(deepseek_model_id, request_data)\n", + "pretty_print_json(response)" + ] + }, + { + "cell_type": "markdown", + "id": "b9de6a5c-ddba-4fa7-9748-09e20993d0e9", + "metadata": {}, + "source": [ + "## 2.3 Use DeepSeek R1 model on Bedrock\n", + "\n", + "Refer to this [tutorial](https://github.com/opensearch-project/ml-commons/blob/main/docs/tutorials/aws/RAG_with_DeepSeek_R1_model_on_Sagemaker.md) for more details.\n", + "\n", + "Make sure you already have DeepSeek R1 model deployed to SageMaker before running next step." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "babdc5c6-4c56-48ba-8212-6c9600913a5b", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your DeepSeek Model SageMaker Inference Endpoint ARN: ········\n", + "Enter your DeepSeek Model SageMaker Inference Endpoint URL: ········\n" + ] + } + ], + "source": [ + "sagemaker_inference_endpoint_arn = getpass(\"Enter your DeepSeek Model SageMaker Inference Endpoint ARN: \")\n", + "sagemaker_inference_endpoint_url = getpass(\"Enter your DeepSeek Model SageMaker Inference Endpoint URL: \")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "c25c47cb-e432-4ad2-926b-f6bfb2cfe660", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Step1: Create IAM role configued in connector\n", + "Created role: my_test_role_deepseek_r1_sagemaker\n", + "----------\n", + "Step 2: Configure IAM role in OpenSearch\n", + "Step 2.1: Create IAM role for Signing create connector request\n", + "Created role: my_test_role_deepseek_r1_sagemaker_create\n", + "----------\n", + "Step 2.2: Map IAM role my_test_role_deepseek_r1_sagemaker_create to OpenSearch permission role\n", + "{\"status\":\"OK\",\"message\":\"'ml_full_access' updated.\"}\n", + "----------\n", + "Step 3: Create connector in OpenSearch\n", + "{\"connector_id\":\"mSlIvpQBts7fa6byGB24\"}\n", + "----------\n" + ] + } + ], + "source": [ + "# You can use existing role if the role permission and trust relationship are correct.\n", + "# But highly suggest to specify new role names. AIConnectorHelper will create role automatically with correct permission.\n", + "# If you see permission issue, always try to create new roles.\n", + "connector_role_name = f'{connector_role_prefix}_deepseek_r1_sagemaker'\n", + "create_connector_role_name = f'{connector_role_prefix}_deepseek_r1_sagemaker_create'\n", + "\n", + "sagemaker_endpoint_region = 'us-east-1' # SageMaker endpoint region could be different with OpenSearch domain region\n", + "connector_role_inline_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"sagemaker:InvokeEndpoint\"\n", + " ],\n", + " \"Resource\": [\n", + " sagemaker_inference_endpoint_arn\n", + " ]\n", + " }\n", + " ]\n", + "}\n", + "\n", + "create_connector_input = {\n", + " \"name\": \"DeepSeek R1 model connector\",\n", + " \"description\": \"Connector for my SageMaker DeepSeek model\",\n", + " \"version\": \"1.0\",\n", + " \"protocol\": \"aws_sigv4\",\n", + " \"parameters\": {\n", + " \"service_name\": \"sagemaker\",\n", + " \"region\": sagemaker_endpoint_region,\n", + " \"do_sample\": True,\n", + " \"top_p\": 0.9,\n", + " \"temperature\": 0.7,\n", + " \"max_new_tokens\": 512\n", + " },\n", + " \"actions\": [\n", + " {\n", + " \"action_type\": \"PREDICT\",\n", + " \"method\": \"POST\",\n", + " \"url\": sagemaker_inference_endpoint_url,\n", + " \"headers\": {\n", + " \"content-type\": \"application/json\"\n", + " },\n", + " \"request_body\": \"{ \\\"inputs\\\": \\\"${parameters.inputs}\\\", \\\"parameters\\\": {\\\"do_sample\\\": ${parameters.do_sample}, \\\"top_p\\\": ${parameters.top_p}, \\\"temperature\\\": ${parameters.temperature}, \\\"max_new_tokens\\\": ${parameters.max_new_tokens}} }\",\n", + " \"post_process_function\": \"\\n if (params.result == null || params.result.length == 0) {\\n throw new Exception('No response available');\\n }\\n \\n def completion = params.result[0].generated_text;\\n return '{' +\\n '\\\"name\\\": \\\"response\\\",'+\\n '\\\"dataAsMap\\\": {' +\\n '\\\"completion\\\":\\\"' + escape(completion) + '\\\"}' +\\n '}';\\n \"\n", + " }\n", + " ]\n", + "}\n", + "\n", + "deepseek_connector_id = helper.create_connector_with_role(connector_role_inline_policy,\n", + " connector_role_name,\n", + " create_connector_role_name,\n", + " create_connector_input,\n", + " sleep_time_in_seconds=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "bdb9c2ef-f2af-40f3-9fa7-bc0e7a941d68", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"task_id\":\"milIvpQBts7fa6byJR0C\",\"status\":\"CREATED\",\"model_id\":\"mylIvpQBts7fa6byJR0c\"}\n" + ] + }, + { + "data": { + "text/plain": [ + "'mylIvpQBts7fa6byJR0c'" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_name='DeepSeek R1 Model on SageMaker'\n", + "description='DeepSeek R1 Model on SageMaker'\n", + "deepseek_model_id = helper.create_model(model_name, description, deepseek_connector_id)\n", + "deepseek_model_id" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "b2f168d4-130f-448b-b7a7-222f22a67853", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"inference_results\": [\n", + " {\n", + " \"output\": [\n", + " {\n", + " \"dataAsMap\": {\n", + " \"completion\": \"hello\\n\\n\\n\\nHello! How can I assist you today? \\ud83d\\ude0a\"\n", + " },\n", + " \"name\": \"response\"\n", + " }\n", + " ],\n", + " \"status_code\": 200\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "request_data={\n", + " \"parameters\": {\n", + " \"inputs\": \"hello\"\n", + " }\n", + "}\n", + "response = helper.predict(deepseek_model_id, request_data)\n", + "pretty_print_json(response)" + ] + }, + { + "cell_type": "markdown", + "id": "06509cc8-7516-4907-bf1e-8e982d102983", + "metadata": {}, + "source": [ + "# 3 Vector Database\n", + "\n", + "Refer to this [tutorial](https://opensearch.org/docs/latest/search-plugins/neural-search-tutorial/) for more details." + ] + }, + { + "cell_type": "markdown", + "id": "a3a19c8a-34a3-4bf7-a622-b23964ffc4ab", + "metadata": {}, + "source": [ + "## 3.1 Create Bedrock Titan Embedding Model" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "956e8c98-102e-4a5a-8d1c-e25351803683", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Step1: Create IAM role configued in connector\n", + "Created role: my_test_role_bedrock_titan_embedding_v2\n", + "----------\n", + "Step 2: Configure IAM role in OpenSearch\n", + "Step 2.1: Create IAM role for Signing create connector request\n", + "Created role: my_test_role_bedrock_titan_embedding_v2_create\n", + "----------\n", + "Step 2.2: Map IAM role my_test_role_bedrock_titan_embedding_v2_create to OpenSearch permission role\n", + "{\"status\":\"OK\",\"message\":\"'ml_full_access' updated.\"}\n", + "----------\n", + "Step 3: Create connector in OpenSearch\n", + "{\"connector_id\":\"q-RIvpQBFSAM-Wcz5bI5\"}\n", + "----------\n" + ] + } + ], + "source": [ + "# You can use existing role if the role permission and trust relationship are correct.\n", + "# But highly suggest to specify new role names. AIConnectorHelper will create role automatically with correct permission.\n", + "# If you see permission issue, always try to create new roles.\n", + "connector_role_name = f'{connector_role_prefix}_bedrock_titan_embedding_v2'\n", + "create_connector_role_name = f'{connector_role_prefix}_bedrock_titan_embedding_v2_create'\n", + "\n", + "bedrock_region = 'us-east-1' # bedrock region could be different with OpenSearch domain region\n", + "\n", + "connector_role_inline_policy = {\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Action\": [\n", + " \"bedrock:InvokeModel\"\n", + " ],\n", + " \"Effect\": \"Allow\",\n", + " \"Resource\": \"arn:aws:bedrock:*::foundation-model/amazon.titan-embed-text-v2:0\"\n", + " }\n", + " ]\n", + "}\n", + "\n", + "\n", + "create_connector_input = {\n", + " \"name\": \"Amazon Bedrock Connector: titan embedding v2\",\n", + " \"description\": \"The connector to bedrock Titan embedding model\",\n", + " \"version\": 1,\n", + " \"protocol\": \"aws_sigv4\",\n", + " \"parameters\": {\n", + " \"region\": bedrock_region,\n", + " \"service_name\": \"bedrock\",\n", + " \"model\": \"amazon.titan-embed-text-v2:0\",\n", + " \"dimensions\": 1024,\n", + " \"normalize\": True,\n", + " \"embeddingTypes\": [\"float\"]\n", + " },\n", + " \"actions\": [\n", + " {\n", + " \"action_type\": \"predict\",\n", + " \"method\": \"POST\",\n", + " \"url\": \"https://bedrock-runtime.${parameters.region}.amazonaws.com/model/${parameters.model}/invoke\",\n", + " \"headers\": {\n", + " \"content-type\": \"application/json\",\n", + " \"x-amz-content-sha256\": \"required\"\n", + " },\n", + " \"request_body\": \"{ \\\"inputText\\\": \\\"${parameters.inputText}\\\", \\\"dimensions\\\": ${parameters.dimensions}, \\\"normalize\\\": ${parameters.normalize}, \\\"embeddingTypes\\\": ${parameters.embeddingTypes} }\",\n", + " \"pre_process_function\": \"connector.pre_process.bedrock.embedding\",\n", + " \"post_process_function\": \"connector.post_process.bedrock.embedding\"\n", + " }\n", + " ]\n", + "}\n", + "\n", + "embedding_connector_id = helper.create_connector_with_role(connector_role_inline_policy,\n", + " connector_role_name,\n", + " create_connector_role_name,\n", + " create_connector_input,\n", + " sleep_time_in_seconds=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "0ed4c062-1efd-4d77-bbf7-cfea92f1b9d8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"task_id\":\"nSlIvpQBts7fa6by-x08\",\"status\":\"CREATED\",\"model_id\":\"nilIvpQBts7fa6by-x1p\"}\n" + ] + }, + { + "data": { + "text/plain": [ + "'nilIvpQBts7fa6by-x1p'" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_name='Bedrock Titan Embedding Model V2'\n", + "description='Bedrock Titan Embedding Model V2'\n", + "embedding_model_id = helper.create_model(model_name, description, embedding_connector_id)\n", + "embedding_model_id" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "767e5807-9b9e-4ee0-a93e-0ef7b3b27fba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"inference_results\":[{\"output\":[{\"name\":\"sentence_embedding\",\"data_type\":\"FLOAT32\",\"shape\":[1024],\"data\":[-0.055150498,0.045168508,...]}],\"status_code\":200}]}'" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "request_data={\n", + " \"parameters\": {\n", + " \"inputText\": \"hello\"\n", + " }\n", + "}\n", + "helper.predict(embedding_model_id, request_data)" + ] + }, + { + "cell_type": "markdown", + "id": "3eae20f1-38cc-4b29-843c-b04920e8e8a4", + "metadata": {}, + "source": [ + "## 3.2 Create Vector Database" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "e4b4e930-c512-4272-aaa8-2cee85c044b9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"acknowledged\":true}'" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create ingest pipeline\n", + "ingest_pipeline_name = 'text-embedding-ingest-pipeline'\n", + "ingest_pipeline_config = {\n", + " \"description\": \"Text embedding ingest pipeline\",\n", + " \"processors\": [\n", + " {\n", + " \"text_embedding\": {\n", + " \"model_id\": embedding_model_id,\n", + " \"field_map\": {\n", + " \"text\": \"passage_embedding\"\n", + " }\n", + " }\n", + " }\n", + " ]\n", + "}\n", + "\n", + "helper.create_ingest_pipeline(ingest_pipeline_name, ingest_pipeline_config)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "f134f4e2-9bb3-494a-9867-87e8898f2259", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"acknowledged\":true,\"shards_acknowledged\":true,\"index\":\"population_data\"}'" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create k-NN index\n", + "index_name = 'population_data'\n", + "index_mapping = {\n", + " \"settings\": {\n", + " \"index.knn\": True,\n", + " \"default_pipeline\": ingest_pipeline_name\n", + " },\n", + " \"mappings\": {\n", + " \"properties\": {\n", + " \"id\": {\n", + " \"type\": \"text\"\n", + " },\n", + " \"passage_embedding\": {\n", + " \"type\": \"knn_vector\",\n", + " \"dimension\": 1024,\n", + " \"method\": {\n", + " \"engine\": \"lucene\",\n", + " \"space_type\": \"l2\",\n", + " \"name\": \"hnsw\",\n", + " \"parameters\": {}\n", + " }\n", + " },\n", + " \"text\": {\n", + " \"type\": \"text\"\n", + " }\n", + " }\n", + " }\n", + "}\n", + "helper.create_index(index_name, index_mapping)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "75200222-a72d-4a66-81e5-a0e813ea4636", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bulk insert successful\n", + "{\n", + " \"took\": 25,\n", + " \"ingest_took\": 203,\n", + " \"errors\": false,\n", + " \"items\": [\n", + " {\n", + " \"index\": {\n", + " \"_index\": \"population_data\",\n", + " \"_id\": \"oClJvpQBts7fa6bynh3a\",\n", + " \"_version\": 1,\n", + " \"result\": \"created\",\n", + " \"_shards\": {\n", + " \"total\": 3,\n", + " \"successful\": 3,\n", + " \"failed\": 0\n", + " },\n", + " \"_seq_no\": 0,\n", + " \"_primary_term\": 1,\n", + " \"status\": 201\n", + " }\n", + " },\n", + " {\n", + " \"index\": {\n", + " \"_index\": \"population_data\",\n", + " \"_id\": \"oSlJvpQBts7fa6bynh3a\",\n", + " \"_version\": 1,\n", + " \"result\": \"created\",\n", + " \"_shards\": {\n", + " \"total\": 3,\n", + " \"successful\": 3,\n", + " \"failed\": 0\n", + " },\n", + " \"_seq_no\": 1,\n", + " \"_primary_term\": 1,\n", + " \"status\": 201\n", + " }\n", + " },\n", + " {\n", + " \"index\": {\n", + " \"_index\": \"population_data\",\n", + " \"_id\": \"oilJvpQBts7fa6bynh3a\",\n", + " \"_version\": 1,\n", + " \"result\": \"created\",\n", + " \"_shards\": {\n", + " \"total\": 3,\n", + " \"successful\": 3,\n", + " \"failed\": 0\n", + " },\n", + " \"_seq_no\": 0,\n", + " \"_primary_term\": 1,\n", + " \"status\": 201\n", + " }\n", + " },\n", + " {\n", + " \"index\": {\n", + " \"_index\": \"population_data\",\n", + " \"_id\": \"oylJvpQBts7fa6bynh3a\",\n", + " \"_version\": 1,\n", + " \"result\": \"created\",\n", + " \"_shards\": {\n", + " \"total\": 3,\n", + " \"successful\": 3,\n", + " \"failed\": 0\n", + " },\n", + " \"_seq_no\": 1,\n", + " \"_primary_term\": 1,\n", + " \"status\": 201\n", + " }\n", + " },\n", + " {\n", + " \"index\": {\n", + " \"_index\": \"population_data\",\n", + " \"_id\": \"pClJvpQBts7fa6bynh3a\",\n", + " \"_version\": 1,\n", + " \"result\": \"created\",\n", + " \"_shards\": {\n", + " \"total\": 3,\n", + " \"successful\": 3,\n", + " \"failed\": 0\n", + " },\n", + " \"_seq_no\": 2,\n", + " \"_primary_term\": 1,\n", + " \"status\": 201\n", + " }\n", + " },\n", + " {\n", + " \"index\": {\n", + " \"_index\": \"population_data\",\n", + " \"_id\": \"pSlJvpQBts7fa6bynh3a\",\n", + " \"_version\": 1,\n", + " \"result\": \"created\",\n", + " \"_shards\": {\n", + " \"total\": 3,\n", + " \"successful\": 3,\n", + " \"failed\": 0\n", + " },\n", + " \"_seq_no\": 0,\n", + " \"_primary_term\": 1,\n", + " \"status\": 201\n", + " }\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "# Load data\n", + "population_data = [\n", + " {\"text\": \"Chart and table of population level and growth rate for the Ogden-Layton metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\nThe current metro area population of Ogden-Layton in 2023 is 750,000, a 1.63% increase from 2022.\\nThe metro area population of Ogden-Layton in 2022 was 738,000, a 1.79% increase from 2021.\\nThe metro area population of Ogden-Layton in 2021 was 725,000, a 1.97% increase from 2020.\\nThe metro area population of Ogden-Layton in 2020 was 711,000, a 2.16% increase from 2019.\"},\n", + " {\"text\": \"Chart and table of population level and growth rate for the New York City metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of New York City in 2023 is 18,937,000, a 0.37% increase from 2022.\\\\nThe metro area population of New York City in 2022 was 18,867,000, a 0.23% increase from 2021.\\\\nThe metro area population of New York City in 2021 was 18,823,000, a 0.1% increase from 2020.\\\\nThe metro area population of New York City in 2020 was 18,804,000, a 0.01% decline from 2019.\"},\n", + " {\"text\": \"Chart and table of population level and growth rate for the Chicago metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Chicago in 2023 is 8,937,000, a 0.4% increase from 2022.\\\\nThe metro area population of Chicago in 2022 was 8,901,000, a 0.27% increase from 2021.\\\\nThe metro area population of Chicago in 2021 was 8,877,000, a 0.14% increase from 2020.\\\\nThe metro area population of Chicago in 2020 was 8,865,000, a 0.03% increase from 2019.\"},\n", + " {\"text\": \"Chart and table of population level and growth rate for the Miami metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Miami in 2023 is 6,265,000, a 0.8% increase from 2022.\\\\nThe metro area population of Miami in 2022 was 6,215,000, a 0.78% increase from 2021.\\\\nThe metro area population of Miami in 2021 was 6,167,000, a 0.74% increase from 2020.\\\\nThe metro area population of Miami in 2020 was 6,122,000, a 0.71% increase from 2019.\"},\n", + " {\"text\": \"Chart and table of population level and growth rate for the Austin metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Austin in 2023 is 2,228,000, a 2.39% increase from 2022.\\\\nThe metro area population of Austin in 2022 was 2,176,000, a 2.79% increase from 2021.\\\\nThe metro area population of Austin in 2021 was 2,117,000, a 3.12% increase from 2020.\\\\nThe metro area population of Austin in 2020 was 2,053,000, a 3.43% increase from 2019.\"},\n", + " {\"text\": \"Chart and table of population level and growth rate for the Seattle metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Seattle in 2023 is 3,519,000, a 0.86% increase from 2022.\\\\nThe metro area population of Seattle in 2022 was 3,489,000, a 0.81% increase from 2021.\\\\nThe metro area population of Seattle in 2021 was 3,461,000, a 0.82% increase from 2020.\\\\nThe metro area population of Seattle in 2020 was 3,433,000, a 0.79% increase from 2019.\"},\n", + "]\n", + "helper.bulk_ingest(index_name, population_data)" + ] + }, + { + "cell_type": "markdown", + "id": "00e32526-246f-4460-81e7-5c7d90b12ec2", + "metadata": {}, + "source": [ + "# 4 Run retrieval-augmented generation (RAG)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "6041e115-84ba-45f8-8957-2fc06052d283", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"acknowledged\":true}'" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Configure search pipeline\n", + "rag_pipeline_name = 'rag-pipeline-deepseek'\n", + "rag_pipeline_config = {\n", + " \"response_processors\": [\n", + " {\n", + " \"retrieval_augmented_generation\": {\n", + " \"tag\": \"Demo pipeline\",\n", + " \"description\": \"Demo pipeline Using DeepSeek R1\",\n", + " \"model_id\": deepseek_model_id,\n", + " \"context_field_list\": [\n", + " \"text\"\n", + " ],\n", + " \"system_prompt\": \"You are a helpful assistant.\",\n", + " \"user_instructions\": \"Generate a concise and informative answer in less than 100 words for the given question\"\n", + " }\n", + " }\n", + " ]\n", + "}\n", + "helper.create_search_pipeline(rag_pipeline_name, rag_pipeline_config)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "97154cf2-50a5-4ab9-8aaa-0c82864329f6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"_shards\": {\n", + " \"failed\": 0,\n", + " \"skipped\": 0,\n", + " \"successful\": 5,\n", + " \"total\": 5\n", + " },\n", + " \"ext\": {\n", + " \"retrieval_augmented_generation\": {\n", + " \"answer\": \"You are a helpful assistant.\\\\nGenerate a concise and informative answer in less than 100 words for the given question\\\\nSEARCH RESULT 1: Chart and table of population level and growth rate for the New York City metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of New York City in 2023 is 18,937,000, a 0.37% increase from 2022.\\\\nThe metro area population of New York City in 2022 was 18,867,000, a 0.23% increase from 2021.\\\\nThe metro area population of New York City in 2021 was 18,823,000, a 0.1% increase from 2020.\\\\nThe metro area population of New York City in 2020 was 18,804,000, a 0.01% decline from 2019.\\\\nSEARCH RESULT 2: Chart and table of population level and growth rate for the Miami metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Miami in 2023 is 6,265,000, a 0.8% increase from 2022.\\\\nThe metro area population of Miami in 2022 was 6,215,000, a 0.78% increase from 2021.\\\\nThe metro area population of Miami in 2021 was 6,167,000, a 0.74% increase from 2020.\\\\nThe metro area population of Miami in 2020 was 6,122,000, a 0.71% increase from 2019.\\\\nSEARCH RESULT 3: Chart and table of population level and growth rate for the Chicago metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Chicago in 2023 is 8,937,000, a 0.4% increase from 2022.\\\\nThe metro area population of Chicago in 2022 was 8,901,000, a 0.27% increase from 2021.\\\\nThe metro area population of Chicago in 2021 was 8,877,000, a 0.14% increase from 2020.\\\\nThe metro area population of Chicago in 2020 was 8,865,000, a 0.03% increase from 2019.\\\\nSEARCH RESULT 4: Chart and table of population level and growth rate for the Seattle metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Seattle in 2023 is 3,519,000, a 0.86% increase from 2022.\\\\nThe metro area population of Seattle in 2022 was 3,489,000, a 0.81% increase from 2021.\\\\nThe metro area population of Seattle in 2021 was 3,461,000, a 0.82% increase from 2020.\\\\nThe metro area population of Seattle in 2020 was 3,433,000, a 0.79% increase from 2019.\\\\nQUESTION: What's the population increase of New York City from 2021 to 2023? How is the trending comparing with Miami?\\\\nOkay, so the user is asking about the population increase of New York City from 2021 to 2023 and how it compares to Miami. Let me break this down step by step. \\n\\nFirst, I need to find the population figures for NYC in 2021 and 2023. From the search results, I see that in 2021, NYC had 18,823,000 people. In 2023, it's 18,937,000. To find the increase, I subtract 2021 from 2023, which gives me 114,000. \\n\\nNext, I should calculate the growth rate. The formula for growth rate is (Final - Initial)/Initial * 100. So, (18,937,000 - 18,823,000)/18,823,000 * 100. Let me do the math: 114,000 divided by 18,823,000 is approximately 0.00607, which is about 0.61%. \\n\\nNow, I need to compare this with Miami. Looking at Miami's data, in 2021 it was 6,167,000 and in 2023 it's 6,265,000. The increase is 98,000. Using the same growth rate formula, (6,265,000 - 6,167,000)/6,167,000 * 100 equals approximately 1.47%. \\n\\nSo, putting it all together, NYC's population increased by 114,000, a 0.61% growth rate, while Miami grew by 98,000, a 1.47% growth rate. That means Miami's growth rate is almost double that of NYC's. \\n\\nI should make sure the numbers are accurate and that I didn't mix up any figures. Let me double-check the search results. Yep, NYC 2021 was 18,823,000 and 2023 is 18,93\"\n", + " }\n", + " },\n", + " \"hits\": {\n", + " \"hits\": [\n", + " {\n", + " \"_id\": \"oSlJvpQBts7fa6bynh3a\",\n", + " \"_index\": \"population_data\",\n", + " \"_score\": 0.5795176,\n", + " \"_source\": {\n", + " \"text\": \"Chart and table of population level and growth rate for the New York City metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of New York City in 2023 is 18,937,000, a 0.37% increase from 2022.\\\\nThe metro area population of New York City in 2022 was 18,867,000, a 0.23% increase from 2021.\\\\nThe metro area population of New York City in 2021 was 18,823,000, a 0.1% increase from 2020.\\\\nThe metro area population of New York City in 2020 was 18,804,000, a 0.01% decline from 2019.\"\n", + " }\n", + " },\n", + " {\n", + " \"_id\": \"oylJvpQBts7fa6bynh3a\",\n", + " \"_index\": \"population_data\",\n", + " \"_score\": 0.48947608,\n", + " \"_source\": {\n", + " \"text\": \"Chart and table of population level and growth rate for the Miami metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Miami in 2023 is 6,265,000, a 0.8% increase from 2022.\\\\nThe metro area population of Miami in 2022 was 6,215,000, a 0.78% increase from 2021.\\\\nThe metro area population of Miami in 2021 was 6,167,000, a 0.74% increase from 2020.\\\\nThe metro area population of Miami in 2020 was 6,122,000, a 0.71% increase from 2019.\"\n", + " }\n", + " },\n", + " {\n", + " \"_id\": \"oilJvpQBts7fa6bynh3a\",\n", + " \"_index\": \"population_data\",\n", + " \"_score\": 0.4230285,\n", + " \"_source\": {\n", + " \"text\": \"Chart and table of population level and growth rate for the Chicago metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Chicago in 2023 is 8,937,000, a 0.4% increase from 2022.\\\\nThe metro area population of Chicago in 2022 was 8,901,000, a 0.27% increase from 2021.\\\\nThe metro area population of Chicago in 2021 was 8,877,000, a 0.14% increase from 2020.\\\\nThe metro area population of Chicago in 2020 was 8,865,000, a 0.03% increase from 2019.\"\n", + " }\n", + " },\n", + " {\n", + " \"_id\": \"pSlJvpQBts7fa6bynh3a\",\n", + " \"_index\": \"population_data\",\n", + " \"_score\": 0.4152995,\n", + " \"_source\": {\n", + " \"text\": \"Chart and table of population level and growth rate for the Seattle metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\\\nThe current metro area population of Seattle in 2023 is 3,519,000, a 0.86% increase from 2022.\\\\nThe metro area population of Seattle in 2022 was 3,489,000, a 0.81% increase from 2021.\\\\nThe metro area population of Seattle in 2021 was 3,461,000, a 0.82% increase from 2020.\\\\nThe metro area population of Seattle in 2020 was 3,433,000, a 0.79% increase from 2019.\"\n", + " }\n", + " }\n", + " ],\n", + " \"max_score\": 0.5795176,\n", + " \"total\": {\n", + " \"relation\": \"eq\",\n", + " \"value\": 6\n", + " }\n", + " },\n", + " \"timed_out\": false,\n", + " \"took\": 5\n", + "}\n" + ] + } + ], + "source": [ + "question = \"What's the population increase of New York City from 2021 to 2023? How is the trending comparing with Miami?\"\n", + "query = {\n", + " \"query\": {\n", + " \"neural\": {\n", + " \"passage_embedding\": {\n", + " \"query_text\": question,\n", + " \"model_id\": embedding_model_id,\n", + " \"k\": 5\n", + " }\n", + " }\n", + " },\n", + " \"size\": 4,\n", + " \"_source\": [\n", + " \"text\"\n", + " ],\n", + " \"ext\": {\n", + " \"generative_qa_parameters\": {\n", + " \"llm_model\": \"bedrock/claude\",\n", + " \"llm_question\": question,\n", + " \"context_size\": 5,\n", + " \"timeout\": 15\n", + " }\n", + " }\n", + "}\n", + "search_response = helper.search(index_name, query, rag_pipeline_name)\n", + "pretty_print_json(search_response)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}