diff --git a/.gitignore b/.gitignore index 885f598..85df1b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ venv/ .aws-sam/ *.zip +package.yaml +config.tsx # Temporary files: *.tmp.* @@ -366,3 +368,4 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ +webui/src/config.tsx diff --git a/Personalize/1.Building_Campaign_HRNN.ipynb b/Personalize/1.Building_Campaign_HRNN.ipynb index e0b4246..2fa4dfa 100644 --- a/Personalize/1.Building_Campaign_HRNN.ipynb +++ b/Personalize/1.Building_Campaign_HRNN.ipynb @@ -36,7 +36,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -59,7 +59,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -145,18 +145,18 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 59, "metadata": {}, "outputs": [], "source": [ - "bucket = \"pocstor-staging\" # replace with the name of your S3 bucket\n", + "bucket = \"teststr-staging\" # replace with the name of your S3 bucket\n", "interactions_filename = \"useritems-interactions.csv\"\n", "items_filename = \"items_w_metadata.csv\"\n", "\n", - "Rerank_arn = 'arn:aws:lambda:us-east-1:011777388888:function:pocstor-Rerank'\n", - "GetRecommendationsByItem_arn = 'arn:aws:lambda:us-east-1:011777388888:function:pocstor-GetRecommendationsByItem'\n", - "GetRecommendations_arn = 'arn:aws:lambda:us-east-1:011777388888:function:pocstor-GetRecommendations'\n", - "PostClickEvent_arn = 'arn:aws:lambda:us-east-1:011777388888:function:pocstor-PostClickEvent'" + "Rerank_arn = 'arn:aws:lambda:us-east-1:962222257213:function:teststr-Rerank'\n", + "GetRecommendationsByItem_arn = 'arn:aws:lambda:us-east-1:962222257213:function:teststr-GetRecommendationsByItem'\n", + "GetRecommendations_arn = 'arn:aws:lambda:us-east-1:962222257213:function:teststr-GetRecommendations'\n", + "PostClickEvent_arn = 'arn:aws:lambda:us-east-1:962222257213:function:teststr-PostClickEvent'" ] }, { @@ -170,9 +170,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bucket Name : teststr-staging\n", + "uploading Dataset to Amazon s3\n", + "upload: Datasets/users.csv to s3://teststr-staging/users.csv \n", + "upload: Datasets/items_w_metadata.csv to s3://teststr-staging/items_w_metadata.csv\n", + "upload: Datasets/useritems-interactions.csv to s3://teststr-staging/useritems-interactions.csv\n" + ] + } + ], "source": [ "!echo \"Bucket Name : $bucket\"\n", "!echo \"uploading Dataset to Amazon s3\"\n", @@ -195,15 +207,93 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
USER_IDITEM_IDTIMESTAMP
0A1L5P841VIO02V18815098181328140800
1AB2W04NI4OEAD18815098181330387200
............
253014APRNS6DB68LLVB00LFPS0CY1405900800
253015A3UJRNI8UR4871B00LFPS0CY1405382400
\n", + "

253016 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " USER_ID ITEM_ID TIMESTAMP\n", + "0 A1L5P841VIO02V 1881509818 1328140800\n", + "1 AB2W04NI4OEAD 1881509818 1330387200\n", + "... ... ... ...\n", + "253014 APRNS6DB68LLV B00LFPS0CY 1405900800\n", + "253015 A3UJRNI8UR4871 B00LFPS0CY 1405382400\n", + "\n", + "[253016 rows x 3 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "ratinguri = f's3://{bucket}/useritems-interactions.csv'\n", "useritems = pd.read_csv(ratinguri, names=['USER_ID', 'ITEM_ID', 'TIMESTAMP'], header=1)\n", "pd.set_option('display.max_rows', 4) #change the bucket name to your bucket name\n", "\n", - "users" + "useritems" ] }, { @@ -215,9 +305,107 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
asintitleimg_urlgenre
020948692455 LED Bicycle Rear Tail Red Bike Torch Laser B...http://ecx.images-amazon.com/images/I/51RtwnJw...Transportation|Vehicle|Bumper|Light|Wheel|Mach...
17245456313Black Mountain Products Resistance Band Set wi...http://ecx.images-amazon.com/images/I/51FdHlZS...Cable|Electronics|Computer|Adapter
...............
18344B00LA12PNI[2 PACK] Premium Dry Bags - two 500D PVC Tarp ...http://ecx.images-amazon.com/images/I/518UdYxF...Apparel|Lifejacket|Clothing|Vest|Bag
18345B00LFPS0CYHydracentials Sporty 25 Oz Insulated Stainless...http://ecx.images-amazon.com/images/I/41oC4FCS...Shaker|Bottle|Water Bottle
\n", + "

18346 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " asin title \\\n", + "0 2094869245 5 LED Bicycle Rear Tail Red Bike Torch Laser B... \n", + "1 7245456313 Black Mountain Products Resistance Band Set wi... \n", + "... ... ... \n", + "18344 B00LA12PNI [2 PACK] Premium Dry Bags - two 500D PVC Tarp ... \n", + "18345 B00LFPS0CY Hydracentials Sporty 25 Oz Insulated Stainless... \n", + "\n", + " img_url \\\n", + "0 http://ecx.images-amazon.com/images/I/51RtwnJw... \n", + "1 http://ecx.images-amazon.com/images/I/51FdHlZS... \n", + "... ... \n", + "18344 http://ecx.images-amazon.com/images/I/518UdYxF... \n", + "18345 http://ecx.images-amazon.com/images/I/41oC4FCS... \n", + "\n", + " genre \n", + "0 Transportation|Vehicle|Bumper|Light|Wheel|Mach... \n", + "1 Cable|Electronics|Computer|Adapter \n", + "... ... \n", + "18344 Apparel|Lifejacket|Clothing|Vest|Bag \n", + "18345 Shaker|Bottle|Water Bottle \n", + "\n", + "[18346 rows x 4 columns]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "ratinguri = f's3://{bucket}/items_w_metadata.csv'\n", "items = pd.read_csv(ratinguri, names=['asin', 'title', 'img_url','genre'], header=1)\n", @@ -235,9 +423,75 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
userid
0A1L5P841VIO02V
1AB2W04NI4OEAD
......
177766AKPYS9VSM3LNX
177767AXBNEFRD90GLM
\n", + "

177768 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " userid\n", + "0 A1L5P841VIO02V\n", + "1 AB2W04NI4OEAD\n", + "... ...\n", + "177766 AKPYS9VSM3LNX\n", + "177767 AXBNEFRD90GLM\n", + "\n", + "[177768 rows x 1 columns]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "ratinguri = f's3://{bucket}/users.csv'\n", "users = pd.read_csv(ratinguri, names=['userid'], header=1)\n", @@ -257,9 +511,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"schemaArn\": \"arn:aws:personalize:us-east-1:962222257213:schema/personalize-demo-usersitems-interactions\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"0f032ccd-259d-4527-8989-cc851646284e\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Mon, 24 Feb 2020 13:34:23 GMT\",\n", + " \"x-amzn-requestid\": \"0f032ccd-259d-4527-8989-cc851646284e\",\n", + " \"content-length\": \"106\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "interactions_schema = {\n", " \"type\": \"record\",\n", @@ -293,9 +569,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"schemaArn\": \"arn:aws:personalize:us-east-1:962222257213:schema/personalize-demo-items\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"916af791-493f-46f7-a41f-6ed9f38e71e4\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Mon, 24 Feb 2020 13:34:24 GMT\",\n", + " \"x-amzn-requestid\": \"916af791-493f-46f7-a41f-6ed9f38e71e4\",\n", + " \"content-length\": \"88\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "items_schema = {\n", " \"type\": \"record\",\n", @@ -350,9 +648,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"datasetGroupArn\": \"arn:aws:personalize:us-east-1:962222257213:dataset-group/personalize-launch-demo\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"7c181529-ffb2-45cf-a42f-c6bc4a9f60f3\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Mon, 24 Feb 2020 13:34:26 GMT\",\n", + " \"x-amzn-requestid\": \"7c181529-ffb2-45cf-a42f-c6bc4a9f60f3\",\n", + " \"content-length\": \"102\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_dataset_group_response = personalize.create_dataset_group(\n", " name = \"personalize-launch-demo\"\n", @@ -373,9 +693,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DatasetGroup: CREATE PENDING\n", + "DatasetGroup: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -402,9 +731,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"datasetArn\": \"arn:aws:personalize:us-east-1:962222257213:dataset/personalize-launch-demo/INTERACTIONS\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"defe64f6-bbe5-49a6-a8e5-5a19af778e15\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Mon, 24 Feb 2020 13:35:28 GMT\",\n", + " \"x-amzn-requestid\": \"defe64f6-bbe5-49a6-a8e5-5a19af778e15\",\n", + " \"content-length\": \"104\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "dataset_type = \"INTERACTIONS\"\n", "create_dataset_response = personalize.create_dataset(\n", @@ -420,9 +771,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"datasetArn\": \"arn:aws:personalize:us-east-1:962222257213:dataset/personalize-launch-demo/ITEMS\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"74858393-396c-4b4e-a077-dd40d8603237\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Mon, 24 Feb 2020 13:35:28 GMT\",\n", + " \"x-amzn-requestid\": \"74858393-396c-4b4e-a077-dd40d8603237\",\n", + " \"content-length\": \"97\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "dataset_type = \"ITEMS\"\n", "create_dataset_response = personalize.create_dataset(\n", @@ -447,9 +820,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'ResponseMetadata': {'RequestId': '94CE7697AC878BC3',\n", + " 'HostId': '/kcldRz6bDNZ0iLzFxQTuAYnnVykCVvtUMJlsc3bPUM8x0OxPMbI3ex7SHyK9VECcshlr0OJcgI=',\n", + " 'HTTPStatusCode': 204,\n", + " 'HTTPHeaders': {'x-amz-id-2': '/kcldRz6bDNZ0iLzFxQTuAYnnVykCVvtUMJlsc3bPUM8x0OxPMbI3ex7SHyK9VECcshlr0OJcgI=',\n", + " 'x-amz-request-id': '94CE7697AC878BC3',\n", + " 'date': 'Mon, 24 Feb 2020 13:35:30 GMT',\n", + " 'server': 'AmazonS3'},\n", + " 'RetryAttempts': 0}}" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "s3 = boto3.client(\"s3\")\n", "\n", @@ -496,9 +887,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"datasetImportJobArn\": \"arn:aws:personalize:us-east-1:962222257213:dataset-import-job/personalize-demo-import-interactions\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"a1247271-bbee-4b3c-bac8-8233838a8524\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Mon, 24 Feb 2020 13:35:29 GMT\",\n", + " \"x-amzn-requestid\": \"a1247271-bbee-4b3c-bac8-8233838a8524\",\n", + " \"content-length\": \"124\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_dataset_import_job_response = personalize.create_dataset_import_job(\n", " jobName = \"personalize-demo-import-interactions\",\n", @@ -524,9 +937,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DatasetImportJob: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -551,9 +972,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 39, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "ResourceAlreadyExistsException", + "evalue": "An error occurred (ResourceAlreadyExistsException) when calling the CreateDatasetImportJob operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:dataset-import-job/personalize-demo-import-items already exists.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\"dataLocation\"\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m\"s3://{}/{}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbucket\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitems_filename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m },\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mroleArn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrole_arn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m )\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_api_call\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 314\u001b[0m \"%s() only accepts keyword arguments.\" % py_operation_name)\n\u001b[1;32m 315\u001b[0m \u001b[0;31m# The \"self\" in this scope is referring to the BaseClient.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 316\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_make_api_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moperation_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 317\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 318\u001b[0m \u001b[0m_api_call\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpy_operation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_make_api_call\u001b[0;34m(self, operation_name, api_params)\u001b[0m\n\u001b[1;32m 624\u001b[0m \u001b[0merror_code\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Error\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Code\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 625\u001b[0m \u001b[0merror_class\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_code\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merror_code\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 626\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merror_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparsed_response\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moperation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 627\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 628\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m: An error occurred (ResourceAlreadyExistsException) when calling the CreateDatasetImportJob operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:dataset-import-job/personalize-demo-import-items already exists." + ] + } + ], "source": [ "create_dataset_import_job_response = personalize.create_dataset_import_job(\n", " jobName = \"personalize-demo-import-items\",\n", @@ -579,9 +1014,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DatasetImportJob: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -617,9 +1060,57 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 41, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'recipes': [{'name': 'aws-hrnn',\n", + " 'recipeArn': 'arn:aws:personalize:::recipe/aws-hrnn',\n", + " 'status': 'ACTIVE',\n", + " 'creationDateTime': datetime.datetime(2019, 6, 10, 0, 0, tzinfo=tzlocal()),\n", + " 'lastUpdatedDateTime': datetime.datetime(2019, 6, 20, 0, 39, 17, 65000, tzinfo=tzlocal())},\n", + " {'name': 'aws-hrnn-coldstart',\n", + " 'recipeArn': 'arn:aws:personalize:::recipe/aws-hrnn-coldstart',\n", + " 'status': 'ACTIVE',\n", + " 'creationDateTime': datetime.datetime(2019, 6, 10, 0, 0, tzinfo=tzlocal()),\n", + " 'lastUpdatedDateTime': datetime.datetime(2019, 6, 20, 0, 39, 17, 64000, tzinfo=tzlocal())},\n", + " {'name': 'aws-hrnn-metadata',\n", + " 'recipeArn': 'arn:aws:personalize:::recipe/aws-hrnn-metadata',\n", + " 'status': 'ACTIVE',\n", + " 'creationDateTime': datetime.datetime(2019, 6, 10, 0, 0, tzinfo=tzlocal()),\n", + " 'lastUpdatedDateTime': datetime.datetime(2019, 6, 20, 0, 39, 17, 64000, tzinfo=tzlocal())},\n", + " {'name': 'aws-personalized-ranking',\n", + " 'recipeArn': 'arn:aws:personalize:::recipe/aws-personalized-ranking',\n", + " 'status': 'ACTIVE',\n", + " 'creationDateTime': datetime.datetime(2019, 6, 10, 0, 0, tzinfo=tzlocal()),\n", + " 'lastUpdatedDateTime': datetime.datetime(2019, 6, 20, 0, 39, 17, 65000, tzinfo=tzlocal())},\n", + " {'name': 'aws-popularity-count',\n", + " 'recipeArn': 'arn:aws:personalize:::recipe/aws-popularity-count',\n", + " 'status': 'ACTIVE',\n", + " 'creationDateTime': datetime.datetime(2019, 6, 10, 0, 0, tzinfo=tzlocal()),\n", + " 'lastUpdatedDateTime': datetime.datetime(2019, 6, 20, 0, 39, 17, 65000, tzinfo=tzlocal())},\n", + " {'name': 'aws-sims',\n", + " 'recipeArn': 'arn:aws:personalize:::recipe/aws-sims',\n", + " 'status': 'ACTIVE',\n", + " 'creationDateTime': datetime.datetime(2019, 6, 10, 0, 0, tzinfo=tzlocal()),\n", + " 'lastUpdatedDateTime': datetime.datetime(2019, 6, 20, 0, 39, 17, 64000, tzinfo=tzlocal())}],\n", + " 'ResponseMetadata': {'RequestId': '1b97d3a3-7de2-4f7f-8c44-a49794e5b4a7',\n", + " 'HTTPStatusCode': 200,\n", + " 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1',\n", + " 'date': 'Mon, 24 Feb 2020 16:48:57 GMT',\n", + " 'x-amzn-requestid': '1b97d3a3-7de2-4f7f-8c44-a49794e5b4a7',\n", + " 'content-length': '1067',\n", + " 'connection': 'keep-alive'},\n", + " 'RetryAttempts': 0}}" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "list_recipes_response = personalize.list_recipes()\n", "hrnn_arn = list_recipes_response['recipes'][0]['recipeArn']\n", @@ -660,9 +1151,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "ResourceAlreadyExistsException", + "evalue": "An error occurred (ResourceAlreadyExistsException) when calling the CreateSolution operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-hrnn already exists.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"personalize-demo-soln-hrnn\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mdatasetGroupArn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdataset_group_arn\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mrecipeArn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhrnn_arn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m )\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_api_call\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 314\u001b[0m \"%s() only accepts keyword arguments.\" % py_operation_name)\n\u001b[1;32m 315\u001b[0m \u001b[0;31m# The \"self\" in this scope is referring to the BaseClient.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 316\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_make_api_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moperation_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 317\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 318\u001b[0m \u001b[0m_api_call\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpy_operation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_make_api_call\u001b[0;34m(self, operation_name, api_params)\u001b[0m\n\u001b[1;32m 624\u001b[0m \u001b[0merror_code\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Error\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Code\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 625\u001b[0m \u001b[0merror_class\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_code\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merror_code\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 626\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merror_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparsed_response\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moperation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 627\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 628\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m: An error occurred (ResourceAlreadyExistsException) when calling the CreateSolution operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-hrnn already exists." + ] + } + ], "source": [ "create_solution_response = personalize.create_solution(\n", " name = \"personalize-demo-soln-hrnn\",\n", @@ -683,9 +1188,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionVersionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-hrnn/e342ae42\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"52b7f5d0-ce28-4794-a099-88e19d50a064\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Mon, 24 Feb 2020 16:49:02 GMT\",\n", + " \"x-amzn-requestid\": \"52b7f5d0-ce28-4794-a099-88e19d50a064\",\n", + " \"content-length\": \"112\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_solution_version_response = personalize.create_solution_version(\n", " solutionArn = hrnn_solution_arn\n", @@ -706,9 +1233,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 47, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SolutionVersion: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -735,9 +1270,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionVersionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-hrnn/e342ae42\",\n", + " \"metrics\": {\n", + " \"coverage\": 0.0643,\n", + " \"mean_reciprocal_rank_at_25\": 0.0091,\n", + " \"normalized_discounted_cumulative_gain_at_10\": 0.0115,\n", + " \"normalized_discounted_cumulative_gain_at_25\": 0.0139,\n", + " \"normalized_discounted_cumulative_gain_at_5\": 0.0104,\n", + " \"precision_at_10\": 0.0016,\n", + " \"precision_at_25\": 0.0011,\n", + " \"precision_at_5\": 0.0025\n", + " },\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"1d22b794-3e6a-47db-887a-e5bd3c9aa61b\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 05:07:54 GMT\",\n", + " \"x-amzn-requestid\": \"1d22b794-3e6a-47db-887a-e5bd3c9aa61b\",\n", + " \"content-length\": \"410\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "get_solution_metrics_response = personalize.get_solution_metrics(\n", " solutionVersionArn = hrnn_solution_version_arn\n", @@ -764,9 +1331,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 49, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "ResourceAlreadyExistsException", + "evalue": "An error occurred (ResourceAlreadyExistsException) when calling the CreateCampaign operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:campaign/personalize-camp-hrnn already exists.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"personalize-camp-hrnn\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0msolutionVersionArn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhrnn_solution_version_arn\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mminProvisionedTPS\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m )\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_api_call\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 314\u001b[0m \"%s() only accepts keyword arguments.\" % py_operation_name)\n\u001b[1;32m 315\u001b[0m \u001b[0;31m# The \"self\" in this scope is referring to the BaseClient.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 316\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_make_api_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moperation_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 317\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 318\u001b[0m \u001b[0m_api_call\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpy_operation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_make_api_call\u001b[0;34m(self, operation_name, api_params)\u001b[0m\n\u001b[1;32m 624\u001b[0m \u001b[0merror_code\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Error\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Code\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 625\u001b[0m \u001b[0merror_class\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_code\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merror_code\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 626\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merror_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparsed_response\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moperation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 627\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 628\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m: An error occurred (ResourceAlreadyExistsException) when calling the CreateCampaign operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:campaign/personalize-camp-hrnn already exists." + ] + } + ], "source": [ "create_campaign_response = personalize.create_campaign(\n", " name = \"personalize-camp-hrnn\",\n", @@ -787,9 +1368,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 50, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Campaign: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -816,9 +1405,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 51, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "USER: A2AM9IPXQKNO8L\n" + ] + } + ], "source": [ "# Getting a random user:\n", "user_id, item_id, _ = useritems.sample().values[0]\n", @@ -827,12 +1424,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "# First load items into memory\n", - "allitemuri = f's3://{bucket}/allitem_w_meta.csv'\n", + "allitemuri = f's3://{bucket}/items_w_metadata.csv'\n", "items = pd.read_csv(allitemuri, sep=',', usecols=[0,1], names=['asin', 'title'], index_col='asin',header=0)\n", "\n", "# print(items)\n", @@ -856,9 +1453,179 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Recommendations for user: A2AM9IPXQKNO8L\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Item Description
0Emergency Mylar Thermal Blankets (Pack of 10)
1Park Tool Vulcanizing Patch Kit - VP-1
2Potable Aqua Water Treatment Tablets
3Petzl E91 Tikkina 2 Headlamp
4GSI Outdoors Glacier Stainless Bottle Cup/Pot
5Gerber 31-000699 Bear Grylls Survival Series F...
6ALPS Mountaineering Compression Sleeping Bag S...
7Eagles Nest Outfitters DryFly Raintarp
8Paracord Planet Type III 7 Strand 550 Paracord...
9Magnesium Fire Starter
10Sawyer Products Mini Water Filtration System
11Maxpedition Fatty Pocket Organizer
12Suisse Sport Adventurer Mummy Ultra-Compactabl...
13Sigma BC 1009 Bicycle Speedometer
14Morakniv Companion Fixed Blade Outdoor Knife w...
15GoHiking Lightweight Burner Classic Camping an...
16Esbit Ultralight Folding Pocket Stove with Six...
17Victorinox Champion Plus Knife
18TETON Sports Explorer4000 Internal Frame Backpack
19Survivor HK-106320 Outdoor Fixed Blade Knife 7...
20Nalgene Tritan Wide Mouth BPA-Free Water Bottl...
21Topeak Aero Wedge Pack with Buckle (Medium)
22Topeak Explorer Bike Rack
23Light My Fire Titanium Spork
24Camelbak Podium Chill Bottle
\n", + "
" + ], + "text/plain": [ + " Item Description\n", + "0 Emergency Mylar Thermal Blankets (Pack of 10)\n", + "1 Park Tool Vulcanizing Patch Kit - VP-1\n", + "2 Potable Aqua Water Treatment Tablets\n", + "3 Petzl E91 Tikkina 2 Headlamp\n", + "4 GSI Outdoors Glacier Stainless Bottle Cup/Pot\n", + "5 Gerber 31-000699 Bear Grylls Survival Series F...\n", + "6 ALPS Mountaineering Compression Sleeping Bag S...\n", + "7 Eagles Nest Outfitters DryFly Raintarp\n", + "8 Paracord Planet Type III 7 Strand 550 Paracord...\n", + "9 Magnesium Fire Starter\n", + "10 Sawyer Products Mini Water Filtration System\n", + "11 Maxpedition Fatty Pocket Organizer\n", + "12 Suisse Sport Adventurer Mummy Ultra-Compactabl...\n", + "13 Sigma BC 1009 Bicycle Speedometer\n", + "14 Morakniv Companion Fixed Blade Outdoor Knife w...\n", + "15 GoHiking Lightweight Burner Classic Camping an...\n", + "16 Esbit Ultralight Folding Pocket Stove with Six...\n", + "17 Victorinox Champion Plus Knife\n", + "18 TETON Sports Explorer4000 Internal Frame Backpack\n", + "19 Survivor HK-106320 Outdoor Fixed Blade Knife 7...\n", + "20 Nalgene Tritan Wide Mouth BPA-Free Water Bottl...\n", + "21 Topeak Aero Wedge Pack with Buckle (Medium)\n", + "22 Topeak Explorer Bike Rack\n", + "23 Light My Fire Titanium Spork\n", + "24 Camelbak Podium Chill Bottle" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "get_recommendations_response = personalize_runtime.get_recommendations(\n", " campaignArn = hrnn_campaign_arn,\n", @@ -905,14 +1672,14 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'Variables': {'Campaign_ARN': 'arn:aws:personalize:us-east-1:011777388888:campaign/personalize-demo-camp', 'ddb_tablename': 'pocstor-Items'}}\n" + "{'Variables': {'Campaign_ARN': 'arn:aws:personalize:us-east-1:387269085412:campaign/personalize-demo-camp', 'ddb_tablename': 'teststr-Items'}}\n" ] } ], @@ -947,7 +1714,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 60, "metadata": {}, "outputs": [ { @@ -956,14 +1723,15 @@ "text": [ "Stored 'Rerank_arn' (str)\n", "Stored 'GetRecommendationsByItem_arn' (str)\n", - "Stored 'PostClickEvent_arn' (str)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "UsageError: Unknown variable 'dataset_group_arn'\n" + "Stored 'PostClickEvent_arn' (str)\n", + "Stored 'dataset_group_arn' (str)\n", + "Stored 'hrnn_campaign_arn' (str)\n", + "Stored 'interactions_dataset_arn' (str)\n", + "Stored 'items_dataset_arn' (str)\n", + "Stored 'useritems' (DataFrame)\n", + "Stored 'recommendations_df' (DataFrame)\n", + "Stored 'bucket' (str)\n", + "Stored 'user_id' (str)\n" ] } ], @@ -977,6 +1745,7 @@ "%store items_dataset_arn\n", "%store useritems\n", "%store recommendations_df\n", + "%store bucket\n", "%store user_id\n" ] }, diff --git a/Personalize/2.Building_Campaign_SIMS.ipynb b/Personalize/2.Building_Campaign_SIMS.ipynb index 05742d8..35234dc 100644 --- a/Personalize/2.Building_Campaign_SIMS.ipynb +++ b/Personalize/2.Building_Campaign_SIMS.ipynb @@ -18,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -52,7 +52,15 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "no stored variable bucket\n" + ] + } + ], "source": [ "%store -r dataset_group_arn\n", "%store -r GetRecommendationsByItem_arn\n", @@ -80,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -106,9 +114,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-sims\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"60b5ef84-1ed6-4fba-a796-e4ed59075573\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 05:09:36 GMT\",\n", + " \"x-amzn-requestid\": \"60b5ef84-1ed6-4fba-a796-e4ed59075573\",\n", + " \"content-length\": \"96\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_solution_response = personalize.create_solution(\n", " name = \"personalize-demo-soln-sims\",\n", @@ -129,9 +159,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionVersionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-sims/82ab4692\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"6539d4eb-cba7-4b55-986d-2f981331a91b\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 05:09:36 GMT\",\n", + " \"x-amzn-requestid\": \"6539d4eb-cba7-4b55-986d-2f981331a91b\",\n", + " \"content-length\": \"112\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_solution_version_response = personalize.create_solution_version(\n", " solutionArn = sims_solution_arn\n", @@ -152,9 +204,56 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SolutionVersion: CREATE PENDING\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: CREATE IN_PROGRESS\n", + "SolutionVersion: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -181,9 +280,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionVersionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-sims/82ab4692\",\n", + " \"metrics\": {\n", + " \"coverage\": 0.0832,\n", + " \"mean_reciprocal_rank_at_25\": 0.0195,\n", + " \"normalized_discounted_cumulative_gain_at_10\": 0.0239,\n", + " \"normalized_discounted_cumulative_gain_at_25\": 0.0261,\n", + " \"normalized_discounted_cumulative_gain_at_5\": 0.0225,\n", + " \"precision_at_10\": 0.003,\n", + " \"precision_at_25\": 0.0015,\n", + " \"precision_at_5\": 0.0051\n", + " },\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"05af6ded-2de7-4498-b96d-dee9f7da4641\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 05:48:39 GMT\",\n", + " \"x-amzn-requestid\": \"05af6ded-2de7-4498-b96d-dee9f7da4641\",\n", + " \"content-length\": \"409\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "get_solution_metrics_response = personalize.get_solution_metrics(\n", " solutionVersionArn = sims_solution_version_arn\n", @@ -210,9 +341,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"campaignArn\": \"arn:aws:personalize:us-east-1:962222257213:campaign/personalize-camp-sims\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"b2790589-b39c-4769-96e5-b9aecad328d2\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 05:48:39 GMT\",\n", + " \"x-amzn-requestid\": \"b2790589-b39c-4769-96e5-b9aecad328d2\",\n", + " \"content-length\": \"91\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_campaign_response = personalize.create_campaign(\n", " name = \"personalize-camp-sims\",\n", @@ -233,9 +386,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Campaign: CREATE PENDING\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: CREATE IN_PROGRESS\n", + "Campaign: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -262,9 +433,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Item: B000A0REKO\n" + ] + } + ], "source": [ "# Getting a random user:\n", "user_id, item_id, _ = useritems.sample().values[0]\n", @@ -273,12 +452,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "# First load items into memory\n", - "allitemuri = f's3://{bucket}/allitem_w_meta.csv'\n", + "%store -r bucket\n", + "allitemuri = f's3://{bucket}/items_w_metadata.csv'\n", "items = pd.read_csv(allitemuri, sep=',', usecols=[0,1], names=['asin', 'title'], index_col='asin',header=0)\n", "\n", "# print(items)\n", @@ -302,9 +482,179 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SIMS for item_id: B000A0REKO\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Item Description
0Butler Creek Lula Universal Pistol Magazine Lo...
1Howard Leight R-01526 Impact Sport Electronic ...
2Rothco 550lb. Type III Nylon Paracord
3Hoppe's BoreSnake Rifle Bore Cleaner (Choose Y...
4Magnesium Fire Starter
5Emergency Mylar Thermal Blankets (Pack of 10)
6OFF SET TACTICAL Weapon Mount For Olight M20/M...
7Butler Creek LULA All-in-One Magazine Speed Lo...
8Morakniv Companion Fixed Blade Outdoor Knife w...
9Ultralight Backpacking Canister Camp Stove wit...
10UTG Tactical OP Bipod - Tactical/Sniper Profil...
11LifeStraw Personal Water Filter
12GDT AR15 AR 15 Front and Rear 45 Degree Rapid ...
13Bushnell Trophy TRS-25 Red Dot Sight Riflescop...
14UTG Bipod, SWAT/Combat Profile, Adjustable Height
15Potable Aqua Water Treatment Tablets
16Rayovac Sportsman LED Lantern SE3DLN
17Mirrycle MTB Bar End Mountain Bicycle Mirror
18Light My Fire Original Swedish FireSteel Army ...
19Survivor HK-106320 Outdoor Fixed Blade Knife 7...
20Hogue Handall Full Size Grip Sleeve
21Ultimate Arms Gear Tactical 4 Reticle Red Dot ...
22Chainmate Cm-24ssp 24-inch Survival Pocket Cha...
23Magpul Gen 2 MBUS Rear Flip Sight, Black
24Cold Steel 80PGTK GI Tanto 7&quot; Carbon
\n", + "
" + ], + "text/plain": [ + " Item Description\n", + "0 Butler Creek Lula Universal Pistol Magazine Lo...\n", + "1 Howard Leight R-01526 Impact Sport Electronic ...\n", + "2 Rothco 550lb. Type III Nylon Paracord\n", + "3 Hoppe's BoreSnake Rifle Bore Cleaner (Choose Y...\n", + "4 Magnesium Fire Starter\n", + "5 Emergency Mylar Thermal Blankets (Pack of 10)\n", + "6 OFF SET TACTICAL Weapon Mount For Olight M20/M...\n", + "7 Butler Creek LULA All-in-One Magazine Speed Lo...\n", + "8 Morakniv Companion Fixed Blade Outdoor Knife w...\n", + "9 Ultralight Backpacking Canister Camp Stove wit...\n", + "10 UTG Tactical OP Bipod - Tactical/Sniper Profil...\n", + "11 LifeStraw Personal Water Filter\n", + "12 GDT AR15 AR 15 Front and Rear 45 Degree Rapid ...\n", + "13 Bushnell Trophy TRS-25 Red Dot Sight Riflescop...\n", + "14 UTG Bipod, SWAT/Combat Profile, Adjustable Height\n", + "15 Potable Aqua Water Treatment Tablets\n", + "16 Rayovac Sportsman LED Lantern SE3DLN\n", + "17 Mirrycle MTB Bar End Mountain Bicycle Mirror\n", + "18 Light My Fire Original Swedish FireSteel Army ...\n", + "19 Survivor HK-106320 Outdoor Fixed Blade Knife 7...\n", + "20 Hogue Handall Full Size Grip Sleeve\n", + "21 Ultimate Arms Gear Tactical 4 Reticle Red Dot ...\n", + "22 Chainmate Cm-24ssp 24-inch Survival Pocket Cha...\n", + "23 Magpul Gen 2 MBUS Rear Flip Sight, Black\n", + "24 Cold Steel 80PGTK GI Tanto 7" Carbon" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "get_recommendations_response = personalize_runtime.get_recommendations(\n", " campaignArn = sims_campaign_arn,\n", @@ -339,14 +689,14 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'Variables': {'Campaign_ARN': 'arn:aws:personalize:us-east-1:011777388888:campaign/personalize-demo-camp-hrnn', 'ddb_tablename': 'pocstor-Items'}}\n" + "{'Variables': {'Campaign_ARN': 'arn:aws:personalize:us-east-1:387269085412:campaign/SIM-campaign', 'ddb_tablename': 'teststr-Items'}}\n" ] } ], diff --git a/Personalize/3.Building_Campaign_P-rank.ipynb b/Personalize/3.Building_Campaign_P-rank.ipynb index 1946165..9e0a942 100644 --- a/Personalize/3.Building_Campaign_P-rank.ipynb +++ b/Personalize/3.Building_Campaign_P-rank.ipynb @@ -18,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -50,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -80,7 +80,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -106,9 +106,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-personal-ranking\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"4122d70a-db86-4d11-8577-53aa3511ae82\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 05:09:41 GMT\",\n", + " \"x-amzn-requestid\": \"4122d70a-db86-4d11-8577-53aa3511ae82\",\n", + " \"content-length\": \"108\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_solution_response = personalize.create_solution(\n", " name = \"personalize-demo-soln-personal-ranking\", # Please change the solution name if you are changing the recipe\n", @@ -129,9 +151,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionVersionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-personal-ranking/c3b11a9a\",\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"e0e61f56-1d22-4179-a930-0c84d42ea0be\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 05:09:41 GMT\",\n", + " \"x-amzn-requestid\": \"e0e61f56-1d22-4179-a930-0c84d42ea0be\",\n", + " \"content-length\": \"124\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "create_solution_version_response = personalize.create_solution_version(\n", " solutionArn = prr_solution_arn\n", @@ -152,9 +196,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SolutionVersion: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -181,9 +233,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"solutionVersionArn\": \"arn:aws:personalize:us-east-1:962222257213:solution/personalize-demo-soln-personal-ranking/c3b11a9a\",\n", + " \"metrics\": {\n", + " \"coverage\": 0.0014,\n", + " \"mean_reciprocal_rank_at_25\": 0.0034,\n", + " \"normalized_discounted_cumulative_gain_at_10\": 0.0051,\n", + " \"normalized_discounted_cumulative_gain_at_25\": 0.0067,\n", + " \"normalized_discounted_cumulative_gain_at_5\": 0.004,\n", + " \"precision_at_10\": 0.0009,\n", + " \"precision_at_25\": 0.0006,\n", + " \"precision_at_5\": 0.0012\n", + " },\n", + " \"ResponseMetadata\": {\n", + " \"RequestId\": \"5b207d94-3a6d-44f3-898f-ab22097aec94\",\n", + " \"HTTPStatusCode\": 200,\n", + " \"HTTPHeaders\": {\n", + " \"content-type\": \"application/x-amz-json-1.1\",\n", + " \"date\": \"Tue, 25 Feb 2020 06:43:12 GMT\",\n", + " \"x-amzn-requestid\": \"5b207d94-3a6d-44f3-898f-ab22097aec94\",\n", + " \"content-length\": \"421\",\n", + " \"connection\": \"keep-alive\"\n", + " },\n", + " \"RetryAttempts\": 0\n", + " }\n", + "}\n" + ] + } + ], "source": [ "get_solution_metrics_response = personalize.get_solution_metrics(\n", " solutionVersionArn = prr_solution_version_arn\n", @@ -210,9 +294,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "ResourceAlreadyExistsException", + "evalue": "An error occurred (ResourceAlreadyExistsException) when calling the CreateCampaign operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:campaign/personalize-campaign-reranking already exists.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"personalize-campaign-reranking\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0msolutionVersionArn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mprr_solution_version_arn\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mminProvisionedTPS\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m )\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_api_call\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 314\u001b[0m \"%s() only accepts keyword arguments.\" % py_operation_name)\n\u001b[1;32m 315\u001b[0m \u001b[0;31m# The \"self\" in this scope is referring to the BaseClient.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 316\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_make_api_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moperation_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 317\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 318\u001b[0m \u001b[0m_api_call\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpy_operation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_make_api_call\u001b[0;34m(self, operation_name, api_params)\u001b[0m\n\u001b[1;32m 624\u001b[0m \u001b[0merror_code\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Error\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Code\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 625\u001b[0m \u001b[0merror_class\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_code\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merror_code\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 626\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merror_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparsed_response\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moperation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 627\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 628\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mResourceAlreadyExistsException\u001b[0m: An error occurred (ResourceAlreadyExistsException) when calling the CreateCampaign operation: Another resource with Arn arn:aws:personalize:us-east-1:962222257213:campaign/personalize-campaign-reranking already exists." + ] + } + ], "source": [ "create_campaign_response = personalize.create_campaign(\n", " name = \"personalize-campaign-reranking\",\n", @@ -233,9 +331,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Campaign: ACTIVE\n" + ] + } + ], "source": [ "max_time = time.time() + 3*60*60 # 3 hours\n", "while time.time() < max_time:\n", @@ -261,7 +367,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -282,12 +388,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "# First load items into memory\n", - "allitemuri = f's3://{bucket}/allitem_w_meta.csv'\n", + "%store -r bucket\n", + "allitemuri = f's3://{bucket}/items_w_metadata.csv'\n", "items = pd.read_csv(allitemuri, sep=',', usecols=[0,1], names=['asin', 'title'], index_col='asin',header=0)\n", "\n", "# print(items)\n", @@ -297,7 +404,7 @@ " Takes in an ID, returns a title\n", " \"\"\"\n", " asin = str(asin)\n", - " return items.loc[asin]['title']\n" + " return items.loc[asin]['title']" ] }, { @@ -311,9 +418,154 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Recommendations for user: A1LWN1D2XNSSYJ\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Item Description
0Butler Creek Lula Universal Pistol Magazine Lo...
1Pro-Shot .22-.45 Caliber Brass Patch Holder
2HiMart Side Picatinny Mount for Tactical Flash...
3Harris Engineering S-BRM Hinged Base 6 - 9-Inc...
4NaN
5Magpul iPhone 4 Executive Field Case, Black
6UTG 2-in-1 Tactical LED Flashlight with Red Laser
78&quot; Round Birchwood Casey Shoot - N - C Se...
8Kershaw 1660 Ken Onion Leek Folding Knife with...
9308 SR-25 / AR-10 Lower Receiver Vise Block Ar...
10Govt Spring Set
11Invicta Men's Speedway 9211
12Topeak Alien II 26-Function Bicycle Tool
13Signal Mirror
14Kershaw Zing-Tanto Blade
15Schwinn 20-Function Bike Computer
16Topeak Road Morph G Bike Pump with Gauge
17Ibera PakRak Bicycle Touring Carrier Plus+ IB-...
18Topeak The Mini 9-Function Bicycle Tool
19Smart Health Walking FIT
\n", + "
" + ], + "text/plain": [ + " Item Description\n", + "0 Butler Creek Lula Universal Pistol Magazine Lo...\n", + "1 Pro-Shot .22-.45 Caliber Brass Patch Holder\n", + "2 HiMart Side Picatinny Mount for Tactical Flash...\n", + "3 Harris Engineering S-BRM Hinged Base 6 - 9-Inc...\n", + "4 NaN\n", + "5 Magpul iPhone 4 Executive Field Case, Black\n", + "6 UTG 2-in-1 Tactical LED Flashlight with Red Laser\n", + "7 8" Round Birchwood Casey Shoot - N - C Se...\n", + "8 Kershaw 1660 Ken Onion Leek Folding Knife with...\n", + "9 308 SR-25 / AR-10 Lower Receiver Vise Block Ar...\n", + "10 Govt Spring Set\n", + "11 Invicta Men's Speedway 9211\n", + "12 Topeak Alien II 26-Function Bicycle Tool\n", + "13 Signal Mirror\n", + "14 Kershaw Zing-Tanto Blade\n", + "15 Schwinn 20-Function Bike Computer\n", + "16 Topeak Road Morph G Bike Pump with Gauge\n", + "17 Ibera PakRak Bicycle Touring Carrier Plus+ IB-...\n", + "18 Topeak The Mini 9-Function Bicycle Tool\n", + "19 Smart Health Walking FIT" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "get_recommendations_response = personalize_runtime.get_personalized_ranking(\n", " campaignArn=prr_campaign_arn,\n", @@ -347,14 +599,14 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'Variables': {'DDB_TABLE': 'pocstor-Items', 'SEARCH_ARN': 'arn:aws:lambda:us-east-1:011777388888:function:pocstor-Search', 'RANKING_ARN': 'arn:aws:personalize:us-east-1:387269085412:campaign/personalize-demo-soln-ranking', 'ESENDPOINT': 'vpc-pocstor-domain-nntynxw4xefxwai4skjrw2exvq.us-east-1.es.amazonaws.com'}}\n" + "{'Variables': {'DDB_TABLE': 'teststr-Items', 'SEARCH_ARN': 'arn:aws:lambda:us-east-1:962222257213:function:teststr-Search', 'RANKING_ARN': 'arn:aws:personalize:us-east-1:387269085412:campaign/personalize-demo-soln-ranking', 'ESENDPOINT': 'vpc-teststr-domain-yyb6n76pkinseg5whgedynqqve.us-east-1.es.amazonaws.com'}}\n" ] } ], @@ -390,13 +642,6 @@ "\n" ] }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "code", "execution_count": null, diff --git a/Personalize/4.View_Campaign_And_Interactions_jit.ipynb b/Personalize/4.View_Campaign_And_Interactions_jit.ipynb index ad34171..5eb3138 100644 --- a/Personalize/4.View_Campaign_And_Interactions_jit.ipynb +++ b/Personalize/4.View_Campaign_And_Interactions_jit.ipynb @@ -15,11 +15,7 @@ }, { "cell_type": "markdown", - "metadata": { - "jupyter": { - "source_hidden": true - } - }, + "metadata": {}, "source": [ "Below we start with just importing libraries that we need to interact with Personalize" ] @@ -48,9 +44,17 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "no stored variable bucket\n" + ] + } + ], "source": [ "# Setup and Config\n", "# Recommendations from Event data\n", @@ -75,20 +79,15 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 3, "metadata": {}, "outputs": [ { - "ename": "ResourceAlreadyExistsException", - "evalue": "An error occurred (ResourceAlreadyExistsException) when calling the CreateEventTracker operation: EventTracker arn:aws:personalize:us-east-1:011777388888:event-tracker/a500b4a4 already exists for DatasetGroup arn:aws:personalize:us-east-1:011777388888:dataset-group/personalize-launch-demo", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mResourceAlreadyExistsException\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m response = personalize.create_event_tracker(\n\u001b[1;32m 2\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'AllstoreClickTracker'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mdatasetGroupArn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdataset_group_arn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m )\n\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'eventTrackerArn'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_api_call\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 355\u001b[0m \"%s() only accepts keyword arguments.\" % py_operation_name)\n\u001b[1;32m 356\u001b[0m \u001b[0;31m# The \"self\" in this scope is referring to the BaseClient.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 357\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_make_api_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moperation_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 358\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 359\u001b[0m \u001b[0m_api_call\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpy_operation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/envs/python3/lib/python3.6/site-packages/botocore/client.py\u001b[0m in \u001b[0;36m_make_api_call\u001b[0;34m(self, operation_name, api_params)\u001b[0m\n\u001b[1;32m 659\u001b[0m \u001b[0merror_code\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Error\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Code\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 660\u001b[0m \u001b[0merror_class\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_code\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merror_code\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 661\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merror_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparsed_response\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moperation_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 662\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 663\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mparsed_response\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mResourceAlreadyExistsException\u001b[0m: An error occurred (ResourceAlreadyExistsException) when calling the CreateEventTracker operation: EventTracker arn:aws:personalize:us-east-1:011777388888:event-tracker/a500b4a4 already exists for DatasetGroup arn:aws:personalize:us-east-1:011777388888:dataset-group/personalize-launch-demo" + "name": "stdout", + "output_type": "stream", + "text": [ + "arn:aws:personalize:us-east-1:962222257213:event-tracker/9c23a5a5\n", + "bfff7247-1fb1-46ca-b80d-8abc1bf675f6\n" ] } ], @@ -111,7 +110,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -129,12 +128,13 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ + "%store -r bucket\n", "# First load items into memory\n", - "allitemuri = f's3://{bucket}/allitem_w_meta.csv'\n", + "allitemuri = f's3://{bucket}/items_w_metadata.csv'\n", "items = pd.read_csv(allitemuri,sep=',', usecols=[0,1], encoding='utf-8', names=['ITEM_ID', 'TITLE','IMGURL','GENRE'], index_col='ITEM_ID')\n", "\n", "def get_product_title(product_id):\n", @@ -156,19 +156,170 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 31, "metadata": {}, "outputs": [ { - "ename": "NameError", - "evalue": "name 'recommendations_df' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrecommendations_df\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mNameError\u001b[0m: name 'recommendations_df' is not defined" - ] + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Item Description
0Emergency Mylar Thermal Blankets (Pack of 10)
1Park Tool Vulcanizing Patch Kit - VP-1
2Potable Aqua Water Treatment Tablets
3Petzl E91 Tikkina 2 Headlamp
4GSI Outdoors Glacier Stainless Bottle Cup/Pot
5Gerber 31-000699 Bear Grylls Survival Series F...
6ALPS Mountaineering Compression Sleeping Bag S...
7Eagles Nest Outfitters DryFly Raintarp
8Paracord Planet Type III 7 Strand 550 Paracord...
9Magnesium Fire Starter
10Sawyer Products Mini Water Filtration System
11Maxpedition Fatty Pocket Organizer
12Suisse Sport Adventurer Mummy Ultra-Compactabl...
13Sigma BC 1009 Bicycle Speedometer
14Morakniv Companion Fixed Blade Outdoor Knife w...
15GoHiking Lightweight Burner Classic Camping an...
16Esbit Ultralight Folding Pocket Stove with Six...
17Victorinox Champion Plus Knife
18TETON Sports Explorer4000 Internal Frame Backpack
19Survivor HK-106320 Outdoor Fixed Blade Knife 7...
20Nalgene Tritan Wide Mouth BPA-Free Water Bottl...
21Topeak Aero Wedge Pack with Buckle (Medium)
22Topeak Explorer Bike Rack
23Light My Fire Titanium Spork
24Camelbak Podium Chill Bottle
\n", + "
" + ], + "text/plain": [ + " Item Description\n", + "0 Emergency Mylar Thermal Blankets (Pack of 10)\n", + "1 Park Tool Vulcanizing Patch Kit - VP-1\n", + "2 Potable Aqua Water Treatment Tablets\n", + "3 Petzl E91 Tikkina 2 Headlamp\n", + "4 GSI Outdoors Glacier Stainless Bottle Cup/Pot\n", + "5 Gerber 31-000699 Bear Grylls Survival Series F...\n", + "6 ALPS Mountaineering Compression Sleeping Bag S...\n", + "7 Eagles Nest Outfitters DryFly Raintarp\n", + "8 Paracord Planet Type III 7 Strand 550 Paracord...\n", + "9 Magnesium Fire Starter\n", + "10 Sawyer Products Mini Water Filtration System\n", + "11 Maxpedition Fatty Pocket Organizer\n", + "12 Suisse Sport Adventurer Mummy Ultra-Compactabl...\n", + "13 Sigma BC 1009 Bicycle Speedometer\n", + "14 Morakniv Companion Fixed Blade Outdoor Knife w...\n", + "15 GoHiking Lightweight Burner Classic Camping an...\n", + "16 Esbit Ultralight Folding Pocket Stove with Six...\n", + "17 Victorinox Champion Plus Knife\n", + "18 TETON Sports Explorer4000 Internal Frame Backpack\n", + "19 Survivor HK-106320 Outdoor Fixed Blade Knife 7...\n", + "20 Nalgene Tritan Wide Mouth BPA-Free Water Bottl...\n", + "21 Topeak Aero Wedge Pack with Buckle (Medium)\n", + "22 Topeak Explorer Bike Rack\n", + "23 Light My Fire Titanium Spork\n", + "24 Camelbak Podium Chill Bottle" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -188,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -197,7 +348,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -245,21 +396,9 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 36, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'user_id' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mproduct_to_click\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1881509818\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mproduct_title_clicked\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mget_product_title\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mproduct_to_click\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0msend_product_click\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mUSER_ID\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser_id\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mITEM_ID\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mproduct_to_click\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mNameError\u001b[0m: name 'user_id' is not defined" - ] - } - ], + "outputs": [], "source": [ "# Pick a product_ID, we will use '1881509818'\n", "product_to_click = 1881509818\n", @@ -276,22 +415,234 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 37, "metadata": {}, "outputs": [ { - "ename": "NameError", - "evalue": "name 'hrnn_campaign_arn' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m get_recommendations_response = personalize_runtime.get_recommendations(\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mcampaignArn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhrnn_campaign_arn\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0muserId\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser_id\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m )\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'hrnn_campaign_arn' is not defined" + "name": "stdout", + "output_type": "stream", + "text": [ + "Recommendations for user: A2AM9IPXQKNO8L\n" ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Item DescriptionNew Recommendations
0Emergency Mylar Thermal Blankets (Pack of 10)Emergency Mylar Thermal Blankets (Pack of 10)
1Park Tool Vulcanizing Patch Kit - VP-1Rothco 550lb. Type III Nylon Paracord
2Potable Aqua Water Treatment TabletsButler Creek Lula Universal Pistol Magazine Lo...
3Petzl E91 Tikkina 2 HeadlampALPS Mountaineering Compression Sleeping Bag S...
4GSI Outdoors Glacier Stainless Bottle Cup/PotCondor Molle Gadget Pouch
5Gerber 31-000699 Bear Grylls Survival Series F...Petzl E91 Tikkina 2 Headlamp
6ALPS Mountaineering Compression Sleeping Bag S...Tac Force TF-705 Series Assisted Opening Foldi...
7Eagles Nest Outfitters DryFly RaintarpMorakniv Companion Fixed Blade Outdoor Knife w...
8Paracord Planet Type III 7 Strand 550 Paracord...WarTech USA Batman Knife with Dual Assist Open...
9Magnesium Fire StarterChampion Men's Compression Short
10Sawyer Products Mini Water Filtration SystemMorakniv Companion Fixed Blade Outdoor Knife w...
11Maxpedition Fatty Pocket OrganizerTac Force TF-711 Series Assisted Opening Foldi...
12Suisse Sport Adventurer Mummy Ultra-Compactabl...Gerber 31-000699 Bear Grylls Survival Series F...
13Sigma BC 1009 Bicycle SpeedometerMaxpedition Fatty Pocket Organizer
14Morakniv Companion Fixed Blade Outdoor Knife w...GoHiking Lightweight Burner Classic Camping an...
15GoHiking Lightweight Burner Classic Camping an...Kershaw 1556TI Cryo II Folding Knife
16Esbit Ultralight Folding Pocket Stove with Six...Soffe Men's Classic Cotton Pocket Short
17Victorinox Champion Plus KnifeUltralight Backpacking Canister Camp Stove wit...
18TETON Sports Explorer4000 Internal Frame BackpackThermarest Compressible Pillow
19Survivor HK-106320 Outdoor Fixed Blade Knife 7...Light My Fire Original Swedish FireSteel Scout...
20Nalgene Tritan Wide Mouth BPA-Free Water Bottl...Champion Men's Performance 2 Pack Stretch Boxe...
21Topeak Aero Wedge Pack with Buckle (Medium)MSR - GroundHog Stakes - 8 Pack
22Topeak Explorer Bike RackQuikClot Sport, Advanced Clotting Sponge 25G
23Light My Fire Titanium SporkKA-BAR #1216 Hard Knife Sheath
24Camelbak Podium Chill BottleTETON Sports Explorer4000 Internal Frame Backpack
\n", + "
" + ], + "text/plain": [ + " Item Description \\\n", + "0 Emergency Mylar Thermal Blankets (Pack of 10) \n", + "1 Park Tool Vulcanizing Patch Kit - VP-1 \n", + "2 Potable Aqua Water Treatment Tablets \n", + "3 Petzl E91 Tikkina 2 Headlamp \n", + "4 GSI Outdoors Glacier Stainless Bottle Cup/Pot \n", + "5 Gerber 31-000699 Bear Grylls Survival Series F... \n", + "6 ALPS Mountaineering Compression Sleeping Bag S... \n", + "7 Eagles Nest Outfitters DryFly Raintarp \n", + "8 Paracord Planet Type III 7 Strand 550 Paracord... \n", + "9 Magnesium Fire Starter \n", + "10 Sawyer Products Mini Water Filtration System \n", + "11 Maxpedition Fatty Pocket Organizer \n", + "12 Suisse Sport Adventurer Mummy Ultra-Compactabl... \n", + "13 Sigma BC 1009 Bicycle Speedometer \n", + "14 Morakniv Companion Fixed Blade Outdoor Knife w... \n", + "15 GoHiking Lightweight Burner Classic Camping an... \n", + "16 Esbit Ultralight Folding Pocket Stove with Six... \n", + "17 Victorinox Champion Plus Knife \n", + "18 TETON Sports Explorer4000 Internal Frame Backpack \n", + "19 Survivor HK-106320 Outdoor Fixed Blade Knife 7... \n", + "20 Nalgene Tritan Wide Mouth BPA-Free Water Bottl... \n", + "21 Topeak Aero Wedge Pack with Buckle (Medium) \n", + "22 Topeak Explorer Bike Rack \n", + "23 Light My Fire Titanium Spork \n", + "24 Camelbak Podium Chill Bottle \n", + "\n", + " New Recommendations \n", + "0 Emergency Mylar Thermal Blankets (Pack of 10) \n", + "1 Rothco 550lb. Type III Nylon Paracord \n", + "2 Butler Creek Lula Universal Pistol Magazine Lo... \n", + "3 ALPS Mountaineering Compression Sleeping Bag S... \n", + "4 Condor Molle Gadget Pouch \n", + "5 Petzl E91 Tikkina 2 Headlamp \n", + "6 Tac Force TF-705 Series Assisted Opening Foldi... \n", + "7 Morakniv Companion Fixed Blade Outdoor Knife w... \n", + "8 WarTech USA Batman Knife with Dual Assist Open... \n", + "9 Champion Men's Compression Short \n", + "10 Morakniv Companion Fixed Blade Outdoor Knife w... \n", + "11 Tac Force TF-711 Series Assisted Opening Foldi... \n", + "12 Gerber 31-000699 Bear Grylls Survival Series F... \n", + "13 Maxpedition Fatty Pocket Organizer \n", + "14 GoHiking Lightweight Burner Classic Camping an... \n", + "15 Kershaw 1556TI Cryo II Folding Knife \n", + "16 Soffe Men's Classic Cotton Pocket Short \n", + "17 Ultralight Backpacking Canister Camp Stove wit... \n", + "18 Thermarest Compressible Pillow \n", + "19 Light My Fire Original Swedish FireSteel Scout... \n", + "20 Champion Men's Performance 2 Pack Stretch Boxe... \n", + "21 MSR - GroundHog Stakes - 8 Pack \n", + "22 QuikClot Sport, Advanced Clotting Sponge 25G \n", + "23 KA-BAR #1216 Hard Knife Sheath \n", + "24 TETON Sports Explorer4000 Internal Frame Backpack " + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ + "%store -r hrnn_campaign_arn\n", "get_recommendations_response = personalize_runtime.get_recommendations(\n", " campaignArn = hrnn_campaign_arn,\n", " userId = str(user_id),\n", @@ -302,15 +653,14 @@ "item_list = get_recommendations_response['itemList']\n", "\n", "recommendation_list = []\n", - "\n", "for item in item_list:\n", " title = get_product_title(item['itemId'])\n", " recommendation_list.append(title)\n", " \n", - "new_rec_DF = pd.DataFrame(recommendation_list, columns = [product_title_clicked])\n", - "\n", - "recommendations_df = recommendations_df.join(new_rec_DF)\n", - "recommendations_df" + "new_rec_DF = pd.DataFrame(recommendation_list,columns =['New Recommendations'])\n", + "com_recommendations_df = recommendations_df.join(new_rec_DF)\n", + "com_recommendations_df\n", + "\n" ] }, { @@ -322,7 +672,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 38, "metadata": {}, "outputs": [ { diff --git a/README.md b/README.md index ab8abe2..b6e4a64 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Folder Structure -``` +``` Tree ├── Personalize [DataPipeline Notebook] │ ├── 1.Building_Campaign_HRNN.ipynb │ ├── 2.Building_Campaign_P-rank.ipynb @@ -37,9 +37,10 @@ ## Deployment Prerequisites -In order to deploy this stack, you'll need: +In order to deploy this stack, you'll need: + +### Installed on your machine -### Installed on your machine: 1. [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) pointed to your target account and region with `aws configure` 1. [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 1. [Docker Desktop](https://www.docker.com/products/docker-desktop) @@ -47,12 +48,13 @@ In order to deploy this stack, you'll need: * [NodeJS v12](https://nodejs.org/en/download/) (You may wish to install Node via the **Node Version Manager** for [Mac/Linux](https://github.com/nvm-sh/nvm#installing-and-updating) or [Windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows)). * If you see Web UI build errors relating to an incompatible version of [Python](https://www.python.org/), you may need to install additional versions of Python via [pyenv](https://github.com/pyenv/pyenv#simple-python-version-management-pyenv) (recommended), [conda](https://docs.conda.io/en/latest/), or any other Python environment management tool of your choice. -### On the AWS cloud: +### On the AWS cloud + 1. Access (and [access keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)) to an AWS Account, with sufficient permissions to create all the required resources. 2. An S3 Bucket to package the source code to, in the same AWS region as you expect to deploy. 3. Created a service linked role for ES, as below in AWS CLI: -``` +``` bash aws iam create-service-linked-role \ --aws-service-name es.amazonaws.com \ --description "My service-linked role to Amazon ElasticSearch" @@ -63,7 +65,8 @@ aws iam create-service-linked-role \ ### Step 1: Build and deploy the stack Run the deployment script, with parameters as follows: -```bin/bash + +``` bash sh deploy.sh ``` @@ -88,13 +91,21 @@ This may take up to and over an hour to complete, mostly on the deployment of in * GetRecommendations * GetRecommendationsByItem 3. In the environment section and replace the ARN with the one create from jupyter notebook. +4. Goto ``/webui``, Open config.tsx file and edit the following varible + * Apitree + * AnonymousPoolId + * StreamName # API doc + +API Document + ## /items/{id} + Get item by item id (asin) ``` HTTP GET -https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/items/B00004NKIQ +https://${Apitree}/withtag/items/B00004NKIQ ``` ``` Respose Example @@ -107,10 +118,11 @@ https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/items/B00004NKIQ ``` ## /recommendations + Get item recommendations anonymously ``` HTTP GET -https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/recommendations/ +https://${Apitree}/withtag/recommendations/ ``` ``` Respose Example @@ -128,10 +140,11 @@ https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/recommendations/ ``` ## /recommendations/{userId} + Get personalize recommendations for userId ``` HTTP GET -https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/recommendations/A1L5P841VIO02V +https://${Apitree}/withtag/recommendations/A1L5P841VIO02V ``` ``` Respose Example @@ -149,10 +162,11 @@ https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/recommendations/A ``` ## /recommendationsitem/{itemId} + Get personalize recommendations base on item similarity ``` HTTP GET -https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/recommendationsitem/2094869245 +https://${Apitree}/withtag/recommendationsitem/2094869245 ``` ``` Respose Example @@ -170,11 +184,12 @@ https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/recommendationsit ``` ## /search?q={query} + Searching ⚠️ {query} cannot be null ``` HTTP GET -https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/search?q=Gun +https://${Apitree}/withtag/search?q=Gun ``` ``` Respose Example @@ -192,11 +207,12 @@ https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/search?q=Gun ``` ## /search?q={query}&u={userid} + Personalize Search ⚠️ {query} cannot be null ``` HTTP GET -https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/search?q=Gun&u=A1L5P841VIO02V +https://${Apitree}/withtag/search?q=Gun&u=A1L5P841VIO02V ``` ``` Respose Example @@ -212,23 +228,3 @@ https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/search?q=Gun&u=A1 "title": "Tipton Gun Vise" }, ..] ``` - -## /clickevent -Submit Click event to kinesis for realtime recommendation - -``` HTTP POST -https://jpn8qvh7ci.execute-api.us-east-1.amazonaws.com/withtag/clickevent - -{ - "userID" : "AB2W04NI4OEAD", - "itemID" : "A148SVSWKTJKU6", - "sessionID" : "AB2W04NI4OEAD" -} -``` - -``` Respose Example -{ - "SequenceNumber": "49602401777761666870538776314728212113850425834150559746", - "ShardId": "shardId-000000000000" -} -``` \ No newline at end of file diff --git a/functions/APIs/PostClickEvent/index.py b/functions/APIs/PostClickEvent/index.py index 7a6c73d..ca5141c 100644 --- a/functions/APIs/PostClickEvent/index.py +++ b/functions/APIs/PostClickEvent/index.py @@ -1,58 +1,44 @@ -from __future__ import print_function - import base64 import json import uuid import boto3 import time +import os +personalize_events = boto3.client(service_name='personalize-events') def handler(event, context): - #print("Received event: " + json.dumps(event, indent=2)) - print("Look Here!!!!!") - for record in event['Records']: # Kinesis data is base64 encoded so decode here payload = base64.b64decode(record['kinesis']['data']) - print(event) - try: - clickEvent = json.loads (payload) - print (clickEvent) - send_movie_click(clickEvent) - print ("Post Event to Personalize Successfully") - except: - print ("Record Failed Processing") + clickEvent = json.loads (payload) + print ('clickEvent: ',clickEvent) + send_clickEvent(clickEvent) + print ("Post Event to Personalize Successfully") + return "Post Event to Personalize Successfully" -def send_movie_click(clickEvent): - """ - Simulates a click as an envent - to send an event to Amazon Personalize's Event Tracker - """ - personalize_events = boto3.client(service_name='personalize-events') - # Configure Session + +def send_clickEvent(clickEvent): try: session_ID = clickEvent['sessionID'] except: session_ID = str(uuid.uuid1()) - # Configure Properties: event = { - "itemId": str(clickEvent['itemID']), + "itemId": str(clickEvent['itemID']), } event_json = json.dumps(event) - print ("**********") - print (session_ID) + print ("SID ",session_ID) # Make Call - personalize_events.put_events( - trackingId = os.environ["TRACKING_ID"], - userId= clickEvent['userID'], - sessionId = session_ID, - eventList = [{ + response = personalize_events.put_events( + trackingId = os.environ["TRACKING_ID"], + userId= clickEvent['userID'], + sessionId = session_ID, + eventList = [{ 'sentAt': int(time.time()), 'eventType': 'EVENT_TYPE', 'properties': event_json }] - ) - + ) \ No newline at end of file diff --git a/package.yaml b/package.yaml deleted file mode 100644 index a68e001..0000000 --- a/package.yaml +++ /dev/null @@ -1,827 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Parameters: - ProjectName: - Description: project. - Type: String - Default: ItemStore -Conditions: - IADRegion: - Fn::Equals: - - Ref: AWS::Region - - us-east-1 -Globals: - Function: - Timeout: 180 - Api: - EndpointConfiguration: REGIONAL - Cors: - AllowMethods: '''*''' - AllowHeaders: '''*''' - AllowOrigin: '''*''' -Resources: - ItemStoreVPC: - Type: AWS::EC2::VPC - Properties: - CidrBlock: 172.31.0.0/16 - ItemStoreInternetGateway: - Type: AWS::EC2::InternetGateway - ItemStoreAttachGateway: - Type: AWS::EC2::VPCGatewayAttachment - Properties: - InternetGatewayId: - Ref: ItemStoreInternetGateway - VpcId: - Ref: ItemStoreVPC - ItemStoreSubnet1: - Type: AWS::EC2::Subnet - Properties: - CidrBlock: - Fn::Select: - - 0 - - Fn::Cidr: - - Fn::GetAtt: - - ItemStoreVPC - - CidrBlock - - 3 - - 8 - VpcId: - Ref: ItemStoreVPC - AvailabilityZone: - Fn::Select: - - 0 - - Fn::GetAZs: - Ref: AWS::Region - ItemStoreSubnet2: - Type: AWS::EC2::Subnet - Properties: - CidrBlock: - Fn::Select: - - 1 - - Fn::Cidr: - - Fn::GetAtt: - - ItemStoreVPC - - CidrBlock - - 3 - - 8 - VpcId: - Ref: ItemStoreVPC - AvailabilityZone: - Fn::Select: - - 1 - - Fn::GetAZs: - Ref: AWS::Region - ItemStoreVPCRouteTable: - Type: AWS::EC2::RouteTable - Properties: - VpcId: - Ref: ItemStoreVPC - ItemStoreVPCPublicRouteTable: - Type: AWS::EC2::RouteTable - Properties: - VpcId: - Ref: ItemStoreVPC - RouteToInternet: - Type: AWS::EC2::Route - Properties: - RouteTableId: - Ref: ItemStoreVPCPublicRouteTable - DestinationCidrBlock: 0.0.0.0/0 - GatewayId: - Ref: ItemStoreInternetGateway - ItemStoreVPCRouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - RouteTableId: - Ref: ItemStoreVPCRouteTable - SubnetId: - Ref: ItemStoreSubnet1 - ItemStoreVPCRouteTableAssociationTwo: - DependsOn: RouteToInternet - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - RouteTableId: - Ref: ItemStoreVPCPublicRouteTable - SubnetId: - Ref: ItemStoreSubnet2 - DynamoDbRole: - Type: AWS::IAM::Role - Properties: - RoleName: - Fn::Sub: ${ProjectName}-DynamoDbLambda - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - Action: - - sts:AssumeRole - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess - Policies: - - PolicyName: TableItemsAccess - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - dynamodb:PutItem - - dynamodb:Query - - dynamodb:UpdateTable - - dynamodb:UpdateItem - - dynamodb:BatchWriteItem - - dynamodb:GetItem - - dynamodb:Scan - - dynamodb:DeleteItem - Resource: - - Fn::GetAtt: - - TableItems - - Arn - - Fn::Join: - - '' - - - Fn::GetAtt: - - TableItems - - Arn - - /* - APIGateWayRole: - Type: AWS::IAM::Role - Properties: - RoleName: - Fn::Sub: ${ProjectName}-APIGateWayRole - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - apigateway.amazonaws.com - Action: - - sts:AssumeRole - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs - - arn:aws:iam::aws:policy/AmazonKinesisFullAccess - TableItems: - Type: AWS::DynamoDB::Table - Properties: - TableName: - Fn::Sub: ${ProjectName}-Items - AttributeDefinitions: - - AttributeName: asin - AttributeType: S - KeySchema: - - AttributeName: asin - KeyType: HASH - ProvisionedThroughput: - ReadCapacityUnits: 1 - WriteCapacityUnits: 1 - StreamSpecification: - StreamViewType: NEW_AND_OLD_IMAGES - LambdaAdminRole: - Type: AWS::IAM::Role - Properties: - RoleName: - Fn::Sub: ${ProjectName}-LambdaAdminRole - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - Action: - - sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/AdministratorAccess - ESSearchRole: - Type: AWS::IAM::Role - Properties: - RoleName: - Fn::Sub: ${ProjectName}-ESSearchRole - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - Action: - - sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole - Policies: - - PolicyName: - Fn::Sub: ${ProjectName}-lambda-policy - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - es:ESHttpPost - - es:ESHttpGet - Resource: - Fn::Join: - - '' - - - 'arn:aws:es:' - - Ref: AWS::Region - - ':' - - Ref: AWS::AccountId - - :domain/ - - Ref: ElasticsearchDomain - - /* - - Effect: Allow - Action: - - s3:ListBucket - - s3:GetObject - Resource: '*' - - Effect: Allow - Action: - - dynamodb:DescribeStream - - dynamodb:GetRecords - - dynamodb:GetShardIterator - - dynamodb:ListStreams - Resource: - - Fn::GetAtt: - - TableItems - - Arn - - Fn::Join: - - '' - - - Fn::GetAtt: - - TableItems - - Arn - - /stream/* - ElasticsearchDomain: - Type: AWS::Elasticsearch::Domain - Properties: - DomainName: - Fn::Sub: ${ProjectName}-domain - ElasticsearchVersion: '7.1' - ElasticsearchClusterConfig: - DedicatedMasterEnabled: false - InstanceCount: 1 - ZoneAwarenessEnabled: false - InstanceType: t2.small.elasticsearch - VPCOptions: - SubnetIds: - - Ref: ItemStoreSubnet1 - EBSOptions: - EBSEnabled: true - Iops: 0 - VolumeSize: 10 - VolumeType: gp2 - AccessPolicies: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - AWS: '*' - Action: - - es:* - Resource: - Fn::Join: - - '' - - - 'arn:aws:es:' - - Ref: AWS::Region - - ':' - - Ref: AWS::AccountId - - :domain/ - - Fn::Sub: ${ProjectName}-domain - - /* - AdvancedOptions: - rest.action.multi.allow_explicit_index: 'true' - UpdateSearchCluster: - Type: AWS::Serverless::Function - DependsOn: - - TableItems - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-UpdateSearchCluster - Description: Update Elasticsearch cluster as items are added - Handler: index.handler - Role: - Fn::GetAtt: - - ESSearchRole - - Arn - Runtime: python3.8 - Timeout: 60 - VpcConfig: - SecurityGroupIds: - - Fn::GetAtt: - - ItemStoreVPC - - DefaultSecurityGroup - SubnetIds: - - Ref: ItemStoreSubnet1 - CodeUri: s3://panyapoc-testsrc/1f802fba366e9f55e9846dae24e94ff5 - Environment: - Variables: - ESENDPOINT: - Fn::GetAtt: - - ElasticsearchDomain - - DomainEndpoint - REGION: - Ref: AWS::Region - Events: - DynamoDB: - Type: DynamoDB - Properties: - Stream: - Fn::GetAtt: - - TableItems - - StreamArn - StartingPosition: TRIM_HORIZON - BatchSize: 1 - Enabled: true - FunctionGetItem: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-GetItem - Description: Get item by id - Handler: getItem.handler - MemorySize: 256 - Runtime: nodejs12.x - Role: - Fn::GetAtt: - - DynamoDbRole - - Arn - Timeout: 120 - Environment: - Variables: - TABLE_NAME: - Fn::Sub: ${ProjectName}-Items - CodeUri: s3://panyapoc-testsrc/6d18b27e82aa1547b76da3d1230e45de - Events: - APIgateway: - Type: Api - Properties: - Path: /items/{id} - Method: get - FunctionGetItemDescription: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-GetItemDescription - Description: Get item description by id from Amazon - Handler: main.handler - MemorySize: 1344 - Runtime: nodejs12.x - Role: - Fn::GetAtt: - - LambdaAdminRole - - Arn - Timeout: 60 - Environment: - Variables: - CUSTOM_CHROME: 'true' - CodeUri: s3://panyapoc-testsrc/f154d4e9a46600912b03e9d0ec895a3c - Events: - APIgateway: - Type: Api - Properties: - Path: /description - Method: get - FunctionListItems: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-ListItems - Description: Get list of items by category - Handler: listItems.handler - MemorySize: 256 - Runtime: nodejs12.x - Role: - Fn::GetAtt: - - DynamoDbRole - - Arn - Timeout: 120 - Environment: - Variables: - TABLE_NAME: - Fn::Sub: ${ProjectName}-Items - CodeUri: s3://panyapoc-testsrc/bb1cecd876f55d60ffe7a4072604ccbe - Events: - APIgateway: - Type: Api - Properties: - Path: /items - Method: get - FunctionUploadItems: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-UploadItems - Description: Upload sample data for items - Handler: uploadItemscsv.handler - Runtime: nodejs12.x - Role: - Fn::GetAtt: - - DynamoDbRole - - Arn - Timeout: 120 - MemorySize: 512 - Environment: - Variables: - TABLE_NAME: - Fn::Sub: ${ProjectName}-Items - S3_BUCKET: products-recommendation-dataset - FILE_NAME: dummyitems.json - CodeUri: s3://panyapoc-testsrc/96d50ac8866973b89968affb44d00107 - FunctionGetRecommendations: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-GetRecommendations - CodeUri: s3://panyapoc-testsrc/f0083b1d0a35d9092ca2091dc70b1a8f - Description: Get the product recommendations by user - Role: - Fn::GetAtt: - - LambdaAdminRole - - Arn - Environment: - Variables: - ddb_tablename: - Fn::Sub: ${ProjectName}-Items - Campaign_ARN: arn:aws:personalize:us-east-1:387269085412:campaign/personalize-demo-camp - Handler: getRecommendation.handler - MemorySize: 256 - Runtime: python3.8 - Timeout: 30 - Events: - APIgateway: - Type: Api - Properties: - Path: /recommendations - Method: get - APIgatewayPath: - Type: Api - Properties: - Path: /recommendations/{userid} - Method: get - FunctionGetRecommendationsByItem: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-GetRecommendationsByItem - CodeUri: s3://panyapoc-testsrc/3683824da49882d28a2ad67f6a1a2484 - Description: Get the product recommendations by item - Role: - Fn::GetAtt: - - LambdaAdminRole - - Arn - Environment: - Variables: - ddb_tablename: - Fn::Sub: ${ProjectName}-Items - Campaign_ARN: arn:aws:personalize:us-east-1:387269085412:campaign/SIM-campaign - Handler: getRecommendationByItem.handler - MemorySize: 256 - Runtime: python3.8 - Timeout: 30 - Events: - APIgateway: - Type: Api - Properties: - Path: /recommendationsitem/{itemid} - Method: get - FunctionSearch: - Type: AWS::Serverless::Function - DependsOn: - - TableItems - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-Search - Description: Search for items across item names, authors, and categories - Handler: index.handler - MemorySize: 256 - Role: - Fn::GetAtt: - - ESSearchRole - - Arn - Runtime: python3.8 - Timeout: 60 - VpcConfig: - SecurityGroupIds: - - Fn::GetAtt: - - ItemStoreVPC - - DefaultSecurityGroup - SubnetIds: - - Ref: ItemStoreSubnet1 - CodeUri: s3://panyapoc-testsrc/ad3b01edfa334ca712eaf0788431342c - Environment: - Variables: - ESENDPOINT: - Fn::GetAtt: - - ElasticsearchDomain - - DomainEndpoint - DDB_TABLE: - Fn::Sub: ${ProjectName}-Items - REGION: - Ref: AWS::Region - FunctionSearchRerank: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-Rerank - Description: Search then rerank - Handler: index.handler - MemorySize: 256 - Role: - Fn::GetAtt: - - LambdaAdminRole - - Arn - Runtime: python3.8 - Timeout: 60 - CodeUri: s3://panyapoc-testsrc/f339c1ad9b3d6ac559cbf8463b79b6fa - Environment: - Variables: - ESENDPOINT: - Fn::GetAtt: - - ElasticsearchDomain - - DomainEndpoint - DDB_TABLE: - Fn::Sub: ${ProjectName}-Items - SEARCH_ARN: - Fn::GetAtt: - - FunctionSearch - - Arn - RANKING_ARN: arn:aws:personalize:us-east-1:387269085412:campaign/personalize-demo-soln-ranking - Events: - APIgateway: - Type: Api - Properties: - Path: /search - Method: get - WebsiteOriginAccessIdentity: - Type: AWS::CloudFront::CloudFrontOriginAccessIdentity - Properties: - CloudFrontOriginAccessIdentityConfig: - Comment: - Fn::Sub: web-access-${WebBucket} - WebBucket: - Type: AWS::S3::Bucket - Properties: - CorsConfiguration: - CorsRules: - - Id: AllowAll - AllowedMethods: - - GET - - HEAD - AllowedOrigins: - - '*' - PublicAccessBlockConfiguration: - BlockPublicAcls: true - BlockPublicPolicy: true - IgnorePublicAcls: true - RestrictPublicBuckets: true - WebsiteConfiguration: - IndexDocument: index.html - ErrorDocument: index.html - WebBucketPolicy: - Type: AWS::S3::BucketPolicy - Properties: - Bucket: - Ref: WebBucket - PolicyDocument: - Statement: - - Action: - - s3:GetObject - Effect: Allow - Resource: - Fn::Join: - - '' - - - 'arn:aws:s3:::' - - Ref: WebBucket - - /* - Principal: - CanonicalUser: - Fn::GetAtt: - - WebsiteOriginAccessIdentity - - S3CanonicalUserId - WebCDN: - Type: AWS::CloudFront::Distribution - Properties: - DistributionConfig: - DefaultCacheBehavior: - AllowedMethods: - - GET - - HEAD - - OPTIONS - CachedMethods: - - GET - - HEAD - - OPTIONS - DefaultTTL: 60 - MaxTTL: 60 - ForwardedValues: - QueryString: true - TargetOriginId: webstatic - ViewerProtocolPolicy: redirect-to-https - CacheBehaviors: - - AllowedMethods: - - DELETE - - GET - - HEAD - - OPTIONS - - PATCH - - POST - - PUT - CachedMethods: - - GET - - HEAD - - OPTIONS - Compress: true - DefaultTTL: 60 - MaxTTL: 60 - ForwardedValues: - Cookies: - Forward: all - Headers: - - Accept - - Referer - - Athorization - - Content-Type - QueryString: true - PathPattern: /api-prod/* - TargetOriginId: api - ViewerProtocolPolicy: https-only - DefaultRootObject: index.html - Enabled: true - HttpVersion: http2 - Origins: - - DomainName: - Fn::Sub: ${WebBucket}.s3.amazonaws.com - Id: webstatic - S3OriginConfig: - OriginAccessIdentity: - Fn::Sub: origin-access-identity/cloudfront/${WebsiteOriginAccessIdentity} - OriginPath: /web - - DomainName: - Fn::Join: - - '' - - - Ref: ServerlessRestApi - - .execute-api. - - Ref: AWS::Region - - .amazonaws.com - Id: api - CustomOriginConfig: - OriginProtocolPolicy: https-only - PriceClass: PriceClass_200 - StagingS3Bucket: - Type: AWS::S3::Bucket - Properties: - BucketName: - Fn::Sub: ${ProjectName}-staging - SageMakerIamRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: sagemaker.amazonaws.com - Action: sts:AssumeRole - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess - - arn:aws:iam::aws:policy/AmazonS3FullAccess - - arn:aws:iam::aws:policy/service-role/AmazonPersonalizeFullAccess - - arn:aws:iam::aws:policy/IAMFullAccess - - arn:aws:iam::aws:policy/AWSLambdaFullAccess - Policies: - - PolicyName: TableItemsAccess - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - dynamodb:PutItem - - dynamodb:Query - - dynamodb:UpdateTable - - dynamodb:UpdateItem - - dynamodb:BatchWriteItem - - dynamodb:GetItem - - dynamodb:Scan - - dynamodb:DeleteItem - Resource: - - Fn::GetAtt: - - TableItems - - Arn - - Fn::Join: - - '' - - - Fn::GetAtt: - - TableItems - - Arn - - /* - NotebookInstance: - Type: AWS::SageMaker::NotebookInstance - Properties: - InstanceType: ml.t2.medium - NotebookInstanceName: - Fn::Sub: ${ProjectName}-Notebook - RoleArn: - Fn::GetAtt: - - SageMakerIamRole - - Arn - VolumeSizeInGB: 10 - DefaultCodeRepository: https://github.com/panyapoc/ItemStorePersonalize - PostClickEventStream: - Type: AWS::Kinesis::Stream - Properties: - Name: - Fn::Sub: ${ProjectName}-Clickstream - RetentionPeriodHours: 24 - ShardCount: 1 - PostClickEventFuction: - Type: AWS::Serverless::Function - Properties: - FunctionName: - Fn::Sub: ${ProjectName}-PostClickEvent - Description: PostClickEvent fucntion - Handler: index.handler - MemorySize: 256 - Runtime: python3.8 - Role: - Fn::GetAtt: - - LambdaAdminRole - - Arn - Timeout: 69 - Environment: - Variables: - TRACKING_ID: 8b1ce80f-3c86-4924-aaeb-f4a7bb992a53 - CodeUri: s3://panyapoc-testsrc/449879dfb09c3a4088c7039bedb3226c - Events: - Clickstream: - Type: Kinesis - Properties: - Stream: - Fn::GetAtt: - - PostClickEventStream - - Arn - StartingPosition: TRIM_HORIZON - UserEventIdentityPool: - Type: AWS::Cognito::IdentityPool - Properties: - AllowUnauthenticatedIdentities: true - IdentityPoolName: - Fn::Sub: ${ProjectName}-UserEventIdentityPool - UserEventIdentityPoolAttachment: - Type: AWS::Cognito::IdentityPoolRoleAttachment - Properties: - IdentityPoolId: - Ref: UserEventIdentityPool - Roles: - authenticated: - Fn::GetAtt: - - UserEventAuthRole - - Arn - unauthenticated: - Fn::GetAtt: - - UserEventAuthRole - - Arn - UserEventAuthRole: - Type: AWS::IAM::Role - Properties: - RoleName: - Fn::Sub: ${ProjectName}-UserEventRole - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Federated: - - cognito-identity.amazonaws.com - Action: - - sts:AssumeRole - Policies: - - PolicyName: KinesisStreamPut - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - kinesis:PutRecord - Resource: - - Fn::GetAtt: - - PostClickEventStream - - Arn - - Fn::Join: - - '' - - - Fn::GetAtt: - - PostClickEventStream - - Arn - - /* -Outputs: - WebBucketName: - Value: - Ref: WebBucket - Description: S3 Bucket for web asset storage - ProdDataEndpoint: - Description: API Prod stage endpoint - Value: - Fn::Sub: https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/ diff --git a/template.yaml b/template.yaml index 529add7..713c7e2 100644 --- a/template.yaml +++ b/template.yaml @@ -141,9 +141,7 @@ Resources: KeySchema: - AttributeName: asin KeyType: HASH - ProvisionedThroughput: - ReadCapacityUnits: 1 - WriteCapacityUnits: 1 + BillingMode: PAY_PER_REQUEST StreamSpecification: StreamViewType: NEW_AND_OLD_IMAGES @@ -339,7 +337,7 @@ Resources: Handler: uploadItemscsv.handler Runtime: nodejs12.x Role: !GetAtt DynamoDbRole.Arn - Timeout: 120 + Timeout: 900 MemorySize: 512 Environment: Variables: @@ -601,20 +599,17 @@ Resources: Type: "AWS::SageMaker::NotebookInstance" Properties: InstanceType: "ml.t2.medium" - NotebookInstanceName: !Sub '${ProjectName}-Notebook' + NotebookInstanceName: !Sub '${ProjectName}-Personalize-Notebook' RoleArn: !GetAtt SageMakerIamRole.Arn - VolumeSizeInGB: 10 + VolumeSizeInGB: 20 DefaultCodeRepository: https://github.com/panyapoc/ItemStorePersonalize - -# TODO: PostClickEvent PostClickEventStream: Type: AWS::Kinesis::Stream Properties: Name: !Sub '${ProjectName}-Clickstream' RetentionPeriodHours: 24 ShardCount: 1 -# TODO: PostClickEventFirehose -> Move to using SDK on clientside PostClickEventFuction: Type: 'AWS::Serverless::Function' Properties: @@ -640,7 +635,8 @@ Resources: Type: AWS::Cognito::IdentityPool Properties: AllowUnauthenticatedIdentities: True - IdentityPoolName: !Sub '${ProjectName}-UserEventIdentityPool' + # number letter underscore space only + IdentityPoolName: !Sub '${ProjectName}_UserEventIdentityPool' UserEventIdentityPoolAttachment: Type: AWS::Cognito::IdentityPoolRoleAttachment Properties: @@ -660,7 +656,7 @@ Resources: Federated: - 'cognito-identity.amazonaws.com' Action: - - 'sts:AssumeRole' + - 'sts:AssumeRoleWithWebIdentity' Policies: - PolicyName: KinesisStreamPut PolicyDocument: @@ -672,13 +668,42 @@ Resources: Resource: - !GetAtt PostClickEventStream.Arn - !Join ['', [!GetAtt PostClickEventStream.Arn, '/*']] + InitItemTable: + DependsOn: + - TableItems + - UpdateSearchCluster + - ElasticsearchDomain + Type: AWS::CloudFormation::CustomResource + Version: "1.0" + Properties: + ServiceToken: !GetAtt FunctionUploadItems.Arn + FunctionName: !Ref FunctionUploadItems Outputs: + ProdDataEndpoint: + Description: "API Prod stage endpoint" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" WebBucketName: Value: !Ref WebBucket Description: S3 Bucket for web asset storage - ProdDataEndpoint: - Description: "API Prod stage endpoint" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" - -# TODO: OutPut Lambda ARN to be update with the campaingn \ No newline at end of file + StagingS3Bucket: + Value: !Ref StagingS3Bucket + Description: S3 Bucket for Data Staging + RerankArn: + Description: "Rerank_arn" + Value: !GetAtt FunctionSearchRerank.Arn + GetRecommendationsByItemArn: + Description: "GetRecommendationsByItem_arn" + Value: !GetAtt FunctionGetRecommendationsByItem.Arn + GetRecommendationsArn: + Description: "GetRecommendations_arn" + Value: !GetAtt FunctionGetRecommendations.Arn + PostClickEventArn: + Description: "PostClickEvent_arn" + Value: !GetAtt PostClickEventFuction.Arn + WebUIStreamName: + Description: "WebUI Config kinesis.StreamName" + Value: !Ref PostClickEventStream + WebUIAnonymousPoolId: + Description: "WebUI Config cognito.AnonymousPoolId" + Value: !Ref UserEventIdentityPool \ No newline at end of file diff --git a/webui/package-lock.json b/webui/package-lock.json index da87a9f..0f43cd8 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -1193,9 +1193,9 @@ } }, "@babel/runtime-corejs2": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.7.6.tgz", - "integrity": "sha512-QYp/8xdH8iMin3pH5gtT/rUuttVfIcOhWBC3wh9Eh/qs4jEe39+3DpCDLgWXhMQgiCTOH8mrLSvQ0OHOCcox9g==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.8.4.tgz", + "integrity": "sha512-7jU2FgNqNHX6yTuU/Dr/vH5/O8eVL9U85MG5aDw1LzGfCvvhXC1shdXfVzCQDsoY967yrAKeLujRv7l8BU+dZA==", "requires": { "core-js": "^2.6.5", "regenerator-runtime": "^0.13.2" @@ -11468,12 +11468,22 @@ } }, "prop-types-extra": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.0.tgz", - "integrity": "sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", "requires": { "react-is": "^16.3.2", - "warning": "^3.0.0" + "warning": "^4.0.0" + }, + "dependencies": { + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + } } }, "proxy-addr": { diff --git a/webui/src/App.css b/webui/src/App.css index 33e3166..aa5d1b7 100644 --- a/webui/src/App.css +++ b/webui/src/App.css @@ -2,18 +2,42 @@ margin-top: 15px; } -.App .navbar-brand { - font-weight: bold; +.navbar-brand { + height: auto; + color: #f69827 !important; } -.App .orange { - color: #f69827; +.product{ + height: 350px; + max-height: 350px !important; + margin-bottom: 10px; +} + +/* .loginAs{ + background: none !important; +} */ + +.itemsForUser div,.similar div { + padding: 0 0 0 0; +} + +.userstate{ + padding: 15px; + margin-right: 20px; +} + +.imgbox{ + height: 350px; + line-height: 350px; } .App .white { color: #fff; } +.navbar-toggle{ + margin-top: 20px; +} .shopping-icon-container { background-color: #f69827; padding: 2px 12px 0 12px; @@ -25,40 +49,17 @@ margin: 0 0 0 4px; } -.line-height-24 { - line-height: 24px; -} - -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .active > a:active { - background-color: transparent !important; - background-image: none !important; - box-shadow: inset 0 0px 0px rgba(0, 0, 0, 0) !important; -} -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .active > a:focus { - background-color: transparent !important; - background-image: none !important; - box-shadow: inset 0 0px 0px rgba(0, 0, 0, 0) !important; +.testimonial-group > .row { + overflow-x: auto; + white-space: nowrap; } -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .active > a:focus-within { - background-color: transparent !important; - background-image: none !important; - box-shadow: inset 0 0px 0px rgba(0, 0, 0, 0) !important; +.testimonial-group > .row > .col-xs-4 { + display: inline-block; + float: none; } -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .active > a:visited { - background-color: transparent !important; - background-image: none !important; - box-shadow: inset 0 0px 0px rgba(0, 0, 0, 0) !important; -} - -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .active > a { - background-color: transparent !important; - background-image: none !important; - box-shadow: inset 0 0px 0px rgba(0, 0, 0, 0) !important; -} +.itemTitle{ + white-space: initial; + width: 290px; +} \ No newline at end of file diff --git a/webui/src/App.tsx b/webui/src/App.tsx index 4d33728..ef64c59 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -1,29 +1,12 @@ -import React, { Component, Fragment } from "react"; -import { LinkContainer } from "react-router-bootstrap"; -import { Nav, Navbar, NavItem, Label } from "react-bootstrap"; -import "./App.css"; -import { - BrowserRouter as Router, - Route, - Link, - withRouter, - Switch, - RouteComponentProps, - Redirect -} from "react-router-dom"; +import React, { Component } from "react"; +import { Navbar, NavDropdown, NavItem, MenuItem, Nav} from "react-bootstrap"; +import { Container } from "react-bootstrap/lib/Tab"; +import { BrowserRouter as Router, withRouter, Switch, RouteComponentProps, Route } from "react-router-dom"; import RecommendationList from "./modules/recommendationList/recommendationList"; -import config from "./config"; import notFound from "./modules/notFound/notFound"; import ProductDetail from "./modules/productDetail/productDetail"; import SearchBar from "./modules/searchBar/searchBar"; -import { Select, Input } from "@material-ui/core"; -import { MenuItem } from "@material-ui/core"; -import queryString from "query-string"; - -const bookstoreIcon = - "data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjMycHgiIGhlaWdodD0iMzJweCIgdmlld0JveD0iMCAwIDMzNS4wOCAzMzUuMDc5IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAzMzUuMDggMzM1LjA3OTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxnPgoJCTxwYXRoIGQ9Ik0zMTEuMTc1LDExNS43NzVjLTEuMzU1LTEwLjE4Ni0xLjU0Ni0yNy43Myw3LjkxNS0zMy42MjFjMC4xNjktMC4xMDgsMC4yOTUtMC4yNjQsMC40NDMtMC4zOTggICAgYzcuNzM1LTIuNDc0LDEzLjA4OC01Ljk0Niw4Ljg4Ni0xMC42MThsLTExNC4xMDItMzQuMzhMMjkuNTYsNjIuNDQ1YzAsMC0yMS4xNTcsMy4wMjQtMTkuMjY3LDM1Ljg5NCAgICBjMS4wMjYsMTcuODksNi42MzcsMjYuNjc2LDExLjU0NCwzMWwtMTUuMTYxLDQuNTY5Yy00LjIwOCw0LjY3MiwxLjE0NCw4LjE0NSw4Ljg4LDEwLjYxNWMwLjE0NywwLjEzOCwwLjI3MSwwLjI5MywwLjQ0MywwLjQwMSAgICBjOS40NTUsNS44OTYsOS4yNzMsMjMuNDM4LDcuOTEzLDMzLjYyNmMtMzMuOTY3LDkuNjQ1LTIxLjc3NCwxMi43ODgtMjEuNzc0LDEyLjc4OGw3LjQ1MSwxLjgwMyAgICBjLTUuMjQxLDQuNzM2LTEwLjQ0NiwxMy43MTctOS40NzEsMzAuNzVjMS44OTEsMzIuODY0LDE5LjI2OSwzNS4xMzIsMTkuMjY5LDM1LjEzMmwxMjAuOTA0LDM5LjI5OGwxODIuNDktNDQuMjAyICAgIGMwLDAsMTIuMTk3LTMuMTQ4LTIxLjc3OS0xMi43OTRjLTEuMzY2LTEwLjE3Mi0xLjU1Ni0yNy43MTIsNy45MjEtMzMuNjIzYzAuMTc0LTAuMTA1LDAuMzAxLTAuMjY0LDAuNDQyLTAuMzk2ICAgIGM3LjczNi0yLjQ3NCwxMy4wODQtNS45NDMsOC44ODEtMTAuNjE1bC03LjkzMi0yLjM5NWM1LjI5LTMuMTksMTMuMjM2LTExLjUyNywxNC40ODEtMzMuMTgzICAgIGMwLjg1OS0xNC44OTYtMy4wMjctMjMuNjItNy41MjUtMjguNzU2bDE1LjY3OC0zLjc5NEMzMzIuOTQ5LDEyOC41NjksMzQ1LjE0NiwxMjUuNDIxLDMxMS4xNzUsMTE1Ljc3NXogTTE1OC41MzMsMTE1LjM1NCAgICBsMzAuNjg4LTYuMzA3bDEwMy43MDgtMjEuMzEybDE1LjQ1MS0zLjE3OGMtNC45MzcsOS4wMzYtNC43MywyMS40MDItMy45MTMsMjkuMzVjMC4xNzksMS43OTgsMC4zODUsMy40NCwwLjU4NSw0LjY4OCAgICBMMjg4LjE0LDEyMi44bC0xMzAuODk3LDMyLjU2M0wxNTguNTMzLDExNS4zNTR6IE0yNi43MSwxNDcuMzM3bDE1LjQ0OSwzLjE3OGw5OS41OTcsMjAuNDc0bDguNzAxLDEuNzgybDAsMGwwLDBsMjYuMDkzLDUuMzYzICAgIGwxLjI4Nyw0MC4wMUw0My4zMDMsMTg0LjY3M2wtMTMuMjYzLTMuMjk2YzAuMTk1LTEuMjUsMC40MDEtMi44OSwwLjU4OC00LjY5M0MzMS40NCwxNjguNzQyLDMxLjY1MSwxNTYuMzczLDI2LjcxLDE0Ny4zMzd6ICAgICBNMjAuNzA4LDk2Ljc1N2MtMC4xODctOC43NDMsMS4zNzEtMTUuMDY2LDQuNTItMTguMjhjMi4wMDQtMi4wNTIsNC4zNjktMi40NzksNS45OTEtMi40NzljMC44NTcsMCwxLjQ3NCwwLjExOSwxLjUxNiwwLjExOSAgICBsNzkuNjA3LDI1Ljk1M2wzOS43MTcsMTIuOTQ5bC0xLjMwMyw0MC4yODlMMzkuMzM0LDEyNC4wN2wtNS44OC0xLjY0N2MtMC4yMTYtMC4wNjEtMC41MDktMC4xMDMtMC43MzUtMC4xMTMgICAgQzMyLjI2LDEyMi4yNzcsMjEuMjQ0LDEyMS4yNjMsMjAuNzA4LDk2Ljc1N3ogTTE0MC41NzksMjgwLjg2NkwyMy4yOCwyNDcuOThjLTAuMjE3LTAuMDYzLTAuNTA3LTAuMTA1LTAuNzMzLTAuMTE2ICAgIGMtMC40NjctMC4wMzEtMTEuNDg4LTEuMDQ0LTEyLjAyMS0yNS41NDRjLTAuMTktOC43NTQsMS4zNzYtMTUuMDcxLDQuNTE5LTE4LjI4OGMyLjAwOS0yLjA1Miw0LjM3NS0yLjQ3OSw1Ljk5NC0yLjQ3OSAgICBjMC44NTksMCwxLjQ3NCwwLjExNSwxLjUxOSwwLjExNWMwLDAsMC4wMDUsMCwwLDBsMTE5LjMxNiwzOC45MDhMMTQwLjU3OSwyODAuODY2eiBNMjk0LjI4NCwyMzkuNDU5ICAgIGMwLjE4NSwxLjgwNCwwLjM5MSwzLjQ0MywwLjU5MSw0LjY5M2wtMTQ3LjgxMiwzNi43NzFsMS4yOTItNDAuMDFsMzEuNjAxLTYuNDk3bDQuNjY3LDEuMTI5bDE3LjQ5Mi01LjY4NWw4MC42MzEtMTYuNTY5ICAgIGwxNS40NTctMy4xOEMyOTMuMjYxLDIxOS4xNDYsMjkzLjQ2NiwyMzEuNTE3LDI5NC4yODQsMjM5LjQ1OXogTTMwMi40MjYsMTg1LjA4NGMtMC4yNjksMC4wMDYtMC41MzgsMC4wNDItMC43OTEsMC4xMjIgICAgbC0xMS4xNDgsMy4xMjFsLTEwNi4xNDgsMjkuNzY0bC0xLjI5OC00MC4yODlsMzQuODI2LTExLjM1OWw4NC4zMjctMjcuNTAxYzAuMDExLTAuMDA1LDQuNDM2LTAuOTg4LDcuNjg0LDIuMzE1ICAgIGMzLjE0NCwzLjIxNCw0LjcwNCw5LjUzNyw0LjUyLDE4LjI4QzMxMy44NDgsMTg0LjAzNSwzMDIuODI3LDE4NS4wNTMsMzAyLjQyNiwxODUuMDg0eiIgZmlsbD0iI2Y2OTgyNyIvPgoJPC9nPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+CjxnPgo8L2c+Cjwvc3ZnPgo="; - -const list = ["{124, 'test', }"]; +import "./App.css"; const userList = [ { @@ -64,178 +47,104 @@ interface User { } interface AppState { - isAuthenticated: boolean; - isAuthenticating: boolean; - users: User[]; selectedUser: User | undefined; - userSelectedName: string | undefined; + userSelectedName : string } -class App extends React.Component, AppState> { +class App extends Component, AppState> { constructor(props: RouteComponentProps) { super(props); - - this.state = { - isAuthenticated: false, - isAuthenticating: true, - users: userList, - selectedUser: undefined, - userSelectedName: undefined - }; - - document.title = "The All Store"; - } - - // async componentWillMount(){ - - // } - - async componentDidMount() { - /* try { - if (await Auth.currentSession()) { - this.userHasAuthenticated(true); - } + let user = localStorage.getItem('user') + if(user){ + let userobj = JSON.parse(user) + this.state = { + selectedUser: userobj, + userSelectedName : `${userobj.firstName} ${userobj.lastName}` + }; + }else{ + this.state = { + selectedUser: undefined, + userSelectedName : '' + }; } - catch(e) { - if (e !== 'No current user') { - alert(e); - } - }*/ - const values = queryString.parse(this.props.location.search); - - if (values != null && values.uid != null) { - this.handleUserSelectChange(values.uid); - } - this.setState({ isAuthenticating: false }); + this.renderSelectOptions = this.renderSelectOptions.bind(this); + document.title = "The All Store"; } - userHasAuthenticated = (authenticated: boolean) => { - this.setState({ isAuthenticated: authenticated }); - }; - - handleLogout = async () => { - // await Auth.signOut(); - - this.userHasAuthenticated(false); - // this.props.history.push("/login"); - }; - showLoggedInBar = () => ; - - showLoggedOutBar = () => ; - - handleUserSelectChange(userId: any) { - // Use cast to any works but is not type safe - var user = this.state.users.find(u => u.id == userId); - if (user != null) { - if (user.firstName != null) { - this.setState({ - userSelectedName: user?.firstName + " " + user?.lastName - }); - } + renderSelectOptions(eventKey : any) { + console.log('eventKey',eventKey) + if(eventKey === 'anonymous'){ + this.setState({ userSelectedName: 'anonymous'}); + this.setState({ selectedUser: undefined}); + localStorage.removeItem('user'); + }else{ + this.setState({ + userSelectedName: `${userList[eventKey].firstName} ${userList[eventKey].lastName}` + }); + this.setState({ selectedUser: userList[eventKey]}); + localStorage.setItem('user', JSON.stringify(userList[eventKey])); } - - this.setState({ selectedUser: user }); - } - - renderSelectOptions() { - return this.state.users.map((dt, i) => { - //console.log(dt); - return ( - - {dt.firstName} {dt.lastName} - - ); - }); } render() { - const childProps = { - isAuthenticated: this.state.isAuthenticated, - userHasAuthenticated: this.userHasAuthenticated - }; - return (
- + + + - - - - {" "} - bookstore - The All Store - Great Prices, Huge Collection - - - - - + + + {' '} + The All Store - Great Prices, Huge Collection + + + -
- ); + ); } } diff --git a/webui/src/RoutedLinkContainer.js b/webui/src/RoutedLinkContainer.js deleted file mode 100644 index e69de29..0000000 diff --git a/webui/src/config.tsx b/webui/src/config.tsx index f56c1ed..a135388 100644 --- a/webui/src/config.tsx +++ b/webui/src/config.tsx @@ -1,23 +1,24 @@ -const apitree = 'https://hpr4qcneol.execute-api.us-east-1.amazonaws.com/Prod'; +const Apitree = 'https://qgehhm7uea.execute-api.us-east-1.amazonaws.com/Prod/'; // Cloudformation ProdDataEndpoint +const AnonymousPoolId = 'us-east-1:545cb159-174b-4ac0-96b3-e6cec441b18c' //Cloudformation WebUIAnonymousPoolId +const StreamName = 'teststr-Clickstream' // Cloudformation WebUIStreamName + export default { region: "us-east-1", kinesis:{ - StreamName: "pocstor-Clickstream", + StreamName: StreamName, PartitionKey: "webpartition" }, cognito: { - SignInUrl: "https://all-store.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=2nr6bddje6ekkd93ac79bsd4l2&redirect_uri=http://localhost:3000/login", - AnonymousPoolId : "us-east-1:5cd563db-7e9b-44f2-97c6-abfe475be5d4" - + AnonymousPoolId : AnonymousPoolId }, api: { - GetListUrl: `${apitree}/recommendations/`, - GetDetailsUrl: `${apitree}/items/`, - ClickEventUrl: `${apitree}/clickevent`, - SearchUrl: `${apitree}/search`, - RecommendSimilar: `${apitree}/recommendationsitem/`, - GetDescriptionForProduct: `${apitree}/description` + GetListUrl: `${Apitree}recommendations/`, + GetDetailsUrl: `${Apitree}items/`, + ClickEventUrl: `${Apitree}clickevent`, + SearchUrl: `${Apitree}search`, + RecommendSimilar: `${Apitree}recommendationsitem/`, + GetDescriptionForProduct: `${Apitree}description` }, user: { id: "AIXZKN4ACSKI" diff --git a/webui/src/index.css b/webui/src/index.css deleted file mode 100644 index b4cc725..0000000 --- a/webui/src/index.css +++ /dev/null @@ -1,5 +0,0 @@ -body { - margin: 0; - padding: 0; - font-family: sans-serif; -} diff --git a/webui/src/index.tsx b/webui/src/index.tsx index bd0ff5f..c359f44 100644 --- a/webui/src/index.tsx +++ b/webui/src/index.tsx @@ -1,19 +1,14 @@ import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter as Router } from "react-router-dom"; -import "./index.css"; -import App from "./App"; -import registerServiceWorker from "./registerServiceWorker"; - -import config from "./config"; import "bootstrap/dist/css/bootstrap.css"; -import "bootstrap/dist/css/bootstrap-theme.css"; +import App from "./App"; + ReactDOM.render( - + , document.getElementById("root") ); -registerServiceWorker(); diff --git a/webui/src/modules/productDetail/productDetail.tsx b/webui/src/modules/productDetail/productDetail.tsx index 07cdbe0..242bddd 100644 --- a/webui/src/modules/productDetail/productDetail.tsx +++ b/webui/src/modules/productDetail/productDetail.tsx @@ -6,27 +6,21 @@ import "./productDetail.css"; import queryString from "query-string"; import RecommendationList from "../recommendationList/recommendationList"; import { - BrowserRouter as Router, - Switch, - Route, - Link, RouteComponentProps } from "react-router-dom"; -import { useParams, withRouter } from "react-router"; - +import { withRouter } from "react-router"; import { Html5Entities } from "html-entities"; +const htmlEntities = new Html5Entities(); + AWS.config.update({ region: config.region, credentials: new AWS.CognitoIdentityCredentials({ IdentityPoolId: config.cognito.AnonymousPoolId }) }); - var kinesis = new AWS.Kinesis(); -const htmlEntities = new Html5Entities(); - type ProductDetailsProp = { id: string; uid: string | undefined; @@ -39,15 +33,9 @@ interface ProductDetailsState { showAMZNLink: boolean; } -class ProductDetails extends React.Component< - RouteComponentProps & ProductDetailsProp, - ProductDetailsState -> { - constructor( - props: RouteComponentProps & ProductDetailsProp - ) { +class ProductDetails extends React.Component & ProductDetailsProp,ProductDetailsState> { + constructor(props: RouteComponentProps & ProductDetailsProp) { super(props); - this.state = { isLoading: true, product: undefined, @@ -68,21 +56,11 @@ class ProductDetails extends React.Component< PartitionKey: config.kinesis.PartitionKey, /* required */ StreamName: config.kinesis.StreamName /* required */ }; + console.table(params) kinesis.putRecord(params, function(err, data) { if (err) console.log(err, err.stack); // an error occurred else console.log(data); // successful response }); - // fetch(config.api.ClickEventUrl, { - // method: "POST", - // headers: { - // Accept: "application/json", - // "Content-Type": "application/json" - // }, - // body: JSON.stringify({ - // userID: values.uid, - // itemID: this.props.match.params.id - // }) - // }); } catch (e) { console.log(e); } @@ -106,10 +84,7 @@ class ProductDetails extends React.Component< } try { - let descriptionUrl = - config.api.GetDescriptionForProduct + - "?asin=" + - this.props.match.params.id; + let descriptionUrl = config.api.GetDescriptionForProduct + "?asin=" +this.props.match.params.id; fetch(descriptionUrl) .then(response => response.json()) @@ -136,9 +111,9 @@ class ProductDetails extends React.Component< const values = queryString.parse(this.props.location.search); const uid = values.uid; let item = this.state.product; - if (item != undefined) { + if (item !== undefined) { let recommendedForUser; - if (uid != null) { + if (uid !== null) { recommendedForUser = (
@@ -153,7 +128,6 @@ class ProductDetails extends React.Component<
); } - let amazonUrl = "https://www.amazon.com/dp/" + item.asin; const descData = this.state.description; @@ -163,7 +137,7 @@ class ProductDetails extends React.Component< - + Buy it on Amazon.com @@ -198,11 +172,11 @@ class ProductDetails extends React.Component<

Similar Items

- + >
{recommendedForUser} diff --git a/webui/src/modules/recommendationList/recommendationList.tsx b/webui/src/modules/recommendationList/recommendationList.tsx index 92f4e6f..6bba8b9 100644 --- a/webui/src/modules/recommendationList/recommendationList.tsx +++ b/webui/src/modules/recommendationList/recommendationList.tsx @@ -1,20 +1,14 @@ import React from "react"; -import PropTypes from "prop-types"; import ProductRow from "../storeItem/storeItem"; import { Product } from "../storeItem/storeItem"; import config from "../../config"; -import { Table } from "@material-ui/core"; -import { uid } from "react-uid"; import "./recommendationList.css"; import { - BrowserRouter as Router, - Switch, - Route, withRouter, - Link, RouteComponentProps } from "react-router-dom"; +import { Col } from "react-bootstrap"; const RecommendationMode = { Normal: "Normal", @@ -59,7 +53,7 @@ export class RecommendationList extends React.Component< let getUrl = config.api.GetListUrl; - if (this.props.mode == RecommendationMode.Normal) { + if (this.props.mode === RecommendationMode.Normal) { if ( this.props.match.params.searchid && this.props.match.params.searchid.length > 0 @@ -71,12 +65,12 @@ export class RecommendationList extends React.Component< queryString += "q=" + this.props.match.params.searchid; if (this.props.userId) { - if (queryString != "") queryString += "&"; + if (queryString !== "") queryString += "&"; queryString += "u=" + this.props.userId; } - if (queryString != "") getUrl = getUrl + queryString; + if (queryString !== "") getUrl = getUrl + queryString; } else { if (this.props.userId != null) getUrl += this.props.userId; } @@ -136,59 +130,106 @@ export class RecommendationList extends React.Component< } createTable = () => { - let table = []; let listItems = this.state.items; - const maxCols = this.props.mode == RecommendationMode.Normal ? 3 : 10; - let currentCol = 0; - let children = []; - - if (listItems != null) { - for (let i = 0; i < listItems.length; i++) { - let product = listItems[i]; - children.push( - - {" "} - - - ); - ++currentCol; - if (currentCol >= maxCols) { - table.push({children}); - children = []; - currentCol = 0; - } - } - if (children.length > 0) { - table.push({children}); - children = []; - } + let userid = this.props.userId; + var xs: number | undefined,md: number | undefined + if (this.props.mode === RecommendationMode.Normal){ + xs = 6; + md = 4; + } + else { + xs = 4; + md = 3; + } + let productcat: JSX.Element[] = []; + + try { + listItems.forEach(function(item, index) { + productcat.push( + + + + ); + }) + } + catch(e){ + console.log(e) } - return table; +// Tavle version + // if (listItems != null) { + // for (let i = 0; i < listItems.length; i++) { + // let product = listItems[i]; + // children.push( + // + // {" "} + // + // + // ); + // ++currentCol; + // if (currentCol >= maxCols) { + // table.push({children}); + // children = []; + // currentCol = 0; + // } + // } + // if (children.length > 0) { + // table.push({children}); + // children = []; + // } + // } + + return productcat; }; render() { let currentClassName; + let productlist; - if (this.props.mode == RecommendationMode.Normal) + if (this.props.mode === RecommendationMode.Normal){ currentClassName = "recommend"; - else if (this.props.mode == RecommendationMode.SimilarItems) + return ( +
+ {this.createTable()} +
+ ); + } + else if (this.props.mode === RecommendationMode.SimilarItems) { currentClassName = "similar"; - else currentClassName = "itemsForUser"; - - return ( -
- - {this.createTable()} -
-
- ); + return ( +
+
+
+ {this.createTable()} +
+
+
+ ); + } + else { + currentClassName = "itemsForUser"; + return ( +
+
+
+ {this.createTable()} +
+
+
+ ); + } } } diff --git a/webui/src/modules/searchBar/searchBar.css b/webui/src/modules/searchBar/searchBar.css index 6b81699..781cfa5 100644 --- a/webui/src/modules/searchBar/searchBar.css +++ b/webui/src/modules/searchBar/searchBar.css @@ -1,6 +1,5 @@ .search-padding { - padding-left: 25px !important; - padding-right: 1rem; + padding: 0 25px 0 25px; } .title-padding { diff --git a/webui/src/modules/searchBar/searchBar.tsx b/webui/src/modules/searchBar/searchBar.tsx index 5d0f020..061f567 100644 --- a/webui/src/modules/searchBar/searchBar.tsx +++ b/webui/src/modules/searchBar/searchBar.tsx @@ -2,11 +2,7 @@ import React from "react"; import "./searchBar.css"; import { Redirect } from "react-router"; import { - BrowserRouter as Router, - Switch, - Route, withRouter, - Link, RouteComponentProps } from "react-router-dom"; diff --git a/webui/src/modules/signup/Home.tsx b/webui/src/modules/signup/Home.tsx index 0971fc8..18480ff 100644 --- a/webui/src/modules/signup/Home.tsx +++ b/webui/src/modules/signup/Home.tsx @@ -66,21 +66,21 @@ export default class Home extends Component {
{/* - Past orders + Past orders */}
{/* - Shopping cart + Shopping cart */}
{/* - Best sellers + Best sellers */}
diff --git a/webui/src/modules/signup/signup.tsx b/webui/src/modules/signup/signup.tsx index c657537..62dc08b 100644 --- a/webui/src/modules/signup/signup.tsx +++ b/webui/src/modules/signup/signup.tsx @@ -2,6 +2,6 @@ import config from "../../config"; export default function signUp() { ; } diff --git a/webui/src/modules/storeItem/storeItem.css b/webui/src/modules/storeItem/storeItem.css index 3c1f356..75bd964 100644 --- a/webui/src/modules/storeItem/storeItem.css +++ b/webui/src/modules/storeItem/storeItem.css @@ -1,3 +1,7 @@ span.recommend { padding: 10px; } + +.prod-img{ + max-height: 300px; +} \ No newline at end of file diff --git a/webui/src/modules/storeItem/storeItem.tsx b/webui/src/modules/storeItem/storeItem.tsx index 3943f4d..26a4fb4 100644 --- a/webui/src/modules/storeItem/storeItem.tsx +++ b/webui/src/modules/storeItem/storeItem.tsx @@ -35,20 +35,19 @@ class ProductRow extends React.Component { render() { return ( - - - + ); } diff --git a/webui/src/registerServiceWorker.ts b/webui/src/registerServiceWorker.ts deleted file mode 100644 index ab9d98a..0000000 --- a/webui/src/registerServiceWorker.ts +++ /dev/null @@ -1,122 +0,0 @@ -// In production, we register a service worker to serve assets from local cache. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on the "N+1" visit to a page, since previously -// cached resources are updated in the background. - -// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. -// This link also includes instructions on opting out of this behavior. - -const isLocalhost = Boolean( - window.location.hostname === "localhost" || - // [::1] is the IPv6 localhost address. - window.location.hostname === "[::1]" || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); - -export default function register() { - if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL( - process.env.PUBLIC_URL, - window.location.toString() - ); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 - return; - } - - window.addEventListener("load", () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Lets check if a service worker still exists or not. - checkValidServiceWorker(swUrl); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - "This web app is being served cache-first by a service " + - "worker. To learn more, visit https://goo.gl/SC7cgQ" - ); - }); - } else { - // Is not local host. Just register service worker - registerValidSW(swUrl); - } - }); - } -} - -function registerValidSW(swUrl: string) { - navigator.serviceWorker - .register(swUrl) - .then(registration => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - if (installingWorker) { - installingWorker.onstatechange = () => { - if (installingWorker.state === "installed") { - if (navigator.serviceWorker.controller) { - // At this point, the old content will have been purged and - // the fresh content will have been added to the cache. - // It's the perfect time to display a "New content is - // available; please refresh." message in your web app. - console.log("New content is available; please refresh."); - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log("Content is cached for offline use."); - } - } - }; - } - }; - }) - .catch(error => { - console.error("Error during service worker registration:", error); - }); -} - -function checkValidServiceWorker(swUrl: string) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl) - .then(response => { - // Ensure service worker exists, and that we really are getting a JS file. - if ( - response.status === 404 || - response.headers.get("content-type")!.indexOf("javascript") === -1 - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { - registration.unregister().then(() => { - window.location.reload(); - }); - }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl); - } - }) - .catch(() => { - console.log( - "No internet connection found. App is running in offline mode." - ); - }); -} - -export function unregister() { - if ("serviceWorker" in navigator) { - navigator.serviceWorker.ready.then(registration => { - registration.unregister(); - }); - } -}