├── .gitignore ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── auto-manufacturing ├── README.md └── chatbot-realtime-smart-monitoring │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── bin │ └── chatbot-realtime-smart-monitoring.ts │ ├── cdk.json │ ├── index-custom-resource │ ├── Dockerfile │ ├── index_custom_resource.py │ └── requirements.txt │ ├── jest.config.js │ ├── lib │ ├── api-stack.ts │ ├── bedrock-stack.ts │ ├── constants.ts │ ├── opensearch-stack.ts │ ├── roles-stack.ts │ └── ui-stack.ts │ ├── package.json │ ├── sampledocs │ ├── EC101.pdf │ ├── PL203.pdf │ └── Training Manual.pdf │ ├── src │ └── troubleshoot-sensor.ts │ ├── static-site │ ├── chatbot.html │ ├── index.html │ ├── script.js │ └── styles.css │ └── tsconfig.json ├── healthcare-life-sciences ├── README.md └── automate-discharge-instructions │ ├── .eslintrc.json │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── api-spec │ └── schema.json │ ├── bin │ └── automate-discharge-instructions.ts │ ├── cdk.json │ ├── index-custom-resource │ ├── Dockerfile │ ├── index_custom_resource.py │ └── requirements.txt │ ├── jest.config.js │ ├── lib │ ├── api-spec-stack.ts │ ├── bedrock-stack.ts │ ├── constants.ts │ ├── opensearch-stack.ts │ └── roles-stack.ts │ ├── migrate.json │ ├── package.json │ ├── sampledocs │ ├── acne │ └── dermatitis │ ├── screenshots │ ├── image-1.png │ ├── image-2.png │ ├── image-3.png │ ├── image-4.png │ ├── image-5.png │ ├── image-6.png │ ├── image-7.png │ ├── image-8.png │ └── image.png │ ├── src │ ├── get-patient │ │ └── index.ts │ └── types │ │ ├── bedrock-action-group-input.ts │ │ └── bedrock-action-group-output.ts │ └── tsconfig.json └── travel-hospitality ├── README.md └── travel-planner ├── .gitignore ├── .npmignore ├── README.md ├── bin └── bedrock-agent-cdk.ts ├── cdk.json ├── jest.config.js ├── lib ├── assets │ ├── api-schema │ │ ├── create_openapi_schema.py │ │ └── schema.json │ └── lambda │ │ ├── Dockerfile │ │ ├── agent.py │ │ └── requirements.txt ├── bedrock-agent-cdk-stack.ts ├── constants.ts └── constructs │ ├── bedrock-agent-construct.ts │ ├── bedrock-agent-iam-construct.ts │ ├── lambda-construct.ts │ ├── lambda-iam-construct.ts │ └── s3-bucket-construct.ts ├── package.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | cucumber-report.html 8 | tsconfig.tsbuildinfo 9 | # Only exists if Bazel was run 10 | /bazel-out 11 | /build 12 | 13 | # CDK 14 | cdk.out 15 | cdk.context.json 16 | 17 | # dependencies 18 | /node_modules 19 | **/node_modules 20 | package-lock.json 21 | 22 | # profiling files 23 | chrome-profiler-events.json 24 | speed-measure-plugin.json 25 | 26 | # IDEs and editors 27 | /.idea 28 | .project 29 | .classpath 30 | .c9/ 31 | *.launch 32 | .settings/ 33 | *.sublime-workspace 34 | 35 | # IDE - VSCode 36 | .vscode/* 37 | !.vscode/settings.json 38 | !.vscode/tasks.json 39 | !.vscode/launch.json 40 | !.vscode/extensions.json 41 | .history/* 42 | 43 | # misc 44 | /.sass-cache 45 | /connect.lock 46 | /coverage 47 | /libpeerconnection.log 48 | npm-debug.log 49 | yarn-error.log 50 | testem.log 51 | /typings 52 | /.nyc_output 53 | /.semrel 54 | /.aws-sam 55 | .env 56 | .env-jest 57 | 58 | # System Files 59 | .DS_Store 60 | Thumbs.db -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "[typescript]": { 4 | "editor.defaultFormatter": "esbenp.prettier-vscode" 5 | }, 6 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amazon Bedrock Agents: Industry Use Cases 2 | 3 | This repository contains pre-built examples to help developers get started with Generative AI agents with Bedrock across multiple industries. The purpose of these templates are to enable GenAI developers and engineers with the proper resources and templates that can be customized with their own proprietary data to be used across various industries. 4 | 5 | ## Contents 6 | 7 | - [Healthcare Life Sciences](healthcare-life-sciences) 8 | - [Automate Discharge Instructions](healthcare-life-sciences/automate-discharge-instructions) - An agent designed to help with patient discharge instructions 9 | - [Auto Manufacturing](auto-manufacturing) 10 | - [Equipment Monitoring Assistant](auto-manufacturing/chatbot-realtime-smart-monitoring) - An intelligent agent that provides real-time equipment monitoring and troubleshooting through natural language interactions 11 | - [Travel & Hospitality](travel-hospitality) 12 | - [Travel Planner](travel-hospitality/travel-planner) - An agent designed to help with finding the best flights, hotels, and plan vacations 13 | 14 | ## Getting Started 15 | 16 | To get started with the code examples, ensure you have access to [Amazon Bedrock](https://aws.amazon.com/bedrock/). Then clone this repo and navigate to one of the folders above. Detailed instructions are provided in each folder's README. Make sure to configure the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) in your environment. 17 | 18 | ## Contributing 19 | 20 | We welcome community contributions! The goal is to keep this sample as a collaborative source-of-truth repository for builders and developers that have industry specific use cases that they have built out on Amazon Bedrock and want to share with the open-source community. The team is constantly building new genAI applications and always looking to push new demos out to automate daily tasks with Amazon Bedrock. 21 | 22 | For any specific questions on how to contribute, please contact puniomp@amazon.com and armdiazg@amazon.com. 23 | 24 | Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. 25 | 26 | ## Security 27 | 28 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 29 | 30 | ## License 31 | 32 | This library is licensed under the MIT-0 License. See the [LICENSE](LICENSE) file. 33 | -------------------------------------------------------------------------------- /auto-manufacturing/README.md: -------------------------------------------------------------------------------- 1 | # AWS Samples - Auto Manufacturing Industry 2 | 3 | This directory contains sample applications demonstrating how to integrate Amazon Web Services with auto manufacturing industry use cases. 4 | 5 | ## Solutions 6 | 7 | ### Equipment Monitoring Assistant 8 | 9 | The Equipment Monitoring Assistant is an intelligent chatbot agent that combines real-time equipment monitoring with natural language processing capabilities. This solution enables: 10 | 11 | - Real-time monitoring and analysis of equipment performance metrics 12 | - Natural language querying of equipment documentation and operational data 13 | - Intelligent alerting and troubleshooting recommendations when metrics deviate from expected ranges 14 | - Seamless integration of equipment manuals and historical data for comprehensive responses 15 | - Interactive dashboard with AI-powered insights for preventive maintenance 16 | 17 | ## Getting Started 18 | 19 | Each subdirectory contains a standalone sample application with its own deployment and usage instructions. Navigate to the specific solution you're interested in to get started. 20 | 21 | ## Security 22 | 23 | See [CONTRIBUTING](../CONTRIBUTING.md) for more information. 24 | 25 | ## License 26 | 27 | This library is licensed under the MIT-0 License. See the LICENSE file. -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/.gitignore: -------------------------------------------------------------------------------- 1 | !jest.config.js 2 | *.d.ts 3 | node_modules 4 | 5 | # CDK asset staging directory 6 | .cdk.staging 7 | cdk.out 8 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/README.md: -------------------------------------------------------------------------------- 1 | # Chatbot for Realtime Smart Monitoring 2 | ================================= 3 | 4 | ## Authors: 5 | - [Rafael Caixeta](https://www.linkedin.com/in/rafaelcaixeta/) @caixeta 6 | - [Alejandro Cayo](https://www.linkedin.com/in/alejandro-c-6623491a9) @acayo 7 | - [Nikhil Parekh](https://www.linkedin.com/in/parekhn/) @nikpaws 8 | - [Bichitresh Saha](https://www.linkedin.com/in/bichitresh-saha/) @btsaha 9 | 10 | # Prerequisites 11 | =============== 12 | * Deploy this infrastructure in the us-east-1 region 13 | * [node](https://nodejs.org/en) >= 16.0.0 14 | * [npm](https://www.npmjs.com/) >= 8.0.0 15 | * [AWS CLI](https://aws.amazon.com/cli/) >= 2.0.0 16 | * [AWS CDK](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html) >= 2.127.0 17 | 18 | 19 | ## Setup AWS Infratructure 20 | 21 | 1. Install NPM Packages 22 | 23 | ```bash 24 | npm i 25 | ``` 26 | 27 | 2. Generate the template 28 | 29 | ```bash 30 | cdk synth -q 31 | ``` 32 | 33 | 3. Bootstrap your AWS Account for CDK (*This only needs to be done once for a AWS Account. If you already bootstrap your AWS Account for CDK you can skip this step.*) 34 | 35 | ```bash 36 | cdk bootstrap 37 | ``` 38 | 39 | 4. Deploy to your AWS Account in context (*Make sure you correctly configure AWS CLI and have a profile and region set*) 40 | 41 | ```bash 42 | cdk deploy roles-stack --require-approval=never 43 | cdk deploy opensearch-stack --require-approval=never 44 | cdk deploy bedrock-stack --require-approval=never 45 | ``` 46 | 47 | - Copy the PDF files from `auto-manufacturing/chatbot-realtime-smart-monitoring/sampledocs` folder to the s3 bucket created by the bedrock-stack. The bucket name can be found under the outputs tab for the stack with a key name 'kbbucketname'. 48 | - After uploading the files, go to the Bedrock Service. Under Knowledge Bases, select the 'mfg-kb' knowledge base, select the Data Source 'diagnostics-kb-datasource' and click on the 'Sync' button. 49 | 50 | ```bash 51 | cdk deploy api-stack --require-approval=never 52 | cdk deploy ui-stack --require-approval=never 53 | ``` 54 | 55 | 5. Update and Upload the UI files 56 | 57 | - Open the `auto-manufacturing/chatbot-realtime-smart-monitoring/static-site/chatbot.html` file and update the API_ENDPOINT URL hostname with the hostname shown ApiEndpoint key in the output tab of the api-stack CloudFormation stack. 58 | - Copy all files from the `auto-manufacturing/chatbot-realtime-smart-monitoring/static-site/` folder to the s3 bucket created by the ui-stack. The bucket name can be found under the outputs tab for the stack with the key name 'smartmons3bucketname' 59 | - Finally, you can access the UI file by launching the URL for the CloudFront distribution deployed by the ui-stack. The URL can be found under the outputs tab under the key 'smartmoncdnurl' 60 | 61 | # How to delete 62 | 63 | From within the root project folder (``auto-manufacturing``), run the following command: 64 | 65 | ```sh 66 | cdk destroy --force --all 67 | ``` 68 | 69 | **Note - if you created any aliases/versions within your agent you would have to manually delete it in the console.** 70 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/bin/chatbot-realtime-smart-monitoring.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as cdk from 'aws-cdk-lib'; 3 | import { RolesStack } from '../lib/roles-stack'; 4 | import { BedrockStack } from '../lib/bedrock-stack'; 5 | import { OpensearchStack } from '../lib/opensearch-stack'; 6 | import { UIStack } from '../lib/ui-stack'; 7 | import { ApiStack } from '../lib/api-stack'; 8 | 9 | const app = new cdk.App(); 10 | new RolesStack(app, 'roles-stack', {}); 11 | new OpensearchStack(app, 'opensearch-stack', {}); 12 | new BedrockStack(app, 'bedrock-stack', {}); 13 | new ApiStack(app, 'api-stack', {}); 14 | new UIStack(app, 'ui-stack', {}); 15 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/chatbot-realtime-smart-monitoring.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 38 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 39 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 40 | "@aws-cdk/aws-route53-patters:useCertificate": true, 41 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 42 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 43 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 44 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 45 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 46 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 47 | "@aws-cdk/aws-redshift:columnId": true, 48 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 49 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 50 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 51 | "@aws-cdk/aws-kms:aliasNameRef": true, 52 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 53 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 54 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 55 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 56 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 57 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 58 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 59 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 60 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 61 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, 62 | "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, 63 | "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, 64 | "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, 65 | "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, 66 | "@aws-cdk/aws-eks:nodegroupNameAttribute": true, 67 | "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, 68 | "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, 69 | "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, 70 | "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, 71 | "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false, 72 | "@aws-cdk/aws-ecs:disableEcsImdsBlocking": true, 73 | "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, 74 | "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, 75 | "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, 76 | "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, 77 | "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, 78 | "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, 79 | "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, 80 | "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true, 81 | "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true, 82 | "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true, 83 | "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true, 84 | "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true, 85 | "@aws-cdk/core:enableAdditionalMetadataCollection": true, 86 | "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": true, 87 | "@aws-cdk/aws-s3:setUniqueReplicationRoleName": true, 88 | "@aws-cdk/aws-events:requireEventBusPolicySid": true 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/index-custom-resource/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.10.2024.03.04.10-x86_64 2 | 3 | # Installs python, removes cache file to make things smaller 4 | RUN yum update -y && \ 5 | yum install -y python3 python3-dev python3-pip gcc && \ 6 | rm -Rf /var/cache/yum 7 | 8 | # Copies requirements.txt file into the container 9 | COPY requirements.txt ./ 10 | # Installs dependencies found in your requirements.txt file 11 | RUN pip install -r requirements.txt 12 | 13 | # Be sure to copy over the function itself! 14 | # Goes last to take advantage of Docker caching. 15 | COPY index_custom_resource.py ./ 16 | 17 | # Points to the handler function of your lambda function 18 | CMD ["index_custom_resource.on_event"] -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/index-custom-resource/index_custom_resource.py: -------------------------------------------------------------------------------- 1 | from opensearchpy import OpenSearch, RequestsHttpConnection 2 | from requests_aws4auth import AWS4Auth 3 | import boto3 4 | import time 5 | import json 6 | import os 7 | 8 | region = os.environ['AWS_REGION'] 9 | collection_endpoint = os.environ['COLLECTION_ENDPOINT'] 10 | vector_field = os.environ['VECTOR_FIELD_NAME'] 11 | vector_index_name = os.environ['VECTOR_INDEX_NAME'] 12 | text_field = os.environ['TEXT_FIELD'] 13 | metadata_field = os.environ['METADATA_FIELD'] 14 | 15 | 16 | def on_event(event, context): 17 | physical_id = "CreatedIndexId" 18 | 19 | print(json.dumps(event)) 20 | request_type = event['RequestType'] 21 | if request_type == 'Create': 22 | return on_create(event, physical_id=physical_id, region=region, 23 | endpoint=collection_endpoint, vector_field=vector_field, 24 | vector_index_name=vector_index_name, text_field=text_field, 25 | metadata_field=metadata_field) 26 | if request_type == 'Update': 27 | return on_update(event, physical_id=physical_id) 28 | if request_type == 'Delete': 29 | return on_delete(event, physical_id=physical_id) 30 | raise Exception("Invalid request type: %s" % request_type) 31 | 32 | 33 | def on_create(event, physical_id, region, endpoint, vector_index_name, 34 | vector_field, text_field, metadata_field): 35 | props = event["ResourceProperties"] 36 | print("create new resource with props %s" % props) 37 | 38 | index_data(region=region, vector_index_name=vector_index_name, 39 | text_field=text_field, metadata_field=metadata_field, 40 | vector_field=vector_field, endpoint=endpoint) 41 | 42 | return {'PhysicalResourceId': physical_id} 43 | 44 | 45 | def on_update(event, physical_id): 46 | props = event["ResourceProperties"] 47 | print("update resource %s with props %s" % (physical_id, props)) 48 | 49 | return {'PhysicalResourceId': physical_id} 50 | 51 | 52 | def on_delete(event, physical_id): 53 | print("delete resource %s" % physical_id) 54 | 55 | return {'PhysicalResourceId': physical_id} 56 | 57 | 58 | def index_data(region, vector_index_name, text_field, 59 | metadata_field, vector_field, endpoint): 60 | 61 | host = endpoint.replace("https://", "") 62 | 63 | # Set up auth for Opensearch client 64 | service = 'aoss' 65 | credentials = boto3.Session().get_credentials() 66 | awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, 67 | region, service, session_token=credentials.token) 68 | 69 | """Create an index""" 70 | # Build the OpenSearch client 71 | client = OpenSearch( 72 | hosts=[{'host': host, 'port': 443}], 73 | http_auth=awsauth, 74 | use_ssl=True, 75 | verify_certs=True, 76 | connection_class=RequestsHttpConnection, 77 | timeout=300 78 | ) 79 | # It can take up to a minute for data access rules to be enforced 80 | time.sleep(45) 81 | 82 | # Create index 83 | body = { 84 | "mappings": { 85 | "properties": { 86 | f"{metadata_field}": { 87 | "type": "text", 88 | "index": False 89 | }, 90 | "id": { 91 | "type": "text", 92 | "fields": { 93 | "keyword": { 94 | "type": "keyword", 95 | "ignore_above": 256 96 | } 97 | } 98 | }, 99 | f"{text_field}": { 100 | "type": "text" 101 | }, 102 | f"{vector_field}": { 103 | "type": "knn_vector", 104 | "dimension": 1536, 105 | "method": { 106 | "engine": "faiss", 107 | "space_type": "l2", 108 | "name": "hnsw", 109 | "parameters": { 110 | "ef_construction": 128, 111 | "m": 16 112 | } 113 | } 114 | } 115 | } 116 | }, 117 | "settings": { 118 | "index": { 119 | "number_of_shards": 2, 120 | "knn.algo_param": { 121 | "ef_search": 512 122 | }, 123 | "knn": True 124 | } 125 | } 126 | } 127 | 128 | response = client.indices.create(index=vector_index_name, body=body) 129 | print('\nCreating index:') 130 | print(response) 131 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/index-custom-resource/requirements.txt: -------------------------------------------------------------------------------- 1 | opensearch-py==2.4.2 2 | boto3==1.34.60 3 | requests-aws4auth==1.2.3 4 | pydantic -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/lib/api-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as lambda from 'aws-cdk-lib/aws-lambda'; 3 | import * as iam from 'aws-cdk-lib/aws-iam'; 4 | import * as nodeLambda from 'aws-cdk-lib/aws-lambda-nodejs'; 5 | import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2'; 6 | import * as apigatewayv2_integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations'; 7 | import path = require('path'); 8 | 9 | export class ApiStack extends cdk.Stack { 10 | public constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { 11 | super(scope, id, props); 12 | 13 | // HTTP API Gateway 14 | const httpApi = new apigatewayv2.HttpApi(this, 'troubleshoot-api', { 15 | corsPreflight: { 16 | allowOrigins: ['*'], 17 | allowMethods: [apigatewayv2.CorsHttpMethod.POST], 18 | allowHeaders: ['*'], 19 | }, 20 | }); 21 | 22 | // Lambda 23 | const troubleshootSensorFunction = new nodeLambda.NodejsFunction(this, `troubleshoot-sensor`, { 24 | runtime: lambda.Runtime.NODEJS_22_X, 25 | architecture: lambda.Architecture.ARM_64, 26 | functionName: 'troubleshoot-sensor', 27 | description: 'Troubleshoot sensor data using LLM and knowledge base', 28 | timeout: cdk.Duration.seconds(30), 29 | memorySize: 256, 30 | handler: 'handler', 31 | entry: path.resolve(__dirname, '../src/troubleshoot-sensor.ts'), 32 | bundling: { 33 | externalModules: ['@aws-sdk/client-bedrock-agent-runtime'], 34 | }, 35 | initialPolicy: [ 36 | new iam.PolicyStatement({ 37 | effect: iam.Effect.ALLOW, 38 | actions: ['bedrock:InvokeAgent'], 39 | resources: [ 40 | `arn:aws:bedrock:${cdk.Stack.of(this).region}:${cdk.Stack.of(this).account}:agent/${cdk.Fn.importValue('AgentId')}`, 41 | `arn:aws:bedrock:${cdk.Stack.of(this).region}:${cdk.Stack.of(this).account}:agent-alias/${cdk.Fn.importValue('AgentId')}/${cdk.Fn.importValue('AgentAliasId')}`, 42 | ], 43 | }), 44 | ], 45 | environment: { 46 | AGENT_ID: cdk.Fn.importValue('AgentId'), 47 | AGENT_ALIAS_ID: cdk.Fn.importValue('AgentAliasId'), 48 | }, 49 | }); 50 | 51 | // Add route integration 52 | const troubleshootIntegration = new apigatewayv2_integrations.HttpLambdaIntegration('TroubleshootIntegration', troubleshootSensorFunction); 53 | httpApi.addRoutes({ 54 | path: '/troubleshooting-info', 55 | methods: [apigatewayv2.HttpMethod.POST], 56 | integration: troubleshootIntegration, 57 | }); 58 | 59 | new cdk.CfnOutput(this, 'ApiEndpoint', { 60 | value: httpApi.apiEndpoint, 61 | exportName: 'TroubleshootApiEndpoint', 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/lib/bedrock-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as iam from 'aws-cdk-lib/aws-iam'; 3 | import * as s3 from 'aws-cdk-lib/aws-s3'; 4 | import * as bedrock from 'aws-cdk-lib/aws-bedrock'; 5 | import { AGENT_NAME, KNOWLEDGE_BASE_NAME, AWS_REGION_NAME } from './constants'; 6 | 7 | export class BedrockStack extends cdk.Stack { 8 | public constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { 9 | super(scope, id, props); 10 | 11 | const kbInstruction = `Use this knowledge base to obtain information regarding equipment maintenance manuals and instructions.`; 12 | const agentInstruction = `You're a maintenance technician specialized in troubleshooting equipment readings based on predefined manuals of procedures and troubleshooting step. 13 | The user may ask you questions pertaining readings from equipment telemetry, your job is to figure out steps and procedures from available data sources how and give the instructions in a detailed way to the user.`; 14 | 15 | const kbBucket = new s3.Bucket(this, 'kb-bucket', { 16 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 17 | encryption: s3.BucketEncryption.S3_MANAGED, 18 | versioned: false, 19 | removalPolicy: cdk.RemovalPolicy.DESTROY, 20 | autoDeleteObjects: true, 21 | enforceSSL: true, 22 | }); 23 | 24 | new cdk.CfnOutput(this, 'kb-bucket-name', { value: kbBucket.bucketName }); 25 | 26 | const agentRole = iam.Role.fromRoleArn(this, 'agentRole', cdk.Fn.importValue('agentRoleArn')); 27 | const kbRole = iam.Role.fromRoleArn(this, 'kbRole', cdk.Fn.importValue('kbRoleArn')); 28 | 29 | const diagnosticsKb = new bedrock.CfnKnowledgeBase(this, 'mfg-kb', { 30 | name: KNOWLEDGE_BASE_NAME, 31 | roleArn: kbRole.roleArn, 32 | storageConfiguration: { 33 | opensearchServerlessConfiguration: { 34 | collectionArn: cdk.Fn.importValue('opensearchArn'), 35 | fieldMapping: { 36 | metadataField: 'metadata', 37 | textField: 'text', 38 | vectorField: 'vector', 39 | }, 40 | vectorIndexName: `mfg-vector-index`, 41 | }, 42 | type: 'OPENSEARCH_SERVERLESS', 43 | }, 44 | knowledgeBaseConfiguration: { 45 | type: 'VECTOR', 46 | vectorKnowledgeBaseConfiguration: { 47 | embeddingModelArn: `arn:aws:bedrock:${AWS_REGION_NAME}::foundation-model/amazon.titan-embed-text-v1`, 48 | }, 49 | }, 50 | }); 51 | new bedrock.CfnDataSource(this, 'mfg-kb-source', { 52 | name: 'diagnostics-kb-datasource', 53 | knowledgeBaseId: diagnosticsKb.attrKnowledgeBaseId, 54 | dataSourceConfiguration: { 55 | type: 'S3', 56 | s3Configuration: { 57 | bucketArn: kbBucket.bucketArn, 58 | }, 59 | }, 60 | }); 61 | 62 | const agent = new bedrock.CfnAgent(this, AGENT_NAME, { 63 | agentName: AGENT_NAME, 64 | instruction: agentInstruction, 65 | foundationModel: 'us.anthropic.claude-3-5-sonnet-20241022-v2:0', 66 | agentResourceRoleArn: agentRole.roleArn, 67 | autoPrepare: false, 68 | knowledgeBases: [ 69 | { 70 | description: kbInstruction, 71 | knowledgeBaseId: diagnosticsKb.attrKnowledgeBaseId, 72 | knowledgeBaseState: 'ENABLED', 73 | }, 74 | ], 75 | }); 76 | 77 | const agentAlias = new bedrock.CfnAgentAlias(this, 'agent-alias', { 78 | agentAliasName: 'DraftAlias', 79 | agentId: agent.attrAgentId, 80 | }); 81 | agentAlias.addDependency(agent); 82 | 83 | // Export agent ID and alias ID 84 | new cdk.CfnOutput(this, 'AgentId', { 85 | value: agent.attrAgentId, 86 | exportName: 'AgentId', 87 | }); 88 | 89 | new cdk.CfnOutput(this, 'AgentAliasId', { 90 | value: agentAlias.attrAgentAliasId, 91 | exportName: 'AgentAliasId', 92 | }); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/lib/constants.ts: -------------------------------------------------------------------------------- 1 | export const AGENT_NAME = 'mfg-chatbot'; 2 | export const KNOWLEDGE_BASE_NAME = 'mfg-kb'; 3 | export const AWS_REGION_NAME = 'us-east-1'; 4 | export const COLLECTION_NAME = 'mfg-collection'; 5 | export const VECTOR_INDEX_NAME = 'mfg-vector-index'; 6 | export const TEXT_FIELD_NAME = 'text'; 7 | export const VECTOR_FIELD_NAME = 'vector'; 8 | export const METADATA_FIELD_NAME = 'metadata'; 9 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/lib/opensearch-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as custom from 'aws-cdk-lib/custom-resources'; 3 | import * as iam from 'aws-cdk-lib/aws-iam'; 4 | import * as lambda from 'aws-cdk-lib/aws-lambda'; 5 | import * as logs from 'aws-cdk-lib/aws-logs'; 6 | import * as opensearchserverless from 'aws-cdk-lib/aws-opensearchserverless'; 7 | import { COLLECTION_NAME, METADATA_FIELD_NAME, TEXT_FIELD_NAME, VECTOR_FIELD_NAME, VECTOR_INDEX_NAME } from './constants'; 8 | 9 | export class OpensearchStack extends cdk.Stack { 10 | public constructor(scope: cdk.App, id: string, props: any) { 11 | super(scope, id, props); 12 | 13 | const kbRole = iam.Role.fromRoleArn(this, 'kb-role', cdk.Fn.importValue('kbRoleArn')); 14 | const customResourceRole = new iam.Role(this, 'index-custom-resource-role', { 15 | assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), 16 | managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], 17 | }); 18 | 19 | const accessPolicy = new opensearchserverless.CfnAccessPolicy(this, 'opensearch-access-policy', { 20 | policy: JSON.stringify([ 21 | { 22 | Description: 'Data access policy to grant access to Amazon Bedrock Knowledge Base', 23 | Rules: [ 24 | { Resource: [`collection/${COLLECTION_NAME}`], Permission: ['aoss:DescribeCollectionItems', 'aoss:CreateCollectionItems', 'aoss:UpdateCollectionItems'], ResourceType: 'collection' }, 25 | { Resource: [`index/${COLLECTION_NAME}/*`], Permission: ['aoss:UpdateIndex', 'aoss:DescribeIndex', 'aoss:ReadDocument', 'aoss:WriteDocument', 'aoss:CreateIndex'], ResourceType: 'index' }, 26 | ], 27 | Principal: [kbRole.roleArn, customResourceRole.roleArn], 28 | }, 29 | ]), 30 | type: 'data', 31 | description: 'Data access policy to grant access to Amazon Bedrock Knowledge Base.', 32 | name: 'smart-mfg-kb-access-policy', 33 | }); 34 | 35 | const encryptionPolicy = new opensearchserverless.CfnSecurityPolicy(this, 'opensearch-encryption-policy', { 36 | policy: JSON.stringify({ Rules: [{ Resource: [`collection/${COLLECTION_NAME}`], ResourceType: 'collection' }], AWSOwnedKey: true }), 37 | type: 'encryption', 38 | description: 'Encryption policy for Amazon Bedrock Knowledge Base vector database.', 39 | name: 'smart-mfg-kb-encryption-policy', 40 | }); 41 | 42 | const networkPolicy = new opensearchserverless.CfnSecurityPolicy(this, 'opensearch-network-policy', { 43 | policy: JSON.stringify([ 44 | { 45 | Rules: [ 46 | { Resource: [`collection/${COLLECTION_NAME}`], ResourceType: 'dashboard' }, 47 | { Resource: [`collection/${COLLECTION_NAME}`], ResourceType: 'collection' }, 48 | ], 49 | AllowFromPublic: true, 50 | }, 51 | ]), 52 | type: 'network', 53 | description: 'Custom network policy created by Amazon Bedrock Knowledge Base service to allow a created IAM role to have permissions on Amazon Open Search collections and indexes.', 54 | name: 'smart-mfg-kb-network-policy', 55 | }); 56 | 57 | const opensearchCollection = new opensearchserverless.CfnCollection(this, 'opensearchCollection', { 58 | name: COLLECTION_NAME, 59 | description: 'Smart manufacturing Amazon Bedrock Knowledge Base vector database', 60 | type: 'VECTORSEARCH', 61 | }); 62 | 63 | opensearchCollection.node.addDependency(encryptionPolicy); 64 | opensearchCollection.node.addDependency(networkPolicy); 65 | opensearchCollection.node.addDependency(accessPolicy); 66 | 67 | // Vector Index 68 | // API Access 69 | customResourceRole.addToPolicy( 70 | new iam.PolicyStatement({ 71 | resources: [opensearchCollection.attrArn], 72 | actions: ['aoss:APIAccessAll'], 73 | }) 74 | ); 75 | 76 | // Lambda Function 77 | const indexCusstomResourceFunction = new lambda.DockerImageFunction(this, 'index-custom-resource-function', { 78 | code: lambda.DockerImageCode.fromImageAsset('index-custom-resource'), 79 | timeout: cdk.Duration.seconds(600), 80 | role: customResourceRole, 81 | environment: { 82 | COLLECTION_ENDPOINT: opensearchCollection.attrCollectionEndpoint, 83 | VECTOR_FIELD_NAME: VECTOR_FIELD_NAME, 84 | VECTOR_INDEX_NAME: VECTOR_INDEX_NAME, 85 | TEXT_FIELD: TEXT_FIELD_NAME, 86 | METADATA_FIELD: METADATA_FIELD_NAME, 87 | }, 88 | }); 89 | indexCusstomResourceFunction.node.addDependency(opensearchCollection); 90 | 91 | // Custom Resource Provider 92 | const provider = new custom.Provider(this, 'index-custom-resource-provider', { 93 | onEventHandler: indexCusstomResourceFunction, 94 | logRetention: logs.RetentionDays.ONE_DAY, 95 | }); 96 | 97 | // Custom Resource 98 | new cdk.CustomResource(this, 'index-custom-resource', { 99 | serviceToken: provider.serviceToken, 100 | }); 101 | 102 | new cdk.CfnOutput(this, 'opensearch-arn', { 103 | value: opensearchCollection.attrArn, 104 | exportName: 'opensearchArn', 105 | }); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/lib/roles-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as iam from 'aws-cdk-lib/aws-iam'; 3 | import { AGENT_NAME, KNOWLEDGE_BASE_NAME } from './constants'; 4 | import { ServiceLinkedRole } from 'upsert-slr'; 5 | 6 | export class RolesStack extends cdk.Stack { 7 | public constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { 8 | super(scope, id, props); 9 | 10 | const agentRole = new iam.Role(this, 'bedrock-agent-role', { 11 | roleName: `AmazonBedrockExecutionRoleForAgents_${AGENT_NAME}`, 12 | assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'), 13 | managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')], 14 | }); 15 | 16 | const kbRole = new iam.Role(this, 'bedrock-kb-role', { 17 | roleName: `AmazonBedrockExecutionRoleForKnowledgeBase_${KNOWLEDGE_BASE_NAME}`, 18 | assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'), 19 | managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')], 20 | }); 21 | 22 | // Create service-linked role for OpenSearch Serverless 23 | new ServiceLinkedRole(this, 'opensearch-service-role', { 24 | awsServiceName: 'observability.aoss.amazonaws.com', 25 | description: 'Service linked role for OpenSearch Serverless', 26 | }); 27 | 28 | new cdk.CfnOutput(this, 'agent-role-arn', { value: agentRole.roleArn, exportName: 'agentRoleArn' }); 29 | new cdk.CfnOutput(this, 'kb-role-arn', { value: kbRole.roleArn, exportName: 'kbRoleArn' }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/lib/ui-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as s3 from 'aws-cdk-lib/aws-s3'; 3 | import * as cf from 'aws-cdk-lib/aws-cloudfront'; 4 | import * as cfo from 'aws-cdk-lib/aws-cloudfront-origins'; 5 | 6 | export class UIStack extends cdk.Stack { 7 | public constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { 8 | super(scope, id, props); 9 | 10 | const bucket = new s3.Bucket(this, 'smart-mon-static-bucket', { 11 | encryption: s3.BucketEncryption.S3_MANAGED, 12 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 13 | enforceSSL: true, 14 | removalPolicy: cdk.RemovalPolicy.RETAIN, 15 | }); 16 | 17 | const oac = new cf.S3OriginAccessControl(this, 'smart-mon-cdn-oac', { originAccessControlName: `smart-mon-oac` }); 18 | const distribution = new cf.Distribution(this, 'smart-mon-cdn', { 19 | httpVersion: cf.HttpVersion.HTTP2_AND_3, 20 | priceClass: cf.PriceClass.PRICE_CLASS_ALL, 21 | enableIpv6: true, 22 | defaultRootObject: 'index.html', 23 | defaultBehavior: { 24 | origin: cfo.S3BucketOrigin.withOriginAccessControl(bucket, { 25 | originAccessControl: oac, 26 | }), 27 | allowedMethods: cf.AllowedMethods.ALLOW_GET_HEAD, 28 | cachedMethods: cf.CachedMethods.CACHE_GET_HEAD, 29 | compress: true, 30 | viewerProtocolPolicy: cf.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, 31 | }, 32 | errorResponses: [ 33 | { 34 | httpStatus: 404, 35 | responseHttpStatus: 200, 36 | responsePagePath: '/index.html', 37 | }, 38 | { 39 | httpStatus: 403, 40 | responseHttpStatus: 200, 41 | responsePagePath: '/index.html', 42 | }, 43 | ], 44 | }); 45 | 46 | new cdk.CfnOutput(this, 'smart-mon-s3-bucket-name', { value: bucket.bucketName }); 47 | new cdk.CfnOutput(this, 'smart-mon-cdn-url', { value: `https://${distribution.distributionDomainName}` }); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatbot-realtime-smart-monitoring", 3 | "version": "0.1.0", 4 | "bin": { 5 | "chatbot-realtime-smart-monitoring": "bin/chatbot-realtime-smart-monitoring.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/aws-lambda": "^8.10.148", 15 | "@types/jest": "^29.5.14", 16 | "@types/node": "22.7.9", 17 | "aws-cdk": "2.1007.0", 18 | "jest": "^29.7.0", 19 | "ts-jest": "^29.2.5", 20 | "ts-node": "^10.9.2", 21 | "typescript": "~5.6.3", 22 | "upsert-slr": "^1.0.6" 23 | }, 24 | "dependencies": { 25 | "@aws-sdk/client-bedrock-agent-runtime": "^3.782.0", 26 | "aws-cdk-lib": "2.186.0", 27 | "constructs": "^10.0.0" 28 | }, 29 | "prettier": { 30 | "singleQuote": true, 31 | "printWidth": 200 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/sampledocs/EC101.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/auto-manufacturing/chatbot-realtime-smart-monitoring/sampledocs/EC101.pdf -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/sampledocs/PL203.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/auto-manufacturing/chatbot-realtime-smart-monitoring/sampledocs/PL203.pdf -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/sampledocs/Training Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/auto-manufacturing/chatbot-realtime-smart-monitoring/sampledocs/Training Manual.pdf -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/src/troubleshoot-sensor.ts: -------------------------------------------------------------------------------- 1 | import { BedrockAgentRuntimeClient, InvokeAgentCommand } from '@aws-sdk/client-bedrock-agent-runtime'; 2 | import { APIGatewayEventRequestContextV2, APIGatewayProxyResultV2 } from 'aws-lambda'; 3 | import { randomUUID } from 'crypto'; 4 | 5 | // Initialize client outside the handler for connection reuse across invocations 6 | const bedrockClient = new BedrockAgentRuntimeClient({}); 7 | 8 | /** 9 | * Lambda handler to process sensor data using AWS Bedrock Agent 10 | * @param {Object} event - API Gateway event 11 | * @returns {Object} API Gateway response 12 | */ 13 | export const handler = async (event: APIGatewayEventRequestContextV2): Promise => { 14 | try { 15 | // Parse request body 16 | const body = parseEventBody(event); 17 | 18 | // Extract parameters 19 | const { sensor, reading, sessionId, userPrompt } = body; 20 | 21 | // Validate parameters - check for valid combinations 22 | if (sensor && reading && !(sessionId && userPrompt)) { 23 | // Use case 1: sensor data 24 | return await processSensorData(sensor, reading); 25 | } else if (sessionId && userPrompt && !(sensor && reading)) { 26 | // Use case 2: direct user prompt 27 | return await processUserPrompt(sessionId, userPrompt); 28 | } else { 29 | // Invalid parameter combination 30 | return createResponse(400, { 31 | message: 'Invalid parameters. Provide either (sensor and reading) OR (sessionId and userPrompt)', 32 | }); 33 | } 34 | } catch (error: any) { 35 | console.error('Error processing request:', error); 36 | // Handle any errors 37 | return createResponse(500, { 38 | message: 'Internal server error', 39 | error: error.message, 40 | }); 41 | } 42 | }; 43 | 44 | /** 45 | * Parse API Gateway event body 46 | * @param {Object} event - API Gateway event 47 | * @returns {Object} Parsed body 48 | */ 49 | function parseEventBody(event: any) { 50 | if (!event.body) return {}; 51 | 52 | const bodyString = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString('utf-8') : event.body; 53 | 54 | try { 55 | return JSON.parse(bodyString); 56 | } catch (error) { 57 | throw new Error('Invalid JSON in request body'); 58 | } 59 | } 60 | 61 | /** 62 | * Process sensor data 63 | * @param {string} sensor - Sensor ID 64 | * @param {string} reading - Sensor reading 65 | * @returns {Object} API Gateway response 66 | */ 67 | async function processSensorData(sensor: string, reading: string) { 68 | const sessionId = randomUUID(); 69 | const prompt = createSensorPrompt(sensor, reading); 70 | 71 | // Call Bedrock agent and get response 72 | const completion = await invokeAgent(sessionId, prompt); 73 | 74 | // Return successful response 75 | return createResponse(200, { 76 | response: completion, 77 | sessionId: sessionId, 78 | }); 79 | } 80 | 81 | /** 82 | * Create prompt for sensor data 83 | * @param {string} sensor - Sensor ID 84 | * @param {string} reading - Sensor reading 85 | * @returns {string} Formatted prompt 86 | */ 87 | function createSensorPrompt(sensor: string, reading: string) { 88 | return ` 89 | Based on existing documentation for troubleshooting, provide the resolution and actions steps to troubleshoot and resolve: 90 | Sensor: ${sensor} 91 | Reading: ${reading} 92 | 93 | Be very specific with the actions for the above type of metric and the reading that the operator received. 94 | If no troubleshooting steps are available for this sensor, then tell the user that and do not attempt to provide instructions.`; 95 | } 96 | 97 | /** 98 | * Process user prompt directly 99 | * @param {string} sessionId - Conversation session ID 100 | * @param {string} userPrompt - User's prompt 101 | * @returns {APIGatewayProxyResultV2} API Gateway response 102 | */ 103 | async function processUserPrompt(sessionId: string, userPrompt: string): Promise { 104 | // Call Bedrock agent and get response 105 | const completion = await invokeAgent(sessionId, userPrompt); 106 | 107 | // Return successful response 108 | return createResponse(200, { 109 | response: completion, 110 | sessionId: sessionId, 111 | }); 112 | } 113 | 114 | /** 115 | * Invoke Bedrock Agent with prompt 116 | * @param {string} sessionId - Session ID 117 | * @param {string} inputText - Prompt text 118 | * @returns {Promise} Agent's response 119 | */ 120 | async function invokeAgent(sessionId: string, inputText: string): Promise { 121 | try { 122 | // Call Bedrock agent 123 | const response = await bedrockClient.send( 124 | new InvokeAgentCommand({ 125 | agentId: process.env.AGENT_ID!, 126 | agentAliasId: process.env.AGENT_ALIAS_ID!, 127 | sessionId: sessionId, 128 | inputText: inputText, 129 | }) 130 | ); 131 | 132 | // Process the agent's response 133 | return await processAgentResponse(response); 134 | } catch (error: any) { 135 | console.error('Error invoking Bedrock agent:', error); 136 | throw new Error(`Failed to get response from Bedrock agent: ${error.message}`); 137 | } 138 | } 139 | 140 | /** 141 | * Process the streaming response from Bedrock Agent 142 | * @param {Object} response - The response from Bedrock Agent 143 | * @returns {Promise} The completed response text 144 | */ 145 | async function processAgentResponse(response: any) { 146 | if (!response.completion) { 147 | return 'No response received from agent.'; 148 | } 149 | 150 | let completion = ''; 151 | 152 | try { 153 | for await (const event of response.completion) { 154 | if (event.chunk && event.chunk.bytes) { 155 | const decodedChunk = new TextDecoder('utf-8').decode(event.chunk.bytes); 156 | completion += decodedChunk; 157 | } 158 | } 159 | return completion; 160 | } catch (error: any) { 161 | console.error('Error processing agent response stream:', error); 162 | throw new Error(`Error processing agent response: ${error.message}`); 163 | } 164 | } 165 | 166 | /** 167 | * Create a formatted API Gateway response 168 | * @param {number} statusCode - HTTP status code 169 | * @param {Object} body - Response body 170 | * @returns {Object} Formatted response 171 | */ 172 | function createResponse(statusCode: number, body: any): APIGatewayProxyResultV2 { 173 | return { 174 | statusCode, 175 | headers: { 'Content-Type': 'application/json' }, 176 | body: JSON.stringify(body), 177 | }; 178 | } 179 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/static-site/chatbot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Digital Twin Assistant 7 | 236 | 237 | 238 |
239 |
240 | 241 |

Digital Twin Assistant

242 |
243 |
244 | 245 |
246 |
247 | 248 |
249 |
250 | 251 | 252 |
253 |
254 | 255 | 417 | 418 | 419 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/static-site/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Digital Twin Dashboard - Factory Maintenance 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Factory Digital Twin Dashboard

14 |
System Online
15 |
16 |
17 | 18 |
19 |
20 |
Loading Dashboard...
21 |
22 | 23 |
24 |
25 |

Machine Status Overview

26 |
27 |
28 | 29 | PLC-001 30 |
31 |

Temperature: 75.2°F

32 |

Pressure: 2.4 bar

33 |
34 |
35 |
36 | 37 | PLC-002 38 |
39 |

Temperature: 72.8°F

40 |

Pressure: 2.2 bar

41 |
42 |
43 |
44 | 45 | PLC-003 46 |
47 |

Temperature: 95.2°F

48 |

Pressure: 3.2 bar

49 |
50 |
51 |
52 |
53 | 54 |
55 |

Temperature Trend

56 |
57 | 58 |
59 |
60 | 61 |
62 |

Production Overview

63 |
64 |
65 |

Daily Output

66 |

5,234 units

67 |
68 |
69 |

Efficiency

70 |

92.7%

71 |
72 |
73 |

Quality Rate

74 |

99.2%

75 |
76 |
77 |
78 | 79 |
80 |

Energy Consumption

81 |
82 | 83 |
84 |
85 | 86 |
87 |

Alerts

88 |
89 | 90 |
91 |
92 | 93 |
94 |

Maintenance Schedule

95 |
96 |
97 | High 98 |

PLC-001 Filter Replacement

99 |

Due: Today

100 |
101 |
102 | Medium 103 |

Calibration Check

104 |

Due: Tomorrow

105 |
106 |
107 | Low 108 |

Software Update

109 |

Due: Next Week

110 |
111 |
112 |
113 | 114 |
115 |

OEE Metrics

116 |
117 |
118 |
119 | 120 |
85%
121 |
122 |

Availability

123 |
124 |
125 |
126 | 127 |
92%
128 |
129 |

Performance

130 |
131 |
132 |
133 | 134 |
98%
135 |
136 |

Quality

137 |
138 |
139 |
140 | 141 |
142 |

Production Line Status

143 |
144 |
145 |
146 | 📦 147 | Raw Materials 148 |
149 |
Active
150 |
151 |
152 |
153 |
154 | ⚙️ 155 | Processing 156 |
157 |
Active
158 |
159 |
160 |
161 |
162 | 🔍 163 | Quality 164 |
165 |
Warning
166 |
167 |
168 |
169 |
170 | 📤 171 | Packaging 172 |
173 |
Active
174 |
175 |
176 |
177 | 178 |
179 |

Environmental Metrics

180 |
181 |
182 | Humidity 183 |
45%
184 |
185 |
186 | CO2 Levels 187 |
420 ppm
188 |
189 |
190 | Noise Level 191 |
72 dB
192 |
193 |
194 |
195 | 196 |
197 |

Quality Control

198 |
199 |
200 | 201 |
202 |
203 |

Latest Defects

204 |
205 | Surface Scratch 206 | 3 207 |
208 |
209 | Dimension Error 210 | 1 211 |
212 |
213 | Color Mismatch 214 | 2 215 |
216 |
217 |
218 |
219 | 220 |
221 |

Resource Utilization

222 |
223 |
224 | CPU Load 225 |
226 |
227 |
228 | 65% 229 |
230 |
231 | Memory Usage 232 |
233 |
234 |
235 | 78% 236 |
237 |
238 | Network Bandwidth 239 |
240 |
241 |
242 | 45% 243 |
244 |
245 |
246 | 247 |
248 |

System Health Overview

249 |
250 |
251 |
252 |
253 | 🖥️ 254 | System Uptime 255 |
256 |
99.9%
257 |
Normal
258 |
259 |
260 |
261 | 📡 262 | Network Latency 263 |
264 |
24ms
265 |
Normal
266 |
267 |
268 |
269 | 🔗 270 | API Response 271 |
272 |
198ms
273 |
Warning
274 |
275 |
276 |
277 | 278 |
279 |
280 |
281 |
282 |
283 | 284 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/static-site/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | console.log('Initializing dashboard...'); 3 | initializeCharts(); 4 | updateDashboard(); 5 | setInterval(updateDashboard, 2000); 6 | document.getElementById('loading-overlay').style.display = 'none'; 7 | document.querySelector('.dashboard-grid').style.display = 'grid'; 8 | }); 9 | 10 | function generateData(min, max, count, previousData = []) { 11 | return Array.from({length: count}, (_, i) => { 12 | const prevValue = previousData[i] || (Math.random() * (max - min) + min); 13 | const change = (Math.random() - 0.5) * (max - min) * 0.1; 14 | return Math.max(min, Math.min(max, prevValue + change)); 15 | }); 16 | } 17 | 18 | function initializeCharts() { 19 | try { 20 | // Temperature Chart with critical temperature highlighted 21 | const tempCtx = document.getElementById('tempChart').getContext('2d'); 22 | window.tempChart = new Chart(tempCtx, { 23 | type: 'line', 24 | data: { 25 | labels: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', 26 | '12:00', '14:00', '16:00', '18:00', '20:00', '22:00'], 27 | datasets: [{ 28 | label: 'Temperature (°F)', 29 | data: generateData(70, 95, 12), 30 | borderColor: '#3498db', 31 | tension: 0.4, 32 | fill: false 33 | }] 34 | }, 35 | options: { 36 | responsive: true, 37 | maintainAspectRatio: false, 38 | animation: { 39 | duration: 800, 40 | easing: 'easeInOutQuad' 41 | }, 42 | plugins: { 43 | legend: { 44 | display: false 45 | } 46 | }, 47 | scales: { 48 | y: { 49 | beginAtZero: false, 50 | suggestedMin: 65, 51 | suggestedMax: 100 52 | } 53 | } 54 | } 55 | }); 56 | 57 | // Energy Chart 58 | const energyCtx = document.getElementById('energyChart').getContext('2d'); 59 | window.energyChart = new Chart(energyCtx, { 60 | type: 'bar', 61 | data: { 62 | labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], 63 | datasets: [{ 64 | label: 'Energy Consumption (kWh)', 65 | data: generateData(500, 1000, 7), 66 | backgroundColor: '#2ecc71' 67 | }] 68 | }, 69 | options: { 70 | responsive: true, 71 | maintainAspectRatio: false, 72 | animation: { 73 | duration: 800, 74 | easing: 'easeInOutQuad' 75 | }, 76 | plugins: { 77 | legend: { 78 | display: false 79 | } 80 | } 81 | } 82 | }); 83 | 84 | // Quality Chart 85 | const qualityCtx = document.getElementById('qualityChart').getContext('2d'); 86 | window.qualityChart = new Chart(qualityCtx, { 87 | type: 'bar', 88 | data: { 89 | labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], 90 | datasets: [{ 91 | label: 'Defect Rate (%)', 92 | data: generateData(0.5, 1.5, 5), 93 | backgroundColor: '#3498db' 94 | }] 95 | }, 96 | options: { 97 | responsive: true, 98 | maintainAspectRatio: false, 99 | animation: { 100 | duration: 800, 101 | easing: 'easeInOutQuad' 102 | }, 103 | plugins: { 104 | legend: { 105 | display: false 106 | } 107 | }, 108 | scales: { 109 | y: { 110 | beginAtZero: true, 111 | max: 2 112 | } 113 | } 114 | } 115 | }); 116 | 117 | // Initialize OEE Gauges 118 | ['availabilityGauge', 'performanceGauge', 'qualityGauge'].forEach((gaugeId, index) => { 119 | const ctx = document.getElementById(gaugeId).getContext('2d'); 120 | window[gaugeId] = new Chart(ctx, { 121 | type: 'doughnut', 122 | data: { 123 | datasets: [{ 124 | data: [85, 15], 125 | backgroundColor: [ 126 | '#2ecc71', 127 | '#ecf0f1' 128 | ] 129 | }] 130 | }, 131 | options: { 132 | responsive: true, 133 | maintainAspectRatio: true, 134 | circumference: 180, 135 | rotation: -90, 136 | cutout: '80%', 137 | plugins: { 138 | legend: { 139 | display: false 140 | }, 141 | tooltip: { 142 | enabled: false 143 | } 144 | } 145 | } 146 | }); 147 | }); 148 | 149 | // System Health Chart 150 | const systemHealthCtx = document.getElementById('systemHealthChart').getContext('2d'); 151 | window.systemHealthChart = new Chart(systemHealthCtx, { 152 | type: 'line', 153 | data: { 154 | labels: Array.from({length: 20}, (_, i) => i), 155 | datasets: [{ 156 | label: 'System Load', 157 | data: generateData(20, 80, 20), 158 | borderColor: '#3498db', 159 | tension: 0.4, 160 | fill: false 161 | }] 162 | }, 163 | options: { 164 | responsive: true, 165 | maintainAspectRatio: false, 166 | plugins: { 167 | legend: { 168 | display: false 169 | } 170 | }, 171 | scales: { 172 | x: { 173 | display: false 174 | }, 175 | y: { 176 | display: false, 177 | suggestedMin: 0, 178 | suggestedMax: 100 179 | } 180 | }, 181 | elements: { 182 | point: { 183 | radius: 0 184 | } 185 | } 186 | } 187 | }); 188 | 189 | } catch (error) { 190 | console.error('Error initializing charts:', error); 191 | } 192 | } 193 | 194 | // Keep the critical temperature steady for PLC-003 195 | function updateReading(id, min, max) { 196 | const element = document.getElementById(id); 197 | if (element) { 198 | let newValue; 199 | if (id === 'temp-reading-3') { 200 | newValue = '95.2'; // Keep critical temperature steady 201 | } else if (id === 'pressure-reading-3') { 202 | newValue = '3.2'; // Keep critical pressure steady 203 | } else { 204 | newValue = (Math.random() * (max - min) + min).toFixed(1); 205 | } 206 | element.textContent = `${newValue}${id.includes('temp') ? '°F' : ' bar'}`; 207 | return newValue; 208 | } 209 | } 210 | 211 | function updateProductionStats() { 212 | const dailyOutput = document.getElementById('daily-output'); 213 | const efficiency = document.getElementById('efficiency'); 214 | const qualityRate = document.getElementById('quality-rate'); 215 | 216 | if (dailyOutput) dailyOutput.textContent = `${Math.floor(Math.random() * 1000 + 5000)} units`; 217 | if (efficiency) efficiency.textContent = `${(Math.random() * 10 + 90).toFixed(1)}%`; 218 | if (qualityRate) qualityRate.textContent = `${(Math.random() * 1 + 98.5).toFixed(1)}%`; 219 | } 220 | 221 | function updateEnvironmentalMetrics() { 222 | document.getElementById('humidity').textContent = `${Math.floor(Math.random() * 20 + 40)}%`; 223 | document.getElementById('co2').textContent = `${Math.floor(Math.random() * 50 + 400)} ppm`; 224 | document.getElementById('noise').textContent = `${Math.floor(Math.random() * 10 + 68)} dB`; 225 | } 226 | 227 | function updateResourceUtilization() { 228 | ['cpu-load', 'memory-usage', 'network-usage'].forEach(resource => { 229 | const element = document.getElementById(resource); 230 | const newValue = Math.floor(Math.random() * 30 + 50); 231 | element.style.width = `${newValue}%`; 232 | element.parentElement.nextElementSibling.textContent = `${newValue}%`; 233 | }); 234 | } 235 | 236 | function updateOEEGauges() { 237 | ['availability', 'performance', 'quality'].forEach(metric => { 238 | const chart = window[`${metric}Gauge`]; 239 | const valueElement = document.getElementById(`${metric}-value`); 240 | const newValue = Math.floor(Math.random() * 20 + 80); 241 | chart.data.datasets[0].data = [newValue, 100 - newValue]; 242 | chart.data.datasets[0].backgroundColor[0] = newValue > 90 ? '#2ecc71' : newValue > 70 ? '#f1c40f' : '#e74c3c'; 243 | chart.update(); 244 | valueElement.textContent = `${newValue}%`; 245 | }); 246 | } 247 | 248 | function updateSystemHealth() { 249 | document.getElementById('system-uptime').textContent = `${(99 + Math.random()).toFixed(2)}%`; 250 | document.getElementById('network-latency').textContent = `${Math.floor(20 + Math.random() * 10)}ms`; 251 | document.getElementById('api-response').textContent = `${Math.floor(180 + Math.random() * 40)}ms`; 252 | 253 | window.systemHealthChart.data.datasets[0].data = generateData(20, 80, 20, 254 | window.systemHealthChart.data.datasets[0].data); 255 | window.systemHealthChart.update(); 256 | } 257 | 258 | function updateTimestamp() { 259 | const now = new Date(); 260 | document.getElementById('timestamp').textContent = `Last updated: ${now.toLocaleString()}`; 261 | } 262 | 263 | function updateDashboard() { 264 | // Update all readings except PLC-003 which stays in critical state 265 | updateReading('temp-reading-1', 70, 80); 266 | updateReading('pressure-reading-1', 2.0, 2.8); 267 | updateReading('temp-reading-2', 70, 80); 268 | updateReading('pressure-reading-2', 2.0, 2.8); 269 | updateReading('temp-reading-3', 95, 95.5); // Keep critical 270 | updateReading('pressure-reading-3', 3.1, 3.3); // Keep critical 271 | 272 | updateProductionStats(); 273 | updateEnvironmentalMetrics(); 274 | updateResourceUtilization(); 275 | updateOEEGauges(); 276 | updateSystemHealth(); 277 | 278 | // Update charts 279 | window.tempChart.data.datasets[0].data = generateData(70, 95, 12, window.tempChart.data.datasets[0].data); 280 | window.tempChart.update(); 281 | 282 | window.energyChart.data.datasets[0].data = generateData(500, 1000, 7, window.energyChart.data.datasets[0].data); 283 | window.energyChart.update(); 284 | 285 | window.qualityChart.data.datasets[0].data = generateData(0.5, 1.5, 5, window.qualityChart.data.datasets[0].data); 286 | window.qualityChart.update(); 287 | 288 | updateTimestamp(); 289 | } 290 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/static-site/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --primary-color: #2c3e50; 3 | --secondary-color: #34495e; 4 | --accent-color: #3498db; 5 | --success-color: #2ecc71; 6 | --warning-color: #f1c40f; 7 | --danger-color: #e74c3c; 8 | --background-color: #ecf0f1; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | padding: 0; 14 | font-family: Arial, sans-serif; 15 | background-color: var(--background-color); 16 | } 17 | 18 | .container { 19 | padding: 20px; 20 | } 21 | 22 | header { 23 | display: flex; 24 | justify-content: space-between; 25 | align-items: center; 26 | margin-bottom: 20px; 27 | flex-wrap: wrap; 28 | } 29 | 30 | .status-indicator { 31 | padding: 8px 16px; 32 | border-radius: 20px; 33 | font-weight: bold; 34 | } 35 | 36 | .status-indicator.online { 37 | background-color: var(--success-color); 38 | color: white; 39 | } 40 | 41 | #timestamp { 42 | color: #666; 43 | font-size: 0.9em; 44 | margin-left: 20px; 45 | } 46 | 47 | .loading-overlay { 48 | position: fixed; 49 | top: 0; 50 | left: 0; 51 | right: 0; 52 | bottom: 0; 53 | background-color: rgba(255, 255, 255, 0.9); 54 | display: flex; 55 | flex-direction: column; 56 | justify-content: center; 57 | align-items: center; 58 | z-index: 1000; 59 | } 60 | 61 | .loading-spinner { 62 | border: 4px solid #f3f3f3; 63 | border-top: 4px solid var(--accent-color); 64 | border-radius: 50%; 65 | width: 40px; 66 | height: 40px; 67 | animation: spin 1s linear infinite; 68 | } 69 | 70 | .loading-text { 71 | margin-top: 20px; 72 | color: var(--primary-color); 73 | } 74 | 75 | @keyframes spin { 76 | 0% { transform: rotate(0deg); } 77 | 100% { transform: rotate(360deg); } 78 | } 79 | 80 | .dashboard-grid { 81 | display: grid; 82 | grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); 83 | gap: 20px; 84 | } 85 | 86 | .card { 87 | background: white; 88 | border-radius: 10px; 89 | padding: 20px; 90 | box-shadow: 0 2px 4px rgba(0,0,0,0.1); 91 | overflow: hidden; 92 | } 93 | 94 | .chart-container { 95 | position: relative; 96 | height: 250px; 97 | width: 100%; 98 | margin-bottom: 10px; 99 | } 100 | 101 | .status-dot { 102 | height: 12px; 103 | width: 12px; 104 | border-radius: 50%; 105 | display: inline-block; 106 | margin-right: 8px; 107 | } 108 | 109 | .status-dot.active { 110 | background-color: var(--success-color); 111 | animation: pulse 2s infinite; 112 | } 113 | 114 | .status-dot.danger { 115 | background-color: var(--danger-color); 116 | animation: pulse 2s infinite; 117 | } 118 | 119 | .machine-status { 120 | padding: 15px; 121 | border: 1px solid #ddd; 122 | border-radius: 5px; 123 | margin-bottom: 10px; 124 | transition: background-color 0.3s ease; 125 | } 126 | 127 | .machine-status.clickable { 128 | cursor: pointer; 129 | } 130 | 131 | .machine-status.clickable:hover { 132 | background-color: #f8f9fa; 133 | } 134 | 135 | .machine-status.danger { 136 | background-color: rgba(231, 76, 60, 0.1); 137 | border-left: 4px solid var(--danger-color); 138 | } 139 | 140 | .danger-text { 141 | color: var(--danger-color); 142 | font-weight: bold; 143 | } 144 | 145 | .readings p { 146 | margin: 5px 0; 147 | } 148 | 149 | .alerts-list { 150 | max-height: 200px; 151 | overflow-y: auto; 152 | } 153 | 154 | .alert-item { 155 | padding: 10px; 156 | border-left: 4px solid; 157 | margin-bottom: 10px; 158 | cursor: pointer; 159 | transition: background-color 0.3s ease; 160 | } 161 | 162 | .alert-item:hover { 163 | background-color: rgba(0,0,0,0.05); 164 | } 165 | 166 | .alert-item.warning { 167 | border-color: var(--warning-color); 168 | background-color: rgba(241, 196, 15, 0.1); 169 | } 170 | 171 | .alert-item.danger { 172 | border-color: var(--danger-color); 173 | background-color: rgba(231, 76, 60, 0.1); 174 | } 175 | 176 | .maintenance-item { 177 | padding: 10px; 178 | border-bottom: 1px solid #ddd; 179 | } 180 | 181 | .maintenance-priority { 182 | padding: 4px 8px; 183 | border-radius: 4px; 184 | font-size: 0.8em; 185 | font-weight: bold; 186 | } 187 | 188 | .maintenance-priority.high { 189 | background-color: var(--danger-color); 190 | color: white; 191 | } 192 | 193 | .maintenance-priority.medium { 194 | background-color: var(--warning-color); 195 | color: white; 196 | } 197 | 198 | .maintenance-priority.low { 199 | background-color: var(--success-color); 200 | color: white; 201 | } 202 | 203 | .production-stats { 204 | display: flex; 205 | justify-content: space-between; 206 | } 207 | 208 | .stat-item { 209 | text-align: center; 210 | flex: 1; 211 | } 212 | 213 | .stat-item h3 { 214 | margin-bottom: 5px; 215 | font-size: 0.9em; 216 | color: var(--secondary-color); 217 | } 218 | 219 | .stat-item p { 220 | font-size: 1.2em; 221 | font-weight: bold; 222 | margin: 0; 223 | } 224 | 225 | /* OEE Metrics */ 226 | .oee-container { 227 | display: flex; 228 | justify-content: space-around; 229 | align-items: center; 230 | padding: 10px 0; 231 | min-height: 200px; 232 | } 233 | 234 | .gauge-container { 235 | text-align: center; 236 | width: 33%; 237 | position: relative; 238 | min-height: 150px; 239 | } 240 | 241 | .gauge-wrapper { 242 | position: relative; 243 | width: 120px; 244 | height: 120px; 245 | margin: 0 auto; 246 | } 247 | 248 | .gauge-value { 249 | position: absolute; 250 | top: 65%; 251 | left: 50%; 252 | transform: translate(-50%, -50%); 253 | font-size: 1.2em; 254 | font-weight: bold; 255 | color: var(--secondary-color); 256 | } 257 | 258 | .gauge-container p { 259 | margin-top: 10px; 260 | font-weight: bold; 261 | color: var(--secondary-color); 262 | } 263 | 264 | /* Production Line */ 265 | .production-line-new { 266 | display: flex; 267 | justify-content: space-between; 268 | align-items: flex-start; 269 | padding: 15px 5px; 270 | gap: 10px; 271 | } 272 | 273 | .production-stage { 274 | flex: 1; 275 | text-align: center; 276 | position: relative; 277 | display: flex; 278 | flex-direction: column; 279 | align-items: center; 280 | gap: 8px; 281 | } 282 | 283 | .stage-header { 284 | display: flex; 285 | flex-direction: column; 286 | align-items: center; 287 | gap: 5px; 288 | } 289 | 290 | .stage-icon { 291 | font-size: 20px; 292 | } 293 | 294 | .stage-name { 295 | font-size: 0.8em; 296 | font-weight: bold; 297 | color: var(--secondary-color); 298 | } 299 | 300 | .stage-status { 301 | font-size: 0.75em; 302 | padding: 3px 8px; 303 | border-radius: 12px; 304 | width: fit-content; 305 | } 306 | 307 | .stage-status.active { 308 | background-color: var(--success-color); 309 | color: white; 310 | } 311 | 312 | .stage-status.danger { 313 | background-color: var(--danger-color); 314 | color: white; 315 | } 316 | 317 | .stage-arrow { 318 | position: absolute; 319 | right: -7px; 320 | top: 50%; 321 | transform: translateY(-50%); 322 | color: var(--secondary-color); 323 | font-size: 1.2em; 324 | } 325 | 326 | .production-stage:last-child .stage-arrow { 327 | display: none; 328 | } 329 | 330 | /* Environmental Metrics */ 331 | .env-metrics { 332 | display: grid; 333 | grid-template-columns: repeat(3, 1fr); 334 | gap: 15px; 335 | } 336 | 337 | .env-item { 338 | text-align: center; 339 | padding: 10px; 340 | border: 1px solid #ddd; 341 | border-radius: 8px; 342 | } 343 | 344 | .env-value { 345 | font-size: 1.5em; 346 | font-weight: bold; 347 | margin-top: 10px; 348 | } 349 | 350 | /* Resource Utilization */ 351 | .resource-metrics { 352 | display: flex; 353 | flex-direction: column; 354 | gap: 15px; 355 | } 356 | 357 | .resource-item { 358 | display: flex; 359 | align-items: center; 360 | gap: 10px; 361 | } 362 | 363 | .resource-item span { 364 | min-width: 120px; 365 | } 366 | 367 | .resource-item span:last-child { 368 | min-width: 50px; 369 | text-align: right; 370 | } 371 | 372 | .progress-bar { 373 | flex: 1; 374 | height: 15px; 375 | background-color: #e0e0e0; 376 | border-radius: 7px; 377 | overflow: hidden; 378 | } 379 | 380 | .progress { 381 | height: 100%; 382 | background-color: var(--accent-color); 383 | transition: width 0.3s ease; 384 | } 385 | 386 | /* System Health */ 387 | .system-health { 388 | display: flex; 389 | flex-direction: column; 390 | gap: 15px; 391 | } 392 | 393 | .health-metrics { 394 | display: grid; 395 | grid-template-columns: repeat(3, 1fr); 396 | gap: 10px; 397 | } 398 | 399 | .health-item { 400 | padding: 10px; 401 | border: 1px solid #ddd; 402 | border-radius: 8px; 403 | text-align: center; 404 | } 405 | 406 | .health-header { 407 | display: flex; 408 | flex-direction: column; 409 | align-items: center; 410 | gap: 5px; 411 | margin-bottom: 8px; 412 | } 413 | 414 | .health-icon { 415 | font-size: 20px; 416 | } 417 | 418 | .health-label { 419 | font-size: 0.8em; 420 | color: var(--secondary-color); 421 | font-weight: bold; 422 | } 423 | 424 | .health-value { 425 | font-size: 1.2em; 426 | font-weight: bold; 427 | margin: 5px 0; 428 | } 429 | 430 | .health-status { 431 | font-size: 0.8em; 432 | padding: 3px 8px; 433 | border-radius: 12px; 434 | display: inline-block; 435 | } 436 | 437 | .health-status.good { 438 | background-color: var(--success-color); 439 | color: white; 440 | } 441 | 442 | .health-status.warning { 443 | background-color: var(--warning-color); 444 | color: white; 445 | } 446 | 447 | .system-chart-container { 448 | height: 100px; 449 | width: 100%; 450 | } 451 | 452 | /* Animations */ 453 | @keyframes pulse { 454 | 0% { opacity: 1; } 455 | 50% { opacity: 0.5; } 456 | 100% { opacity: 1; } 457 | } 458 | 459 | .warning { 460 | animation: blink 2s infinite; 461 | } 462 | 463 | @keyframes blink { 464 | 0% { opacity: 1; } 465 | 50% { opacity: 0.5; } 466 | 100% { opacity: 1; } 467 | } 468 | 469 | /* Responsive Design */ 470 | @media (max-width: 768px) { 471 | .dashboard-grid { 472 | grid-template-columns: 1fr; 473 | } 474 | 475 | .production-stats { 476 | flex-direction: column; 477 | gap: 10px; 478 | } 479 | 480 | .env-metrics { 481 | grid-template-columns: 1fr; 482 | } 483 | 484 | .health-metrics { 485 | grid-template-columns: 1fr; 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /auto-manufacturing/chatbot-realtime-smart-monitoring/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /healthcare-life-sciences/README.md: -------------------------------------------------------------------------------- 1 | # Healthcare Life Sciences 2 | 3 | Agents the delivery of generative AI applications that can manage and perform tasks by making API calls to your company systems. Agents extend FMs to understand user requests, break down complex tasks into multiple steps, carry on a conversation to collect additional information, and take actions to fulfill the request. 4 | 5 | This section of the repository contains *Healthcare Life Sciences* use-cases to get you started with Amazon Bedrock Agents. 6 | 7 | ## Contents 8 | 9 | - [Automate Discharge Instructions](automate-discharge-instructions) - An agent designed to generate discharge instructions for a given patient and medical diagnosis 10 | 11 | 12 | ## Contributing 13 | 14 | We welcome community contributions! Please ensure your sample aligns with AWS [best practices](https://aws.amazon.com/architecture/well-architected/), and please update the **Contents** section of this README file with a link to your sample, along with a description. 15 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { "project": "./tsconfig.json" }, 5 | "env": { "es6": true }, 6 | "ignorePatterns": ["node_modules", "build", "coverage"], 7 | "plugins": ["import", "eslint-comments", "unused-imports"], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:eslint-comments/recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "plugin:import/typescript", 13 | "prettier" 14 | ], 15 | "globals": { "BigInt": true, "console": true, "WebAssembly": true }, 16 | "rules": { 17 | "@typescript-eslint/explicit-module-boundary-types": "off", 18 | "@typescript-eslint/no-explicit-any": "off", 19 | "@typescript-eslint/no-var-requires": "off", 20 | "eslint-comments/disable-enable-pair": [ 21 | "error", 22 | { "allowWholeFile": true } 23 | ], 24 | "eslint-comments/no-unused-disable": "error", 25 | "unused-imports/no-unused-imports": "error", 26 | "import/order": [ 27 | "error", 28 | { "newlines-between": "never", "alphabetize": { "order": "asc" } } 29 | ], 30 | "sort-imports": [ 31 | "error", 32 | { "ignoreDeclarationSort": true, "ignoreCase": true } 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/README.md: -------------------------------------------------------------------------------- 1 | # Automate Discharge Instructions 2 | ================================= 3 | 4 | ## Authors: 5 | - [Rafael Caixeta](https://www.linkedin.com/in/rafaelcaixeta/) @caixeta 6 | - [Vamsi Pitta](https://www.linkedin.com/in/vamsipitta/) @vvpitta 7 | - [Armando Diaz](https://www.linkedin.com/in/armando-diaz-47a498113/) @armdiazg 8 | - [Marco Punio](https://www.linkedin.com/in/marcpunio/) @puniomp 9 | 10 | This guide details how to install, configure, and use an [Agent for Amazon Bedrock](https://aws.amazon.com/bedrock/agents/) that will use an example patient API and an example [Knowledge Bases for Amazon Bedrock](https://aws.amazon.com/bedrock/knowledge-bases/) to take in promps like `generate discharge instructions for [patient-id] and [diagnostic]` and consult both the example API and Knowledge Base to generate discharge instructions based on a provided template. 11 | 12 | Example prompt and response is available in details on instructions below. 13 | 14 | 15 | # Prerequisites 16 | =============== 17 | 18 | * [node](https://nodejs.org/en) >= 16.0.0 19 | * [npm](https://www.npmjs.com/) >= 8.0.0 20 | * [AWS CLI](https://aws.amazon.com/cli/) >= 2.0.0 21 | * [AWS CDK](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html) >= 2.127.0 22 | * [Docker](https://www.docker.com/): 23 | - Install [Docker](https://docs.docker.com/desktop/) or 24 | - Create an [AWS Cloud9](https://docs.aws.amazon.com/cloud9/latest/user-guide/create-environment-main.html) environment 25 | 26 | *Note: In some cases, you might need to authenticate Docker to Amazon ECR registry with get-login-password. Run the aws ecr [get-login-password](https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-cli.html) command. `aws ecr get-login-password --region region | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com`* 27 | 28 | ## Setup AWS Infratructure 29 | 30 | 1. Install NPM Packages 31 | 32 | ```bash 33 | npm i 34 | ``` 35 | 36 | 2. Generate the template 37 | 38 | ```bash 39 | cdk synth -q 40 | ``` 41 | 42 | 3. Bootstrap your AWS Account for CDK (*This only needs to be done once for a AWS Account. If you already bootstrap your AWS Account for CDK you can skip this step.*) 43 | 44 | ```bash 45 | cdk bootstrap 46 | ``` 47 | 48 | 4. Deploy to your AWS Account in context (*Make sure you correctly configure AWS CLI and have a profile and region set*) 49 | 50 | ```bash 51 | cdk deploy roles 52 | cdk deploy opensearch 53 | cdk deploy api-spec 54 | ``` 55 | 5. Copy *'apiSpecBucketName'* value from *Outputs* and run the below command after updating *{BUCKET_NAME}* 56 | 57 | ```bash 58 | aws s3 cp api-spec/schema.json s3://{BUCKET_NAME} 59 | cdk deploy bedrock 60 | ``` 61 | ## Create Sample Patient Data 62 | 63 | 1. Open [Amazon DynamoDB](https://us-east-1.console.aws.amazon.com/dynamodbv2/home) and search for '*patients*' table. 64 | 65 | 66 | 67 | 2. Click *Actions->Create item* 68 | 69 | 70 | 71 | 3. Switch to JSON view and paste the following sample record 72 | 73 | ```json 74 | { 75 | "id": "PAT-0001", 76 | "name": "John Doe", 77 | "dateOfBirth": "1990-01-01" 78 | } 79 | ``` 80 | 81 | 82 | 83 | ## Testing Amazon Bedrock Knowledge Base 84 | 85 | 1. Open [Amazon S3](https://s3.console.aws.amazon.com/s3/buckets) and search for '*kbBucket*' 86 | 87 | 88 | 89 | 2. Click bucket named '*bedrock-kbbucketXXXXXXXXX*' and upload your actual documents. For this demo, you can upload files from /sampledocs folder. 90 | 91 | 92 | 93 | 3. Open [Amazon Bedrock](https://us-east-1.console.aws.amazon.com/bedrock/home) and click from Knowledge Base from the navigation. 94 | 95 | 96 | 97 | 4. Click on '*Sync data source*' 98 | 99 | 100 | 101 | 5. Wait for sync to finish and click '*Select Model*' and select '*Claude Instant 1.2*' Model. 102 | 103 | 104 | 6. Paste the sample prompt provided below and click '*Run*' 105 | 106 | ``` 107 | Write a discharge report for the patient 'PAT-0001' and diagnostic 'acne'. 108 | 109 | Utilize the following template to write this report, make sure you add all the information required and don't leave any {} tags: 110 | 111 | Discharge Summary 112 | 113 | Patient Name: {patient name} 114 | Date of Birth: {patient date of birth} 115 | Primary Diagnostic: {diagnostic name} 116 | 117 | {diagnostic details} 118 | 119 | {diagnostic medicines} 120 | 121 | {diagnostic care} 122 | 123 | {diagnostic more} 124 | ``` 125 | 126 | Model response 127 | 128 | ``` 129 | Discharge Summary 130 | 131 | Patient Name: 132 | Date of Birth: 133 | Primary Diagnostic: Acne 134 | 135 | Acne is a medical condition that occurs when pores on the surface of the skin become plugged. A pore is an opening of a hair follicle (root) and an oil gland. Pores get blocked when the glands make too much oil. Dirt collects, which causes bacteria to grow in the glands. The skin swells and forms painful bumps, commonly called pimples.[1] 136 | 137 | Topical medicine: These medicines include gels, ointments, creams, pastes, or liquid solutions that are put on your skin. They help decrease swelling and skin shedding. Hormone medicine: These medicines help control the production of oil from the oil glands. Birth control pills are an example of hormone medicine. Acne medicine: These are vitamin-based medicines, which are most useful in treating severe acne. These medicines may have serious side effects. You must not get pregnant or breastfeed while you are using this medicine. Steroids: This medicine may be given to decrease inflammation.[2] 138 | 139 | Be gentle when you wash: Do not rub or scrub your skin with a washcloth. Do not use hot water. Gently pat your skin dry with a clean towel or cloth. Be careful with the medicines you are taking: Certain medicines, including natural and herbal medicines, may trigger an acne flare-up. Always check for skin changes when you take your medicines. Ask your primary healthcare provider before you use herbal medicines or products to control acne. Do not squeeze, pop, or pick your pimples: This may damage your skin and cause infection or scarring. Protect your skin from the sun: Wear sunscreen that has a sun protectant factor (SPF) approved by your primary healthcare provider. Follow the directions on the label when you use sunscreen. Use water-based, oil-free makeup, soaps, or skin cleansers: Oil-based makeup may make acne worse. Check product labels on water-based makeup, since even these may have some added oil.[3] 140 | 141 | Contact your primary healthcare provider dermatologist if: 142 | - Your acne is not getting better or gets worse after treatment. 143 | - You think you are pregnant and need to make sure it is safe to take your acne medicine. 144 | - You have questions about your condition or care.[4] 145 | ``` 146 | 147 | # How to delete 148 | 149 | From within the root project folder (``automate-discharge-instructions``), run the following command: 150 | 151 | ```sh 152 | cdk destroy --force --all 153 | ``` 154 | 155 | **Note - if you created any aliases/versions within your agent you would have to manually delete it in the console.** 156 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/api-spec/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Patient Data API", 5 | "version": "1.0.0", 6 | "description": "" 7 | }, 8 | "paths": { 9 | "/patient/{patientId}": { 10 | "get": { 11 | "summary": "Get patient data", 12 | "description": "Retrieve patient data by a specified patient id", 13 | "operationId": "getPatient", 14 | "parameters": [ 15 | { 16 | "in": "path", 17 | "name": "patientId", 18 | "schema": { "type": "string" }, 19 | "required": true, 20 | "description": "ID of the patient to get" 21 | } 22 | ], 23 | "responses": { 24 | "200": { 25 | "description": "Patient data", 26 | "content": { 27 | "application/json": { 28 | "schema": { 29 | "type": "object", 30 | "properties": { 31 | "id": { 32 | "type": "string", 33 | "description": "Patient id." 34 | }, 35 | "dateOfBirth": { 36 | "type": "string", 37 | "description": "Patient data of birth." 38 | }, 39 | "name": { 40 | "type": "string", 41 | "description": "Patient name." 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/bin/automate-discharge-instructions.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import 'source-map-support/register'; 3 | import * as cdk from 'aws-cdk-lib'; 4 | import { OpensearchStack } from '../lib/opensearch-stack'; 5 | import { RolesStack } from '../lib/roles-stack'; 6 | import { BedrockStack } from '../lib/bedrock-stack'; 7 | import { ApiSpecStack } from '../lib/api-spec-stack'; 8 | 9 | const app = new cdk.App(); 10 | new RolesStack(app, 'roles', {}); 11 | new OpensearchStack(app, 'opensearch', {}); 12 | new ApiSpecStack(app, 'api-spec', {}); 13 | new BedrockStack(app, 'bedrock', {}); 14 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/automate-discharge-instructions.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 38 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 39 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 40 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 41 | "@aws-cdk/aws-route53-patters:useCertificate": true, 42 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 43 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 44 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 45 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 46 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 47 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 48 | "@aws-cdk/aws-redshift:columnId": true, 49 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 50 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 51 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 52 | "@aws-cdk/aws-kms:aliasNameRef": true, 53 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 54 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 55 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 56 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 57 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 58 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 59 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 60 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 61 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 62 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, 63 | "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, 64 | "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, 65 | "cdk-migrate": true 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/index-custom-resource/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.10.2024.03.04.10-x86_64 2 | 3 | # Installs python, removes cache file to make things smaller 4 | RUN yum update -y && \ 5 | yum install -y python3 python3-dev python3-pip gcc && \ 6 | rm -Rf /var/cache/yum 7 | 8 | # Copies requirements.txt file into the container 9 | COPY requirements.txt ./ 10 | # Installs dependencies found in your requirements.txt file 11 | RUN pip install -r requirements.txt 12 | 13 | # Be sure to copy over the function itself! 14 | # Goes last to take advantage of Docker caching. 15 | COPY index_custom_resource.py ./ 16 | 17 | # Points to the handler function of your lambda function 18 | CMD ["index_custom_resource.on_event"] -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/index-custom-resource/index_custom_resource.py: -------------------------------------------------------------------------------- 1 | from opensearchpy import OpenSearch, RequestsHttpConnection 2 | from requests_aws4auth import AWS4Auth 3 | import boto3 4 | import time 5 | import json 6 | import os 7 | 8 | region = os.environ['AWS_REGION'] 9 | collection_endpoint = os.environ['COLLECTION_ENDPOINT'] 10 | vector_field = os.environ['VECTOR_FIELD_NAME'] 11 | vector_index_name = os.environ['VECTOR_INDEX_NAME'] 12 | text_field = os.environ['TEXT_FIELD'] 13 | metadata_field = os.environ['METADATA_FIELD'] 14 | 15 | 16 | def on_event(event, context): 17 | physical_id = "CreatedIndexId" 18 | 19 | print(json.dumps(event)) 20 | request_type = event['RequestType'] 21 | if request_type == 'Create': 22 | return on_create(event, physical_id=physical_id, region=region, 23 | endpoint=collection_endpoint, vector_field=vector_field, 24 | vector_index_name=vector_index_name, text_field=text_field, 25 | metadata_field=metadata_field) 26 | if request_type == 'Update': 27 | return on_update(event, physical_id=physical_id) 28 | if request_type == 'Delete': 29 | return on_delete(event, physical_id=physical_id) 30 | raise Exception("Invalid request type: %s" % request_type) 31 | 32 | 33 | def on_create(event, physical_id, region, endpoint, vector_index_name, 34 | vector_field, text_field, metadata_field): 35 | props = event["ResourceProperties"] 36 | print("create new resource with props %s" % props) 37 | 38 | index_data(region=region, vector_index_name=vector_index_name, 39 | text_field=text_field, metadata_field=metadata_field, 40 | vector_field=vector_field, endpoint=endpoint) 41 | 42 | return {'PhysicalResourceId': physical_id} 43 | 44 | 45 | def on_update(event, physical_id): 46 | props = event["ResourceProperties"] 47 | print("update resource %s with props %s" % (physical_id, props)) 48 | 49 | return {'PhysicalResourceId': physical_id} 50 | 51 | 52 | def on_delete(event, physical_id): 53 | print("delete resource %s" % physical_id) 54 | 55 | return {'PhysicalResourceId': physical_id} 56 | 57 | 58 | def index_data(region, vector_index_name, text_field, 59 | metadata_field, vector_field, endpoint): 60 | 61 | host = endpoint.replace("https://", "") 62 | 63 | # Set up auth for Opensearch client 64 | service = 'aoss' 65 | credentials = boto3.Session().get_credentials() 66 | awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, 67 | region, service, session_token=credentials.token) 68 | 69 | """Create an index""" 70 | # Build the OpenSearch client 71 | client = OpenSearch( 72 | hosts=[{'host': host, 'port': 443}], 73 | http_auth=awsauth, 74 | use_ssl=True, 75 | verify_certs=True, 76 | connection_class=RequestsHttpConnection, 77 | timeout=300 78 | ) 79 | # It can take up to a minute for data access rules to be enforced 80 | time.sleep(45) 81 | 82 | # Create index 83 | body = { 84 | "mappings": { 85 | "properties": { 86 | f"{metadata_field}": { 87 | "type": "text", 88 | "index": False 89 | }, 90 | "id": { 91 | "type": "text", 92 | "fields": { 93 | "keyword": { 94 | "type": "keyword", 95 | "ignore_above": 256 96 | } 97 | } 98 | }, 99 | f"{text_field}": { 100 | "type": "text" 101 | # "index": False 102 | }, 103 | f"{vector_field}": { 104 | "type": "knn_vector", 105 | "dimension": 1536, 106 | "method": { 107 | "engine": "faiss", 108 | "space_type": "l2", 109 | "name": "hnsw" 110 | } 111 | } 112 | } 113 | }, 114 | "settings": { 115 | "index": { 116 | "number_of_shards": 2, 117 | "knn.algo_param": { 118 | "ef_search": 512 119 | }, 120 | "knn": True, 121 | } 122 | } 123 | } 124 | 125 | response = client.indices.create(index=vector_index_name, body=body) 126 | print('\nCreating index:') 127 | print(response) 128 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/index-custom-resource/requirements.txt: -------------------------------------------------------------------------------- 1 | opensearch-py==2.4.2 2 | boto3==1.34.60 3 | requests-aws4auth==1.2.3 4 | pydantic -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/lib/api-spec-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as s3 from 'aws-cdk-lib/aws-s3'; 3 | 4 | export class ApiSpecStack extends cdk.Stack { 5 | public constructor(scope: cdk.App, id: string, props: any) { 6 | super(scope, id, props); 7 | 8 | const apiSpecBucket = new s3.Bucket(this, 'api-spec-bucket', { 9 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 10 | encryption: s3.BucketEncryption.S3_MANAGED, 11 | versioned: false, 12 | removalPolicy: cdk.RemovalPolicy.DESTROY, 13 | autoDeleteObjects: true, 14 | }); 15 | 16 | new cdk.CfnOutput(this, 'apiSpecBucketName', { 17 | value: apiSpecBucket.bucketName, 18 | exportName: 'apiSpecBucketName', 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/lib/bedrock-stack.ts: -------------------------------------------------------------------------------- 1 | import * as bedrockagents from 'bedrock-agents-cdk'; 2 | import * as cdk from 'aws-cdk-lib'; 3 | import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; 4 | import * as iam from 'aws-cdk-lib/aws-iam'; 5 | import * as lambda from 'aws-cdk-lib/aws-lambda'; 6 | import * as nodeLambda from 'aws-cdk-lib/aws-lambda-nodejs'; 7 | import * as s3 from 'aws-cdk-lib/aws-s3'; 8 | import { AGENT_NAME, KNOWLEDGE_BASE_NAME, AWS_REGION_NAME } from './constants'; 9 | import path = require('path'); 10 | 11 | export interface AutomateDischargeInstructionsStackProps extends cdk.StackProps {} 12 | 13 | const kbInstruction = ` 14 | Use this knowledge base to obtain detailed information on the diagnostic provided by the user.`; 15 | const agentInstruction = ` 16 | You're a clinician specialized on writing discharge reports on behalf of the doctor. 17 | You'll have access to patient data and diagnostics data. 18 | The user is going to provide information on patient and diagnostic and a template. 19 | Follow the template strictly to generate the desired report.`; 20 | 21 | export class BedrockStack extends cdk.Stack { 22 | public constructor(scope: cdk.App, id: string, props: AutomateDischargeInstructionsStackProps) { 23 | super(scope, id, props); 24 | 25 | // Dynamo Db 26 | const patientTable = new dynamodb.Table(this, 'patients-table', { 27 | tableName: 'patients', 28 | partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, 29 | billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, 30 | pointInTimeRecovery: false, 31 | deletionProtection: false, 32 | tableClass: dynamodb.TableClass.STANDARD, 33 | removalPolicy: cdk.RemovalPolicy.DESTROY, 34 | }); 35 | 36 | // KB S3 Bucket 37 | const kbBucket = new s3.Bucket(this, 'kbBucket', { 38 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 39 | encryption: s3.BucketEncryption.S3_MANAGED, 40 | versioned: false, 41 | removalPolicy: cdk.RemovalPolicy.DESTROY, 42 | autoDeleteObjects: true, 43 | }); 44 | 45 | // Lambda 46 | const getPatientFunction = new nodeLambda.NodejsFunction(this, `get-patient`, { 47 | runtime: lambda.Runtime.NODEJS_20_X, 48 | architecture: lambda.Architecture.ARM_64, 49 | functionName: 'get-patient', 50 | description: 'Obtain patient data from database with provided ID', 51 | timeout: cdk.Duration.seconds(30), 52 | memorySize: 256, 53 | handler: 'main', 54 | entry: path.resolve(__dirname, '../src/get-patient/index.ts'), 55 | bundling: { 56 | externalModules: ['@aws-sdk/client-dynamodb', '@aws-sdk/lib-dynamodb'], 57 | }, 58 | environment: { 59 | TABLE_NAME: patientTable.tableName, 60 | }, 61 | }); 62 | patientTable.grantFullAccess(getPatientFunction); 63 | 64 | const agentRole = iam.Role.fromRoleArn(this, 'agentRole', cdk.Fn.importValue('agentRoleArn')); 65 | const kbRole = iam.Role.fromRoleArn(this, 'kbRole', cdk.Fn.importValue('kbRoleArn')); 66 | 67 | // Bedrock 68 | const diagnosticsKb = new bedrockagents.BedrockKnowledgeBase(this, KNOWLEDGE_BASE_NAME, { 69 | name: KNOWLEDGE_BASE_NAME, 70 | roleArn: kbRole.roleArn, 71 | storageConfiguration: { 72 | opensearchServerlessConfiguration: { 73 | collectionArn: cdk.Fn.importValue('opensearchArn'), 74 | fieldMapping: { 75 | metadataField: 'metadata', 76 | textField: 'text', 77 | vectorField: 'vector', 78 | }, 79 | vectorIndexName: `${KNOWLEDGE_BASE_NAME}-default-index`, 80 | }, 81 | type: 'OPENSEARCH_SERVERLESS', 82 | }, 83 | dataSource: { 84 | name: 'diagnostics-kb-datasource', 85 | dataSourceConfiguration: { 86 | s3Configuration: { 87 | bucketArn: kbBucket.bucketArn, 88 | }, 89 | }, 90 | }, 91 | knowledgeBaseConfiguration: { 92 | type: 'VECTOR', 93 | vectorKnowledgeBaseConfiguration: { 94 | embeddingModelArn: `arn:aws:bedrock:${AWS_REGION_NAME}::foundation-model/amazon.titan-embed-text-v1` 95 | } 96 | } 97 | }); 98 | diagnosticsKb.node.addDependency(kbBucket); 99 | 100 | const agent = new bedrockagents.BedrockAgent(this, AGENT_NAME, { 101 | agentName: AGENT_NAME, 102 | instruction: agentInstruction, 103 | foundationModel: 'anthropic.claude-instant-v1', 104 | agentResourceRoleArn: agentRole.roleArn, 105 | actionGroups: [ 106 | { 107 | actionGroupName: 'patient-api', 108 | actionGroupExecutor: getPatientFunction.functionArn, 109 | s3BucketName: cdk.Fn.importValue('apiSpecBucketName'), 110 | s3ObjectKey: 'schema.json', 111 | description: 'API to obtain patient data.', 112 | }, 113 | ], 114 | knowledgeBaseAssociations: [ 115 | { 116 | knowledgeBaseName: KNOWLEDGE_BASE_NAME, 117 | instruction: kbInstruction, 118 | }, 119 | ], 120 | }); 121 | agent.node.addDependency(diagnosticsKb); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/lib/constants.ts: -------------------------------------------------------------------------------- 1 | export const AGENT_NAME = 'discharge-agent'; 2 | export const KNOWLEDGE_BASE_NAME = 'diagnostics-kb'; 3 | export const COLLECTION_NAME = 'diagnostics-kb'; 4 | export const AWS_REGION_NAME = 'us-east-1'; 5 | 6 | export const VECTOR_INDEX_NAME = `${COLLECTION_NAME}-default-index`; 7 | export const VECTOR_FIELD_NAME = 'vector'; 8 | export const TEXT_FIELD_NAME = 'text'; 9 | export const METADATA_FIELD_NAME = 'metadata'; -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/lib/opensearch-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as custom from 'aws-cdk-lib/custom-resources'; 3 | import * as iam from 'aws-cdk-lib/aws-iam'; 4 | import * as lambda from 'aws-cdk-lib/aws-lambda'; 5 | import * as logs from 'aws-cdk-lib/aws-logs'; 6 | import * as opensearchserverless from 'aws-cdk-lib/aws-opensearchserverless'; 7 | import { COLLECTION_NAME, METADATA_FIELD_NAME, TEXT_FIELD_NAME, VECTOR_FIELD_NAME, VECTOR_INDEX_NAME } from './constants'; 8 | 9 | 10 | export class OpensearchStack extends cdk.Stack { 11 | public constructor(scope: cdk.App, id: string, props: any) { 12 | super(scope, id, props); 13 | 14 | const kbRole = iam.Role.fromRoleArn(this, 'kbRole', cdk.Fn.importValue('kbRoleArn')); 15 | const customResourceRole = new iam.Role(this, 'index-custom-resource-role', { 16 | assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), 17 | managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], 18 | }); 19 | 20 | const accessPolicy = new opensearchserverless.CfnAccessPolicy(this, 'opensearchAccessPolicy', { 21 | policy: JSON.stringify([ 22 | { 23 | Description: "Data access policy to grant access to Amazon Bedrock Knowledge Base", 24 | Rules: [ 25 | { Resource: [`collection/${COLLECTION_NAME}`], Permission: ["aoss:DescribeCollectionItems", "aoss:CreateCollectionItems", "aoss:UpdateCollectionItems"], ResourceType: "collection" }, 26 | { Resource: [`index/${COLLECTION_NAME}/*`], Permission: ["aoss:UpdateIndex", "aoss:DescribeIndex", "aoss:ReadDocument", "aoss:WriteDocument", "aoss:CreateIndex"], ResourceType: "index" }, 27 | ], 28 | Principal: [kbRole.roleArn, customResourceRole.roleArn] 29 | } 30 | ]), 31 | type: 'data', 32 | description: 'Data access policy to grant access to Amazon Bedrock Knowledge Base.', 33 | name: 'diagnostics-kb-access-policy', 34 | }); 35 | 36 | const encryptionPolicy = new opensearchserverless.CfnSecurityPolicy(this, 'opensearchEncryptionPolicy', { 37 | policy: JSON.stringify({ Rules: [{ Resource: [`collection/${COLLECTION_NAME}`], ResourceType: "collection" }], AWSOwnedKey: true }), 38 | type: 'encryption', 39 | description: 'Encryption policy for Amazon Bedrock Knowledge Base vector database.', 40 | name: 'diagnostics-kb-encryption-policy', 41 | }); 42 | 43 | const networkPolicy = new opensearchserverless.CfnSecurityPolicy(this, 'opensearchNetworkPolicy', { 44 | policy: JSON.stringify([{ 45 | Rules: [ 46 | { Resource: [`collection/${COLLECTION_NAME}`], ResourceType: "dashboard" }, 47 | { Resource: [`collection/${COLLECTION_NAME}`], ResourceType: "collection" } 48 | ], 49 | AllowFromPublic: true 50 | }]), 51 | type: 'network', 52 | description: 'Custom network policy created by Amazon Bedrock Knowledge Base service to allow a created IAM role to have permissions on Amazon Open Search collections and indexes.', 53 | name: 'diagnostics-kb-network-policy', 54 | }); 55 | 56 | const opensearchCollection = new opensearchserverless.CfnCollection(this, 'opensearchCollection', { 57 | name: COLLECTION_NAME, 58 | description: 'Diagnostics Amazon Bedrock Knowledge Base vector database', 59 | type: 'VECTORSEARCH', 60 | }); 61 | 62 | opensearchCollection.node.addDependency(encryptionPolicy); 63 | opensearchCollection.node.addDependency(networkPolicy); 64 | opensearchCollection.node.addDependency(accessPolicy); 65 | 66 | // Vector Index 67 | // API Access 68 | customResourceRole.addToPolicy( 69 | new iam.PolicyStatement({ 70 | resources: [opensearchCollection.attrArn], 71 | actions: ['aoss:APIAccessAll'], 72 | }), 73 | ); 74 | 75 | // Lambda Function 76 | const indexCusstomResourceFunction = new lambda.DockerImageFunction(this, "index-custom-resource-function", { 77 | code: lambda.DockerImageCode.fromImageAsset('index-custom-resource'), 78 | timeout: cdk.Duration.seconds(600), 79 | role: customResourceRole, 80 | environment: { 81 | COLLECTION_ENDPOINT: opensearchCollection.attrCollectionEndpoint, 82 | VECTOR_FIELD_NAME: VECTOR_FIELD_NAME, 83 | VECTOR_INDEX_NAME: VECTOR_INDEX_NAME, 84 | TEXT_FIELD: TEXT_FIELD_NAME, 85 | METADATA_FIELD: METADATA_FIELD_NAME, 86 | }, 87 | } 88 | ); 89 | indexCusstomResourceFunction.node.addDependency(opensearchCollection); 90 | 91 | // Custom Resource Provider 92 | const provider = new custom.Provider(this, 'index-custom-resource-provider', { 93 | onEventHandler: indexCusstomResourceFunction, 94 | logRetention: logs.RetentionDays.ONE_DAY, 95 | }); 96 | 97 | // Custom Resource 98 | new cdk.CustomResource(this, 'index-custom-resource', { 99 | serviceToken: provider.serviceToken, 100 | }); 101 | 102 | new cdk.CfnOutput(this, "opensearchArn", { 103 | value: opensearchCollection.attrArn, 104 | exportName: "opensearchArn", 105 | }); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/lib/roles-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import * as iam from 'aws-cdk-lib/aws-iam'; 3 | import { AGENT_NAME, KNOWLEDGE_BASE_NAME } from './constants'; 4 | import { ServiceLinkedRole } from 'upsert-slr'; 5 | 6 | export class RolesStack extends cdk.Stack { 7 | public constructor(scope: cdk.App, id: string, props: any) { 8 | super(scope, id, props); 9 | 10 | const agentRole = new iam.Role(this, 'bedrockAgentRole', { 11 | roleName: `AmazonBedrockExecutionRoleForAgents_${AGENT_NAME}`, 12 | assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'), 13 | managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')], 14 | }); 15 | 16 | const kbRole = new iam.Role(this, 'bedrockKbRole', { 17 | roleName: `AmazonBedrockExecutionRoleForKnowledgeBase_${KNOWLEDGE_BASE_NAME}`, 18 | assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'), 19 | managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')], 20 | }); 21 | 22 | // const serviceRole = new iam.CfnServiceLinkedRole(this, 'opensearchServiceRole', { 23 | // awsServiceName: 'observability.aoss.amazonaws.com', 24 | // }); 25 | // serviceRole.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.RETAIN; 26 | 27 | new ServiceLinkedRole(this, 'opensearchServiceRole', { 28 | awsServiceName: 'observability.aoss.amazonaws.com', 29 | description: 'Service linked role for OpenSearch Serverless', 30 | }); 31 | 32 | new cdk.CfnOutput(this, "agentRoleArn", { 33 | value: agentRole.roleArn, 34 | exportName: "agentRoleArn", 35 | }); 36 | new cdk.CfnOutput(this, "kbRoleArn", { 37 | value: kbRole.roleArn, 38 | exportName: "kbRoleArn", 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/migrate.json: -------------------------------------------------------------------------------- 1 | { 2 | "//": "This file is generated by cdk migrate. It will be automatically deleted after the first successful deployment of this app to the environment of the original resources.", 3 | "Source": "arn:aws:cloudformation:us-east-1:730335288991:generatedTemplate/feae4e7e-a770-4aac-90f5-e3c37190f718", 4 | "Resources": [ 5 | { 6 | "ResourceType": "AWS::DynamoDB::Table", 7 | "LogicalResourceId": "DynamoDBTable00diagnosticspatients00s26Cy", 8 | "ResourceIdentifier": { 9 | "TableName": "diagnostics-patients" 10 | } 11 | }, 12 | { 13 | "ResourceType": "AWS::IAM::Role", 14 | "LogicalResourceId": "IAMRole00AWSServiceRoleForAmazonOpenSearchServerless00gENqt", 15 | "ResourceIdentifier": { 16 | "RoleName": "AWSServiceRoleForAmazonOpenSearchServerless" 17 | } 18 | }, 19 | { 20 | "ResourceType": "AWS::IAM::Role", 21 | "LogicalResourceId": "IAMRole00AmazonBedrockExecutionRoleForAgentsYYUXPY9VC6M00l6ClL", 22 | "ResourceIdentifier": { 23 | "RoleName": "AmazonBedrockExecutionRoleForAgents_YYUXPY9VC6M" 24 | } 25 | }, 26 | { 27 | "ResourceType": "AWS::IAM::Role", 28 | "LogicalResourceId": "IAMRole00AmazonBedrockExecutionRoleForKnowledgeBasehls00nZvLH", 29 | "ResourceIdentifier": { 30 | "RoleName": "AmazonBedrockExecutionRoleForKnowledgeBase_hls" 31 | } 32 | }, 33 | { 34 | "ResourceType": "AWS::IAM::Role", 35 | "LogicalResourceId": "IAMRole00diagnosticsgeneraterportroleubecr1da00fRFBv", 36 | "ResourceIdentifier": { 37 | "RoleName": "diagnostics-generate-rport-role-ubecr1da" 38 | } 39 | }, 40 | { 41 | "ResourceType": "AWS::IAM::Role", 42 | "LogicalResourceId": "IAMRole00diagnosticsgetpatientrole31hddgs500an7k7", 43 | "ResourceIdentifier": { 44 | "RoleName": "diagnostics-get-patient-role-31hddgs5" 45 | } 46 | }, 47 | { 48 | "ResourceType": "AWS::Lambda::Function", 49 | "LogicalResourceId": "LambdaFunction00diagnosticsgeneraterport00Kk7WO", 50 | "ResourceIdentifier": { 51 | "FunctionName": "diagnostics-generate-rport" 52 | } 53 | }, 54 | { 55 | "ResourceType": "AWS::Lambda::Function", 56 | "LogicalResourceId": "LambdaFunction00diagnosticsgetpatient00YjBjK", 57 | "ResourceIdentifier": { 58 | "FunctionName": "diagnostics-get-patient" 59 | } 60 | }, 61 | { 62 | "ResourceType": "AWS::Lambda::Permission", 63 | "LogicalResourceId": "LambdaPermission00functiondiagnosticsgetpatient00BG0yo", 64 | "ResourceIdentifier": { 65 | "FunctionName": "arn:aws:lambda:us-east-1:730335288991:function:diagnostics-get-patient", 66 | "Id": "bedrock" 67 | } 68 | }, 69 | { 70 | "ResourceType": "AWS::Logs::LogGroup", 71 | "LogicalResourceId": "LogsLogGroup00awslambdadiagnosticsgeneraterport00ryPcX", 72 | "ResourceIdentifier": { 73 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 74 | } 75 | }, 76 | { 77 | "ResourceType": "AWS::Logs::LogGroup", 78 | "LogicalResourceId": "LogsLogGroup00awslambdadiagnosticsgetpatient00EYlNt", 79 | "ResourceIdentifier": { 80 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 81 | } 82 | }, 83 | { 84 | "ResourceType": "AWS::Logs::LogStream", 85 | "LogicalResourceId": "LogsLogStream0020240206LATEST2842199d4abf468289c5dec7d42c9f5600KQWT4", 86 | "ResourceIdentifier": { 87 | "LogStreamName": "2024/02/06/[$LATEST]2842199d4abf468289c5dec7d42c9f56", 88 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 89 | } 90 | }, 91 | { 92 | "ResourceType": "AWS::Logs::LogStream", 93 | "LogicalResourceId": "LogsLogStream0020240206LATEST33ccacb179354a4b914e8ba894be09c200XXFTE", 94 | "ResourceIdentifier": { 95 | "LogStreamName": "2024/02/06/[$LATEST]33ccacb179354a4b914e8ba894be09c2", 96 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 97 | } 98 | }, 99 | { 100 | "ResourceType": "AWS::Logs::LogStream", 101 | "LogicalResourceId": "LogsLogStream0020240206LATEST4e9d140553974797830384d99e1f2ce300DJ0i7", 102 | "ResourceIdentifier": { 103 | "LogStreamName": "2024/02/06/[$LATEST]4e9d140553974797830384d99e1f2ce3", 104 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 105 | } 106 | }, 107 | { 108 | "ResourceType": "AWS::Logs::LogStream", 109 | "LogicalResourceId": "LogsLogStream0020240206LATEST513d00848abe4e93bde5c0884ee43b4000Kyxld", 110 | "ResourceIdentifier": { 111 | "LogStreamName": "2024/02/06/[$LATEST]513d00848abe4e93bde5c0884ee43b40", 112 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 113 | } 114 | }, 115 | { 116 | "ResourceType": "AWS::Logs::LogStream", 117 | "LogicalResourceId": "LogsLogStream0020240206LATEST7a1f85a08fb2464b98c1e040399d4d5c0075yle", 118 | "ResourceIdentifier": { 119 | "LogStreamName": "2024/02/06/[$LATEST]7a1f85a08fb2464b98c1e040399d4d5c", 120 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 121 | } 122 | }, 123 | { 124 | "ResourceType": "AWS::Logs::LogStream", 125 | "LogicalResourceId": "LogsLogStream0020240206LATEST8c94ebaa77194405a5535011512f857800hnoKz", 126 | "ResourceIdentifier": { 127 | "LogStreamName": "2024/02/06/[$LATEST]8c94ebaa77194405a5535011512f8578", 128 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 129 | } 130 | }, 131 | { 132 | "ResourceType": "AWS::Logs::LogStream", 133 | "LogicalResourceId": "LogsLogStream0020240206LATESTa8583df1cc714ec5aad553e60ec8278c00f6CS9", 134 | "ResourceIdentifier": { 135 | "LogStreamName": "2024/02/06/[$LATEST]a8583df1cc714ec5aad553e60ec8278c", 136 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 137 | } 138 | }, 139 | { 140 | "ResourceType": "AWS::Logs::LogStream", 141 | "LogicalResourceId": "LogsLogStream0020240206LATESTccd5c0d26c1b4dbb876184aca1476e8c00oF4U2", 142 | "ResourceIdentifier": { 143 | "LogStreamName": "2024/02/06/[$LATEST]ccd5c0d26c1b4dbb876184aca1476e8c", 144 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 145 | } 146 | }, 147 | { 148 | "ResourceType": "AWS::Logs::LogStream", 149 | "LogicalResourceId": "LogsLogStream0020240206LATESTd496694d2e4f4ac9ab27a1d367fcc79800S6Ke4", 150 | "ResourceIdentifier": { 151 | "LogStreamName": "2024/02/06/[$LATEST]d496694d2e4f4ac9ab27a1d367fcc798", 152 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 153 | } 154 | }, 155 | { 156 | "ResourceType": "AWS::Logs::LogStream", 157 | "LogicalResourceId": "LogsLogStream0020240208LATEST0b449ccf3b6c4b26b7ab7bad4ffc97b700NhufF", 158 | "ResourceIdentifier": { 159 | "LogStreamName": "2024/02/08/[$LATEST]0b449ccf3b6c4b26b7ab7bad4ffc97b7", 160 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 161 | } 162 | }, 163 | { 164 | "ResourceType": "AWS::Logs::LogStream", 165 | "LogicalResourceId": "LogsLogStream0020240208LATEST0e429286763d440aa6cd7ac45b6b3ea800qz1t1", 166 | "ResourceIdentifier": { 167 | "LogStreamName": "2024/02/08/[$LATEST]0e429286763d440aa6cd7ac45b6b3ea8", 168 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 169 | } 170 | }, 171 | { 172 | "ResourceType": "AWS::Logs::LogStream", 173 | "LogicalResourceId": "LogsLogStream0020240208LATEST1941cee36c4d49dd94cf407792b4329400AZHfa", 174 | "ResourceIdentifier": { 175 | "LogStreamName": "2024/02/08/[$LATEST]1941cee36c4d49dd94cf407792b43294", 176 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 177 | } 178 | }, 179 | { 180 | "ResourceType": "AWS::Logs::LogStream", 181 | "LogicalResourceId": "LogsLogStream0020240208LATEST28af4c921e034219bd30e35dfdfb511b00t3v1M", 182 | "ResourceIdentifier": { 183 | "LogStreamName": "2024/02/08/[$LATEST]28af4c921e034219bd30e35dfdfb511b", 184 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 185 | } 186 | }, 187 | { 188 | "ResourceType": "AWS::Logs::LogStream", 189 | "LogicalResourceId": "LogsLogStream0020240208LATEST387a9ad8c7394f4b905d00a8e700223e00ayw9z", 190 | "ResourceIdentifier": { 191 | "LogStreamName": "2024/02/08/[$LATEST]387a9ad8c7394f4b905d00a8e700223e", 192 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 193 | } 194 | }, 195 | { 196 | "ResourceType": "AWS::Logs::LogStream", 197 | "LogicalResourceId": "LogsLogStream0020240208LATEST4049c2e9894a4e40abca9df75de098e100jQaWF", 198 | "ResourceIdentifier": { 199 | "LogStreamName": "2024/02/08/[$LATEST]4049c2e9894a4e40abca9df75de098e1", 200 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 201 | } 202 | }, 203 | { 204 | "ResourceType": "AWS::Logs::LogStream", 205 | "LogicalResourceId": "LogsLogStream0020240208LATEST48cd2cea99414e4ab0ded3d79a043eaa00DlLfb", 206 | "ResourceIdentifier": { 207 | "LogStreamName": "2024/02/08/[$LATEST]48cd2cea99414e4ab0ded3d79a043eaa", 208 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 209 | } 210 | }, 211 | { 212 | "ResourceType": "AWS::Logs::LogStream", 213 | "LogicalResourceId": "LogsLogStream0020240208LATEST56ec3183b90543a08f6ad6a505917e7a00KoJj7", 214 | "ResourceIdentifier": { 215 | "LogStreamName": "2024/02/08/[$LATEST]56ec3183b90543a08f6ad6a505917e7a", 216 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 217 | } 218 | }, 219 | { 220 | "ResourceType": "AWS::Logs::LogStream", 221 | "LogicalResourceId": "LogsLogStream0020240208LATEST72227e81bc1541eebceccc199983b1b800LX8h0", 222 | "ResourceIdentifier": { 223 | "LogStreamName": "2024/02/08/[$LATEST]72227e81bc1541eebceccc199983b1b8", 224 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 225 | } 226 | }, 227 | { 228 | "ResourceType": "AWS::Logs::LogStream", 229 | "LogicalResourceId": "LogsLogStream0020240208LATEST822a9a886dbe46488376927cee5eab1e00Rmiit", 230 | "ResourceIdentifier": { 231 | "LogStreamName": "2024/02/08/[$LATEST]822a9a886dbe46488376927cee5eab1e", 232 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 233 | } 234 | }, 235 | { 236 | "ResourceType": "AWS::Logs::LogStream", 237 | "LogicalResourceId": "LogsLogStream0020240208LATEST8b9823aedca042b181fb05940c45af3f00VqNrh", 238 | "ResourceIdentifier": { 239 | "LogStreamName": "2024/02/08/[$LATEST]8b9823aedca042b181fb05940c45af3f", 240 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 241 | } 242 | }, 243 | { 244 | "ResourceType": "AWS::Logs::LogStream", 245 | "LogicalResourceId": "LogsLogStream0020240208LATEST8cdcef53786444a3b317ed6c71fc034100yxm8j", 246 | "ResourceIdentifier": { 247 | "LogStreamName": "2024/02/08/[$LATEST]8cdcef53786444a3b317ed6c71fc0341", 248 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 249 | } 250 | }, 251 | { 252 | "ResourceType": "AWS::Logs::LogStream", 253 | "LogicalResourceId": "LogsLogStream0020240208LATEST9e5d4ac12d694f8bbc04cf6c9f48df6c00ntH83", 254 | "ResourceIdentifier": { 255 | "LogStreamName": "2024/02/08/[$LATEST]9e5d4ac12d694f8bbc04cf6c9f48df6c", 256 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 257 | } 258 | }, 259 | { 260 | "ResourceType": "AWS::Logs::LogStream", 261 | "LogicalResourceId": "LogsLogStream0020240208LATESTae903421461f4aeca1bd562d4030b3d400lolaO", 262 | "ResourceIdentifier": { 263 | "LogStreamName": "2024/02/08/[$LATEST]ae903421461f4aeca1bd562d4030b3d4", 264 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 265 | } 266 | }, 267 | { 268 | "ResourceType": "AWS::Logs::LogStream", 269 | "LogicalResourceId": "LogsLogStream0020240208LATESTc66a47301f844067a405a5157ba612f000Or772", 270 | "ResourceIdentifier": { 271 | "LogStreamName": "2024/02/08/[$LATEST]c66a47301f844067a405a5157ba612f0", 272 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 273 | } 274 | }, 275 | { 276 | "ResourceType": "AWS::Logs::LogStream", 277 | "LogicalResourceId": "LogsLogStream0020240208LATESTccfabfb492574b7baa70f48e76092c3400dYRXI", 278 | "ResourceIdentifier": { 279 | "LogStreamName": "2024/02/08/[$LATEST]ccfabfb492574b7baa70f48e76092c34", 280 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 281 | } 282 | }, 283 | { 284 | "ResourceType": "AWS::Logs::LogStream", 285 | "LogicalResourceId": "LogsLogStream0020240208LATESTdc91e57797ff43359521d8fdfa3b897300pM1jW", 286 | "ResourceIdentifier": { 287 | "LogStreamName": "2024/02/08/[$LATEST]dc91e57797ff43359521d8fdfa3b8973", 288 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 289 | } 290 | }, 291 | { 292 | "ResourceType": "AWS::Logs::LogStream", 293 | "LogicalResourceId": "LogsLogStream0020240208LATESTe7fdc3dade50482481d60b0718b8927400rCXqx", 294 | "ResourceIdentifier": { 295 | "LogStreamName": "2024/02/08/[$LATEST]e7fdc3dade50482481d60b0718b89274", 296 | "LogGroupName": "/aws/lambda/diagnostics-generate-rport" 297 | } 298 | }, 299 | { 300 | "ResourceType": "AWS::Logs::LogStream", 301 | "LogicalResourceId": "LogsLogStream0020240208LATESTf1660c4d1de7462aa55a4397223e975d00ZKAEZ", 302 | "ResourceIdentifier": { 303 | "LogStreamName": "2024/02/08/[$LATEST]f1660c4d1de7462aa55a4397223e975d", 304 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 305 | } 306 | }, 307 | { 308 | "ResourceType": "AWS::Logs::LogStream", 309 | "LogicalResourceId": "LogsLogStream0020240209LATEST8214c0dbb95c440b9e1e49b8aa83772200yU5wI", 310 | "ResourceIdentifier": { 311 | "LogStreamName": "2024/02/09/[$LATEST]8214c0dbb95c440b9e1e49b8aa837722", 312 | "LogGroupName": "/aws/lambda/diagnostics-get-patient" 313 | } 314 | }, 315 | { 316 | "ResourceType": "AWS::OpenSearchServerless::AccessPolicy", 317 | "LogicalResourceId": "OpenSearchServerlessAccessPolicy00data00Qbzmx", 318 | "ResourceIdentifier": { 319 | "Type": "data", 320 | "Name": "bedrock-knowledge-base-g059ag" 321 | } 322 | }, 323 | { 324 | "ResourceType": "AWS::OpenSearchServerless::SecurityPolicy", 325 | "LogicalResourceId": "OpenSearchServerlessSecurityPolicy00encryption002RgDI", 326 | "ResourceIdentifier": { 327 | "Type": "encryption", 328 | "Name": "bedrock-knowledge-base-w9tx5j" 329 | } 330 | }, 331 | { 332 | "ResourceType": "AWS::OpenSearchServerless::SecurityPolicy", 333 | "LogicalResourceId": "OpenSearchServerlessSecurityPolicy00network00F0B3i", 334 | "ResourceIdentifier": { 335 | "Type": "network", 336 | "Name": "bedrock-knowledge-base-w9tx5j" 337 | } 338 | }, 339 | { 340 | "ResourceType": "AWS::S3::Bucket", 341 | "LogicalResourceId": "S3Bucket00caixetagenaidemodisagnostics00K5V2j", 342 | "ResourceIdentifier": { 343 | "BucketName": "caixeta-genai-demo-disagnostics" 344 | } 345 | }, 346 | { 347 | "ResourceType": "AWS::S3::Bucket", 348 | "LogicalResourceId": "S3Bucket00caixetagenaidemodisagnosticsmetadata00hRcfJ", 349 | "ResourceIdentifier": { 350 | "BucketName": "caixeta-genai-demo-disagnostics-metadata" 351 | } 352 | } 353 | ] 354 | } -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "automate-discharge-instructions", 3 | "version": "0.1.0", 4 | "bin": { 5 | "automate-discharge-instructions": "bin/automate-discharge-instructions.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "dependencies": { 14 | "@aws-sdk/client-dynamodb": "^3.518.0", 15 | "@aws-sdk/lib-dynamodb": "^3.518.0", 16 | "esbuild": "^0.20.1", 17 | "eslint": "^8.56.0", 18 | "eslint-config-prettier": "^9.1.0", 19 | "eslint-plugin-eslint-comments": "^3.2.0", 20 | "eslint-plugin-import": "^2.29.1", 21 | "eslint-plugin-unused-imports": "^3.1.0", 22 | "prettier": "^3.2.5", 23 | "upsert-slr": "^1.0.3" 24 | }, 25 | "devDependencies": { 26 | "@types/aws-lambda": "^8.10.134", 27 | "@types/jest": "^29.5.12", 28 | "@types/node": "20.11.16", 29 | "aws-cdk": "2.127.0", 30 | "aws-cdk-lib": "2.127.0", 31 | "bedrock-agents-cdk": "^0.0.9", 32 | "constructs": "^10.3.0", 33 | "jest": "^29.7.0", 34 | "source-map-support": "^0.5.21", 35 | "ts-jest": "^29.1.2", 36 | "ts-node": "^10.9.2", 37 | "typescript": "~5.3.3" 38 | }, 39 | "prettier": { 40 | "singleQuote": true, 41 | "printWidth": 200 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/sampledocs/acne: -------------------------------------------------------------------------------- 1 | Acne 2 | 3 |
4 | Acne is a medical condition that occurs when pores on the surface of the skin become plugged. A pore is an opening of a hair follicle (root) and an oil gland. Pores get blocked when the glands make too much oil. Dirt collects, which causes bacteria to grow in the glands. The skin swells and forms painful bumps, commonly called pimples. 5 |
6 | 7 | 8 | Topical medicine: These medicines include gels, ointments, creams, pastes, or liquid solutions that are put on your skin. They help decrease swelling and skin shedding. 9 | Hormone medicine: These medicines help control the production of oil from the oil glands. Birth control pills are an example of hormone medicine. 10 | Acne medicine: These are vitamin-based medicines, which are most useful in treating severe acne. These medicines may have serious side effects. You must not get pregnant or breastfeed while you are using this medicine. 11 | Steroids: This medicine may be given to decrease inflammation. 12 | Take your medicine as directed: Call your primary healthcare provider if you think your medicine is not working as expected. Tell him if you are allergic to any medicine. Keep a current list of the medicines, vitamins, and herbs you take. Include the amounts, and when, how, and why you take them. Take the list or the pill bottles to follow-up visits. Carry your medicine list with you in case of an emergency. Throw away old medicine lists. 13 | Follow up with your primary healthcare provider or dermatologist as directed: 14 | Write down your questions so you remember to ask them during your visits. 15 | 16 | 17 | 18 |

Skin care:

19 | Be gentle when you wash: Do not rub or scrub your skin with a washcloth. Do not use hot water. Gently pat your skin dry with a clean towel or cloth. 20 | Be careful with the medicines you are taking: Certain medicines, including natural and herbal medicines, may trigger an acne flare-up. Always check for skin changes when you take your medicines. Ask your primary healthcare provider before you use herbal medicines or products to control acne. 21 | Do not squeeze, pop, or pick your pimples: This may damage your skin and cause infection or scarring. 22 | Protect your skin from the sun: Wear sunscreen that has a sun protectant factor (SPF) approved by your primary healthcare provider. Follow the directions on the label when you use sunscreen. 23 | Use water-based, oil-free makeup, soaps, or skin cleansers: Oil-based makeup may make acne worse. Check product labels on water-based makeup, since even these may have some added oil. Use mild soaps or cleansers that are oil-free and do not irritate acne. 24 | Treatment options 25 | The following list of medications are in some way related to or used in the treatment of this condition. 26 | 27 | - Accutane 28 | - Doxycycline 29 | - Spironolactone 30 | - Aldactone 31 | - Retin-A 32 |
33 | 34 | 35 |

Contact your primary healthcare provider dermatologist if:

36 | - Your acne is not getting better or gets worse after treatment. 37 | - You think you are pregnant and need to make sure it is safe to take your acne medicine. 38 | - You have questions about your condition or care. 39 | 40 |

Seek care immediately or call 911 if:

41 | - The fluid that comes out of your acne has a bad smell. 42 | - You have chest pain, or new or worsening heartburn. 43 | - You get a severe headache, blurred vision, or feel faint or dizzy. 44 | - You begin to throw up or you have a seizure. 45 | - You develop hives, a swollen face or mouth, or you have trouble breathing all of a sudden. 46 | - You have severe stomach, bowel, or pelvic pain, trouble swallowing, or painful swallowing. 47 | - You have diarrhea that contains blood. 48 | - Your skin or the whites of your eyes turn yellow. 49 | - You have new muscle weakness, or joint or back pain. 50 | - The above information is an educational aid only. It is not intended as medical advice for individual conditions or treatments. Talk to your doctor, nurse or pharmacist before following any medical regimen to see if it is safe and effective for you. 51 |
52 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/sampledocs/dermatitis: -------------------------------------------------------------------------------- 1 | Dermatitis 2 | 3 | 4 |
5 | Dermatitis is skin inflammation. Dermatitis may be caused by allergens such as dust mites, pet dander, pollen, and certain foods. Dermatitis can also develop when something touches your skin and irritates it or causes an allergic reaction. Examples include soaps, chemicals, latex, and poison ivy. 6 |
7 | 8 | 9 | 10 | 11 | 12 |

Care options:

13 | - Apply a cool compress to your rash. This will help soothe your skin. 14 | - Apply lotions or creams to the area. These help keep your skin moist and decrease itching. Apply the lotion or cream right after a lukewarm bath or shower when your skin is still damp. Use products that do not contain dye or a scent. 15 | - Avoid skin irritants. Examples include makeup, hair products, soaps, and cleansers. Use products that do not contain a scent or dye. 16 | 17 |

Treatment options:

18 | The following list of medications are in some way related to or used in the treatment of this condition. 19 | 20 | triamcinolone 21 | Kenalog 22 | Clobex 23 | Elocon 24 | Cutivate 25 |
26 | 27 | 28 |

Contact your primary healthcare provider dermatologist if:

29 | - Your skin blisters, oozes white or yellow pus, or has a foul-smelling discharge. 30 | - Your rash spreads or does not get better, even after treatment. 31 | - You have questions or concerns about your condition or care. 32 | 33 |

Seek immediate care if:

34 | - You develop a fever or have red streaks going up your arm or leg. 35 | - Your rash gets more swollen, red, or hot. 36 | 37 |

Call your local emergency number (911 in the US) or have someone call if:

38 | - You have symptoms of anaphylaxis, such as sudden trouble breathing, throat swelling, or feeling dizzy or lightheaded. 39 |
40 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-1.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-2.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-3.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-4.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-5.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-6.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-7.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image-8.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/screenshots/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-bedrock-industry-use-cases/f75fd327c8d0bf47f696b8dc263d2f30c27669d0/healthcare-life-sciences/automate-discharge-instructions/screenshots/image.png -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/src/get-patient/index.ts: -------------------------------------------------------------------------------- 1 | import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; 2 | import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb'; 3 | import { Context } from 'aws-lambda'; 4 | import { AmazonBedrockActionGroupInput } from '../types/bedrock-action-group-input'; 5 | import { AmazonBedrockActionGroupOutput } from '../types/bedrock-action-group-output'; 6 | 7 | export const main = async (event: AmazonBedrockActionGroupInput, context: Context): Promise => { 8 | return await new GetPatient().handler(event, context); 9 | }; 10 | 11 | export class GetPatient { 12 | private docClient: DynamoDBDocumentClient; 13 | 14 | constructor() { 15 | const client = new DynamoDBClient({}); 16 | this.docClient = DynamoDBDocumentClient.from(client); 17 | } 18 | 19 | public async handler(event: AmazonBedrockActionGroupInput, _context: Context) { 20 | const command = new GetCommand({ 21 | TableName: process.env['TABLE_NAME'], 22 | Key: { 23 | id: event.parameters?.[0]?.value ?? '', 24 | }, 25 | }); 26 | const response = await this.docClient.send(command); 27 | 28 | const actionResponse = { 29 | actionGroup: event.actionGroup, 30 | apiPath: event.apiPath, 31 | httpMethod: event.httpMethod, 32 | httpStatusCode: 200, 33 | responseBody: { 34 | 'application/json': { 35 | body: JSON.stringify(response?.Item ?? {}), 36 | }, 37 | }, 38 | sessionAttributes: event.sessionAttributes, 39 | promptSessionAttributes: event.promptSessionAttributes, 40 | }; 41 | 42 | const apiResponse: AmazonBedrockActionGroupOutput = { 43 | messageVersion: '1.0', 44 | response: actionResponse, 45 | }; 46 | 47 | return apiResponse; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/src/types/bedrock-action-group-input.ts: -------------------------------------------------------------------------------- 1 | export interface AmazonBedrockActionGroupInput { 2 | messageVersion: '1.0'; 3 | agent: { 4 | name: string; 5 | id: string; 6 | alias: string; 7 | version: string; 8 | }; 9 | inputText: string; 10 | sessionId: string; 11 | actionGroup: string; 12 | apiPath: string; 13 | httpMethod: string; 14 | parameters: { 15 | name: string; 16 | type: string; 17 | value: string; 18 | }[]; 19 | requestBody: { 20 | content: { 21 | [contentType: string]: { 22 | properties: { 23 | name: string; 24 | type: string; 25 | value: string; 26 | }[]; 27 | }; 28 | }; 29 | }; 30 | sessionAttributes: { 31 | [key: string]: string; 32 | }; 33 | promptSessionAttributes: { 34 | [key: string]: string; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/src/types/bedrock-action-group-output.ts: -------------------------------------------------------------------------------- 1 | export interface AmazonBedrockActionGroupOutput { 2 | messageVersion: '1.0'; 3 | response: { 4 | actionGroup: string; 5 | apiPath: string; 6 | httpMethod: string; 7 | httpStatusCode: number; 8 | responseBody: { 9 | [contentType: string]: { 10 | body: string; 11 | }; 12 | }; 13 | sessionAttributes?: { 14 | [key: string]: string; 15 | }; 16 | promptSessionAttributes?: { 17 | [key: string]: string; 18 | }; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /healthcare-life-sciences/automate-discharge-instructions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /travel-hospitality/README.md: -------------------------------------------------------------------------------- 1 | # Travel & Hospitality 2 | 3 | Agents the delivery of generative AI applications that can manage and perform tasks by making API calls to your company systems. Agents extend FMs to understand user requests, break down complex tasks into multiple steps, carry on a conversation to collect additional information, and take actions to fulfill the request. 4 | 5 | This section of the repository contains *Travel & Hospitality* use-cases to get you started with Amazon Bedrock Agents. 6 | 7 | ## Contents 8 | 9 | - [Travel Planner](travel-planner) - An agent designed to help with finding the best flights, hotels, and plan vacations 10 | 11 | 12 | ## Contributing 13 | 14 | We welcome community contributions! Please ensure your sample aligns with AWS [best practices](https://aws.amazon.com/architecture/well-architected/), and please update the **Contents** section of this README file with a link to your sample, along with a description. 15 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/README.md: -------------------------------------------------------------------------------- 1 | # Travel Planner 2 | ================ 3 | 4 | ## Authors: 5 | - [Armando Diaz](https://www.linkedin.com/in/armando-diaz-47a498113/) @armdiazg 6 | - [Marco Punio](https://www.linkedin.com/in/marcpunio/) @puniomp 7 | 8 | This guide details how to install, configure, and use the agent CDK deployment. The instructions assume that the deployment will be deployed from a terminal running from Linux or MacOS. 9 | 10 | Resources provisioned by deployment: 11 | 12 | * S3 bucket 13 | * Bedrock Agent 14 | * Bedrock Agent IAM role 15 | * Bedrock Agent Action Group 16 | * Lambda function 17 | * Lambda service-policy permission 18 | * Lambda IAM role 19 | 20 | The tutorial deploys Bedrock agent backed by Anthropic Clause V2 model and creates an Action Group within this agent with the schema located in ``lib/assets/api-schema`` and Python function located in ``lib/assets/lambda``. To do that, the demo also creates an S3 bucket and uploads schema to it. IAM roles are provisioned by CDK. Make sure to modify the policies appropriate for your needs. 21 | 22 | # Prerequisites 23 | =============== 24 | 25 | * [SerpApi API Key](https://serpapi.com/) 26 | 1) Go to https://serpapi.com/dashboard 27 | 2) Sign in to your Serp API account or create one if you don't have it. 28 | 3) In your dashboard, generate an API key. This key will be essential for accessing the Serp API services and stack deployment. 29 | * [node](https://nodejs.org/en) >= 16.0.0 30 | * [npm](https://www.npmjs.com/) >= 8.0.0 31 | * [AWS CLI](https://aws.amazon.com/cli/) >= 2.0.0 32 | * [AWS CDK](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html) >= 2.130.0 33 | * [Docker](https://www.docker.com/): 34 | - Install [Docker](https://docs.docker.com/desktop/) or 35 | - Create an [AWS Cloud9](https://docs.aws.amazon.com/cloud9/latest/user-guide/create-environment-main.html) environment 36 | 37 | *Note: In some cases, you might need to authenticate Docker to Amazon ECR registry with get-login-password. Run the aws ecr [get-login-password](https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-cli.html) command. `aws ecr get-login-password --region region | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com`* 38 | 39 | # How to run 40 | 41 | From within the root project folder (``travel-planner``), run the following commands: 42 | 43 | ```sh 44 | npm install 45 | ``` 46 | Note - if you have `npm ERR!` erros related to overlapping dependencies, run `npm install --force`. 47 | ```sh 48 | cdk bootstrap 49 | ``` 50 | 51 | Substitute "my-api-key" with your SerpApi Api Key: 52 | ```sh 53 | cdk deploy -c apiKey="my-api-key" 54 | ``` 55 | 56 | Optional - if you want to change the [default settings](lib/constants.ts) you can deploy the stack like this (substituting "my-agent-name", "my-api-key", "my-agent-instruction", "my-agent-model", or "my-agent-description" with your desired values): 57 | 58 | ```sh 59 | cdk deploy -c agentName="my-agent-name" -c apiKey="my-api-key" -c agentInstruction="my-agent-instruction" -c agentModel="my-agent-model" -c agentDescription="my-agent-description" 60 | ``` 61 | 62 | # Sample prompts: 63 | 64 | + *What is the cheapest flight from Atlanta to Miami in October, 2024?* 65 | + *Can you find me a hotel under $150/night in San Francisco from December 4th to December 15th, 2024?* 66 | 67 | # Automatic OpenAPI generator with Powertools for AWS Lambda (Python): 68 | 69 | The [OpenAPI schema](https://docs.aws.amazon.com/bedrock/latest/userguide/agents-api-schema.html) defines a group of APIs that the agent can invoke. You can create your own OpenAPI schema following our [example](lib/assets//api-schema/create_openapi_schema.py), which autogenerates an OpenAPI schema in JSON using [Powertools for AWS Lambda](https://github.com/aws-powertools/powertools-lambda-python). 70 | 71 | # How to delete 72 | 73 | From within the root project folder (``travel-planner``), run the following command: 74 | 75 | ```sh 76 | cdk destroy --force 77 | ``` 78 | 79 | **Note - if you created any aliases/versions within your agent you would have to manually delete it in the console.** 80 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/bin/bedrock-agent-cdk.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import 'source-map-support/register'; 3 | import * as path from 'path'; 4 | import * as glob from 'glob'; 5 | import * as cdk from 'aws-cdk-lib'; 6 | import { BedrockAgentCdkStack } from '../lib/bedrock-agent-cdk-stack'; 7 | 8 | const app = new cdk.App(); 9 | 10 | // Get the spec file found in lambda dir 11 | const specDir = 'lib/assets/api-schema'; 12 | const jsonOrYmlFile = glob.sync('**/*', { cwd: specDir }); 13 | const specFilePath = jsonOrYmlFile[0]; 14 | const specFile = path.basename(specFilePath) 15 | 16 | // Get the .py file found in lambda dir 17 | const lambdaDir = 'lib/assets/lambda'; 18 | const pyFile = glob.sync('**/*.py', { cwd: lambdaDir }); 19 | const lambdaFilePath = pyFile[0]; 20 | const lambdaFile = path.basename(lambdaFilePath.replace(/\.py$/, '')) 21 | 22 | const appStack = new BedrockAgentCdkStack(app, `BedrockAgentCDKStack`, { 23 | specFile: specFile, 24 | lambdaFile: lambdaFile, 25 | }); -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/bedrock-agent-cdk.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 38 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 39 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 40 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 41 | "@aws-cdk/aws-route53-patters:useCertificate": true, 42 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 43 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 44 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 45 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 46 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 47 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 48 | "@aws-cdk/aws-redshift:columnId": true, 49 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 50 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 51 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 52 | "@aws-cdk/aws-kms:aliasNameRef": true, 53 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 54 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 55 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 56 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 57 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 58 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 59 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 60 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 61 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 62 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, 63 | "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, 64 | "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/assets/api-schema/create_openapi_schema.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from typing import List 4 | from typing_extensions import Annotated 5 | 6 | from serpapi import GoogleSearch 7 | from aws_lambda_powertools import Logger, Tracer 8 | from aws_lambda_powertools.event_handler.openapi.params import Query 9 | from aws_lambda_powertools.event_handler import BedrockAgentResolver 10 | from aws_lambda_powertools.utilities.typing import LambdaContext 11 | 12 | API_KEY = os.environ.get('API_KEY') 13 | 14 | tracer = Tracer() 15 | logger = Logger() 16 | app = BedrockAgentResolver() 17 | 18 | 19 | @app.get("/get_flights", description="Gets best flight results from Google Flights") 20 | @tracer.capture_method 21 | def get_flights( 22 | departure_id: Annotated[str, Query(description="Parameter defines the departure airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport.")], 23 | arrival_id: Annotated[str, Query(description="Parameter defines the arrival airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport.")], 24 | outbound_date: Annotated[str, Query(description="Parameter defines the outbound date. The format is YYYY-MM-DD. e.g. 2024-02-08")], 25 | return_date: Annotated[str, Query(description="Parameter defines the return date. The format is YYYY-MM-DD. e.g. 2024-02-08")], 26 | ) -> List[dict]: 27 | 28 | params = { 29 | "engine": "google_flights", 30 | "departure_id": departure_id, 31 | "arrival_id": arrival_id, 32 | "outbound_date": outbound_date, 33 | "return_date": return_date, 34 | "currency": "USD", 35 | "hl": "en", 36 | "api_key": API_KEY 37 | } 38 | 39 | search = GoogleSearch(params) 40 | results = search.get_dict() 41 | 42 | if results.get('error'): 43 | output = results['error'] + "Ask the user for more information related to the context received about the function." 44 | elif results.get("best_flights"): 45 | output = results.get("best_flights") 46 | elif results.get("other_flights"): 47 | output = results.get("other_flights") 48 | else: 49 | output = results + "Unknown Error." 50 | return output 51 | 52 | 53 | @app.get("/get_hotels", description="Gets hotels properties from Google Hotels") 54 | @tracer.capture_method 55 | def get_hotels( 56 | q: Annotated[str, Query(description="Parameter defines the location. e.g. Bali Resorts")], 57 | check_in_date: Annotated[str, Query(description="Parameter defines the check-in date. The format is YYYY-MM-DD. e.g. 2024-02-10")], 58 | check_out_date: Annotated[str, Query(description="Parameter defines the check-out date. The format is YYYY-MM-DD. e.g. 2024-02-10")], 59 | adults: Annotated[str, Query(description="Parameter defines the number of adults")] = "", 60 | country_search: Annotated[str, Query(description="Parameter defines the country to use for the Google Hotels search. It's a two-letter country code. (e.g., us for the United States, uk for United Kingdom, or fr for France) Head to the Google countries page for a full list of supported Google countries.")] = "us" 61 | ) -> List[dict]: 62 | 63 | params = { 64 | "engine": "google_hotels", 65 | "q": q, 66 | "check_in_date": check_in_date, 67 | "check_out_date": check_out_date, 68 | "adults": adults, 69 | "currency": "USD", 70 | "gl": country_search.lower(), 71 | "hl": "en", 72 | "api_key": API_KEY 73 | } 74 | 75 | logger.info(f'params: {params}') 76 | search = GoogleSearch(params) 77 | results = search.get_dict() 78 | logger.info(f'all results: {results}') 79 | if results.get('error'): 80 | output = results['error'] + "Ask the user for more information related to the context received about the function." 81 | elif results.get("properties"): 82 | output = results.get("properties")[0:2] if len(results) > 2 else results.get("properties") 83 | else: 84 | output = results + "Unknown Error." 85 | 86 | logger.info(f'results: {output}') 87 | return output 88 | 89 | 90 | @logger.inject_lambda_context 91 | @tracer.capture_lambda_handler 92 | def lambda_handler(event: dict, context: LambdaContext): 93 | return app.resolve(event, context) 94 | 95 | 96 | if __name__ == "__main__": 97 | # This displays the autogenerated openapi schema by aws_lambda_powertools 98 | print( 99 | app.get_openapi_json_schema( 100 | title="Travel Planner Bot API", 101 | version="1.0.0", 102 | description="Travel Planner API for searching the best flight and hotel deals", 103 | tags=["travel", "flights", "hotels"], 104 | ), 105 | ) -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/assets/api-schema/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Travel Planner Bot API", 5 | "description": "Travel Planner API for searching the best flight and hotel deals", 6 | "version": "1.0.0" 7 | }, 8 | "servers": [ 9 | { 10 | "url": "/" 11 | } 12 | ], 13 | "paths": { 14 | "/get_flights": { 15 | "get": { 16 | "summary": "GET /get_flights", 17 | "description": "Gets best flight results from Google Flights", 18 | "operationId": "get_flights_get_flights_get", 19 | "parameters": [ 20 | { 21 | "description": "Parameter defines the departure airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport.", 22 | "required": true, 23 | "schema": { 24 | "type": "string", 25 | "title": "Departure Id", 26 | "description": "Parameter defines the departure airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport." 27 | }, 28 | "name": "departure_id", 29 | "in": "query" 30 | }, 31 | { 32 | "description": "Parameter defines the arrival airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport.", 33 | "required": true, 34 | "schema": { 35 | "type": "string", 36 | "title": "Arrival Id", 37 | "description": "Parameter defines the arrival airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport." 38 | }, 39 | "name": "arrival_id", 40 | "in": "query" 41 | }, 42 | { 43 | "description": "Parameter defines the outbound date. The format is YYYY-MM-DD. e.g. 2024-02-08", 44 | "required": true, 45 | "schema": { 46 | "type": "string", 47 | "title": "Outbound Date", 48 | "description": "Parameter defines the outbound date. The format is YYYY-MM-DD. e.g. 2024-02-08" 49 | }, 50 | "name": "outbound_date", 51 | "in": "query" 52 | }, 53 | { 54 | "description": "Parameter defines the return date. The format is YYYY-MM-DD. e.g. 2024-02-08", 55 | "required": true, 56 | "schema": { 57 | "type": "string", 58 | "title": "Return Date", 59 | "description": "Parameter defines the return date. The format is YYYY-MM-DD. e.g. 2024-02-08" 60 | }, 61 | "name": "return_date", 62 | "in": "query" 63 | } 64 | ], 65 | "responses": { 66 | "200": { 67 | "description": "Successful Response", 68 | "content": { 69 | "application/json": { 70 | "schema": { 71 | "items": { 72 | "type": "object" 73 | }, 74 | "type": "array", 75 | "title": "Return" 76 | } 77 | } 78 | } 79 | }, 80 | "422": { 81 | "description": "Validation Error", 82 | "content": { 83 | "application/json": { 84 | "schema": { 85 | "$ref": "#/components/schemas/HTTPValidationError" 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | }, 93 | "/get_hotels": { 94 | "get": { 95 | "summary": "GET /get_hotels", 96 | "description": "Gets hotels properties from Google Hotels", 97 | "operationId": "get_hotels_get_hotels_get", 98 | "parameters": [ 99 | { 100 | "description": "Parameter defines the location. e.g. Bali Resorts", 101 | "required": true, 102 | "schema": { 103 | "type": "string", 104 | "title": "Q", 105 | "description": "Parameter defines the location. e.g. Bali Resorts" 106 | }, 107 | "name": "q", 108 | "in": "query" 109 | }, 110 | { 111 | "description": "Parameter defines the check-in date. The format is YYYY-MM-DD. e.g. 2024-02-10", 112 | "required": true, 113 | "schema": { 114 | "type": "string", 115 | "title": "Check In Date", 116 | "description": "Parameter defines the check-in date. The format is YYYY-MM-DD. e.g. 2024-02-10" 117 | }, 118 | "name": "check_in_date", 119 | "in": "query" 120 | }, 121 | { 122 | "description": "Parameter defines the check-out date. The format is YYYY-MM-DD. e.g. 2024-02-10", 123 | "required": true, 124 | "schema": { 125 | "type": "string", 126 | "title": "Check Out Date", 127 | "description": "Parameter defines the check-out date. The format is YYYY-MM-DD. e.g. 2024-02-10" 128 | }, 129 | "name": "check_out_date", 130 | "in": "query" 131 | }, 132 | { 133 | "description": "Parameter defines the number of adults", 134 | "required": false, 135 | "schema": { 136 | "type": "string", 137 | "title": "Adults", 138 | "description": "Parameter defines the number of adults", 139 | "default": "" 140 | }, 141 | "name": "adults", 142 | "in": "query" 143 | }, 144 | { 145 | "description": "Parameter defines the country to use for the Google Hotels search. It's a two-letter country code. (e.g., us for the United States, uk for United Kingdom, or fr for France) Head to the Google countries page for a full list of supported Google countries.", 146 | "required": false, 147 | "schema": { 148 | "type": "string", 149 | "title": "Country Search", 150 | "description": "Parameter defines the country to use for the Google Hotels search. It's a two-letter country code. (e.g., us for the United States, uk for United Kingdom, or fr for France) Head to the Google countries page for a full list of supported Google countries.", 151 | "default": "us" 152 | }, 153 | "name": "country_search", 154 | "in": "query" 155 | } 156 | ], 157 | "responses": { 158 | "200": { 159 | "description": "Successful Response", 160 | "content": { 161 | "application/json": { 162 | "schema": { 163 | "items": { 164 | "type": "object" 165 | }, 166 | "type": "array", 167 | "title": "Return" 168 | } 169 | } 170 | } 171 | }, 172 | "422": { 173 | "description": "Validation Error", 174 | "content": { 175 | "application/json": { 176 | "schema": { 177 | "$ref": "#/components/schemas/HTTPValidationError" 178 | } 179 | } 180 | } 181 | } 182 | } 183 | } 184 | } 185 | }, 186 | "components": { 187 | "schemas": { 188 | "HTTPValidationError": { 189 | "properties": { 190 | "detail": { 191 | "items": { 192 | "$ref": "#/components/schemas/ValidationError" 193 | }, 194 | "type": "array", 195 | "title": "Detail" 196 | } 197 | }, 198 | "type": "object", 199 | "title": "HTTPValidationError" 200 | }, 201 | "ValidationError": { 202 | "properties": { 203 | "loc": { 204 | "items": { 205 | "anyOf": [ 206 | { 207 | "type": "string" 208 | }, 209 | { 210 | "type": "integer" 211 | } 212 | ] 213 | }, 214 | "type": "array", 215 | "title": "Location" 216 | }, 217 | "msg": { 218 | "type": "string", 219 | "title": "Message" 220 | }, 221 | "type": { 222 | "type": "string", 223 | "title": "Error Type" 224 | } 225 | }, 226 | "type": "object", 227 | "required": [ 228 | "loc", 229 | "msg", 230 | "type" 231 | ], 232 | "title": "ValidationError" 233 | } 234 | } 235 | }, 236 | "tags": [ 237 | { 238 | "name": "travel" 239 | }, 240 | { 241 | "name": "flights" 242 | }, 243 | { 244 | "name": "hotels" 245 | } 246 | ] 247 | } -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/assets/lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.9.2024.03.04.10-x86_64 2 | 3 | # Installs python, removes cache file to make things smaller 4 | RUN yum update -y && \ 5 | yum install -y python3 python3-dev python3-pip gcc && \ 6 | rm -Rf /var/cache/yum 7 | 8 | # Copies requirements.txt file into the container 9 | COPY requirements.txt ./ 10 | # Installs dependencies found in your requirements.txt file 11 | RUN pip install -r requirements.txt 12 | 13 | # Be sure to copy over the function itself! 14 | # Goes last to take advantage of Docker caching. 15 | COPY agent.py ./ 16 | 17 | # Points to the handler function of your lambda function 18 | CMD ["agent.lambda_handler"] -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/assets/lambda/agent.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from typing import List 4 | from typing_extensions import Annotated 5 | 6 | from serpapi import GoogleSearch 7 | from aws_lambda_powertools import Logger, Tracer 8 | from aws_lambda_powertools.event_handler.openapi.params import Query 9 | from aws_lambda_powertools.event_handler import BedrockAgentResolver 10 | from aws_lambda_powertools.utilities.typing import LambdaContext 11 | 12 | API_KEY = os.environ.get('API_KEY') 13 | 14 | tracer = Tracer() 15 | logger = Logger() 16 | app = BedrockAgentResolver() 17 | 18 | 19 | @app.get("/get_flights", description="Gets best flight results from Google Flights") 20 | @tracer.capture_method 21 | def get_flights( 22 | departure_id: Annotated[str, Query(description="Parameter defines the departure airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport.")], 23 | arrival_id: Annotated[str, Query(description="Parameter defines the arrival airport code or location kgmid. An airport code is an uppercase 3-letter code. For example, CDG is Paris Charles de Gaulle Airport and AUS is Austin-Bergstrom International Airport.")], 24 | outbound_date: Annotated[str, Query(description="Parameter defines the outbound date. The format is YYYY-MM-DD. e.g. 2024-02-08")], 25 | return_date: Annotated[str, Query(description="Parameter defines the return date. The format is YYYY-MM-DD. e.g. 2024-02-08")], 26 | ) -> List[dict]: 27 | 28 | params = { 29 | "engine": "google_flights", 30 | "departure_id": departure_id, 31 | "arrival_id": arrival_id, 32 | "outbound_date": outbound_date, 33 | "return_date": return_date, 34 | "currency": "USD", 35 | "hl": "en", 36 | "api_key": API_KEY 37 | } 38 | 39 | logger.info(f"params: {params}") 40 | 41 | search = GoogleSearch(params) 42 | results = search.get_dict() 43 | 44 | logger.info(f"response: {results}") 45 | 46 | if results.get('error'): 47 | output = results['error'] + "Ask the user for more information related to the context received about the function." 48 | elif results.get("best_flights"): 49 | output = results.get("best_flights") 50 | elif results.get("other_flights"): 51 | output = results.get("other_flights") 52 | else: 53 | output = results + "Unknown Error." 54 | return output 55 | 56 | 57 | @app.get("/get_hotels", description="Gets hotels properties from Google Hotels") 58 | @tracer.capture_method 59 | def get_hotels( 60 | q: Annotated[str, Query(description="Parameter defines the location. e.g. Bali Resorts")], 61 | check_in_date: Annotated[str, Query(description="Parameter defines the check-in date. The format is YYYY-MM-DD. e.g. 2024-02-10")], 62 | check_out_date: Annotated[str, Query(description="Parameter defines the check-out date. The format is YYYY-MM-DD. e.g. 2024-02-10")], 63 | adults: Annotated[str, Query(description="Parameter defines the number of adults")] = "", 64 | country_search: Annotated[str, Query(description="Parameter defines the country to use for the Google Hotels search. It's a two-letter country code. (e.g., us for the United States, uk for United Kingdom, or fr for France) Head to the Google countries page for a full list of supported Google countries.")] = "us" 65 | ) -> List[dict]: 66 | 67 | params = { 68 | "engine": "google_hotels", 69 | "q": q, 70 | "check_in_date": check_in_date, 71 | "check_out_date": check_out_date, 72 | "adults": adults, 73 | "currency": "USD", 74 | "gl": country_search.lower(), 75 | "hl": "en", 76 | "api_key": API_KEY 77 | } 78 | 79 | logger.info(f"params: {params}") 80 | 81 | search = GoogleSearch(params) 82 | results = search.get_dict() 83 | 84 | logger.info(f'response: {results}') 85 | 86 | if results.get('error'): 87 | output = results['error'] + "Ask the user for more information related to the context received about the function." 88 | elif results.get("properties"): 89 | output = results.get("properties")[0:2] if len(results) > 2 else results.get("properties") 90 | else: 91 | output = results + "Unknown Error." 92 | 93 | logger.info(f'results: {output}') 94 | return output 95 | 96 | 97 | @logger.inject_lambda_context 98 | @tracer.capture_lambda_handler 99 | def lambda_handler(event: dict, context: LambdaContext): 100 | return app.resolve(event, context) 101 | 102 | 103 | if __name__ == "__main__": 104 | # This displays the autogenerated openapi schema by aws_lambda_powertools 105 | print( 106 | app.get_openapi_json_schema( 107 | title="Travel Planner Bot API", 108 | version="1.0.0", 109 | description="Travel Planner API for searching the best flight and hotel deals", 110 | tags=["travel", "flights", "hotels"], 111 | ), 112 | ) -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/assets/lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | aws-lambda-powertools==2.37.0 2 | boto3==1.34.105 3 | google-search-results 4 | pydantic==1.10.15 5 | aws-xray-sdk==2.13.0 6 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/bedrock-agent-cdk-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import { Construct } from 'constructs'; 3 | import { S3Construct } from './constructs/s3-bucket-construct'; 4 | import { BedrockIamConstruct } from './constructs/bedrock-agent-iam-construct'; 5 | import { LambdaIamConstruct } from './constructs/lambda-iam-construct'; 6 | import { LambdaConstruct } from './constructs/lambda-construct'; 7 | import { BedrockAgentConstruct } from './constructs/bedrock-agent-construct'; 8 | 9 | import { AGENT_NAME, API_KEY, AGENT_INSTRUCTION, AGENT_MODEL, AGENT_DESCRIPTION } from './constants'; 10 | 11 | export interface BedrockAgentCdkProps extends cdk.StackProps { 12 | readonly specFile: string; 13 | readonly lambdaFile: string; 14 | } 15 | 16 | export class BedrockAgentCdkStack extends cdk.Stack { 17 | constructor(scope: Construct, id: string, props: BedrockAgentCdkProps) { 18 | super(scope, id, props); 19 | 20 | // Generate random number to avoid roles and lambda duplicates 21 | const randomPrefix = Math.floor(Math.random() * (10000 - 100) + 100); 22 | const apiKey = this.node.tryGetContext("apiKey") || API_KEY; 23 | const agentInstruction = this.node.tryGetContext("agentInstruction") || AGENT_INSTRUCTION; 24 | const agentName = this.node.tryGetContext("agentName") || AGENT_NAME; 25 | const agentModel = this.node.tryGetContext("agentModel") || AGENT_MODEL; 26 | const agentDescription = this.node.tryGetContext("apiKey") || AGENT_DESCRIPTION; 27 | const lambdaName = `bedrock-agent-lambda-${randomPrefix}`; 28 | const lambdaRoleName = `bedrock-agent-lambda-role-${randomPrefix}`; 29 | const agentResourceRoleName = `AmazonBedrockExecutionRoleForAgents_${randomPrefix}`; 30 | 31 | const lambdaRole = new LambdaIamConstruct(this, `LambdaIamConstruct-${randomPrefix}`, { roleName: lambdaRoleName }); 32 | const s3Construct = new S3Construct(this, `agent-assets-${randomPrefix}`, {}); 33 | const bedrockAgentRole = new BedrockIamConstruct(this, `BedrockIamConstruct-${randomPrefix}`, { 34 | roleName: agentResourceRoleName, 35 | lambdaRoleArn: lambdaRole.lambdaRole.roleArn, 36 | s3BucketArn: s3Construct.bucket.bucketArn, 37 | }); 38 | bedrockAgentRole.node.addDependency(lambdaRole); 39 | bedrockAgentRole.node.addDependency(s3Construct); 40 | const agentLambdaConstruct = new LambdaConstruct(this, `LambdaConstruct-${randomPrefix}`, { 41 | apiKey: apiKey, 42 | lambdaName: lambdaName, 43 | lambdaFile: props.lambdaFile, 44 | lambdaRoleName: lambdaRoleName, 45 | iamRole: lambdaRole.lambdaRole 46 | }); 47 | agentLambdaConstruct.node.addDependency(lambdaRole); 48 | 49 | const bedrockAgentConstruct = new BedrockAgentConstruct(this, `BedrockConstruct-${randomPrefix}`, { 50 | apiKey: apiKey, 51 | agentName: agentName, 52 | agentModel: agentModel, 53 | agentInstruction: agentInstruction, 54 | agentDescription: agentDescription, 55 | agentRoleArn: bedrockAgentRole.roleArn, 56 | lambdaArn: agentLambdaConstruct.lambdaArn, 57 | s3BucketName: s3Construct.bucketName 58 | }); 59 | bedrockAgentConstruct.node.addDependency(bedrockAgentRole); 60 | bedrockAgentConstruct.node.addDependency(s3Construct); 61 | bedrockAgentConstruct.node.addDependency(agentLambdaConstruct); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/constants.ts: -------------------------------------------------------------------------------- 1 | export const AGENT_NAME = 'travel-agent'; 2 | export const API_KEY = ''; 3 | export const AGENT_INSTRUCTION = ` 4 | You are a personal travel AI assistant that helps users search for flights, hotels, and plan vacations. 5 | The user is going to provide details on desired destinations, travel dates and preferences - ask clarifying questions if needed. 6 | Use this information to suggest optimal flights, accommodations, and provide a personalized travel itinerary. 7 | Work closely with the user to ensure your suggested itineraries and accommodations meet user's travel needs. 8 | If you do not have an answer, ask follow up questions. Make sure you have the dates and all details to assist the user.`; 9 | export const AGENT_MODEL = `anthropic.claude-3-haiku-20240307-v1:0`; 10 | export const AGENT_DESCRIPTION = ` 11 | This travel AI assistant searches for the best flight and hotel deals for your trips in seconds. 12 | `; -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/constructs/bedrock-agent-construct.ts: -------------------------------------------------------------------------------- 1 | import * as bedrockagents from 'bedrock-agents-cdk'; 2 | import * as cdk from 'aws-cdk-lib'; 3 | import { Construct } from "constructs"; 4 | 5 | export interface AutomateDischargeInstructionsStackProps extends cdk.StackProps {} 6 | 7 | export interface BedrockProps extends cdk.StackProps { 8 | readonly apiKey: string; 9 | readonly agentName: string; 10 | readonly agentInstruction: string; 11 | readonly agentDescription: string; 12 | readonly agentModel: string; 13 | readonly agentRoleArn: string; 14 | readonly lambdaArn: string; 15 | readonly s3BucketName: string; 16 | } 17 | 18 | const defaultProps: Partial = {}; 19 | 20 | export class BedrockAgentConstruct extends Construct { 21 | public agentName: string; 22 | 23 | constructor(scope: Construct, name: string, props: BedrockProps) { 24 | super(scope, name); 25 | 26 | props = { ...defaultProps, ...props }; 27 | 28 | const agent = new bedrockagents.BedrockAgent(this, props.agentName, { 29 | agentName: props.agentName, 30 | instruction: props.agentInstruction, 31 | description: props.agentDescription, 32 | foundationModel: props.agentModel, 33 | agentResourceRoleArn: props.agentRoleArn, 34 | actionGroups: [ 35 | { 36 | actionGroupName: 'travel-api', 37 | actionGroupExecutor: props.lambdaArn, 38 | s3BucketName: props.s3BucketName, 39 | s3ObjectKey: 'api-schema/schema.json', 40 | description: 'API to obtain flights and hotels from SerpAPI.', 41 | }, 42 | ], 43 | }); 44 | 45 | new cdk.CfnOutput(this, "BedrockAgentArn", { 46 | value: agent.agentArn, 47 | }); 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/constructs/bedrock-agent-iam-construct.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | 4 | export interface BedrockIamProps extends cdk.StackProps { 5 | readonly roleName: string; 6 | readonly lambdaRoleArn: string; 7 | readonly s3BucketArn: string; 8 | } 9 | 10 | const defaultProps: Partial = {}; 11 | 12 | export class BedrockIamConstruct extends Construct { 13 | public roleArn: string; 14 | 15 | constructor(scope: Construct, name: string, props: BedrockIamProps) { 16 | super(scope, name); 17 | 18 | props = { ...defaultProps, ...props }; 19 | 20 | const bedrockAgentRole = new cdk.aws_iam.Role(this, "BedrockAgentRole", { 21 | roleName: props.roleName, 22 | assumedBy: new cdk.aws_iam.ServicePrincipal('bedrock.amazonaws.com'), 23 | }); 24 | 25 | const bedrockAgentLambdaPolicy = new cdk.aws_iam.Policy(this, "BedrockAgentLambdaPolicy", { 26 | policyName: "BedrockAgentLambdaPolicy", 27 | statements: [ 28 | new cdk.aws_iam.PolicyStatement({ 29 | effect: cdk.aws_iam.Effect.ALLOW, 30 | resources: [props.lambdaRoleArn], 31 | actions: [ 32 | '*', 33 | ]}) 34 | ] 35 | }); 36 | 37 | const bedrockAgentS3BucketPolicy = new cdk.aws_iam.Policy(this, "BedrockAgentS3BucketPolicy", { 38 | policyName: "BedrockAgentS3BucketPolicy", 39 | statements: [ 40 | new cdk.aws_iam.PolicyStatement({ 41 | effect: cdk.aws_iam.Effect.ALLOW, 42 | resources: [props.s3BucketArn, `${props.s3BucketArn}/*`], 43 | actions: [ 44 | '*', 45 | ]}) 46 | ] 47 | }); 48 | 49 | const bedrockAgentBedrockModelPolicy = new cdk.aws_iam.Policy(this, "BedrockAgentBedrockModelPolicy", { 50 | policyName: "BedrockAgentBedrockModelPolicy", 51 | statements: [ 52 | new cdk.aws_iam.PolicyStatement({ 53 | effect: cdk.aws_iam.Effect.ALLOW, 54 | resources: ['*'], 55 | actions: [ 56 | 'bedrock:*', 57 | ]}) 58 | ] 59 | }); 60 | 61 | 62 | bedrockAgentBedrockModelPolicy.node.addDependency(bedrockAgentRole); 63 | bedrockAgentLambdaPolicy.node.addDependency(bedrockAgentRole); 64 | bedrockAgentS3BucketPolicy.node.addDependency(bedrockAgentRole); 65 | 66 | bedrockAgentRole.attachInlinePolicy(bedrockAgentLambdaPolicy); 67 | bedrockAgentRole.attachInlinePolicy(bedrockAgentS3BucketPolicy); 68 | bedrockAgentRole.attachInlinePolicy(bedrockAgentBedrockModelPolicy); 69 | 70 | new cdk.CfnOutput(this, "BedrockAgentRoleArn", { 71 | value: bedrockAgentRole.roleArn, 72 | }); 73 | 74 | this.roleArn = bedrockAgentRole.roleArn; 75 | } 76 | } -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/constructs/lambda-construct.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | 4 | export interface LambdaProps extends cdk.StackProps { 5 | readonly apiKey: string; 6 | readonly lambdaRoleName: string; 7 | readonly lambdaFile: string; 8 | readonly lambdaName: string; 9 | readonly iamRole: cdk.aws_iam.Role; 10 | } 11 | 12 | const defaultProps: Partial = {}; 13 | 14 | export class LambdaConstruct extends Construct { 15 | public lambdaArn: string; 16 | 17 | constructor(scope: Construct, name: string, props: LambdaProps) { 18 | super(scope, name); 19 | 20 | props = { ...defaultProps, ...props }; 21 | 22 | const bedrockAgentLambda = new cdk.aws_lambda.DockerImageFunction(this, "BedrockAgentLambda", { 23 | code: cdk.aws_lambda.DockerImageCode.fromImageAsset('lib/assets/lambda'), 24 | timeout: cdk.Duration.seconds(300), 25 | role: props.iamRole, 26 | environment: { 27 | API_KEY: props.apiKey 28 | }, 29 | } 30 | ); 31 | 32 | bedrockAgentLambda.grantInvoke(new cdk.aws_iam.ServicePrincipal("bedrock.amazonaws.com")); 33 | 34 | new cdk.CfnOutput(this, "BedrockAgentLambdaArn", { 35 | value: bedrockAgentLambda.functionArn, 36 | }); 37 | 38 | this.lambdaArn = bedrockAgentLambda.functionArn; 39 | } 40 | } -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/constructs/lambda-iam-construct.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | 4 | export interface LambdaIamProps extends cdk.StackProps { 5 | readonly roleName: string; 6 | } 7 | 8 | const defaultProps: Partial = {}; 9 | 10 | export class LambdaIamConstruct extends Construct { 11 | public lambdaRole: cdk.aws_iam.Role; 12 | 13 | constructor(scope: Construct, name: string, props: LambdaIamProps) { 14 | super(scope, name); 15 | 16 | props = { ...defaultProps, ...props }; 17 | 18 | const lambdaRole = new cdk.aws_iam.Role(this, "LambdaRole", { 19 | roleName: props.roleName, 20 | assumedBy: new cdk.aws_iam.ServicePrincipal('lambda.amazonaws.com'), 21 | managedPolicies: [cdk.aws_iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLogsFullAccess')] 22 | }); 23 | 24 | new cdk.CfnOutput(this, "LambdaRoleArn", { 25 | value: lambdaRole.roleArn, 26 | }); 27 | 28 | this.lambdaRole = lambdaRole; 29 | } 30 | } -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/lib/constructs/s3-bucket-construct.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | 4 | export interface S3Props extends cdk.StackProps {} 5 | 6 | const defaultProps: Partial = {}; 7 | 8 | export class S3Construct extends Construct { 9 | public bucket: cdk.aws_s3.Bucket; 10 | public bucketName: string; 11 | 12 | constructor(parent: Construct, name: string, props: S3Props) { 13 | super(parent, name); 14 | 15 | props = { ...defaultProps, ...props }; 16 | 17 | const s3Bucket = new cdk.aws_s3.Bucket(this, "Bucket", { 18 | autoDeleteObjects: true, 19 | bucketName: `${name}-bucket`, 20 | blockPublicAccess: cdk.aws_s3.BlockPublicAccess.BLOCK_ALL, 21 | encryption: cdk.aws_s3.BucketEncryption.S3_MANAGED, 22 | removalPolicy: cdk.RemovalPolicy.DESTROY, 23 | enforceSSL: true, 24 | }); 25 | 26 | new cdk.aws_s3_deployment.BucketDeployment(this, "ApiSchemaBucket", { 27 | sources: [ 28 | cdk.aws_s3_deployment.Source.asset( 29 | "lib/assets/api-schema" 30 | ), 31 | ], 32 | destinationBucket: s3Bucket, 33 | destinationKeyPrefix: "api-schema", 34 | }); 35 | 36 | new cdk.CfnOutput(this, `${name}-bucket`, { 37 | value: `${s3Bucket.bucketName}`, 38 | }); 39 | 40 | this.bucketName = s3Bucket.bucketName; 41 | this.bucket = s3Bucket; 42 | } 43 | } -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "travel-companion", 3 | "version": "0.1.0", 4 | "bin": { 5 | "bedrock-agent-cdk": "bin/bedrock-agent-cdk.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/jest": "^29.5.12", 15 | "@types/node": "20.11.19", 16 | "jest": "^29.7.0", 17 | "ts-jest": "^29.1.2", 18 | "aws-cdk": "2.141.0", 19 | "ts-node": "^10.9.2", 20 | "typescript": "~5.3.3", 21 | "glob": "^10.3.10", 22 | "bedrock-agents-cdk": "^0.0.11" 23 | }, 24 | "dependencies": { 25 | "aws-cdk-lib": "2.141.0", 26 | "constructs": "^10.0.0", 27 | "source-map-support": "^0.5.21" 28 | } 29 | } -------------------------------------------------------------------------------- /travel-hospitality/travel-planner/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | --------------------------------------------------------------------------------