From 4685d3565143186ab6711276edcc12327435cf21 Mon Sep 17 00:00:00 2001 From: Max Henkel-Wallace Date: Wed, 5 Jul 2023 18:12:24 -0700 Subject: [PATCH 1/3] AWS Lex Conversational FAQ Demo: CDK code to create lambdas, lex bot and sagemaker endpoint. User uploads file to create index --- DEVELOPMENT.md | 45 +++++ README.md | 125 ++++++++++++- diagram.png | Bin 0 -> 153009 bytes src/lex-gen-ai-demo-cdk/app.py | 14 ++ src/lex-gen-ai-demo-cdk/cdk.json | 51 +++++ src/lex-gen-ai-demo-cdk/endpoint_handler.py | 99 ++++++++++ .../index-creation-docker-image/Dockerfile | 14 ++ .../index_creation_app.py | 126 +++++++++++++ .../index_creation_requirements.txt | 6 + .../lex-gen-ai-demo-docker-image/Dockerfile | 14 ++ .../runtime_lambda_app.py | 176 ++++++++++++++++++ .../runtime_lambda_requirements.txt | 4 + .../lex_gen_ai_demo_cdk_files/__init__.py | 0 .../lex_gen_ai_demo_cdk_files_stack.py | 130 +++++++++++++ src/lex-gen-ai-demo-cdk/requirements.txt | 4 + src/lex-gen-ai-demo-cdk/shut_down_endpoint.py | 26 +++ src/lex-gen-ai-demo-cdk/source.bat | 13 ++ src/lex-gen-ai-demo-cdk/upload_file_to_s3.py | 37 ++++ 18 files changed, 875 insertions(+), 9 deletions(-) create mode 100644 DEVELOPMENT.md create mode 100644 diagram.png create mode 100644 src/lex-gen-ai-demo-cdk/app.py create mode 100644 src/lex-gen-ai-demo-cdk/cdk.json create mode 100644 src/lex-gen-ai-demo-cdk/endpoint_handler.py create mode 100644 src/lex-gen-ai-demo-cdk/index-creation-docker-image/Dockerfile create mode 100644 src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_app.py create mode 100644 src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_requirements.txt create mode 100644 src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/Dockerfile create mode 100644 src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_app.py create mode 100644 src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt create mode 100644 src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/__init__.py create mode 100644 src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py create mode 100644 src/lex-gen-ai-demo-cdk/requirements.txt create mode 100644 src/lex-gen-ai-demo-cdk/shut_down_endpoint.py create mode 100644 src/lex-gen-ai-demo-cdk/source.bat create mode 100644 src/lex-gen-ai-demo-cdk/upload_file_to_s3.py diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 00000000..893dd7ea --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,45 @@ + +### Project Structure within src/lex-gen-ai-demo-cdk: +``` +AWSLexKoiosBlogDemo/src/lex-gen-ai-demo-cdk +- app.py +- cdk.json +- endpoint_handler.py +- upload_file_to_s3.py +- shutdown_endpoint.py +- index-creation-docker-image/ + - index_creation_app.py + - Dockerfile + - index_creation_requirements.txt +- lex_gen_ai_demo_cdk_files/ + - __init__.py + - lex_gen_ai_demo_file_stack.py +- lex-gen-ai-demo-docker-image/ + - runtime_lambda_app.py + - Dockerfile + - runtime_lambda_requirements.txt +- requirements.txt +- source.bat +``` + +## Common Errors & Troubleshooting + +### "ValueError: Must setup local AWS configuration with a region supported by SageMaker." +Solution: You must set an aws region with `export AWS_DEFAULT_REGION=` + +### Error creating role +``` +botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the CreateRole operation: User: is not authorized to perform: iam:CreateRole on resource: because no identity-based policy allows the iam:CreateRole action +``` +Solution: you must ensure the Iam role you are using has sufficient permissions to create Iam roles + +### Error LexGenAIDemoFilesStack: fail: docker push exited with error code 1: tag does not exist +Issue: Error while building the image. Here are some common ones + +#### Error processing tar file(exit status 1): write /path/libcublas.so.11: no space left on device +Issue: Docker has run out of memory due to too many images +Solution: Delete unused images in the Docker application and then [prune docker](https://docs.docker.com/config/pruning/) in command line + +#### ConnectionResetError: [Errno 104] Connection reset by peer +Issue: Pip issue +Solution: Clear pip cache (`python3 -m pip cache purge`) and run again diff --git a/README.md b/README.md index 7f922047..25567239 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,124 @@ -## My Project +# AWS Lex Conversational FAQ Demo -TODO: Fill this README out! +Demonstration of LLM integration into a lex bot using Lambda codehooks and a Sagemaker endpoint. -Be sure to: +![Diagram](diagram.png) -* Change the title in this README -* Edit your repository description on GitHub +### What resources will be created? +This CDK code will create the following: + - 1 Sagemaker endpoint hosting a model (falcon-7b-instruct on ml.g5.8xlarge by default but this is configurable) + - 1 Lex bot + - 2 S3 buckets (one for your uploaded source, one for the created index) + - 2 Lambda functions (one to ingest the source and create an image, one to be invoked as codehook during lambda and provide an FAQ answer when needed) + - 1 Event listener attached to an S3 bucket to call the index creation lambda automatically when a file is uploaded + - 2 Iam roles (one for the lex bot to call lambda, one for the lambdas to call sagemaker and S3) -## Security +## Requirements -See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. +### AWS setup +**Region** -## License +If you have not yet run `aws configure` and set a default region, you must do so, or you can also run `export AWS_DEFAULT_REGION=` -This library is licensed under the MIT-0 License. See the LICENSE file. +**Authorization** +You must use a role that has sufficient permissions to create Iam roles, as well as cloudformation resources + +### Python >3.7 +Make sure you have [python3](https://www.python.org/downloads/) installed at a version >=3.7.x + +### Docker +Make sure you have [Docker](https://www.docker.com/products/docker-desktop/) installed on your machine and running in the background + +### AWS CDK +Make sure you have the [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install) installed on your machine + + +## Setup + +### Set up virtual enviroment and gather packages + +``` +cd src/lex-gen-ai-demo-cdk-files +``` + +Install the required dependencies (aws-cdk-lib and constructs) into your Python environment +``` +pip install -r requirements.txt +``` + +### Gather and deploy resources with the CDK + +First synthesize, which executes the application, defines which resources will be created and translates this into a cloudformation template +``` +cdk synth +``` +Now bootstrap, which provisions the resources you'll use when deploying the application +``` +cdk bootstrap +``` +and deploy with +``` +cdk deploy LexGenAIDemoFilesStack +``` + +The deployment will create a lex bot and S3 buckets and will dockerize the code in the koios_cdk_files/koios-docker-image directory and push that image to ECR so it can run in Lambda. Dont worry if this step takes a long time while pushing to ECR, we are bundling up two docker images and uploading them so it will take some time. + +## Usage +Once all the resources are created after `cdk deploy` finishes running you must upload a .PDF or .txt file at least once so an index can be created. You can use our upload script `upload_file_to_s3.py path/to/your/file` or you can navigate to the S3 console and manually upload a file. On upload the ingestion lambda will read the file and create an embedding which it will upload to the other S3 bucket. Now that an embedding exists you can go to your bot and begin using it. If you want to update the embedding you can upload a new file and a new embedding will overwrite the old embedding. Once you have a new embedding you must restart the runtime lambda function for it to start using the new embedding. + +Note, the first time the embedding lambda and the runtime lambda are called the latency will be much slower as it must load resources and save them in the lambda enviroment. Once loaded these resources will stay in the enviroment as long as the ECR image is not deleted. This means your first request will be slow but after that it will speed up now that the resources are cached. + +### Uploading files +Now, you have to upload your source file so the indexing lambda can create an index for the runtime lambda function to use. You can use our script with any PDF or .txt file by running +``` +python3 upload_file_to_s3.py path/to/your/file +``` +or you can open the S3 bucket in the console and manually upload a file. On upload an index will automatically be generated. +Note: If you upload a large file, the index will be large and the S3 read time on cold start may become large. + +Once you've uploaded your file, wait a little for your index to be created and then you can go into the Lex console and test your bot (no need to build your bot unless you've made changes after creation). The first time you create an index and the first time you query the bot it will take a little longer (around 90 seconds) as we need to load models and cache them in the lambda-ECR enviroment but after they are cached there is no need to download them and latency will be much faster. These resources will remain cached as long as the ECR image is not deleted. Additionally for better cold start performance you can an instance for your runtime lambda function. There are directions to do so below. + +### Configurations + +🚨 **Remember to shut down your endpoint if you're done using it!** 🚨 + +We have provided a script to deactivate an endpoint and endpoint configuration with whatever name is in the endpoint creation script. To run: +``` +python3 shut_down_endpoint.py +``` + +#### Custom model and instance type configuration: + +The function `create_endpoint_from_HF_image()` is called in `app.py`. This function acceptst the following arguments: + - hf_model_id (required): For the purposes of the demo we have this set to [tiiuae/falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b). You can find any https://huggingface.co/ and feed it in + - instance_type (optional, default is ml.g5.8xlarge): If you dont give an argument we'll use ml.g5.8xlarge. You can use any endpoint [sage instance type](https://aws.amazon.com/sagemaker/pricing/) + - endpoint_name (optional, default is whatever SAGEMAKER_ENDPOINT_NAME is set to in the file endpoint_handler.py): You can give your endpoint a custom name. It is recomended that you don't do this but if you do, you have to change it in the lamdba images (constant is called ENDPOINT_NAME in index_creation_app.py and runtime_lambda_app.py) + - number_of_gpu (optional, default is 1): Set this to any number of GPUs the hardware you chose allows. + + If you have in invalid configuration the endpoint will fail to create. You can see the specific error in the cloudwatch logs. If you fail creation you can run `python3 shut_down_endpoint.py` to clean up the endpoint but if you do so manually in the console **you must delete both the endpoint and the endpoint configuration** + +#### Fruther configuration +If you would like to further configure the endpoint you can change the specific code in `endpoint_handler.py` + +The LLM is hosted on a sagemaker endpoint and deployed as a sagemaker [HuggingFaceModel](https://sagemaker.readthedocs.io/en/stable/frameworks/huggingface/sagemaker.huggingface.html). We are also using a huggingface model image. You can read more about it [here](https://aws.amazon.com/blogs/machine-learning/announcing-the-launch-of-new-hugging-face-llm-inference-containers-on-amazon-sagemaker/). For further model configuration you can read about sagemaker model deployments [here](https://docs.aws.amazon.com/sagemaker/latest/dg/realtime-endpoints-deployment.html). + +For our indexing and retrieval we are using [llama-index](https://github.com/jerryjliu/llama_index). If you would like to configure the index retriever you can do so in the `runtime_lambda_app.py` file in the `VectorIndexRetriever` object on line 70. If you want to update index creation you can update the constants defined at the top of the index creation and runtime lambdas (`index_creation_app.py` and `runtime_lambda_app.py`). Make sure to familiarize yourself with [llama-index terms](https://gpt-index.readthedocs.io/en/latest/guides/tutorials/terms_definitions_tutorial.html) and the [llama-index prompthelper](https://gpt-index.readthedocs.io/en/latest/reference/service_context/prompt_helper.html) for best results. + +### Tips for best results + +**Keep your lambda perpetually warm by provisioning an instance for the runtime lambda (lex-codehook-fn)** + +Go to Lambda console > select the function lex-codehook-fn + +Versions > Publish new version + +Under this version + - Provisioned Concurrency > set value to 1 + - Permissions > Resource based policy statements > Add Permissions > AWS Service > Other, your-policy-name, lexv2.amazonaws.com, your-lambda-arn, lamdba:InvokeFunction + +Go to your Lex Bot (LexGenAIDemoBotCfn) + +Aliases > your-alias > your-language > change lambda function version or alias > change to your-version + +This will keep an instance running at all times and keep your lambda ready so that you wont have cold start latency. This will cost a bit extra (https://aws.amazon.com/lambda/pricing/) so use thoughfully. \ No newline at end of file diff --git a/diagram.png b/diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..689c0a1f2178f5b6d10df4595d543f49b158ab6c GIT binary patch literal 153009 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%0DcLBWHNVbkXiM&(Ynta~-i0=XI9D}x_ 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Ⓢ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 K)*a1*0sja2n93{w literal 0 HcmV?d00001 diff --git a/src/lex-gen-ai-demo-cdk/app.py b/src/lex-gen-ai-demo-cdk/app.py new file mode 100644 index 00000000..c2fb9cbb --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/app.py @@ -0,0 +1,14 @@ + +import aws_cdk as cdk + +from lex_gen_ai_demo_cdk_files.lex_gen_ai_demo_cdk_files_stack import LexGenAIDemoFilesStack +from endpoint_handler import create_endpoint_from_HF_image + +# create_endpoint_from_HF_image(hf_model_id, instance_type="ml.g5.8xlarge", endpoint_name=SAGEMAKER_ENDPOINT_NAME, number_of_gpu=1) +# You can run with no arguments to get default values of google/flan-t5-xxl on ml.g5.8xlarge, or pass in your own arguments +create_endpoint_from_HF_image(hf_model_id="tiiuae/falcon-7b-instruct") + +app = cdk.App() +filestack = LexGenAIDemoFilesStack(app, "LexGenAIDemoFilesStack") + +app.synth() diff --git a/src/lex-gen-ai-demo-cdk/cdk.json b/src/lex-gen-ai-demo-cdk/cdk.json new file mode 100644 index 00000000..095c4b11 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/cdk.json @@ -0,0 +1,51 @@ +{ + "app": "python3 app.py", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "requirements*.txt", + "source.bat", + "**/__init__.py", + "python/__pycache__", + "tests" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true + } + } \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/endpoint_handler.py b/src/lex-gen-ai-demo-cdk/endpoint_handler.py new file mode 100644 index 00000000..9fee1ab1 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/endpoint_handler.py @@ -0,0 +1,99 @@ +import json +import boto3 +import time +from sagemaker.huggingface import get_huggingface_llm_image_uri +from sagemaker.huggingface import HuggingFaceModel + +# get image from huggingface +llm_image = get_huggingface_llm_image_uri( + "huggingface", + version="0.8.2" +) + +assume_role_policy_document = json.dumps({ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "sagemaker.amazonaws.com", + "ecs.amazonaws.com" + ] + }, + "Action": "sts:AssumeRole" + } + ] +}) + +# editable to whatever you want your endpoint and role to be. You can use an existing role or a new one +# IMPORTANT: make sure your lambda endpoint name in lambda_app.py is consisitent if you change it here +SAGEMAKER_IAM_ROLE_NAME = 'Sagemaker-Endpoint-Creation-Role' +SAGEMAKER_ENDPOINT_NAME = "huggingface-pytorch-sagemaker-endpoint" + +# Create role and give sagemaker permissions +def get_iam_role(role_name=SAGEMAKER_IAM_ROLE_NAME): + iam_client = boto3.client('iam') + + try: + role = iam_client.get_role(RoleName=role_name) + role_arn = role['Role']['Arn'] + print(f"Role {role_arn} found!") + return role_arn + + except: + role_arn = iam_client.create_role( + RoleName=SAGEMAKER_IAM_ROLE_NAME, + AssumeRolePolicyDocument=assume_role_policy_document + )['Role']['Arn'] + + time.sleep(10) # give the policy some time to properly create + + response = iam_client.attach_role_policy( + PolicyArn='arn:aws:iam::aws:policy/AmazonSageMakerFullAccess', + RoleName=SAGEMAKER_IAM_ROLE_NAME, + ) + print(f"Creating {role_arn}") + time.sleep(20) # give iam time to let the role create + return role_arn + + +# Define Model and Endpoint configuration parameter + +health_check_timeout = 300 +trust_remote_code = True + +# Create sagemaker endpoint, default values are flan t5 xxl in a g5.8xl instance +def create_endpoint_from_HF_image(hf_model_id, instance_type="ml.g5.8xlarge", endpoint_name=SAGEMAKER_ENDPOINT_NAME, number_of_gpu=1): + sagemaker_client = boto3.client('sagemaker') + + try: # check if endpoint already existst + sagemaker_client.describe_endpoint(EndpointName=SAGEMAKER_ENDPOINT_NAME) + print(f"Endpoint with name {SAGEMAKER_ENDPOINT_NAME} found!") + return + + except: + print(f"Creating endpoint with model{hf_model_id} on {instance_type}...") + + # create HuggingFaceModel with the image uri + llm_model = HuggingFaceModel( + role=get_iam_role(), + image_uri=llm_image, + env={ + 'HF_MODEL_ID': hf_model_id, + 'SM_NUM_GPUS': json.dumps(number_of_gpu), + 'HF_MODEL_TRUST_REMOTE_CODE': json.dumps(trust_remote_code) + } + ) + + # Deploy model to an endpoint + # https://sagemaker.readthedocs.io/en/stable/api/inference/model.html#sagemaker.model.Model.deploy + llm = llm_model.deploy( + endpoint_name=endpoint_name, + initial_instance_count=1, + instance_type=instance_type, + # volume_size=400, # If using an instance with local SSD storage, volume_size must be None, e.g. p4 but not p3 + container_startup_health_check_timeout=health_check_timeout # 10 minutes to be able to load the model + ) + + print(f"\nEndpoint created ({endpoint_name})") diff --git a/src/lex-gen-ai-demo-cdk/index-creation-docker-image/Dockerfile b/src/lex-gen-ai-demo-cdk/index-creation-docker-image/Dockerfile new file mode 100644 index 00000000..6fadfb43 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/index-creation-docker-image/Dockerfile @@ -0,0 +1,14 @@ +FROM public.ecr.aws/lambda/python:3.8 + +COPY index_creation_requirements.txt . +RUN pip3 install -r index_creation_requirements.txt --target "${LAMBDA_TASK_ROOT}" + +# Copy function code +COPY *.py ${LAMBDA_TASK_ROOT} + +# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) +CMD [ "index_creation_app.handler" ] + +# Set cache to a location lambda can write to +ENV TRANSFORMERS_CACHE="/tmp/TRANSFORMERS_CACHE" + diff --git a/src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_app.py b/src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_app.py new file mode 100644 index 00000000..03716455 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_app.py @@ -0,0 +1,126 @@ +import boto3 +import json +from pathlib import Path + +import logging +from langchain.llms.base import LLM +from typing import Optional, List, Mapping, Any +import os +from llama_index import ( + LangchainEmbedding, + GPTVectorStoreIndex, + LLMPredictor, + ServiceContext, + Document, + PromptHelper, + download_loader +) + +from langchain.embeddings import HuggingFaceEmbeddings + +import logging +from botocore.exceptions import ClientError + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +ACCOUNT_ID = boto3.client('sts').get_caller_identity().get('Account') +INDEX_BUCKET = "lexgenaistack-created-index-bucket-"+ACCOUNT_ID +S3_BUCKET = "lexgenaistack-source-materials-bucket-"+ACCOUNT_ID +ENDPOINT_NAME = "huggingface-pytorch-sagemaker-endpoint" +DELIMITER = "\n\n\n" +LOCAL_INDEX_LOC = "/tmp/index_files" + +def handler(event, context): + event_record = event['Records'][0] + if event_record['eventName'] == "ObjectCreated:Put": + if ".txt" in event_record['s3']['object']['key'].lower() or ".pdf" in event_record['s3']['object']['key'].lower(): + source_material_key = event_record['s3']['object']['key'] + logger.info(f"Source file {source_material_key} found") + else: + logger.error("INVALID FILE, MUST END IN .TXT or .PDF") + return + else: + logger.error("NON OBJECTCREATION INVOCATION") + return + + s3_client = boto3.client('s3') + try: + s3_client.download_file(S3_BUCKET, source_material_key, "/tmp/"+source_material_key) + logger.info(f"Downloaded {source_material_key}") + except ClientError as e: + logger.error(e) + return "ERROR READING FILE" + + if ".pdf" in source_material_key.lower(): + PDFReader = download_loader("PDFReader", custom_path="/tmp/llama_cache") + loader = PDFReader() + documents = loader.load_data(file=Path("/tmp/"+source_material_key)) + else: + with open("/tmp/"+source_material_key) as f: + text_list = f.read().split(DELIMITER) + logger.info(f"Reading text with delimiter {repr(DELIMITER)}") + documents = [Document(t) for t in text_list] + + # define prompt helper + max_input_size = 400 # set maximum input size + num_output = 50 # set number of output tokens + max_chunk_overlap = 0 # set maximum chunk overlap + prompt_helper = PromptHelper(max_input_size, num_output, max_chunk_overlap) + + # define our LLM + llm_predictor = LLMPredictor(llm=CustomLLM()) + embed_model = LangchainEmbedding(HuggingFaceEmbeddings(cache_folder="/tmp/HF_CACHE")) + service_context = ServiceContext.from_defaults( + llm_predictor=llm_predictor, prompt_helper=prompt_helper, embed_model=embed_model, + ) + + index = GPTVectorStoreIndex.from_documents(documents, service_context=service_context) + index.storage_context.persist(persist_dir=LOCAL_INDEX_LOC) + + for file in os.listdir(LOCAL_INDEX_LOC): + s3_client.upload_file(LOCAL_INDEX_LOC+"/"+file, INDEX_BUCKET, file) # ASSUMES IT CAN OVERWRITE, I.E. S3 OBJECT LOCK MUST BE OFF + + logger.info("Index successfully created") + return + +def call_sagemaker(prompt, endpoint_name=ENDPOINT_NAME): + payload = { + "inputs": prompt, + "parameters": { + "do_sample": False, + # "top_p": 0.9, + "temperature": 0.1, + "max_new_tokens": 200, + "repetition_penalty": 1.03, + "stop": ["\nUser:", "<|endoftext|>", ""] + } + } + + sagemaker_client = boto3.client("sagemaker-runtime") + payload = json.dumps(payload) + response = sagemaker_client.invoke_endpoint( + EndpointName=endpoint_name, ContentType="application/json", Body=payload + ) + response_string = response["Body"].read().decode() + return response_string + +def get_response_sagemaker_inference(prompt, endpoint_name=ENDPOINT_NAME): + resp = call_sagemaker(prompt, endpoint_name) + resp = json.loads(resp)[0]["generated_text"][len(prompt):] + return resp + +class CustomLLM(LLM): + model_name = "tiiuae/falcon-7b-instruct" + + def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str: + response = get_response_sagemaker_inference(prompt, ENDPOINT_NAME) + return response + + @property + def _identifying_params(self) -> Mapping[str, Any]: + return {"name_of_model": self.model_name} + + @property + def _llm_type(self) -> str: + return "custom" \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_requirements.txt b/src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_requirements.txt new file mode 100644 index 00000000..91b261b8 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/index-creation-docker-image/index_creation_requirements.txt @@ -0,0 +1,6 @@ +transformers==4.25.1 +langchain +llama-index==0.6.20 +sentence-transformers +pypdf +typing_extensions \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/Dockerfile b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/Dockerfile new file mode 100644 index 00000000..25be1f60 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/Dockerfile @@ -0,0 +1,14 @@ +FROM public.ecr.aws/lambda/python:3.8 + +COPY runtime_lambda_requirements.txt . +RUN pip3 install -r runtime_lambda_requirements.txt --target "${LAMBDA_TASK_ROOT}" + +# Copy function code +COPY *.py ${LAMBDA_TASK_ROOT} + +# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) +CMD [ "runtime_lambda_app.handler" ] + +# Set cache to a location lambda can write to +ENV TRANSFORMERS_CACHE="/tmp/TRANSFORMERS_CACHE" + diff --git a/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_app.py b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_app.py new file mode 100644 index 00000000..467c3d81 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_app.py @@ -0,0 +1,176 @@ +import boto3 +from botocore.exceptions import ClientError +import logging +import json +import os +from typing import Optional, List, Mapping, Any +from langchain.llms.base import LLM +from llama_index import ( + LangchainEmbedding, + PromptHelper, + ResponseSynthesizer, + LLMPredictor, + ServiceContext, + Prompt, +) + +from langchain.embeddings import HuggingFaceEmbeddings +from llama_index.query_engine import RetrieverQueryEngine +from llama_index.retrievers import VectorIndexRetriever +from llama_index.vector_stores.types import VectorStoreQueryMode +from llama_index import StorageContext, load_index_from_storage + +s3_client = boto3.client('s3') + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +ENDPOINT_NAME = "huggingface-pytorch-sagemaker-endpoint" +OUT_OF_DOMAIN_RESPONSE = "I'm sorry, but I am only able to give responses regarding the source topic" +INDEX_WRITE_LOCATION = "/tmp/index" +ACCOUNT_ID = boto3.client('sts').get_caller_identity().get('Account') +INDEX_BUCKET = "lexgenaistack-created-index-bucket-"+ACCOUNT_ID +RETRIEVAL_THRESHOLD = 0.4 + +# define prompt helper +max_input_size = 400 # set maximum input size +num_output = 50 # set number of output tokens +max_chunk_overlap = 0 # set maximum chunk overlap +prompt_helper = PromptHelper(max_input_size, num_output, max_chunk_overlap) + + +def handler(event, context): + + # lamda can only write to /tmp/ + initialize_cache() + + # define our LLM + llm_predictor = LLMPredictor(llm=CustomLLM()) + embed_model = LangchainEmbedding(HuggingFaceEmbeddings(cache_folder="/tmp/HF_CACHE")) + service_context = ServiceContext.from_defaults( + llm_predictor=llm_predictor, prompt_helper=prompt_helper, embed_model=embed_model, + ) + + ### Download index here + if not os.path.exists(INDEX_WRITE_LOCATION): + os.mkdir(INDEX_WRITE_LOCATION) + try: + s3_client.download_file(INDEX_BUCKET, "docstore.json", INDEX_WRITE_LOCATION + "/docstore.json") + s3_client.download_file(INDEX_BUCKET, "index_store.json", INDEX_WRITE_LOCATION + "/index_store.json") + s3_client.download_file(INDEX_BUCKET, "vector_store.json", INDEX_WRITE_LOCATION + "/vector_store.json") + + # load index + storage_context = StorageContext.from_defaults(persist_dir=INDEX_WRITE_LOCATION) + index = load_index_from_storage(storage_context, service_context=service_context) + logger.info("Index successfully loaded") + except ClientError as e: + logger.error(e) + return "ERROR LOADING/READING INDEX" + + retriever = VectorIndexRetriever( + service_context=service_context, + index=index, + similarity_top_k=5, + vector_store_query_mode=VectorStoreQueryMode.DEFAULT, # doesn't work with simple + alpha=0.5, + ) + + # configure response synthesizer + synth = ResponseSynthesizer.from_args( + response_mode="simple_summarize", + service_context=service_context + ) + + query_engine = RetrieverQueryEngine(retriever=retriever, response_synthesizer=synth) + query_input = event["inputTranscript"] + + try: + answer = query_engine.query(query_input) + if answer.source_nodes[0].score < RETRIEVAL_THRESHOLD: + answer = OUT_OF_DOMAIN_RESPONSE + except: + answer = OUT_OF_DOMAIN_RESPONSE + + response = generate_lex_response(event, {}, "Fulfilled", answer) + jsonified_resp = json.loads(json.dumps(response, default=str)) + return jsonified_resp + +def generate_lex_response(intent_request, session_attributes, fulfillment_state, message): + intent_request['sessionState']['intent']['state'] = fulfillment_state + return { + 'sessionState': { + 'sessionAttributes': session_attributes, + 'dialogAction': { + 'type': 'Close' + }, + 'intent': intent_request['sessionState']['intent'] + }, + 'messages': [ + { + "contentType": "PlainText", + "content": message + } + ], + 'requestAttributes': intent_request['requestAttributes'] if 'requestAttributes' in intent_request else None + } + +# define prompt template +template = ( + "We have provided context information below. \n" + "---------------------\n" + "CONTEXT1:\n" + "{context_str}\n\n" + "CONTEXT2:\n" + "CANNOTANSWER" + "\n---------------------\n" + 'Given this context, please answer the question if answerable based on on the CONTEXT1 and CONTEXT2: "{query_str}"\n; ' # otherwise specify it as CANNOTANSWER +) +my_qa_template = Prompt(template) + +def call_sagemaker(prompt, endpoint_name=ENDPOINT_NAME): + payload = { + "inputs": prompt, + "parameters": { + "do_sample": False, + # "top_p": 0.9, + "temperature": 0.1, + "max_new_tokens": 200, + "repetition_penalty": 1.03, + "stop": ["\nUser:", "<|endoftext|>", ""] + } + } + + sagemaker_client = boto3.client("sagemaker-runtime") + payload = json.dumps(payload) + response = sagemaker_client.invoke_endpoint( + EndpointName=endpoint_name, ContentType="application/json", Body=payload + ) + response_string = response["Body"].read().decode() + return response_string + +def get_response_sagemaker_inference(prompt, endpoint_name=ENDPOINT_NAME): + resp = call_sagemaker(prompt, endpoint_name) + resp = json.loads(resp)[0]["generated_text"][len(prompt):] + return resp + +class CustomLLM(LLM): + model_name = "tiiuae/falcon-7b-instruct" + + def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str: + response = get_response_sagemaker_inference(prompt, ENDPOINT_NAME) + return response + + @property + def _identifying_params(self) -> Mapping[str, Any]: + return {"name_of_model": self.model_name} + + @property + def _llm_type(self) -> str: + return "custom" + +def initialize_cache(): + if not os.path.exists("/tmp/TRANSFORMERS_CACHE"): + os.mkdir("/tmp/TRANSFORMERS_CACHE") + + if not os.path.exists("/tmp/HF_CACHE"): + os.mkdir("/tmp/HF_CACHE") \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt new file mode 100644 index 00000000..be0597b3 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt @@ -0,0 +1,4 @@ +transformers==4.25.1 +langchain +llama-index==0.6.20 +sentence-transformers \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/__init__.py b/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py b/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py new file mode 100644 index 00000000..035ac52d --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py @@ -0,0 +1,130 @@ +from aws_cdk import ( + Duration, App, Stack, CfnResource, + aws_lex as lex, + aws_s3 as s3, + aws_s3_notifications as s3n, + aws_s3_deployment as s3deploy, + aws_iam as iam, + aws_lambda as lambda_ +) + +from constructs import Construct + +class LexGenAIDemoFilesStack(Stack): + + def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: + super().__init__(scope, construct_id, **kwargs) + + # Iam role for bot to invoke lambda + lex_cfn_role = iam.Role(self, "CfnLexGenAIDemoRole", + assumed_by=iam.ServicePrincipal("lexv2.amazonaws.com") + ) + lex_cfn_role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("AWSLambdaExecute")) + + # Iam role for lambda to invoke sagemaker + lambda_cfn_role = iam.Role(self, "CfnLambdaGenAIDemoRole", + assumed_by=iam.ServicePrincipal("lambda.amazonaws.com") + ) + lambda_cfn_role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("AmazonSageMakerFullAccess")) + lambda_cfn_role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("AmazonS3FullAccess")) + + # will append account id to this string to avoid in region collisions + source_bucket_name = "lexgenaistack-source-materials-bucket-" + index_bucket_name = "lexgenaistack-created-index-bucket-" + + # S3 Buckets for materials to index and for the resulting indexes + source_bucket = s3.Bucket(self, "SourceMatBucketID-CFN", + bucket_name=source_bucket_name+lex_cfn_role.principal_account, + block_public_access=s3.BlockPublicAccess.BLOCK_ALL, + encryption=s3.BucketEncryption.S3_MANAGED, + enforce_ssl=True, + versioned=True) + + index_bucket = s3.Bucket(self, "IndexBucket-CFN", + bucket_name=index_bucket_name+lex_cfn_role.principal_account, + block_public_access=s3.BlockPublicAccess.BLOCK_ALL, + encryption=s3.BucketEncryption.S3_MANAGED, + enforce_ssl=True, + versioned=True) + + # create lambda image for on demand index creation + read_source_and_build_index_function = lambda_.DockerImageFunction(self, "read-source-and-build-index-function-CFN", function_name="read-source-and-build-index-fn", + code=lambda_.DockerImageCode.from_image_asset("index-creation-docker-image"), + role=lambda_cfn_role, + memory_size=10240, + timeout=Duration.minutes(5) + ) + source_bucket.add_event_notification(s3.EventType.OBJECT_CREATED, s3n.LambdaDestination(read_source_and_build_index_function)) + + # create image of lex-gen-ai-demo-docker-image, push to ECR and into a lambda function + runtime_function = lambda_.DockerImageFunction(self, "CFN-runtime-fn", function_name="lex-codehook-fn", + code=lambda_.DockerImageCode.from_image_asset("lex-gen-ai-demo-docker-image"), + role=lambda_cfn_role, + memory_size=10240, + timeout=Duration.minutes(5) + ) + runtime_function.grant_invoke(iam.ServicePrincipal("lexv2.amazonaws.com")) + + ### BOT SETUP + + # alias settings, where we define the lambda function with the ECR container with our LLM dialog code (defined in the lex-gen-ai-demo-docker-image directory) + # test bot alias for demo, create a dedicated alias for serving traffic + bot_alias_settings = lex.CfnBot.TestBotAliasSettingsProperty( + bot_alias_locale_settings=[lex.CfnBot.BotAliasLocaleSettingsItemProperty( + bot_alias_locale_setting=lex.CfnBot.BotAliasLocaleSettingsProperty( + enabled=True, + code_hook_specification=lex.CfnBot.CodeHookSpecificationProperty( + lambda_code_hook=lex.CfnBot.LambdaCodeHookProperty( + code_hook_interface_version="1.0", + lambda_arn=runtime_function.function_arn + ) + ) + ), + locale_id="en_US" + )]) + + # lambda itself is tied to alias but codehook settings are intent specific + initial_response_codehook_settings = lex.CfnBot.InitialResponseSettingProperty( + code_hook=lex.CfnBot.DialogCodeHookInvocationSettingProperty( + enable_code_hook_invocation=True, + is_active=True, + post_code_hook_specification=lex.CfnBot.PostDialogCodeHookInvocationSpecificationProperty() + ) + ) + + # placeholder intent to be missed for this demo + placeholder_intent = lex.CfnBot.IntentProperty( + name="placeHolderIntent", + initial_response_setting=initial_response_codehook_settings, + sample_utterances=[lex.CfnBot.SampleUtteranceProperty( + utterance="utterance" + )] + ) + + fallback_intent = lex.CfnBot.IntentProperty( + name="FallbackIntent", + parent_intent_signature="AMAZON.FallbackIntent", + initial_response_setting=initial_response_codehook_settings, + fulfillment_code_hook=lex.CfnBot.FulfillmentCodeHookSettingProperty( + enabled=True, + is_active=True, + post_fulfillment_status_specification=lex.CfnBot.PostFulfillmentStatusSpecificationProperty() + ) + ) + + # Create actual Lex Bot + cfn_bot = lex.CfnBot(self, "LexGenAIDemoCfnBot", + data_privacy={"ChildDirected":"false"}, + idle_session_ttl_in_seconds=300, + name="LexGenAIDemoBotCfn", + role_arn=lex_cfn_role.role_arn, + bot_locales=[lex.CfnBot.BotLocaleProperty( + locale_id="en_US", + nlu_confidence_threshold=0.4, + intents=[placeholder_intent, fallback_intent]) + ], + test_bot_alias_settings = bot_alias_settings, + auto_build_bot_locales=True + ) + + diff --git a/src/lex-gen-ai-demo-cdk/requirements.txt b/src/lex-gen-ai-demo-cdk/requirements.txt new file mode 100644 index 00000000..b9360e07 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/requirements.txt @@ -0,0 +1,4 @@ +aws-cdk-lib==2.80.0 +constructs>=10.0.0,<11.0.0 +sagemaker==2.163.0 +boto3 \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/shut_down_endpoint.py b/src/lex-gen-ai-demo-cdk/shut_down_endpoint.py new file mode 100644 index 00000000..844755f3 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/shut_down_endpoint.py @@ -0,0 +1,26 @@ +import boto3 +from botocore.exceptions import ClientError + +from endpoint_handler import SAGEMAKER_ENDPOINT_NAME + + +sagemaker_client = boto3.client('sagemaker') + + +try: + # verify endpoint exists + endpoint = sagemaker_client.describe_endpoint(EndpointName=SAGEMAKER_ENDPOINT_NAME) + print(f"Endpoint {endpoint['EndpointName']} found, shutting down") + + try: # delete both endpoint and configuration + sagemaker_client.delete_endpoint( + EndpointName=SAGEMAKER_ENDPOINT_NAME + ) + sagemaker_client.delete_endpoint_config( + EndpointConfigName=SAGEMAKER_ENDPOINT_NAME + ) + print(f"Endpoint {SAGEMAKER_ENDPOINT_NAME} shut down") + except ClientError as e: + print(e) +except: + print(f"Endpoint {SAGEMAKER_ENDPOINT_NAME} does not exist in account {boto3.client('sts').get_caller_identity().get('Account')}") \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/source.bat b/src/lex-gen-ai-demo-cdk/source.bat new file mode 100644 index 00000000..5cfcddd0 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/source.bat @@ -0,0 +1,13 @@ +@echo off + +rem The sole purpose of this script is to make the command +rem +rem source .venv/bin/activate +rem +rem (which activates a Python virtualenv on Linux or Mac OS X) work on Windows. +rem On Windows, this command just runs this batch file (the argument is ignored). +rem +rem Now we don't need to document a Windows command for activating a virtualenv. + +echo Executing .venv\Scripts\activate.bat for you +.venv\Scripts\activate.bat \ No newline at end of file diff --git a/src/lex-gen-ai-demo-cdk/upload_file_to_s3.py b/src/lex-gen-ai-demo-cdk/upload_file_to_s3.py new file mode 100644 index 00000000..7020b5a8 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/upload_file_to_s3.py @@ -0,0 +1,37 @@ +import sys +import boto3 +from botocore.exceptions import ClientError +import logging + +ACCOUNT_ID = boto3.client('sts').get_caller_identity().get('Account') +S3_BUCKET = "lexgenaistack-source-materials-bucket-"+ACCOUNT_ID +s3_client = boto3.client("s3") + +def main(): + if len(sys.argv) == 1: + print(f"[ERROR] You must specify file to upload") + elif len(sys.argv) == 2: + filepath = sys.argv[1] + upload(filepath) + elif len(sys.argv) == 3: + filepath = sys.argv[2] + upload(filepath) + else: + print("[ERROR] Too many arguments, only include /path/to/your/file") + + +def upload(filepath): + if filepath[-4:].lower() == '.txt' or filepath[-4:].lower() == '.pdf': + print(f"Uploading file at {filepath}") + try: + upload_name = filepath.split("/")[-1].replace(" ","").replace("/","") + s3_client.upload_file(filepath, S3_BUCKET, upload_name) + print(f"Successfully uploaded file at {filepath}, creating index...") + except ClientError as e: + logging.error(e) + else: + print("[ERROR] File must be txt or PDF") + + +if __name__ == "__main__": + main() \ No newline at end of file From b38fb2bc8d02c0d48670fb62255351a26382528f Mon Sep 17 00:00:00 2001 From: Max Henkel-Wallace Date: Wed, 5 Jul 2023 18:15:56 -0700 Subject: [PATCH 2/3] Addition of a lambda for web crawling to create index --- src/lex-gen-ai-demo-cdk/app.py | 2 + .../create_web_crawler_lambda.py | 36 +++++ .../lex_gen_ai_demo_cdk_files_stack.py | 2 +- .../web-crawler-docker-image/Dockerfile | 11 ++ .../web_crawler_app.py | 125 ++++++++++++++++++ .../web_crawler_requirements.txt | 4 + src/lex-gen-ai-demo-cdk/web_crawl.py | 43 ++++++ 7 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/lex-gen-ai-demo-cdk/create_web_crawler_lambda.py create mode 100644 src/lex-gen-ai-demo-cdk/web-crawler-docker-image/Dockerfile create mode 100644 src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_app.py create mode 100644 src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_requirements.txt create mode 100644 src/lex-gen-ai-demo-cdk/web_crawl.py diff --git a/src/lex-gen-ai-demo-cdk/app.py b/src/lex-gen-ai-demo-cdk/app.py index c2fb9cbb..10a393b3 100644 --- a/src/lex-gen-ai-demo-cdk/app.py +++ b/src/lex-gen-ai-demo-cdk/app.py @@ -2,6 +2,7 @@ import aws_cdk as cdk from lex_gen_ai_demo_cdk_files.lex_gen_ai_demo_cdk_files_stack import LexGenAIDemoFilesStack +from create_web_crawler_lambda import LambdaStack from endpoint_handler import create_endpoint_from_HF_image # create_endpoint_from_HF_image(hf_model_id, instance_type="ml.g5.8xlarge", endpoint_name=SAGEMAKER_ENDPOINT_NAME, number_of_gpu=1) @@ -10,5 +11,6 @@ app = cdk.App() filestack = LexGenAIDemoFilesStack(app, "LexGenAIDemoFilesStack") +web_crawler_lambda_stack = LambdaStack(app, 'LexGenAIDemoFilesStack-Webcrawler') app.synth() diff --git a/src/lex-gen-ai-demo-cdk/create_web_crawler_lambda.py b/src/lex-gen-ai-demo-cdk/create_web_crawler_lambda.py new file mode 100644 index 00000000..5aca2aae --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/create_web_crawler_lambda.py @@ -0,0 +1,36 @@ +from aws_cdk import ( + Duration, Stack, + aws_lambda as lambda_, + aws_s3 as s3, + aws_iam as iam +) + +from constructs import Construct + +class LambdaStack(Stack): + + def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: + super().__init__(scope, construct_id, **kwargs) + # Iam role for lambda to invoke sagemaker + web_crawl_lambda_cfn_role = iam.Role(self, "Cfn-gen-ai-demo-web-crawler", + assumed_by=iam.ServicePrincipal("lambda.amazonaws.com") + ) + web_crawl_lambda_cfn_role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("AmazonS3FullAccess")) + web_crawl_lambda_cfn_role.add_to_policy( + iam.PolicyStatement( + actions=[ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + resources=["*"] + ) + ) + # Lambda function + lambda_function= lambda_.DockerImageFunction(self, "web-crawler-docker-image-CFN", + function_name="WebCrawlerLambda", + code=lambda_.DockerImageCode.from_image_asset("web-crawler-docker-image"), + role=web_crawl_lambda_cfn_role, + memory_size=1024, + timeout=Duration.minutes(5) + ) diff --git a/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py b/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py index 035ac52d..05746f9e 100644 --- a/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py +++ b/src/lex-gen-ai-demo-cdk/lex_gen_ai_demo_cdk_files/lex_gen_ai_demo_cdk_files_stack.py @@ -127,4 +127,4 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: auto_build_bot_locales=True ) - + diff --git a/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/Dockerfile b/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/Dockerfile new file mode 100644 index 00000000..c7e2b358 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/Dockerfile @@ -0,0 +1,11 @@ +FROM public.ecr.aws/lambda/python:3.8 + +COPY web_crawler_requirements.txt . +RUN pip3 install -r web_crawler_requirements.txt --target "${LAMBDA_TASK_ROOT}" + +# Copy function code +COPY *.py ${LAMBDA_TASK_ROOT} + +# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) +CMD [ "web_crawler_app.handler" ] + diff --git a/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_app.py b/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_app.py new file mode 100644 index 00000000..25af7799 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_app.py @@ -0,0 +1,125 @@ +import boto3 +import requests +import html2text +from typing import List +import re +import logging +import json +import traceback + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def find_http_urls_in_parentheses(s: str, prefix: str = None): + pattern = r'\((https?://[^)]+)\)' + urls = re.findall(pattern, s) + + matched = [] + if prefix is not None: + for url in urls: + if str(url).startswith(prefix): + matched.append(url) + else: + matched = urls + + return list(set(matched)) # remove duplicates by converting to set, then convert back to list + + + +class EZWebLoader: + + def __init__(self, default_header: str = None): + self._html_to_text_parser = html2text + if default_header is None: + self._default_header = {"User-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36"} + else: + self._default_header = default_header + + def load_data(self, + urls: List[str], + num_levels: int = 0, + level_prefix: str = None, + headers: str = None) -> List[str]: + + logging.info(f"Number of urls: {len(urls)}.") + + if headers is None: + headers = self._default_header + + documents = [] + visited = {} + for url in urls: + q = [url] + depth = num_levels + for page in q: + if page not in visited: #prevent cycles by checking to see if we already crawled a link + logging.info(f"Crawling {page}") + visited[page] = True #add entry to visited to prevent re-crawling pages + response = requests.get(page, headers=headers).text + response = self._html_to_text_parser.html2text(response) #reduce html to text + documents.append(response) + if depth > 0: + #crawl linked pages + ingest_urls = find_http_urls_in_parentheses(response, level_prefix) + logging.info(f"Found {len(ingest_urls)} pages to crawl.") + q.extend(ingest_urls) + depth -= 1 #reduce the depth counter so we go only num_levels deep in our crawl + else: + logging.info(f"Skipping {page} as it has already been crawled") + logging.info(f"Number of documents: {len(documents)}.") + return documents + +ACCOUNT_ID = boto3.client('sts').get_caller_identity().get('Account') +S3_BUCKET = "lexgenaistack-source-materials-bucket-" + ACCOUNT_ID +FILE_NAME = 'web-crawl-results.txt' + + +def handler(event, context): + url = "http://www.zappos.com/general-questions" + depth = 1 + level_prefix = "https://www.zappos.com/" + + if event is not None: + if "url" in event: + url = event["url"] + if "depth" in event: + depth = int(event["depth"]) + if "level_prefix" in event: + level_prefix = event["level_prefix"] + + # crawl the website + try: + logger.info(f"Crawling {url} to depth of {depth}...") + loader = EZWebLoader() + documents = loader.load_data([url], depth, level_prefix) + doc_string = json.dumps(documents, indent=1) + logger.info(f"Crawling {url} to depth of {depth} succeeded") + except Exception as e: + # If there's an error, print the error message + logging.error(f"An error occurred during the crawl of {url}.") + exception_traceback = traceback.format_exc() + logger.error(exception_traceback) + return { + "status": 500, + "message": exception_traceback + } + # save the results for indexing + try: + # Use the S3 client to write the string to S3 + s3 = boto3.client('s3') + s3.put_object(Body=doc_string, Bucket=S3_BUCKET, Key=FILE_NAME) + success_msg = f'Successfully put {FILE_NAME} to {S3_BUCKET}' + logging.info(success_msg) + return { + "status": 200, + "message": success_msg + } + except Exception as e: + # If there's an error, print the error message + exception_traceback = traceback.format_exc() + logger.error(exception_traceback) + return { + "status": 500, + "message": exception_traceback + } diff --git a/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_requirements.txt b/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_requirements.txt new file mode 100644 index 00000000..388c7bea --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/web-crawler-docker-image/web_crawler_requirements.txt @@ -0,0 +1,4 @@ +requests +html2text +accelerate +boto3 diff --git a/src/lex-gen-ai-demo-cdk/web_crawl.py b/src/lex-gen-ai-demo-cdk/web_crawl.py new file mode 100644 index 00000000..c2d596c5 --- /dev/null +++ b/src/lex-gen-ai-demo-cdk/web_crawl.py @@ -0,0 +1,43 @@ +import boto3 +import argparse +import json + + +def invoke_lambda(url=None, depth="1", level_prefix=None): + client = boto3.client('lambda') + + # Prepare the payload + payload = {} + if url is not None: + payload["url"] = url + if depth is not None: + payload["depth"] = depth + if level_prefix is not None: + payload["level_prefix"] = level_prefix + + try: + response = client.invoke( + FunctionName='WebCrawlerLambda', + InvocationType='RequestResponse', + LogType='Tail', + # The payload must be a JSON-formatted string + Payload=json.dumps(payload) + ) + + # The response from Lambda will be a JSON string, so you need to parse it + result = response['Payload'].read().decode('utf-8') + + print("Response: " + result) + + except Exception as e: + print(e) + + +# Parse command-line arguments +parser = argparse.ArgumentParser() +parser.add_argument('--url', type=str, help='The URL to process.', required=False, default=None) +parser.add_argument('--depth', type=int, help='The depth of the crawl.', required=False, default="1") +parser.add_argument('--level_prefix', type=str, help='The prefix that any links must contain to crawl.', required=False, default=None) +args = parser.parse_args() + +invoke_lambda(args.url, args.depth, args.level_prefix) From 700897df961d341df265cb76dc27d0578c82ee4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 01:16:22 +0000 Subject: [PATCH 3/3] Bump transformers Bumps [transformers](https://github.com/huggingface/transformers) from 4.25.1 to 4.30.0. - [Release notes](https://github.com/huggingface/transformers/releases) - [Commits](https://github.com/huggingface/transformers/compare/v4.25.1...v4.30.0) --- updated-dependencies: - dependency-name: transformers dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .../runtime_lambda_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt index be0597b3..3105a486 100644 --- a/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt +++ b/src/lex-gen-ai-demo-cdk/lex-gen-ai-demo-docker-image/runtime_lambda_requirements.txt @@ -1,4 +1,4 @@ -transformers==4.25.1 +transformers==4.30.0 langchain llama-index==0.6.20 sentence-transformers \ No newline at end of file