├── src ├── react-app-env.d.ts ├── images │ └── banner.jpg ├── App.test.js ├── index.css ├── reportWebVitals.js ├── index.js ├── components │ ├── MyTextField.js │ ├── MyFlexibleTable.js │ ├── Header.js │ ├── About.js │ ├── ResponseCard.js │ ├── Conversations.js │ └── Interact.js ├── App.css ├── aws-exports.ts ├── App.js └── graphql │ ├── queries.js │ ├── subscriptions.js │ └── mutations.js ├── amplify ├── backend │ ├── function │ │ └── assistantFulfillment │ │ │ ├── src │ │ │ ├── src.egg-info │ │ │ │ ├── top_level.txt │ │ │ │ ├── dependency_links.txt │ │ │ │ ├── SOURCES.txt │ │ │ │ └── PKG-INFO │ │ │ ├── event.json │ │ │ ├── setup.py │ │ │ └── index.py │ │ │ ├── function-parameters.json │ │ │ ├── custom-policies.json │ │ │ ├── amplify.state │ │ │ ├── Pipfile │ │ │ ├── Pipfile.lock │ │ │ └── assistantFulfillment-cloudformation-template.json │ ├── api │ │ └── awsAssistantBackend │ │ │ ├── transform.conf.json │ │ │ ├── parameters.json │ │ │ ├── resolvers │ │ │ └── README.md │ │ │ ├── cli-inputs.json │ │ │ ├── .migration-backup │ │ │ └── schema.graphql │ │ │ ├── schema.graphql │ │ │ ├── .migration-config-backup │ │ │ └── cli.json │ │ │ └── stacks │ │ │ └── CustomResources.json │ ├── tags.json │ ├── types │ │ └── amplify-dependent-resources-ref.d.ts │ ├── hosting │ │ └── amplifyhosting │ │ │ └── amplifyhosting-template.json │ ├── auth │ │ └── awsassistantfcd2b45d │ │ │ └── cli-inputs.json │ └── backend-config.json ├── README.md ├── hooks │ └── README.md ├── .config │ └── project-config.json └── cli.json ├── bot ├── Manifest.json └── cloud-assistant │ ├── Bot.json │ └── BotLocales │ └── en_US │ ├── BotLocale.json │ ├── SlotTypes │ ├── objName │ │ └── SlotType.json │ ├── bucketName │ │ └── SlotType.json │ ├── subnetType │ │ └── SlotType.json │ ├── ipAddress │ │ └── SlotType.json │ ├── region │ │ └── SlotType.json │ ├── ami │ │ └── SlotType.json │ └── instanceType │ │ └── SlotType.json │ └── Intents │ ├── FallbackIntent │ └── Intent.json │ ├── s3-list-buckets │ └── Intent.json │ ├── ec2-terminate │ └── Intent.json │ ├── s3-copy-to-new-bucket │ └── Intent.json │ ├── set-region │ ├── Intent.json │ └── Slots │ │ └── region │ │ └── Slot.json │ ├── get-help │ └── Intent.json │ ├── sg-rule-list │ └── Intent.json │ ├── s3-create-bucket │ ├── Intent.json │ └── Slots │ │ └── bucketName │ │ └── Slot.json │ ├── ec2-create │ ├── Intent.json │ └── Slots │ │ ├── count │ │ └── Slot.json │ │ ├── ami │ │ └── Slot.json │ │ └── instanceType │ │ └── Slot.json │ ├── sg-rule-replace │ ├── Intent.json │ └── Slots │ │ └── ipAddress │ │ └── Slot.json │ ├── ec2-list │ ├── Slots │ │ ├── ami │ │ │ └── Slot.json │ │ ├── subnetType │ │ │ └── Slot.json │ │ └── instanceType │ │ │ └── Slot.json │ └── Intent.json │ └── s3-search │ ├── Intent.json │ └── Slots │ ├── bucketIndex │ └── Slot.json │ └── objName │ └── Slot.json ├── public ├── robots.txt ├── manifest.json └── index.html ├── static └── images │ └── architecture.png ├── CODE_OF_CONDUCT.md ├── .graphqlconfig.yml ├── tsconfig.json ├── .gitignore ├── LICENSE ├── package.json ├── CONTRIBUTING.md └── README.md /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/src/src.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/src/event.json: -------------------------------------------------------------------------------- 1 | { "test": "event" } 2 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/src/src.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bot/Manifest.json: -------------------------------------------------------------------------------- 1 | {"metaData":{"fileFormat":"LexJson","resourceType":"BOT","schemaVersion":"1"}} -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/function-parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "lambdaLayers": [] 3 | } -------------------------------------------------------------------------------- /src/images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-amplify-cloud-assistant-app/HEAD/src/images/banner.jpg -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/transform.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": 5, 3 | "ElasticsearchWarning": true 4 | } -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/src/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup(name='src', version='1.0') 4 | -------------------------------------------------------------------------------- /static/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-amplify-cloud-assistant-app/HEAD/static/images/architecture.png -------------------------------------------------------------------------------- /bot/cloud-assistant/Bot.json: -------------------------------------------------------------------------------- 1 | {"name":"cloud-assistant","version":"2","description":null,"identifier":"TOJAY8JVIP","dataPrivacy":{"childDirected":false},"idleSessionTTLInSeconds":60} -------------------------------------------------------------------------------- /amplify/backend/tags.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Key": "user:Stack", 4 | "Value": "{project-env}" 5 | }, 6 | { 7 | "Key": "user:Application", 8 | "Value": "{project-name}" 9 | } 10 | ] -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/BotLocale.json: -------------------------------------------------------------------------------- 1 | {"name":"English (US)","identifier":"en_US","version":null,"description":null,"voiceSettings":{"engine":"standard","voiceId":"Joanna"},"nluConfidenceThreshold":0.4} -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/src/src.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | index.py 2 | setup.py 3 | src.egg-info/PKG-INFO 4 | src.egg-info/SOURCES.txt 5 | src.egg-info/dependency_links.txt 6 | src.egg-info/top_level.txt -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/custom-policies.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Action": ["ec2:*"], 4 | "Resource": ["*"] 5 | }, 6 | { 7 | "Action": ["s3:*"], 8 | "Resource": ["*"] 9 | } 10 | ] -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/amplify.state: -------------------------------------------------------------------------------- 1 | { 2 | "pluginId": "amplify-python-function-runtime-provider", 3 | "functionRuntime": "python", 4 | "useLegacyBuild": false, 5 | "defaultEditorFile": "src/index.py" 6 | } -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/src/src.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: src 3 | Version: 1.0 4 | Summary: UNKNOWN 5 | Home-page: UNKNOWN 6 | License: UNKNOWN 7 | Platform: UNKNOWN 8 | 9 | UNKNOWN 10 | 11 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | src = {editable = true, path = "./src"} 10 | 11 | [requires] 12 | python_version = "3.8" 13 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/SlotTypes/objName/SlotType.json: -------------------------------------------------------------------------------- 1 | {"name":"objName","identifier":"XKU9YIFF4Z","description":null,"slotTypeValues":null,"parentSlotTypeSignature":"AMAZON.AlphaNumeric","valueSelectionSetting":{"regexFilter":{"pattern":"[0-9][a-z]"},"resolutionStrategy":"ORIGINAL_VALUE"}} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/SlotTypes/bucketName/SlotType.json: -------------------------------------------------------------------------------- 1 | {"name":"bucketName","identifier":"FJEG6LWUY0","description":null,"slotTypeValues":null,"parentSlotTypeSignature":"AMAZON.AlphaNumeric","valueSelectionSetting":{"regexFilter":{"pattern":"[0-9][a-z]-"},"resolutionStrategy":"ORIGINAL_VALUE"}} -------------------------------------------------------------------------------- /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. 5 | -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSyncApiName": "awsAssistantBackend", 3 | "DynamoDBBillingMode": "PAY_PER_REQUEST", 4 | "DynamoDBEnableServerSideEncryption": false, 5 | "AuthCognitoUserPoolId": { 6 | "Fn::GetAtt": [ 7 | "authawsassistantfcd2b45d", 8 | "Outputs.UserPoolId" 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/resolvers/README.md: -------------------------------------------------------------------------------- 1 | Any resolvers that you add in this directory will override the ones automatically generated by Amplify CLI and will be directly copied to the cloud. 2 | For more information, visit [https://docs.amplify.aws/cli/graphql-transformer/resolvers](https://docs.amplify.aws/cli/graphql-transformer/resolvers) -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/SlotTypes/subnetType/SlotType.json: -------------------------------------------------------------------------------- 1 | {"name":"subnetType","identifier":"XZZJY286HX","description":null,"slotTypeValues":[{"sampleValue":{"value":"private"},"synonyms":[{"value":"private"}]},{"sampleValue":{"value":"public"},"synonyms":[{"value":"public"}]}],"parentSlotTypeSignature":null,"valueSelectionSetting":{"regexFilter":null,"resolutionStrategy":"TOP_RESOLUTION"}} -------------------------------------------------------------------------------- /.graphqlconfig.yml: -------------------------------------------------------------------------------- 1 | projects: 2 | awsAssistantBackend: 3 | schemaPath: src/graphql/schema.json 4 | includes: 5 | - src/graphql/**/*.js 6 | excludes: 7 | - ./amplify/** 8 | extensions: 9 | amplify: 10 | codeGenTarget: javascript 11 | generatedFileName: '' 12 | docsFilePath: src/graphql 13 | extensions: 14 | amplify: 15 | version: 3 16 | -------------------------------------------------------------------------------- /amplify/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Amplify CLI 2 | This directory was generated by [Amplify CLI](https://docs.amplify.aws/cli). 3 | 4 | Helpful resources: 5 | - Amplify documentation: https://docs.amplify.aws 6 | - Amplify CLI documentation: https://docs.amplify.aws/cli 7 | - More details on this folder & generated files: https://docs.amplify.aws/cli/reference/files 8 | - Join Amplify's community: https://amplify.aws/community/ 9 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /amplify/hooks/README.md: -------------------------------------------------------------------------------- 1 | # Command Hooks 2 | 3 | Command hooks can be used to run custom scripts upon Amplify CLI lifecycle events like pre-push, post-add-function, etc. 4 | 5 | To get started, add your script files based on the expected naming convention in this directory. 6 | 7 | Learn more about the script file naming convention, hook parameters, third party dependencies, and advanced configurations at https://docs.amplify.aws/cli/usage/command-hooks 8 | -------------------------------------------------------------------------------- /amplify/.config/project-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "awsassistant", 3 | "version": "3.1", 4 | "frontend": "javascript", 5 | "javascript": { 6 | "framework": "react", 7 | "config": { 8 | "SourceDir": "src", 9 | "DistributionDir": "build", 10 | "BuildCommand": "npm.cmd run-script build", 11 | "StartCommand": "npm.cmd run-script start" 12 | } 13 | }, 14 | "providers": [ 15 | "awscloudformation" 16 | ] 17 | } -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/cli-inputs.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "serviceConfiguration": { 4 | "serviceName": "AppSync", 5 | "defaultAuthType": { 6 | "mode": "AMAZON_COGNITO_USER_POOLS", 7 | "cognitoUserPoolId": "authawsassistantfcd2b45d" 8 | }, 9 | "conflictResolution": {}, 10 | "apiName": "awsAssistantBackend", 11 | "gqlSchemaPath": "C:\\Users\\wbenhal\\Documents\\React Projects\\aws-assistant\\amplify\\backend\\api\\awsAssistantBackend\\schema.graphql" 12 | } 13 | } -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/SlotTypes/ipAddress/SlotType.json: -------------------------------------------------------------------------------- 1 | {"name":"ipAddress","identifier":"TYPH1224JI","description":null,"slotTypeValues":[{"sampleValue":{"value":"0.0.0.0"},"synonyms":null},{"sampleValue":{"value":"255.255.255.255"},"synonyms":null},{"sampleValue":{"value":"76.243.176.78"},"synonyms":null},{"sampleValue":{"value":"10.10.255.255"},"synonyms":null},{"sampleValue":{"value":"123.26.200.10"},"synonyms":null}],"parentSlotTypeSignature":null,"valueSelectionSetting":{"regexFilter":null,"resolutionStrategy":"ORIGINAL_VALUE"}} -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/SlotTypes/region/SlotType.json: -------------------------------------------------------------------------------- 1 | {"name":"region","identifier":"YKF03KOAZE","description":null,"slotTypeValues":[{"sampleValue":{"value":"us-east-1"},"synonyms":[{"value":"us-east-1"},{"value":"virginia"}]},{"sampleValue":{"value":"us-east-2"},"synonyms":[{"value":"us-east-2"},{"value":"ohio"}]},{"sampleValue":{"value":"us-west-1"},"synonyms":[{"value":"us-west-1"},{"value":"california"}]},{"sampleValue":{"value":"us-west-2"},"synonyms":[{"value":"us-west-2"},{"value":"oregon"}]}],"parentSlotTypeSignature":null,"valueSelectionSetting":{"regexFilter":null,"resolutionStrategy":"TOP_RESOLUTION"}} -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/components/MyTextField.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { TextField } from '@mui/material' 3 | 4 | const MyTextField = ({newQuery, setNewQuery, handleKeyPress, SendButton}) => { 5 | return ( 6 | }} 10 | autoComplete="off" value={newQuery} 11 | onChange={(e) => {setNewQuery(e.target.value)}} 12 | onKeyDown={handleKeyPress}> 13 | ) 14 | } 15 | 16 | export default MyTextField 17 | -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/.migration-backup/schema.graphql: -------------------------------------------------------------------------------- 1 | type Conversation @model 2 | @key(name: "conversationsByUser", fields: ["user", "createdAt"], queryField: "conversationsByUser"){ 3 | id: ID! 4 | name: String! 5 | user: String! 6 | description: String 7 | createdAt: String! 8 | utterances: [Utterance] @connection(keyName: "byConversationId", fields: ["id"]) 9 | } 10 | 11 | 12 | type Utterance @model 13 | @key(name: "byConversationId", fields: ["conversationId", "createdAt"]) { 14 | id: ID! 15 | text: String! 16 | author: String! 17 | conversationId: ID! 18 | data: String 19 | createdAt: String! 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/schema.graphql: -------------------------------------------------------------------------------- 1 | type Conversation @model @auth(rules: [{allow: owner}]) { 2 | id: ID! 3 | name: String! 4 | user: String! @index(name: "conversationsByUser", queryField: "conversationsByUser", sortKeyFields: ["createdAt"]) 5 | description: String 6 | createdAt: String! 7 | utterances: [Utterance] @hasMany(indexName: "byConversationId", fields: ["id"]) 8 | } 9 | 10 | type Utterance @model @auth(rules: [{allow: owner}]) { 11 | id: ID! 12 | text: String! 13 | author: String! 14 | conversationId: ID! @index(name: "byConversationId", sortKeyFields: ["createdAt"]) 15 | data: String 16 | createdAt: String! 17 | } 18 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "20a5580e79d8b5a7a360dfdbab4ee3c05dce7388bd6c4f2e7c30c18288e02f68" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "src": { 20 | "editable": true, 21 | "path": "./src" 22 | } 23 | }, 24 | "develop": {} 25 | } 26 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /amplify/backend/types/amplify-dependent-resources-ref.d.ts: -------------------------------------------------------------------------------- 1 | export type AmplifyDependentResourcesAttributes = { 2 | "api": { 3 | "awsAssistantBackend": { 4 | "GraphQLAPIEndpointOutput": "string", 5 | "GraphQLAPIIdOutput": "string" 6 | } 7 | }, 8 | "auth": { 9 | "awsassistantfcd2b45d": { 10 | "AppClientID": "string", 11 | "AppClientIDWeb": "string", 12 | "IdentityPoolId": "string", 13 | "IdentityPoolName": "string", 14 | "UserPoolArn": "string", 15 | "UserPoolId": "string", 16 | "UserPoolName": "string" 17 | } 18 | }, 19 | "function": { 20 | "assistantFulfillment": { 21 | "Arn": "string", 22 | "LambdaExecutionRole": "string", 23 | "Name": "string", 24 | "Region": "string" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/SlotTypes/ami/SlotType.json: -------------------------------------------------------------------------------- 1 | {"name":"ami","identifier":"3SKZ8SGUHR","description":null,"slotTypeValues":[{"sampleValue":{"value":"ami-00c39f71452c08778"},"synonyms":[{"value":"Amazon linux 2"},{"value":"amazon linux"}]},{"sampleValue":{"value":"ami-0c9978668f8d55984"},"synonyms":[{"value":"red hat enterprise linux 8"},{"value":"red hat"}]},{"sampleValue":{"value":"ami-0557a15b87f6559cf"},"synonyms":[{"value":"ubuntu server 20.04"},{"value":" ubuntu server"},{"value":" ubuntu"}]},{"sampleValue":{"value":"ami-0e38fa17744b2f6a5"},"synonyms":[{"value":"Microsoft Windows Server 2019 Base"},{"value":"Microsoft Windows"},{"value":"Windows Server"},{"value":"windows"}]}],"parentSlotTypeSignature":null,"valueSelectionSetting":{"regexFilter":null,"resolutionStrategy":"TOP_RESOLUTION"}} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | #amplify-do-not-edit-begin 26 | amplify/\#current-cloud-backend 27 | amplify/.config/local-* 28 | amplify/logs 29 | amplify/mock-data 30 | amplify/backend/amplify-meta.json 31 | amplify/backend/awscloudformation 32 | amplify/backend/.temp 33 | build/ 34 | dist/ 35 | node_modules/ 36 | aws-exports.js 37 | awsconfiguration.json 38 | amplifyconfiguration.json 39 | amplifyconfiguration.dart 40 | amplify-build-config.json 41 | amplify-gradle-config.json 42 | amplifytools.xcconfig 43 | .secret-* 44 | **.sample 45 | #amplify-do-not-edit-end 46 | 47 | # IDE 48 | .vscode -------------------------------------------------------------------------------- /amplify/backend/hosting/amplifyhosting/amplifyhosting-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "{\"createdOn\":\"Windows\",\"createdBy\":\"Amplify\",\"createdWith\":\"8.0.2\",\"stackType\":\"hosting-amplifyhosting\",\"metadata\":{}}", 4 | "Parameters": { 5 | "env": { 6 | "Type": "String" 7 | }, 8 | "appId": { 9 | "Type": "String" 10 | }, 11 | "type": { 12 | "Type": "String" 13 | } 14 | }, 15 | "Conditions": { 16 | "isManual": { 17 | "Fn::Equals": [ 18 | { 19 | "Ref": "type" 20 | }, 21 | "manual" 22 | ] 23 | } 24 | }, 25 | "Resources": { 26 | "AmplifyBranch": { 27 | "Condition": "isManual", 28 | "Type": "AWS::Amplify::Branch", 29 | "Properties": { 30 | "BranchName": { 31 | "Ref": "env" 32 | }, 33 | "AppId": { 34 | "Ref": "appId" 35 | } 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /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 | 18 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/SlotTypes/instanceType/SlotType.json: -------------------------------------------------------------------------------- 1 | {"name":"instanceType","identifier":"NAEKHHXJ2F","description":null,"slotTypeValues":[{"sampleValue":{"value":"t2.micro"},"synonyms":[{"value":"t2 micro"},{"value":"micro t2"}]},{"sampleValue":{"value":"t2.small"},"synonyms":[{"value":"t2 small"},{"value":"small t2"}]},{"sampleValue":{"value":"t2.medium"},"synonyms":[{"value":"t2 medium"},{"value":"medium t2"}]},{"sampleValue":{"value":"t2.large"},"synonyms":[{"value":"t2 large"},{"value":"large t2"}]},{"sampleValue":{"value":"t2.xlarge"},"synonyms":[{"value":"t2 extra large"},{"value":"extra large t2"}]},{"sampleValue":{"value":"t3.micro"},"synonyms":[{"value":"t3 micro"},{"value":"micro t3"}]},{"sampleValue":{"value":"t3.small"},"synonyms":[{"value":"t3 small"},{"value":"small t3"}]},{"sampleValue":{"value":"t3.medium"},"synonyms":[{"value":"t3 medium"},{"value":"medium t3"}]},{"sampleValue":{"value":"t3.large"},"synonyms":[{"value":"t3 large"},{"value":"large t3"}]},{"sampleValue":{"value":"t3.xlarge"},"synonyms":[{"value":"t3 extra large"},{"value":"extra large t3"}]}],"parentSlotTypeSignature":null,"valueSelectionSetting":{"regexFilter":null,"resolutionStrategy":"TOP_RESOLUTION"}} -------------------------------------------------------------------------------- /src/aws-exports.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten. 3 | 4 | const awsmobile = { 5 | "aws_project_region": "us-east-1", 6 | "aws_cognito_identity_pool_id": "us-east-1:0b3fa6df-883a-4b25-aa47-bcc13fc2f013", 7 | "aws_cognito_region": "us-east-1", 8 | "aws_user_pools_id": "us-east-1_uRmkPZXXv", 9 | "aws_user_pools_web_client_id": "3b3i2nmqp4nk8lb7h60imh6que", 10 | "oauth": {}, 11 | "aws_cognito_username_attributes": [ 12 | "EMAIL" 13 | ], 14 | "aws_cognito_social_providers": [], 15 | "aws_cognito_signup_attributes": [ 16 | "EMAIL" 17 | ], 18 | "aws_cognito_mfa_configuration": "OFF", 19 | "aws_cognito_mfa_types": [ 20 | "SMS" 21 | ], 22 | "aws_cognito_password_protection_settings": { 23 | "passwordPolicyMinLength": 8, 24 | "passwordPolicyCharacters": [] 25 | }, 26 | "aws_cognito_verification_mechanisms": [ 27 | "EMAIL" 28 | ], 29 | "aws_appsync_graphqlEndpoint": "https://qxwwlnpchfbqfmcq4kqo3didnu.appsync-api.us-east-1.amazonaws.com/graphql", 30 | "aws_appsync_region": "us-east-1", 31 | "aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS" 32 | }; 33 | 34 | 35 | export default awsmobile; 36 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/FallbackIntent/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"FallbackIntent","identifier":"FALLBCKINT","description":"Default intent when no other intent matches","parentIntentSignature":"AMAZON.FallbackIntent","sampleUtterances":null,"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":null,"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":null,"slotPriorities":[]} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-assistant", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@aws-amplify/ui-react": "^1.2.20", 7 | "@emotion/react": "^11.4.1", 8 | "@emotion/styled": "^11.3.0", 9 | "@fontsource/roboto": "^4.5.1", 10 | "@mui/icons-material": "^5.0.1", 11 | "@mui/material": "^5.0.2", 12 | "@mui/x-data-grid": "^5.0.0-beta.5", 13 | "@testing-library/jest-dom": "^5.14.1", 14 | "@testing-library/react": "^11.2.7", 15 | "@testing-library/user-event": "^12.8.3", 16 | "@thefat32/aws-amplify-lex-provider-v2": "^1.0.3", 17 | "aws-amplify": "^4.3.2", 18 | "react": "^17.0.2", 19 | "react-dom": "^17.0.2", 20 | "react-router-dom": "^5.3.0", 21 | "react-scripts": "4.0.3", 22 | "web-vitals": "^1.1.2" 23 | }, 24 | "scripts": { 25 | "start": "react-scripts start", 26 | "build": "react-scripts build", 27 | "test": "react-scripts test", 28 | "eject": "react-scripts eject" 29 | }, 30 | "eslintConfig": { 31 | "extends": [ 32 | "react-app", 33 | "react-app/jest" 34 | ] 35 | }, 36 | "browserslist": { 37 | "production": [ 38 | ">0.2%", 39 | "not dead", 40 | "not op_mini all" 41 | ], 42 | "development": [ 43 | "last 1 chrome version", 44 | "last 1 firefox version", 45 | "last 1 safari version" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/components/MyFlexibleTable.js: -------------------------------------------------------------------------------- 1 | 2 | // Material Imports 3 | import { TableContainer, Table, TableHead, TableRow, TableCell, TableBody } from "@mui/material"; 4 | import { Paper } from "@mui/material"; 5 | 6 | const MyFlexibleTable = ({rows, cols, rowIndex}) => { 7 | 8 | return ( 9 | 10 | 11 | 12 | 13 | {cols.map((col, index) => ( 14 | index === 0 ? {col} : {col} 15 | ))} 16 | 17 | 18 | 19 | {rows.map((row) => ( 20 | 21 | {row.map((attribute, index) => ( 22 | index === 0 ? {attribute} : {attribute} 23 | ))} 24 | 25 | ))} 26 | 27 |
28 |
29 | ) 30 | } 31 | 32 | export default MyFlexibleTable 33 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/s3-list-buckets/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"s3-list-buckets","identifier":"IFLU5J6MAP","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"list all S3 buckets"},{"utterance":"show me all my buckets"},{"utterance":"show all s3 buckets"},{"utterance":"how many S3 buckets do I have?"},{"utterance":"show a list of all S3 buckets"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":[{"name":"buckets-listed","timeToLiveInSeconds":3600,"turnsToLive":5}],"kendraConfiguration":null,"dialogCodeHook":{"enabled":true},"fulfillmentCodeHook":null,"slotPriorities":[]} -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/.migration-config-backup/cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "features": { 3 | "graphqltransformer": { 4 | "addmissingownerfields": true, 5 | "improvepluralization": false, 6 | "validatetypenamereservedwords": true, 7 | "useexperimentalpipelinedtransformer": false, 8 | "enableiterativegsiupdates": true, 9 | "secondarykeyasgsi": true, 10 | "skipoverridemutationinputtypes": true, 11 | "securityEnhancementNotification": false, 12 | "showfieldauthnotification": false 13 | }, 14 | "frontend-ios": { 15 | "enablexcodeintegration": true 16 | }, 17 | "auth": { 18 | "enablecaseinsensitivity": true, 19 | "useinclusiveterminology": true, 20 | "breakcirculardependency": true, 21 | "forcealiasattributes": false 22 | }, 23 | "codegen": { 24 | "useappsyncmodelgenplugin": true, 25 | "usedocsgeneratorplugin": true, 26 | "usetypesgeneratorplugin": true, 27 | "cleangeneratedmodelsdirectory": true, 28 | "retaincasestyle": true, 29 | "addtimestampfields": true, 30 | "handlelistnullabilitytransparently": true, 31 | "emitauthprovider": true, 32 | "generateindexrules": true, 33 | "enabledartnullsafety": true 34 | }, 35 | "appsync": { 36 | "generategraphqlpermissions": true 37 | }, 38 | "latestregionsupport": { 39 | "pinpoint": 1, 40 | "translate": 1, 41 | "transcribe": 1, 42 | "rekognition": 1, 43 | "textract": 1, 44 | "comprehend": 1 45 | }, 46 | "project": { 47 | "overrides": true 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /amplify/backend/auth/awsassistantfcd2b45d/cli-inputs.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "cognitoConfig": { 4 | "authSelections": "identityPoolAndUserPool", 5 | "requiredAttributes": [ 6 | "email" 7 | ], 8 | "resourceName": "awsassistantfcd2b45d", 9 | "serviceName": "Cognito", 10 | "useDefault": "default", 11 | "userpoolClientReadAttributes": [ 12 | "email" 13 | ], 14 | "userpoolClientWriteAttributes": [ 15 | "email" 16 | ], 17 | "aliasAttributes": [], 18 | "resourceNameTruncated": "awsassfcd2b45d", 19 | "sharedId": "fcd2b45d", 20 | "userPoolGroupList": [], 21 | "userPoolName": "awsassistantfcd2b45d_userpool_fcd2b45d", 22 | "usernameAttributes": [ 23 | "email" 24 | ], 25 | "usernameCaseSensitive": false, 26 | "userpoolClientRefreshTokenValidity": 30, 27 | "userpoolClientSetAttributes": false, 28 | "userpoolClientGenerateSecret": false, 29 | "userpoolClientLambdaRole": "awsassfcd2b45d_userpoolclient_lambda_role", 30 | "passwordPolicyCharacters": [], 31 | "passwordPolicyMinLength": 8, 32 | "mfaConfiguration": "OFF", 33 | "mfaTypes": [ 34 | "SMS Text Message" 35 | ], 36 | "smsAuthenticationMessage": "Your authentication code is {####}", 37 | "emailVerificationMessage": "Your verification code is {####}", 38 | "emailVerificationSubject": "Your verification code", 39 | "smsVerificationMessage": "Your verification code is {####}", 40 | "autoVerifiedAttributes": [], 41 | "identityPoolName": "awsassistantfcd2b45d_identitypool_fcd2b45d", 42 | "allowUnauthenticatedIdentities": true 43 | } 44 | } -------------------------------------------------------------------------------- /amplify/cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "features": { 3 | "graphqltransformer": { 4 | "addmissingownerfields": true, 5 | "improvepluralization": false, 6 | "validatetypenamereservedwords": true, 7 | "useexperimentalpipelinedtransformer": true, 8 | "enableiterativegsiupdates": true, 9 | "secondarykeyasgsi": true, 10 | "skipoverridemutationinputtypes": true, 11 | "securityEnhancementNotification": false, 12 | "showfieldauthnotification": false, 13 | "transformerversion": 2, 14 | "suppressschemamigrationprompt": true 15 | }, 16 | "frontend-ios": { 17 | "enablexcodeintegration": true 18 | }, 19 | "auth": { 20 | "enablecaseinsensitivity": true, 21 | "useinclusiveterminology": true, 22 | "breakcirculardependency": true, 23 | "forcealiasattributes": false 24 | }, 25 | "codegen": { 26 | "useappsyncmodelgenplugin": true, 27 | "usedocsgeneratorplugin": true, 28 | "usetypesgeneratorplugin": true, 29 | "cleangeneratedmodelsdirectory": true, 30 | "retaincasestyle": true, 31 | "addtimestampfields": true, 32 | "handlelistnullabilitytransparently": true, 33 | "emitauthprovider": true, 34 | "generateindexrules": true, 35 | "enabledartnullsafety": true 36 | }, 37 | "appsync": { 38 | "generategraphqlpermissions": true 39 | }, 40 | "latestregionsupport": { 41 | "pinpoint": 1, 42 | "translate": 1, 43 | "transcribe": 1, 44 | "rekognition": 1, 45 | "textract": 1, 46 | "comprehend": 1 47 | }, 48 | "project": { 49 | "overrides": true 50 | } 51 | }, 52 | "debug": { 53 | "shareProjectConfig": false 54 | } 55 | } -------------------------------------------------------------------------------- /amplify/backend/api/awsAssistantBackend/stacks/CustomResources.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "An auto-generated nested stack.", 4 | "Metadata": {}, 5 | "Parameters": { 6 | "AppSyncApiId": { 7 | "Type": "String", 8 | "Description": "The id of the AppSync API associated with this project." 9 | }, 10 | "AppSyncApiName": { 11 | "Type": "String", 12 | "Description": "The name of the AppSync API", 13 | "Default": "AppSyncSimpleTransform" 14 | }, 15 | "env": { 16 | "Type": "String", 17 | "Description": "The environment name. e.g. Dev, Test, or Production", 18 | "Default": "NONE" 19 | }, 20 | "S3DeploymentBucket": { 21 | "Type": "String", 22 | "Description": "The S3 bucket containing all deployment assets for the project." 23 | }, 24 | "S3DeploymentRootKey": { 25 | "Type": "String", 26 | "Description": "An S3 key relative to the S3DeploymentBucket that points to the root\nof the deployment directory." 27 | } 28 | }, 29 | "Resources": { 30 | "EmptyResource": { 31 | "Type": "Custom::EmptyResource", 32 | "Condition": "AlwaysFalse" 33 | } 34 | }, 35 | "Conditions": { 36 | "HasEnvironmentParameter": { 37 | "Fn::Not": [ 38 | { 39 | "Fn::Equals": [ 40 | { 41 | "Ref": "env" 42 | }, 43 | "NONE" 44 | ] 45 | } 46 | ] 47 | }, 48 | "AlwaysFalse": { 49 | "Fn::Equals": ["true", "false"] 50 | } 51 | }, 52 | "Outputs": { 53 | "EmptyOutput": { 54 | "Description": "An empty output. You may delete this if you have at least one resource above.", 55 | "Value": "" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | 2 | import './App.css'; 3 | 4 | // React router components - test 3 5 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; 6 | 7 | // Import ROBOTO 8 | import '@fontsource/roboto/300.css'; 9 | import '@fontsource/roboto/400.css'; 10 | import '@fontsource/roboto/500.css'; 11 | import '@fontsource/roboto/700.css'; 12 | 13 | // Import key components 14 | import Interact from './components/Interact' 15 | import Conversations from './components/Conversations'; 16 | import About from './components/About'; 17 | import Header from './components/Header'; 18 | 19 | // Bot related imports 20 | import { Interactions } from 'aws-amplify'; 21 | import AWSLex2Provider from '@thefat32/aws-amplify-lex-provider-v2'; 22 | 23 | // Amplify components section 24 | import Amplify from 'aws-amplify'; 25 | import awsmobile from './aws-exports'; 26 | import {withAuthenticator} from '@aws-amplify/ui-react' 27 | 28 | 29 | // Start of body 30 | Interactions.addPluggable(new AWSLex2Provider()) 31 | 32 | Amplify.configure({ 33 | ...awsmobile, 34 | bots: { 35 | "AWS-Configurator": { 36 | botId: "FJZEEWWPBU", 37 | botAliasId: "G0UH3YLBPS", 38 | localeId: "en_US", 39 | region: "us-east-1", 40 | providerName: "AWSLex2Provider" 41 | } 42 | } 43 | }) 44 | 45 | function App() { 46 | return ( 47 | 48 | {/* Header Component */} 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | ); 58 | } 59 | 60 | export default withAuthenticator(App); 61 | // export default App; 62 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-terminate/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"ec2-terminate","identifier":"MTCLLOJKJP","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"Terminate these instances"},{"utterance":"Terminate selected instances"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":[{"name":"selected-instances","timeToLiveInSeconds":null,"turnsToLive":null}],"outputContexts":null,"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[]} -------------------------------------------------------------------------------- /src/components/Header.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // React imports 4 | import { useHistory } from 'react-router'; 5 | 6 | // Material UI components 7 | import { Button, IconButton } from '@mui/material'; 8 | import { AppBar, Box, Toolbar, Typography} from '@mui/material'; 9 | import { Link } from 'react-router-dom'; 10 | import { Menu as MenuIcon } from '@mui/icons-material'; 11 | 12 | // Amplify imports 13 | import Auth from '@aws-amplify/auth'; 14 | import { Hub } from '@aws-amplify/core'; 15 | 16 | 17 | const Header = () => { 18 | 19 | let history = useHistory() 20 | const signout = async () => { 21 | try { 22 | await Auth.signOut(); 23 | Hub.dispatch('UI Auth', { // channel must be 'UI Auth' 24 | event: 'AuthStateChange', // event must be 'AuthStateChange' 25 | message: 'signedout' // message must be 'signedout' 26 | }); 27 | } catch (error) { 28 | console.log('error signing out: ', error); 29 | } 30 | } 31 | 32 | return ( 33 | 34 | theme.zIndex.drawer + 1}}> 35 | 36 | 37 | 38 | 39 | Cloud Assistant 40 | 41 | {/* */} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | ) 50 | } 51 | 52 | export default Header 53 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/s3-copy-to-new-bucket/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"s3-copy-to-new-bucket","identifier":"GNOURKBS0J","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"copy files to new S3 bucket"},{"utterance":"copy files to new bucket"},{"utterance":"copy search results to new S3 bucket"},{"utterance":"copy search results to new bucket"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":null,"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[]} -------------------------------------------------------------------------------- /amplify/backend/backend-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "api": { 3 | "awsAssistantBackend": { 4 | "output": { 5 | "authConfig": { 6 | "additionalAuthenticationProviders": [], 7 | "defaultAuthentication": { 8 | "authenticationType": "AMAZON_COGNITO_USER_POOLS", 9 | "userPoolConfig": { 10 | "userPoolId": "authawsassistantfcd2b45d" 11 | } 12 | } 13 | } 14 | }, 15 | "providerPlugin": "awscloudformation", 16 | "service": "AppSync" 17 | } 18 | }, 19 | "auth": { 20 | "awsassistantfcd2b45d": { 21 | "customAuth": false, 22 | "dependsOn": [], 23 | "frontendAuthConfig": { 24 | "loginMechanisms": [ 25 | "EMAIL" 26 | ], 27 | "mfaConfiguration": "OFF", 28 | "mfaTypes": [ 29 | "SMS" 30 | ], 31 | "passwordProtectionSettings": { 32 | "passwordPolicyCharacters": [], 33 | "passwordPolicyMinLength": 8 34 | }, 35 | "signupAttributes": [ 36 | "EMAIL" 37 | ], 38 | "verificationMechanisms": [ 39 | "EMAIL" 40 | ] 41 | }, 42 | "providerPlugin": "awscloudformation", 43 | "service": "Cognito" 44 | } 45 | }, 46 | "function": { 47 | "assistantFulfillment": { 48 | "build": true, 49 | "providerPlugin": "awscloudformation", 50 | "service": "Lambda" 51 | } 52 | }, 53 | "hosting": { 54 | "amplifyhosting": { 55 | "providerPlugin": "awscloudformation", 56 | "service": "amplifyhosting", 57 | "type": "manual" 58 | } 59 | }, 60 | "parameters": { 61 | "AMPLIFY_hosting_amplifyhosting_appId": { 62 | "usedBy": [ 63 | { 64 | "category": "hosting", 65 | "resourceName": "amplifyhosting" 66 | } 67 | ] 68 | }, 69 | "AMPLIFY_hosting_amplifyhosting_type": { 70 | "usedBy": [ 71 | { 72 | "category": "hosting", 73 | "resourceName": "amplifyhosting" 74 | } 75 | ] 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/set-region/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"set-region","identifier":"LGDQ1GV02P","description":"Used to change the region in which the chatbot will operate. Does this through context variable.","parentIntentSignature":null,"sampleUtterances":[{"utterance":"Change region to {region}"},{"utterance":"set the primary region to {region}"},{"utterance":"use the {region} region"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"ElicitSlot","suppressNextMessage":null,"slotToElicit":"region"}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":null,"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[{"priority":1,"slotName":"region"}]} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/get-help/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"get-help","identifier":"1WNHGFB5PE","description":null,"parentIntentSignature":"AMAZON.HelpIntent","sampleUtterances":null,"intentConfirmationSetting":null,"intentClosingSetting":{"isActive":true,"closingResponse":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"I can help you configure various AWS services by relying solely on your natural language input. "},"imageResponseCard":null},"variations":[{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"I can help you perform various types of operations on resources like instances, buckets, security group rules..."},"imageResponseCard":null},{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"Here are a few example requests you can try: \"show me all my instances\", \"find all instances running on t2 micro\", \"Launch a windows instance\", \"list all my S3 buckets\"..."},"imageResponseCard":null}]}],"allowInterrupt":true},"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}}},"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"CloseIntent","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":null,"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":null,"slotPriorities":[]} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/sg-rule-list/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"sg-rule-list","identifier":"XRWX0WJ0BQ","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"are there any wide open rules in my security group?"},{"utterance":"is all inbound traffic allowed through my security group?"},{"utterance":"what ports are open to everyone from the internet in my security group?"},{"utterance":"list unrestricted security group rules"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":[{"name":"selected-sg-rules","timeToLiveInSeconds":3600,"turnsToLive":5}],"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[]} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/s3-create-bucket/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"s3-create-bucket","identifier":"WXAVI2MATO","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"Create a bucket named {bucketName} "},{"utterance":"Create a bucket with the following name: {bucketName} "},{"utterance":"Create an S3 bucket named {bucketName} "},{"utterance":"Create an S3 bucket"},{"utterance":"Create a new S3 bucket named {bucketName}"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"ElicitSlot","suppressNextMessage":null,"slotToElicit":"bucketName"}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":[{"name":"s3-bucket-created","timeToLiveInSeconds":3600,"turnsToLive":5}],"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[{"priority":1,"slotName":"bucketName"}]} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-create/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"ec2-create","identifier":"KACQBIDTL5","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"Create {count} {ami} instances on {instanceType} instance class"},{"utterance":"Launch {count} {instanceType} instances using {ami} image"},{"utterance":"Start {count} {ami} instances using the {instanceType} instance type"},{"utterance":"launch {count} {ami} instances"},{"utterance":"launch a {ami} instance"},{"utterance":"launch a {instanceType} instance"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"ElicitSlot","suppressNextMessage":null,"slotToElicit":"instanceType"}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":[{"name":"selected-instances","timeToLiveInSeconds":90,"turnsToLive":5}],"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[{"priority":3,"slotName":"ami"},{"priority":1,"slotName":"count"},{"priority":2,"slotName":"instanceType"}]} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/sg-rule-replace/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"sg-rule-replace","identifier":"Q9UC9PRMEV","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"Restrict source traffic for selected rules to my ip address only"},{"utterance":"Modify selected security group rules to allow traffic from my ip address only"},{"utterance":"Replace source traffic in selected rules with jump box ip address"},{"utterance":"restrict source traffic for selected rules to {ipAddress} only"},{"utterance":"Modify selected security group rules to allow traffic from {ipAddress} only"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":[{"name":"selected-sg-rules","timeToLiveInSeconds":null,"turnsToLive":null}],"outputContexts":null,"kendraConfiguration":null,"dialogCodeHook":{"enabled":false},"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[{"priority":1,"slotName":"ipAddress"}]} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-list/Slots/ami/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"ami","identifier":"PHNFHUT0YR","description":null,"slotTypeName":"ami","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":null,"captureConditional":null,"failureResponse":null,"failureNextStep":null,"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what AMI would you like to filter by?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Optional","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-list/Slots/subnetType/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"subnetType","identifier":"JEUR57U2KJ","description":null,"slotTypeName":"subnetType","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":null,"captureConditional":null,"failureResponse":null,"failureNextStep":null,"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what type of subnet? private or public?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Optional","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/sg-rule-replace/Slots/ipAddress/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"ipAddress","identifier":"MPXNSWPEXY","description":null,"slotTypeName":"ipAddress","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":null,"captureConditional":null,"failureResponse":null,"failureNextStep":null,"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"What ip address would you like to use?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Optional","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-list/Slots/instanceType/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"instanceType","identifier":"AUE1VX4VWG","description":null,"slotTypeName":"instanceType","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":null,"captureConditional":null,"failureResponse":null,"failureNextStep":null,"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what instance type would you like to filter by?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Optional","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-create/Slots/count/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"count","identifier":"LQNOCFUSWT","description":null,"slotTypeName":"AMAZON.Number","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":null,"captureConditional":null,"failureResponse":null,"failureNextStep":null,"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"how many instances would you like to launch?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Optional","defaultValueSpecification":{"defaultValueList":[{"defaultValue":"1"}]},"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/s3-search/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"s3-search","identifier":"DBES2PYJL2","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"search for {objName} in all s3 buckets"},{"utterance":"search for files named {objName} in S3"},{"utterance":"Search for {objName} in S3"},{"utterance":"search for s3 objects containing {objName}"},{"utterance":"search for {objName} in bucket {bucketIndex}"},{"utterance":"search for files named {objName} in bucket {bucketIndex}"},{"utterance":"Search for {objName} in S3 bucket {bucketIndex}"},{"utterance":"search for s3 objects containing {objName} in bucket {bucketIndex}"},{"utterance":"search for objects containing {objName} across all buckets"},{"utterance":"search for {objName} across all buckets?"},{"utterance":"search for objects containing the keyword {objName} in S3"},{"utterance":"search for objects containing the keyword {objName} in bucket {bucketIndex}"}],"intentConfirmationSetting":null,"intentClosingSetting":null,"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"ElicitSlot","suppressNextMessage":null,"slotToElicit":"objName"}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":[{"name":"s3-search-results","timeToLiveInSeconds":3600,"turnsToLive":5}],"kendraConfiguration":null,"dialogCodeHook":{"enabled":false},"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[{"priority":1,"slotName":"bucketIndex"},{"priority":2,"slotName":"objName"}]} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/s3-search/Slots/bucketIndex/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"bucketIndex","identifier":"NNKVS4BM9K","description":null,"slotTypeName":"AMAZON.Number","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":null,"captureConditional":null,"failureResponse":null,"failureNextStep":null,"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"Please specify the index of the bucket where the search should be performed."},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Optional","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-list/Intent.json: -------------------------------------------------------------------------------- 1 | {"name":"ec2-list","identifier":"DX3WYFGOTL","description":null,"parentIntentSignature":null,"sampleUtterances":[{"utterance":"List all EC2 instances"},{"utterance":"what instances are in my account? "},{"utterance":"show my instances"},{"utterance":"list all instances with a {ami} image"},{"utterance":"list all instances of type {instanceType}"},{"utterance":"list all {instanceType} instances"},{"utterance":"list my {ami} instances"},{"utterance":"do I have any instances in a {subnetType} subnet?"},{"utterance":"are there any instances deployed to a {subnetType} subnet?"}],"intentConfirmationSetting":null,"intentClosingSetting":{"isActive":true,"closingResponse":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"Requested instances have been listed."},"imageResponseCard":null},"variations":null}],"allowInterrupt":true},"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}}},"initialResponseSetting":{"codeHook":{"isActive":true,"enableCodeHookInvocation":true,"invocationLabel":null,"postCodeHookSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"successConditional":null,"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutConditional":null,"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null}},"conditional":null,"nextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"InvokeDialogCodeHook","suppressNextMessage":null,"slotToElicit":null}},"initialResponse":null},"inputContexts":null,"outputContexts":[{"name":"selected-instances","timeToLiveInSeconds":3600,"turnsToLive":5}],"kendraConfiguration":null,"dialogCodeHook":null,"fulfillmentCodeHook":{"postFulfillmentStatusSpecification":{"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"timeoutResponse":null,"timeoutNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"EndConversation","suppressNextMessage":null,"slotToElicit":null}},"successNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"CloseIntent","suppressNextMessage":null,"slotToElicit":null}},"successResponse":null},"fulfillmentUpdatesSpecification":null,"enabled":true},"slotPriorities":[{"priority":2,"slotName":"instanceType"},{"priority":3,"slotName":"subnetType"},{"priority":1,"slotName":"ami"}]} -------------------------------------------------------------------------------- /src/graphql/queries.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // this is an auto generated file. This will be overwritten 3 | 4 | export const getConversation = /* GraphQL */ ` 5 | query GetConversation($id: ID!) { 6 | getConversation(id: $id) { 7 | id 8 | name 9 | user 10 | description 11 | createdAt 12 | utterances { 13 | items { 14 | id 15 | text 16 | author 17 | conversationId 18 | data 19 | createdAt 20 | updatedAt 21 | owner 22 | } 23 | nextToken 24 | } 25 | updatedAt 26 | owner 27 | } 28 | } 29 | `; 30 | export const listConversations = /* GraphQL */ ` 31 | query ListConversations( 32 | $filter: ModelConversationFilterInput 33 | $limit: Int 34 | $nextToken: String 35 | ) { 36 | listConversations(filter: $filter, limit: $limit, nextToken: $nextToken) { 37 | items { 38 | id 39 | name 40 | user 41 | description 42 | createdAt 43 | utterances { 44 | nextToken 45 | } 46 | updatedAt 47 | owner 48 | } 49 | nextToken 50 | } 51 | } 52 | `; 53 | export const getUtterance = /* GraphQL */ ` 54 | query GetUtterance($id: ID!) { 55 | getUtterance(id: $id) { 56 | id 57 | text 58 | author 59 | conversationId 60 | data 61 | createdAt 62 | updatedAt 63 | owner 64 | } 65 | } 66 | `; 67 | export const listUtterances = /* GraphQL */ ` 68 | query ListUtterances( 69 | $filter: ModelUtteranceFilterInput 70 | $limit: Int 71 | $nextToken: String 72 | ) { 73 | listUtterances(filter: $filter, limit: $limit, nextToken: $nextToken) { 74 | items { 75 | id 76 | text 77 | author 78 | conversationId 79 | data 80 | createdAt 81 | updatedAt 82 | owner 83 | } 84 | nextToken 85 | } 86 | } 87 | `; 88 | export const conversationsByUser = /* GraphQL */ ` 89 | query ConversationsByUser( 90 | $user: String! 91 | $createdAt: ModelStringKeyConditionInput 92 | $sortDirection: ModelSortDirection 93 | $filter: ModelConversationFilterInput 94 | $limit: Int 95 | $nextToken: String 96 | ) { 97 | conversationsByUser( 98 | user: $user 99 | createdAt: $createdAt 100 | sortDirection: $sortDirection 101 | filter: $filter 102 | limit: $limit 103 | nextToken: $nextToken 104 | ) { 105 | items { 106 | id 107 | name 108 | user 109 | description 110 | createdAt 111 | utterances { 112 | nextToken 113 | } 114 | updatedAt 115 | owner 116 | } 117 | nextToken 118 | } 119 | } 120 | `; 121 | -------------------------------------------------------------------------------- /src/graphql/subscriptions.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // this is an auto generated file. This will be overwritten 3 | 4 | export const onCreateConversation = /* GraphQL */ ` 5 | subscription OnCreateConversation($owner: String) { 6 | onCreateConversation(owner: $owner) { 7 | id 8 | name 9 | user 10 | description 11 | createdAt 12 | utterances { 13 | items { 14 | id 15 | text 16 | author 17 | conversationId 18 | data 19 | createdAt 20 | updatedAt 21 | owner 22 | } 23 | nextToken 24 | } 25 | updatedAt 26 | owner 27 | } 28 | } 29 | `; 30 | export const onUpdateConversation = /* GraphQL */ ` 31 | subscription OnUpdateConversation($owner: String) { 32 | onUpdateConversation(owner: $owner) { 33 | id 34 | name 35 | user 36 | description 37 | createdAt 38 | utterances { 39 | items { 40 | id 41 | text 42 | author 43 | conversationId 44 | data 45 | createdAt 46 | updatedAt 47 | owner 48 | } 49 | nextToken 50 | } 51 | updatedAt 52 | owner 53 | } 54 | } 55 | `; 56 | export const onDeleteConversation = /* GraphQL */ ` 57 | subscription OnDeleteConversation($owner: String) { 58 | onDeleteConversation(owner: $owner) { 59 | id 60 | name 61 | user 62 | description 63 | createdAt 64 | utterances { 65 | items { 66 | id 67 | text 68 | author 69 | conversationId 70 | data 71 | createdAt 72 | updatedAt 73 | owner 74 | } 75 | nextToken 76 | } 77 | updatedAt 78 | owner 79 | } 80 | } 81 | `; 82 | export const onCreateUtterance = /* GraphQL */ ` 83 | subscription OnCreateUtterance($owner: String) { 84 | onCreateUtterance(owner: $owner) { 85 | id 86 | text 87 | author 88 | conversationId 89 | data 90 | createdAt 91 | updatedAt 92 | owner 93 | } 94 | } 95 | `; 96 | export const onUpdateUtterance = /* GraphQL */ ` 97 | subscription OnUpdateUtterance($owner: String) { 98 | onUpdateUtterance(owner: $owner) { 99 | id 100 | text 101 | author 102 | conversationId 103 | data 104 | createdAt 105 | updatedAt 106 | owner 107 | } 108 | } 109 | `; 110 | export const onDeleteUtterance = /* GraphQL */ ` 111 | subscription OnDeleteUtterance($owner: String) { 112 | onDeleteUtterance(owner: $owner) { 113 | id 114 | text 115 | author 116 | conversationId 117 | data 118 | createdAt 119 | updatedAt 120 | owner 121 | } 122 | } 123 | `; 124 | -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-create/Slots/ami/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"ami","identifier":"IZ0MEJG2WX","description":null,"slotTypeName":"ami","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"captureConditional":null,"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":{"name":"FallbackIntent","slots":null},"dialogAction":{"type":"StartIntent","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what AMI would you like to use?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Required","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/set-region/Slots/region/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"region","identifier":"HIYSFNM8II","description":null,"slotTypeName":"region","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"captureConditional":null,"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":{"name":"FallbackIntent","slots":null},"dialogAction":{"type":"StartIntent","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what AWS region would you like to use?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Required","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/s3-search/Slots/objName/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"objName","identifier":"YBVCG8SQ0Q","description":null,"slotTypeName":"AMAZON.AlphaNumeric","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"captureConditional":null,"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":{"name":"FallbackIntent","slots":null},"dialogAction":{"type":"StartIntent","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what string are you searching for?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Required","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/ec2-create/Slots/instanceType/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"instanceType","identifier":"MRE0NEMBUU","description":null,"slotTypeName":"instanceType","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"ElicitSlot","suppressNextMessage":null,"slotToElicit":"ami"}},"captureConditional":null,"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":{"name":"FallbackIntent","slots":null},"dialogAction":{"type":"StartIntent","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what type of instance would you like to use?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Required","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /bot/cloud-assistant/BotLocales/en_US/Intents/s3-create-bucket/Slots/bucketName/Slot.json: -------------------------------------------------------------------------------- 1 | {"name":"bucketName","identifier":"M7WIPBBW1F","description":null,"slotTypeName":"AMAZON.AlphaNumeric","obfuscationSetting":null,"valueElicitationSetting":{"slotCaptureSetting":{"codeHook":null,"captureResponse":null,"captureNextStep":{"sessionAttributes":null,"intent":null,"dialogAction":{"type":"FulfillIntent","suppressNextMessage":null,"slotToElicit":null}},"captureConditional":null,"failureResponse":null,"failureNextStep":{"sessionAttributes":null,"intent":{"name":"FallbackIntent","slots":null},"dialogAction":{"type":"StartIntent","suppressNextMessage":null,"slotToElicit":null}},"failureConditional":null,"elicitationCodeHook":{"enableCodeHookInvocation":true,"invocationLabel":null}},"promptSpecification":{"messageGroupsList":[{"message":{"ssmlMessage":null,"customPayload":null,"plainTextMessage":{"value":"what would you like to name your bucket?"},"imageResponseCard":null},"variations":null}],"maxRetries":4,"allowInterrupt":true,"messageSelectionStrategy":"Random","promptAttemptsSpecification":{"Retry2":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry3":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Initial":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry1":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}},"Retry4":{"allowedInputTypes":{"allowAudioInput":true,"allowDTMFInput":true},"audioAndDTMFInputSpecification":{"dtmfSpecification":{"maxLength":513,"deletionCharacter":"*","endCharacter":"#","endTimeoutMs":5000},"startTimeoutMs":4000,"audioSpecification":{"maxLengthMs":15000,"endTimeoutMs":640}},"allowInterrupt":true,"textInputSpecification":{"startTimeoutMs":30000}}}},"slotConstraint":"Required","defaultValueSpecification":null,"sampleUtterances":null,"waitAndContinueSpecification":null},"multipleValuesSetting":null} -------------------------------------------------------------------------------- /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. 60 | -------------------------------------------------------------------------------- /src/graphql/mutations.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // this is an auto generated file. This will be overwritten 3 | 4 | export const createConversation = /* GraphQL */ ` 5 | mutation CreateConversation( 6 | $input: CreateConversationInput! 7 | $condition: ModelConversationConditionInput 8 | ) { 9 | createConversation(input: $input, condition: $condition) { 10 | id 11 | name 12 | user 13 | description 14 | createdAt 15 | utterances { 16 | items { 17 | id 18 | text 19 | author 20 | conversationId 21 | data 22 | createdAt 23 | updatedAt 24 | owner 25 | } 26 | nextToken 27 | } 28 | updatedAt 29 | owner 30 | } 31 | } 32 | `; 33 | export const updateConversation = /* GraphQL */ ` 34 | mutation UpdateConversation( 35 | $input: UpdateConversationInput! 36 | $condition: ModelConversationConditionInput 37 | ) { 38 | updateConversation(input: $input, condition: $condition) { 39 | id 40 | name 41 | user 42 | description 43 | createdAt 44 | utterances { 45 | items { 46 | id 47 | text 48 | author 49 | conversationId 50 | data 51 | createdAt 52 | updatedAt 53 | owner 54 | } 55 | nextToken 56 | } 57 | updatedAt 58 | owner 59 | } 60 | } 61 | `; 62 | export const deleteConversation = /* GraphQL */ ` 63 | mutation DeleteConversation( 64 | $input: DeleteConversationInput! 65 | $condition: ModelConversationConditionInput 66 | ) { 67 | deleteConversation(input: $input, condition: $condition) { 68 | id 69 | name 70 | user 71 | description 72 | createdAt 73 | utterances { 74 | items { 75 | id 76 | text 77 | author 78 | conversationId 79 | data 80 | createdAt 81 | updatedAt 82 | owner 83 | } 84 | nextToken 85 | } 86 | updatedAt 87 | owner 88 | } 89 | } 90 | `; 91 | export const createUtterance = /* GraphQL */ ` 92 | mutation CreateUtterance( 93 | $input: CreateUtteranceInput! 94 | $condition: ModelUtteranceConditionInput 95 | ) { 96 | createUtterance(input: $input, condition: $condition) { 97 | id 98 | text 99 | author 100 | conversationId 101 | data 102 | createdAt 103 | updatedAt 104 | owner 105 | } 106 | } 107 | `; 108 | export const updateUtterance = /* GraphQL */ ` 109 | mutation UpdateUtterance( 110 | $input: UpdateUtteranceInput! 111 | $condition: ModelUtteranceConditionInput 112 | ) { 113 | updateUtterance(input: $input, condition: $condition) { 114 | id 115 | text 116 | author 117 | conversationId 118 | data 119 | createdAt 120 | updatedAt 121 | owner 122 | } 123 | } 124 | `; 125 | export const deleteUtterance = /* GraphQL */ ` 126 | mutation DeleteUtterance( 127 | $input: DeleteUtteranceInput! 128 | $condition: ModelUtteranceConditionInput 129 | ) { 130 | deleteUtterance(input: $input, condition: $condition) { 131 | id 132 | text 133 | author 134 | conversationId 135 | data 136 | createdAt 137 | updatedAt 138 | owner 139 | } 140 | } 141 | `; 142 | -------------------------------------------------------------------------------- /src/components/About.js: -------------------------------------------------------------------------------- 1 | import { Card, CardContent, Grid, Typography, List, ListItem } from '@mui/material' 2 | import React from 'react' 3 | 4 | const About = () => { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | About the Cloud Assistant 13 | 14 | 15 | The Cloud assistant provides users with a conversational 16 | interface leveraging Natural Language Understanding (NLU) to interact with various AWS services and 17 | automates/performs all sorts of simple or advanced operations on behalf of users. It allows users to 18 | manage their AWS accounts using natural language thus reducing time spent navigating the AWS 19 | console or figuring out the proper CLI commands. 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Example EC2 Queries 31 | 32 | * Can you show me all my ec2 instances? 33 | * Launch 1 linux instance on t2 micro 34 | * Launch 2 windows instances on t3 micro 35 | * List ec2 instances 36 | * Find all windows instances 37 | * Find all instances running on t2 micro 38 | * Are there instances deployed to a public subnet? 39 | * Terminate these instances 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Example S3 Queries 48 | 49 | * Show me all my S3 buckets 50 | * Search for "py" in bucket 7 51 | * Search for "ppt" in bucket 7 52 | * Search for "ppt" across all buckets 53 | * Create a new S3 bucket 54 | * Copy found files to new bucket 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Other Example Queries 65 | 66 | * Switch region to ohio 67 | * Switch back region to Virginia 68 | * Are there any wide open security group rules? 69 | * Modify security group rules to allow traffic from 10.11.12.13 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | ) 79 | } 80 | 81 | export default About 82 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/assistantFulfillment-cloudformation-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "{\"createdOn\":\"Windows\",\"createdBy\":\"Amplify\",\"createdWith\":\"8.0.2\",\"stackType\":\"function-Lambda\",\"metadata\":{}}", 4 | "Parameters": { 5 | "CloudWatchRule": { 6 | "Type": "String", 7 | "Default": "NONE", 8 | "Description": " Schedule Expression" 9 | }, 10 | "deploymentBucketName": { 11 | "Type": "String" 12 | }, 13 | "env": { 14 | "Type": "String" 15 | }, 16 | "s3Key": { 17 | "Type": "String" 18 | } 19 | }, 20 | "Conditions": { 21 | "ShouldNotCreateEnvResources": { 22 | "Fn::Equals": [ 23 | { 24 | "Ref": "env" 25 | }, 26 | "NONE" 27 | ] 28 | } 29 | }, 30 | "Resources": { 31 | "LambdaFunction": { 32 | "Type": "AWS::Lambda::Function", 33 | "Metadata": { 34 | "aws:asset:path": "./src", 35 | "aws:asset:property": "Code" 36 | }, 37 | "Properties": { 38 | "Code": { 39 | "S3Bucket": { 40 | "Ref": "deploymentBucketName" 41 | }, 42 | "S3Key": { 43 | "Ref": "s3Key" 44 | } 45 | }, 46 | "Handler": "index.handler", 47 | "FunctionName": { 48 | "Fn::If": [ 49 | "ShouldNotCreateEnvResources", 50 | "assistantFulfillment", 51 | { 52 | "Fn::Join": [ 53 | "", 54 | [ 55 | "assistantFulfillment", 56 | "-", 57 | { 58 | "Ref": "env" 59 | } 60 | ] 61 | ] 62 | } 63 | ] 64 | }, 65 | "Environment": { 66 | "Variables": { 67 | "ENV": { 68 | "Ref": "env" 69 | }, 70 | "REGION": { 71 | "Ref": "AWS::Region" 72 | } 73 | } 74 | }, 75 | "Role": { 76 | "Fn::GetAtt": [ 77 | "LambdaExecutionRole", 78 | "Arn" 79 | ] 80 | }, 81 | "Runtime": "python3.8", 82 | "Layers": [], 83 | "Timeout": 60 84 | } 85 | }, 86 | "LambdaExecutionRole": { 87 | "Type": "AWS::IAM::Role", 88 | "Properties": { 89 | "RoleName": { 90 | "Fn::If": [ 91 | "ShouldNotCreateEnvResources", 92 | "awsassistantLambdaRole70d4ed92", 93 | { 94 | "Fn::Join": [ 95 | "", 96 | [ 97 | "awsassistantLambdaRole70d4ed92", 98 | "-", 99 | { 100 | "Ref": "env" 101 | } 102 | ] 103 | ] 104 | } 105 | ] 106 | }, 107 | "AssumeRolePolicyDocument": { 108 | "Version": "2012-10-17", 109 | "Statement": [ 110 | { 111 | "Effect": "Allow", 112 | "Principal": { 113 | "Service": [ 114 | "lambda.amazonaws.com" 115 | ] 116 | }, 117 | "Action": [ 118 | "sts:AssumeRole" 119 | ] 120 | } 121 | ] 122 | } 123 | } 124 | }, 125 | "lambdaexecutionpolicy": { 126 | "DependsOn": [ 127 | "LambdaExecutionRole" 128 | ], 129 | "Type": "AWS::IAM::Policy", 130 | "Properties": { 131 | "PolicyName": "lambda-execution-policy", 132 | "Roles": [ 133 | { 134 | "Ref": "LambdaExecutionRole" 135 | } 136 | ], 137 | "PolicyDocument": { 138 | "Version": "2012-10-17", 139 | "Statement": [ 140 | { 141 | "Effect": "Allow", 142 | "Action": [ 143 | "logs:CreateLogGroup", 144 | "logs:CreateLogStream", 145 | "logs:PutLogEvents" 146 | ], 147 | "Resource": { 148 | "Fn::Sub": [ 149 | "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*", 150 | { 151 | "region": { 152 | "Ref": "AWS::Region" 153 | }, 154 | "account": { 155 | "Ref": "AWS::AccountId" 156 | }, 157 | "lambda": { 158 | "Ref": "LambdaFunction" 159 | } 160 | } 161 | ] 162 | } 163 | } 164 | ] 165 | } 166 | } 167 | }, 168 | "CustomLambdaExecutionPolicy": { 169 | "Type": "AWS::IAM::Policy", 170 | "Properties": { 171 | "PolicyName": "custom-lambda-execution-policy", 172 | "PolicyDocument": { 173 | "Version": "2012-10-17", 174 | "Statement": [ 175 | { 176 | "Action": [ 177 | "ec2:*" 178 | ], 179 | "Resource": [ 180 | "*" 181 | ], 182 | "Effect": "Allow" 183 | }, 184 | { 185 | "Action": [ 186 | "s3:*" 187 | ], 188 | "Resource": [ 189 | "*" 190 | ], 191 | "Effect": "Allow" 192 | } 193 | ] 194 | }, 195 | "Roles": [ 196 | { 197 | "Ref": "LambdaExecutionRole" 198 | } 199 | ] 200 | }, 201 | "DependsOn": "LambdaExecutionRole" 202 | } 203 | }, 204 | "Outputs": { 205 | "Name": { 206 | "Value": { 207 | "Ref": "LambdaFunction" 208 | } 209 | }, 210 | "Arn": { 211 | "Value": { 212 | "Fn::GetAtt": [ 213 | "LambdaFunction", 214 | "Arn" 215 | ] 216 | } 217 | }, 218 | "Region": { 219 | "Value": { 220 | "Ref": "AWS::Region" 221 | } 222 | }, 223 | "LambdaExecutionRole": { 224 | "Value": { 225 | "Ref": "LambdaExecutionRole" 226 | } 227 | } 228 | } 229 | } -------------------------------------------------------------------------------- /src/components/ResponseCard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | // Material Imports 4 | import { Grid, Card, Typography, CardContent, CardActions, Button } from "@mui/material" 5 | import { Alert } from "@mui/material"; 6 | import { Stack } from "@mui/material"; 7 | import LaunchIcon from "@mui/icons-material/Launch" 8 | 9 | // My components 10 | import MyFlexibleTable from './MyFlexibleTable' 11 | 12 | 13 | 14 | const ResponseCard = ({intent, cardDescription, data}) => { 15 | 16 | const getCardTitle = () => { 17 | console.log('Getting card title') 18 | let cardTitle = "" 19 | switch(intent){ 20 | case 'ec2-list': 21 | cardTitle = 'EC2 Instance List' 22 | break 23 | case 'ec2-create': 24 | cardTitle = 'New EC2 Instance' 25 | break 26 | case 'ec2-terminate': 27 | cardTitle = 'Terminated EC2 Instance' 28 | break 29 | case 's3-copy-to-new-bucket': 30 | cardTitle = 'S3 Object Copy' 31 | break 32 | case 's3-create-bucket': 33 | cardTitle = 'New S3 Bucket' 34 | break 35 | case 's3-list-buckets': 36 | cardTitle = 'S3 Bucket List' 37 | break 38 | case 's3-search': 39 | cardTitle = 'S3 Search Results' 40 | break 41 | case 'set-region': 42 | cardTitle = 'Region Switch' 43 | break 44 | case 'sg-rule-list': 45 | cardTitle = 'Security Group Rules' 46 | break 47 | default: 48 | cardTitle = intent 49 | } 50 | return cardTitle 51 | } 52 | 53 | 54 | const getVisual = () => { 55 | const visual = "" 56 | 57 | let rows = [] 58 | let cols = [] 59 | switch(intent){ 60 | 61 | case 'ec2-list': 62 | // console.log("Building visual for instance list") 63 | // console.log(data) 64 | const allInstanceData = JSON.parse(data.sessionAttributes.instances) 65 | if(allInstanceData.length === 0) return (null) 66 | 67 | allInstanceData.forEach(instance => { 68 | const AZ = instance.Placement.AvailabilityZone 69 | const state = instance.State.Name 70 | delete instance.Placement 71 | delete instance.State 72 | delete instance.KeyName 73 | instance.AZ = AZ 74 | instance.State = state 75 | 76 | if (!("PublicIpAddress" in instance)){ 77 | instance.PublicIpAddress = "N/A"; 78 | }else{ 79 | const publicIp = instance.PublicIpAddress 80 | delete instance.PublicIpAddress 81 | instance.PublicIpAddress = publicIp 82 | } 83 | // console.log(instance) 84 | rows.push(Object.values(instance)) 85 | }) 86 | cols = Object.keys(allInstanceData[0]) 87 | const rowIndex = cols.indexOf('InstanceId') 88 | return 89 | 90 | case 'ec2-create': 91 | const newInstancesData = JSON.parse(data.sessionAttributes.instances) 92 | return ( 93 | 94 | {newInstancesData.map((instanceData) => ( 95 | Instance {instanceData.InstanceId} was launched successfully with the following private IP: {instanceData.PrivateIpAddress} 96 | ))} 97 | 98 | ) 99 | 100 | case 'ec2-terminate': 101 | const terminatedInstancesData = JSON.parse(data.sessionAttributes.instances) 102 | return ( 103 | 104 | {terminatedInstancesData.map((instanceData) => ( 105 | Instance {instanceData.InstanceId} was successfully terminated 106 | ))} 107 | 108 | 109 | ) 110 | 111 | case 's3-copy-to-new-bucket': 112 | break 113 | 114 | case 's3-create-bucket': 115 | break 116 | 117 | case 's3-list-buckets': 118 | // console.log("Building visual for bucket list") 119 | const allBucketData = JSON.parse(data.sessionAttributes['s3-bucket-list']) 120 | // console.log(allBucketData) 121 | if(allBucketData.length === 0) return (null) 122 | cols = ['Index', 'Bucket Name', 'Creation Date', 'Versioning'] 123 | for (let i=0; i < allBucketData.length; i++){ 124 | rows.push([i+1, allBucketData[i].Name, allBucketData[i].CreationDate, allBucketData[i].Versioning.toString()]) 125 | } 126 | return 127 | 128 | case 's3-search': 129 | const searchResultsData = JSON.parse(data.sessionAttributes['s3-found-objects']) 130 | console.log(searchResultsData) 131 | if(searchResultsData.length === 0) return (null) 132 | cols = ['Object Key', 'Bucket Name', 'Last Modified', 'Size', 'Storage Class'] 133 | for (let i=0; i < searchResultsData.length; i++){ 134 | rows.push([searchResultsData[i].Key, searchResultsData[i].Bucket, searchResultsData[i].LastModified, searchResultsData[i]['Size'], searchResultsData[i].StorageClass]) 135 | } 136 | return 137 | 138 | case 'set-region': 139 | break 140 | 141 | case 'sg-rule-list': 142 | break 143 | 144 | default: 145 | return visual 146 | } 147 | return visual 148 | } 149 | 150 | 151 | return ( 152 | 153 | 154 | 155 | 156 | {getCardTitle()} 157 | 158 | 159 | {cardDescription} 160 | 161 | {getVisual()} 162 | 163 | {Object.keys(data).length > 0 && 164 | 165 | 166 | 167 | 168 | } 169 | 170 | 171 | 172 | ) 173 | } 174 | 175 | export default React.memo(ResponseCard) 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Cloud Assistant 2 | 3 | This application demonstrates how AWS Amplify can be used to build and deploy an automated AWS account management web application powered by a conversational AI built with Amazon Lex (Figure 1). This application (hereinafter referred to as the cloud assistant) provides users with a conversational interface leveraging Natural Language Understanding (NLU) to interact with various AWS services and automates/performs all sorts of simple or advanced operations on behalf of users. It allows users to manage their AWS accounts using natural language thus reducing time spent navigating the AWS console or figuring out the proper CLI commands. You can use this sample application as an example of how Amplify in combination with other AWS services can be used to build any other kind of assistant-powered web application.  4 | 5 | For more information, please read the associated AWS blog post here. 6 | 7 | ![Architecture Diagram](/static/images/architecture.png)*Figure 1: Application Architecture* 8 | 9 | This project uses React framework and leverages AWS Amplify. This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 10 | 11 | [[_TOC_]] 12 | 13 | ## Pre-Requisites 14 | - AWS Account 15 | - Install NodeJS and NPM 16 | - Install and configure AWS Amplify CLI 17 | - Install Amplify CLI using: ```npm install -g @aws-amplify/cli``` 18 | - Configure Amplify profile using: ```amplify configure``` 19 | - Prepare Python Environment 20 | - Install Python 3.8 21 | - Create virtualenv using: ```python -m venv pathToEnv``` 22 | - Activate python virtualenv using: ```source pathToEnv/Scripts/activate``` 23 | - Install pipenv in virtual environment with ```pip3 install pipenv``` 24 | 25 | > Important: make sure to run all subsequent Amplify commands with the python virtual environment activated! 26 | 27 | 28 | ## Step I - Initialize and deploy Amplify backend 29 | Initialize the Amplify project with: ```amplify init --app https://github.com/aws-samples/aws-amplify-cloud-assistant-app.git```. The command will: 30 | - Clone the repository into local directory (i.e., where command is run) 31 | - Initialize Amplify project: Make sure to select Amplify profile created during ```amplify configure``` step. 32 | - Deploy the application backend (Auth, Api, Lambda, Hosting) 33 | - Configure the frontend to use the backend 34 | - Start the application on a local development server 35 | 36 | After the command has completed, open the repository directory in your favorite code editor (e.g. Visual Studio Code) 37 | 38 | ## Step II - Create the assistant bot using Amazon Lex 39 | 1. Create a zip file containing the contents of “bot” directory 40 | 2. Navigate to the Amazon Lex console and click "Get Started" 41 | - Select "Import" from the "Action" dropdown to import the bot 42 | - Name the bot and upload the zip file created in step 1 43 | - Select Create a role with basic Amazon Lex permissions 44 | - Choose "No" under the Children's Online Privacy Protection Act (COPPA) 45 | - Set the session timeout to 5 minutes 46 | 3. Build the draft version of the bot 47 | - Select the newly created bot, and navigate to the "Intents" section of the "Draft version" 48 | - Select the "Build" button at the top and wait for the build to finish 49 | 4. Create a new bot version 50 | - Navigate to the "Bot versions" section from the left-hand menu 51 | - Click "Create version", and push the "Create" button 52 | 5. Create a new Alias for the bot to be used by the application 53 | - Navigate to the "Aliases" section of the menu and select "Create alias" 54 | - Name the alias "AliasForApp" Choose the newly created version (i.e. Version 1) 55 | - Navigate to the newly created alias, click on "English (US)" to choose the backend lambda 56 | - Choose the assistantFulfillment-{envName} lambda with "$LATEST" version, and save 57 | 58 | 59 | 60 | ## Step III - Integrate bot with application front-end 61 | 1. Take note of key bot information from the Lex console 62 | - Locate the Bot ID from the bot page 63 | - Locate the Bot Alias ID from the Alias page 64 | 2. Edit the App.js under the src folder of the repository 65 | - Update the bot ID (line 36) 66 | - Update the bot alias ID (line 37) 67 | - Update the region if bot was not deployed to us-east-1 68 | 3. Allow the Cognito Auth role access to the Lex bot 69 | - Navigate to the "Roles" section of the IAM console 70 | - Search for the "authRole". Select role matching this format: amplify-awsassistant-sampledev-{number}-authRole 71 | - Select "Attach Policies" from the "Add permissions" drop down. 72 | - Search for this policy "AmazonLexRunBotsOnly", select it, and click "Attach policies" 73 | 74 | 75 | ## Step IV - Publish and test application 76 | 1. Publish the application front-end using ```amplify publish``` 77 | 2. Navigate to the Amplify console, select the "awsassistant" app 78 | 3. Select the "Hosting environments" tab, and copy the Domain URL 79 | 4. Open a new web browser tab, and navigate to the copied URL 80 | 5. Select "Create account" to create a new account and login 81 | - Provide a username (should be an email), password, email, and phone number. Click "Create Account" 82 | - Due to the privileges given to authenticated users, a confirmation code will not be sent 83 | - Click "Back to Sign In", and follow next step to confirm user 84 | 6. To confirm the user, navigate to the Cognito service on the AWS console 85 | - Select "User Pools", and select the assistant user pool 86 | - Navigate to "Users" tab, and select the new user (should have an "Unconfirmed" status) 87 | - Click on "Actions" button at the top of the page, then "Confirm account", and confirm 88 | 7. Sign in to the application 89 | - Sign in with your previously created username and password 90 | - You can choose to configure account recovery or skip it 91 | 8. Select "NEW CONVERSATION" to create a new conversation with the assistant 92 | - Provide a title and description for the conversation, and click "Create" 93 | 9. Navigate to the newly created conversation 94 | - Click on "GO TO CONVERSATION" on your newly created conversation card 95 | - Try out the example commands below (e.g. "Launch 1 linux instance on t2 micro") 96 | 97 | ## Example Commands 98 | 99 | #### EC2 Instance Commands 100 | ``` 101 | > Can you show me all my ec2 instances? 102 | > Launch 1 linux instance on t2 micro 103 | > Launch 2 red hat instances on t3 micro 104 | > List ec2 instances 105 | > Find all red hat instances 106 | > Find all instances running on t2 micro 107 | > Are there any instances deployed to a public subnet? 108 | > Terminate these instances (Note: Make sure to run this command AFTER a previous command has already identified some instances such as any of the commands above) 109 | ``` 110 | 116 | #### Security Group Rules Commands 117 | ``` 118 | > Are there any wide open security group rules? (Note: if this command returns no rules, edit the default security group through the AWS console, and introduce some rules with access from 0.0.0.0 on a couple of ports (e.g. HTTP or SSH), then try the command again) 119 | > Modify security group rules to allow traffic from 10.11.12.13 120 | ``` 121 | 122 | #### S3 Commands 123 | ``` 124 | > Show me all my S3 buckets 125 | > Search for "py" in bucket 7 (Note: replace number with bucket index from the "list S3 buckets" command) 126 | > Search for "ppt" in bucket 7 (Note: replace number with bucket index from the "list S3 buckets" command) 127 | > Search for "ppt" across all buckets 128 | > Create a new S3 bucket (Note: the assistant will follow-up to ask you for a bucket name. Do not include any spaces in the bucket name) 129 | > Copy found files to new bucket 130 | ``` 131 | 132 | 133 | 134 | ## Cleanup 135 | To cleanup all created resources, perform the following:  136 | - Navigate to the Amplify console, select the “awsassistant” app, click the Actions dropdown and select “Delete App” 137 | - Navigate to the Amazon Lex console, select the assistant bot, click the Actions dropdown, and select “Delete” 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/components/Conversations.js: -------------------------------------------------------------------------------- 1 | 2 | // React imports 3 | import React, { useEffect } from 'react' 4 | import { useState } from 'react' 5 | import { Link } from 'react-router-dom' 6 | 7 | // Material UI Imports 8 | import { Box } from '@mui/system' 9 | import { Stack } from '@mui/material' 10 | import { Button, Card, CardMedia, CardContent, CardActions, Typography, Grid } from '@mui/material' 11 | // import { createTheme } from '@mui/system' 12 | import { TextField } from '@mui/material' 13 | import {Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle} from '@mui/material' 14 | 15 | // Amplify imports 16 | import {API, graphqlOperation} from 'aws-amplify' 17 | import Auth from '@aws-amplify/auth' 18 | 19 | // GraphQL code imports 20 | import { createConversation, deleteConversation } from '../graphql/mutations' 21 | import { conversationsByUser } from '../graphql/queries' 22 | 23 | // Other imports 24 | import image from '../images/banner.jpg' 25 | 26 | // // Create theme 27 | // const theme = createTheme({ 28 | // status: { 29 | // danger: '#e53e3e', 30 | // }, 31 | // palette: { 32 | // primary: { 33 | // main: '#0971f1', 34 | // darker: '#053e85', 35 | // }, 36 | // neutral: { 37 | // main: '#64748B', 38 | // contrastText: '#fff', 39 | // }, 40 | // }, 41 | // }); 42 | 43 | 44 | const createConversationHandler = async(handleCreateDialog, name, description, userConversations, setUserConversations) => { 45 | console.log('Create conversation wil happen here...') 46 | 47 | // Close dialog 48 | handleCreateDialog(false) 49 | 50 | // Create conversation 51 | let conversation = { 52 | name: name, 53 | description: description, 54 | user: Auth.user.attributes.email 55 | } 56 | console.log(conversation) 57 | console.log(Auth.user) 58 | 59 | // Call mutation 60 | let result = await API.graphql(graphqlOperation(createConversation, {input: conversation})) 61 | let newConversationObj = result.data.createConversation 62 | console.log(newConversationObj) 63 | 64 | // Update state information 65 | setUserConversations(userConversations => [...userConversations, newConversationObj]) 66 | } 67 | 68 | const fetchUserConversations = async() => { 69 | // Get username 70 | const userId = Auth.user.attributes.email 71 | 72 | // Call query 73 | let result = await API.graphql(graphqlOperation(conversationsByUser, {user: userId, sortDirection: "DESC"})) 74 | return result 75 | } 76 | 77 | const deleteConversationHandler = async(handleDeleteDialog, conversationToRemove, userConversations, setUserConversations) => { 78 | 79 | // Close dialog 80 | handleDeleteDialog(false) 81 | 82 | // API call 83 | console.log("Removing conversation: ", conversationToRemove.id) 84 | let result = await API.graphql(graphqlOperation(deleteConversation, {input: {id: conversationToRemove.id}})) 85 | 86 | // Remove from list 87 | setUserConversations(userConversations.filter((conversation) => conversation.id !== conversationToRemove.id)) 88 | 89 | } 90 | 91 | const Conversations = () => { 92 | 93 | // create conversation dialog state 94 | const [createDialogOpen, setCreateDialogOpen] = useState(false) 95 | const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) 96 | const [conversationToDelete, setConversationToDelete] = useState(null) 97 | const [conversationName, setConversationName] = useState("") 98 | const [conversationDescription, setConversationDescription] = useState("") 99 | const [userConversations, setUserConversations] = useState([]) 100 | 101 | // Effect to initialize conversations 102 | useEffect(() => { 103 | async function loadUserConversations() { 104 | const result = await fetchUserConversations() 105 | const userConversations = result.data.conversationsByUser.items 106 | console.log(userConversations) 107 | setUserConversations(userConversations) 108 | 109 | } 110 | loadUserConversations() 111 | }, []) 112 | 113 | 114 | // Create Dialog handler 115 | const handleCreateDialog = (desiredState) => { 116 | setCreateDialogOpen(desiredState) 117 | 118 | if(desiredState === false){ 119 | setConversationName("") 120 | setConversationDescription("") 121 | } 122 | } 123 | // Delete Dialog handler 124 | const handleDeleteDialog = (desiredState, conversation) => { 125 | setDeleteDialogOpen(desiredState) 126 | 127 | if(desiredState === true){ 128 | setConversationToDelete(conversation) 129 | } 130 | } 131 | 132 | return ( 133 |
134 | 135 | 136 | 143 | 144 | 145 | (handleCreateDialog(false))}> 146 | Create New Conversation 147 | 148 | 149 | To create a new conversation with the assistant, please provide a conversation title and description. 150 | 151 | 152 | {setConversationName(e.target.value)}} 162 | /> 163 | {setConversationDescription(e.target.value)}} 172 | /> 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | (handleDeleteDialog(false))} 184 | aria-labelledby="alert-dialog-title" 185 | aria-describedby="alert-dialog-description" 186 | > 187 | 188 | {"Delete Conversation?"} 189 | 190 | 191 | 192 | Are you sure you want to delete this conversation? All data and dialog information 193 | associated with the conversation will be permanently deleted! 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | Previous Conversations 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | {userConversations.map((conversation) => ( 213 | 214 | {/* */} 215 | 216 | 217 | 218 | 219 | {conversation.name} 220 | 221 | 222 | Description - {conversation.description} 223 | 224 | 225 | 226 | 227 | Created On: {conversation.createdAt} 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | {/* */} 245 | 246 | 247 | 248 | ))} 249 | 250 | 251 | {/* 252 | 253 | */} 254 | 255 |
256 | ) 257 | } 258 | 259 | export default Conversations 260 | -------------------------------------------------------------------------------- /src/components/Interact.js: -------------------------------------------------------------------------------- 1 | // React Components 2 | import * as React from 'react'; 3 | import { useState, useEffect, useRef } from 'react'; 4 | import { useParams } from 'react-router'; 5 | 6 | // Material Components 7 | import { Grid, Divider} from '@mui/material'; 8 | import { Typography } from '@mui/material'; 9 | import { Box, Drawer, Toolbar, List, ListItem, ListItemText } from '@mui/material'; 10 | import SendIcon from '@mui/icons-material/Send' 11 | import { IconButton } from '@mui/material'; 12 | import { ListItemAvatar, Avatar } from '@mui/material'; 13 | import { blue, orange } from '@mui/material/colors'; 14 | import ResponseCard from './ResponseCard'; 15 | import MyTextField from './MyTextField'; 16 | import { LinearProgress } from '@mui/material'; 17 | 18 | // Amplify Imports 19 | import Interactions from '@aws-amplify/interactions'; 20 | import Auth from '@aws-amplify/auth'; 21 | 22 | // GraphQL imports 23 | import {API, graphqlOperation} from 'aws-amplify' 24 | import { getConversation } from '../graphql/queries'; 25 | import { createUtterance } from '../graphql/mutations'; 26 | 27 | 28 | // Initial values for state variables 29 | const chatWidth = 360 30 | const initialDialogs = [ 31 | { 32 | text: "Hello, How can I help you today?", 33 | author: "AWS" 34 | }, 35 | ] 36 | const initialAnswers = [ 37 | { 38 | intent: "Introducing the Cloud Assistant", 39 | description: "The Cloud Assistant is an AI designed to help you configure your AWS account using natural language. The assistant leverages advanced NLU (Natural Language Understanding) models as well as a flexible fullfillment serverless backend to perform all sorts of simple or advanced configurations in your AWS account on your behalf.", 40 | data: {} 41 | }, 42 | ] 43 | 44 | 45 | // Component for AWS dialog item 46 | const AwsDialogItem = ({text}) => { 47 | return ( 48 | 49 | 50 | AWS 51 | 52 | {text} 55 | } 56 | /> 57 | 58 | ) 59 | } 60 | 61 | // Component for user dialog item 62 | const MeDialogItem = ({text, reusePreviousDialog, userInitials}) => ( 63 | 64 | {text} 67 | } 68 | /> 69 | 70 | {userInitials} 71 | 72 | 73 | ) 74 | 75 | const fetchConversationDetails = async(conversationId) => { 76 | 77 | // Make API call 78 | console.log('Fetching conversation: ', conversationId) 79 | let result = await API.graphql(graphqlOperation(getConversation, {id: conversationId})) 80 | return result 81 | 82 | } 83 | 84 | const Interact = () => { 85 | 86 | // Get parameters 87 | let { conversationId } = useParams() 88 | 89 | // Define state variables here 90 | const [dialogs, setDialogs] = useState(initialDialogs) 91 | const [newQuery, setNewQuery] = useState("") 92 | const [answers, setAnswers] = useState(initialAnswers) 93 | const [loading, setLoading] = useState(false) 94 | const [userInitials, setUserInitials] = useState("") 95 | const [conversation, setConversation] = useState(null) 96 | 97 | // References 98 | const scrollRef = useRef(null) 99 | const dialogScrollRef = useRef(null) 100 | 101 | // Effects 102 | useEffect(() => { 103 | if (scrollRef.current) { 104 | scrollRef.current.scrollIntoView({behaviour: "smooth"}) 105 | } 106 | }, [answers]) 107 | 108 | useEffect(() => { 109 | if (dialogScrollRef.current) { 110 | dialogScrollRef.current.scrollIntoView({behaviour: "smooth"}) 111 | } 112 | }, [dialogs]) 113 | 114 | // Effect for loading user 115 | useEffect(() => { 116 | let username = Auth.user.attributes.email 117 | console.log('Logged username: ', username) 118 | const userInitials = username.substring(0, 2).toUpperCase() 119 | console.log('Logged user initials: ', userInitials) 120 | setUserInitials(userInitials) 121 | }, []) 122 | 123 | // Effect for loading conversation 124 | useEffect(() => { 125 | async function loadConversationDetails(){ 126 | let result = await fetchConversationDetails(conversationId) 127 | 128 | // set conversation state 129 | if(result) { 130 | let conversation = result.data.getConversation 131 | setConversation(conversation) 132 | console.log(conversation) 133 | 134 | // Get utterances 135 | const utterances = conversation.utterances.items 136 | 137 | // Set dialogs state 138 | let dialogsArray = initialDialogs.concat(utterances) 139 | setDialogs(dialogsArray) 140 | 141 | // Set answers state 142 | let answersArray = [] 143 | utterances.forEach((utterance) => { 144 | if (utterance.author !== "AWS") return 145 | if (utterance.data === "{}") return 146 | const responseData = JSON.parse(utterance.data) 147 | console.log(responseData) 148 | answersArray.push({ 149 | intent: responseData.sessionState.intent.name, 150 | description: responseData.messages[0].content, 151 | data: responseData.sessionState 152 | }) 153 | }) 154 | console.log('Cards will be built from the answers below') 155 | console.log(answersArray) 156 | 157 | // Set the answers state 158 | answersArray.unshift(initialAnswers[0]) 159 | setAnswers(answersArray) 160 | 161 | } 162 | 163 | } 164 | loadConversationDetails() 165 | }, []) 166 | 167 | 168 | // Define function for creating dialog item 169 | const createDialogEntry = async(author, text, data, conversationId) => { 170 | 171 | // Create dialog object 172 | const newDialog = { 173 | author: author, 174 | text: text 175 | } 176 | 177 | // Add dialog object to dialogs state 178 | setDialogs(prevDialogs => [...prevDialogs, newDialog]) 179 | console.log('New dialog was created and added to state:' + newDialog) 180 | 181 | // API call to persist in DB 182 | let conversation = { 183 | author: author, 184 | text: text, 185 | data: data, 186 | conversationId 187 | } 188 | let result = await API.graphql(graphqlOperation(createUtterance, {input: conversation})) 189 | console.log("Create utterance in this conversation") 190 | console.log(result) 191 | 192 | } 193 | 194 | // Define functions that update state 195 | const sendQuery = async () => { 196 | 197 | // Create dialog entry 198 | await createDialogEntry(userInitials, newQuery, {}, conversationId) 199 | 200 | // Reset the query field and show loader 201 | setNewQuery("") 202 | setLoading(true) 203 | 204 | // Send query to assistant 205 | const response = await Interactions.send("AWS-Configurator", newQuery) 206 | 207 | // // Get IP address 208 | // const res = await axios.get('https://geolocation-db.com/json/') 209 | // console.log(res.data); 210 | 211 | 212 | // Remove load and log response 213 | setLoading(false) 214 | console.log(response) 215 | 216 | // Check if messages exist 217 | if(response.messages) { 218 | 219 | // Add answer to answer state if dialog is closed 220 | if (response.sessionState.dialogAction.type === "Close") { 221 | const newAnswer = {intent: response.sessionState.intent.name, description: response.messages[0].content, data: response.sessionState} 222 | setAnswers(prevAnswers => [...prevAnswers, newAnswer]) 223 | console.log(answers) 224 | await createDialogEntry('AWS', response.messages[0].content, JSON.stringify({messages: response.messages, sessionState: response.sessionState}), conversationId) 225 | }else{ 226 | await createDialogEntry('AWS', response.messages[0].content, {}, conversationId) 227 | } 228 | } 229 | // Fall back intent 230 | else{ 231 | const fallbackText = "Sorry, can you say that again?" 232 | await createDialogEntry('AWS', fallbackText, {}, conversationId) 233 | } 234 | 235 | } 236 | 237 | // Send query if users clicks on the ENTER key 238 | const handleKeyPress = (e) => { 239 | // console.log('--->A key was pressed', e.keyCode) 240 | if(e.keyCode === 13){ 241 | console.log('value', e.target.value); 242 | sendQuery() 243 | } 244 | } 245 | 246 | // Send button component 247 | const SendButton = () => ( 248 | 249 | 250 | 251 | ) 252 | 253 | // Initialize query text with previous query 254 | const reusePreviousDialog = (e) => { 255 | console.log(e) 256 | setNewQuery(e.target.textContent) 257 | } 258 | 259 | return ( 260 | 261 | 262 | {/* DRAWER SECTION - DIALOG SECTION */} 263 | 274 | 275 | 276 | 277 | {dialogs.map((dialog, index) => ( 278 | 279 | {dialog.author === "AWS" ? : } 280 | 281 | 282 | ))} 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | {/* MAIN CONTENT SECTION FOR SHOWING ASSISTANT RESPONSE DATA */} 291 | 292 | {/*

293 | {conversation.name} 294 |

*/} 295 | 296 | {answers.map((answer, index) => ( 297 | <> 298 | 299 | 300 | ))} 301 | 302 | {loading && } 303 | 304 | 305 | 306 | 307 | 308 |
309 |
310 | ) 311 | } 312 | 313 | export default Interact 314 | 315 | -------------------------------------------------------------------------------- /amplify/backend/function/assistantFulfillment/src/index.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code sample demonstrates an implementation of the Lex Code Hook Interface 3 | in order to serve a bot which manages dentist appointments. 4 | Bot, Intent, and Slot models which are compatible with this sample can be found in the Lex Console 5 | as part of the 'MakeAppointment' template. 6 | 7 | For instructions on how to set up and test this bot, as well as additional samples, 8 | visit the Lex Getting Started documentation http://docs.aws.amazon.com/lex/latest/dg/getting-started.html. 9 | """ 10 | 11 | import json 12 | import dateutil.parser 13 | import datetime 14 | import time 15 | import os 16 | import math 17 | import random 18 | import logging 19 | import boto3 20 | import copy 21 | from botocore.config import Config 22 | from botocore.exceptions import ClientError 23 | 24 | logger = logging.getLogger() 25 | logger.setLevel(logging.INFO) 26 | 27 | 28 | 29 | """ --- Helpers to build responses which match the structure of the necessary dialog actions --- """ 30 | 31 | 32 | def elicit_slot(session_attributes, intent_name, slots, slot_to_elicit, message, response_card): 33 | return { 34 | 'sessionAttributes': session_attributes, 35 | 'dialogAction': { 36 | 'type': 'ElicitSlot', 37 | 'intentName': intent_name, 38 | 'slots': slots, 39 | 'slotToElicit': slot_to_elicit, 40 | 'message': message, 41 | 'responseCard': response_card 42 | } 43 | } 44 | 45 | 46 | def confirm_intent(session_attributes, intent_name, slots, message, response_card): 47 | return { 48 | 'sessionAttributes': session_attributes, 49 | 'dialogAction': { 50 | 'type': 'ConfirmIntent', 51 | 'intentName': intent_name, 52 | 'slots': slots, 53 | 'message': message, 54 | 'responseCard': response_card 55 | } 56 | } 57 | 58 | 59 | def close(session_attributes, fulfillment_state, message): 60 | response = { 61 | 'sessionAttributes': session_attributes, 62 | 'dialogAction': { 63 | 'type': 'Close', 64 | 'fulfillmentState': fulfillment_state, 65 | 'message': message 66 | } 67 | } 68 | 69 | return response 70 | 71 | 72 | def delegate(session_attributes, slots): 73 | return { 74 | 'sessionAttributes': session_attributes, 75 | 'dialogAction': { 76 | 'type': 'Delegate', 77 | 'slots': slots 78 | } 79 | } 80 | 81 | 82 | def build_response_card(title, subtitle, options): 83 | """ 84 | Build a responseCard with a title, subtitle, and an optional set of options which should be displayed as buttons. 85 | """ 86 | buttons = None 87 | if options is not None: 88 | buttons = [] 89 | for i in range(min(5, len(options))): 90 | buttons.append(options[i]) 91 | 92 | return { 93 | 'contentType': 'application/vnd.amazonaws.card.generic', 94 | 'version': 1, 95 | 'genericAttachments': [{ 96 | 'title': title, 97 | 'subTitle': subtitle, 98 | 'buttons': buttons 99 | }] 100 | } 101 | 102 | 103 | 104 | def buildConfig(intent_request): 105 | 106 | # Get session attributes 107 | sessionAttributes = intent_request['sessionState'].get('sessionAttributes') 108 | 109 | # Set region to virginia if no session attributes or region variable 110 | if not sessionAttributes or sessionAttributes.get('region') is None: 111 | region = 'us-east-1' 112 | else: 113 | region = sessionAttributes['region'] 114 | 115 | # Create dict config 116 | my_config = Config( 117 | region_name = region, 118 | signature_version = 'v4', 119 | retries = { 120 | 'max_attempts': 10, 121 | 'mode': 'standard' 122 | } 123 | ) 124 | 125 | # Return config 126 | return my_config 127 | 128 | 129 | """ --- Intents --- """ 130 | def listInstances(intent_request): 131 | logger.info('Received a request to list EC2 instances') 132 | 133 | # Build config 134 | config = buildConfig(intent_request) 135 | 136 | # Create client 137 | ec2 = boto3.client('ec2', config = config) 138 | 139 | # Get optional filter variables 140 | slots = intent_request['sessionState']['intent']['slots'] 141 | instanceAmi = slots['ami'] 142 | instanceType = slots['instanceType'] 143 | subnetType = slots['subnetType'] 144 | 145 | # Build list of filters 146 | filters = [] 147 | if instanceAmi is not None: 148 | filters.append({ 149 | 'Name': 'image-id', 150 | 'Values': [instanceAmi['value']['interpretedValue']] 151 | }) 152 | 153 | if instanceType is not None: 154 | filters.append({ 155 | 'Name': 'instance-type', 156 | 'Values': [instanceType['value']['interpretedValue']] 157 | }) 158 | 159 | 160 | 161 | # Describe instances 162 | response = ec2.describe_instances(Filters = filters) 163 | instancesFilteredAttributes = filterInstanceAttributes(response) 164 | 165 | # Additional filtering (for filters that requires additional API calls) 166 | if subnetType is not None: 167 | instancesFilteredAttributes = filterInstancesBySubnetType(ec2, instancesFilteredAttributes, subnetType['value']['interpretedValue']) 168 | 169 | # Extract instance Ids 170 | instanceIds = [instance['InstanceId'] for instance in instancesFilteredAttributes] 171 | logger.info(instancesFilteredAttributes) 172 | 173 | # Add instance to session attributes 174 | sessionAttributes = updateSessionAttributes(intent_request, 'instances', json.dumps(instancesFilteredAttributes, default=str)) 175 | 176 | # Prepare resulting message 177 | if len(filters) > 0 or subnetType is not None: 178 | # message = "You have a total of {} instances based on your filters. InstanceIds are: {}. Additional information is attached.".format(len(instancesFilteredAttributes), instanceIds) 179 | message = "You have a total of {} instances based on your filters. Additional information is attached".format(len(instancesFilteredAttributes)) 180 | else: 181 | # message = "You have a total of {} instances. InstanceIds are: {}. Additional information is attached.".format(len(instancesFilteredAttributes), instanceIds) 182 | message = "You have a total of {} instances. Additional information is attached.".format(len(instancesFilteredAttributes)) 183 | 184 | 185 | 186 | # Add selected-instances context 187 | # contexts = [{ 188 | # 'name': 'selected-instances', 189 | # 'contextAttributes': {}, 190 | # 'timeToLive': { 191 | # 'timeToLiveInSeconds': 3600, 192 | # 'turnsToLive': 5 193 | # } 194 | # }] 195 | 196 | 197 | # Return response 198 | intentName = intent_request['sessionState']['intent']['name'] 199 | return prepareResponse(intentName, sessionAttributes, message, []) 200 | 201 | 202 | 203 | def filterInstanceAttributes(ec2DescribeResponse): 204 | 205 | # Aggregate instances 206 | instances = [] 207 | for reservation in ec2DescribeResponse.get('Reservations'): 208 | reservationInstances = reservation.get('Instances') 209 | instances += reservationInstances 210 | 211 | # Filter instance attributes 212 | desiredAttributes = ['ImageId', 'InstanceId', 'InstanceType', 'State', 'KeyName', 'LaunchTime', 'Placement', 'PrivateIpAddress', 'PublicIpAddress', 'SubnetId'] 213 | instancesFilteredAttributes = [{attribute:value for attribute, value in instance.items() if attribute in desiredAttributes} for instance in instances] 214 | 215 | # Eliminate terminated instances 216 | instancesFilteredAttributes = [instance for instance in instancesFilteredAttributes if instance['State']['Name'] != 'terminated'] 217 | 218 | # Return 219 | return instancesFilteredAttributes 220 | 221 | 222 | def filterInstancesBySubnetType(ec2, instances, targetSubnetType): 223 | 224 | # Initialize results 225 | filteredInstances = [] 226 | 227 | # Loop through instances 228 | for instance in instances: 229 | 230 | # Get subnet type for instance 231 | subnetType = getSubnetType(ec2, instance['SubnetId']) 232 | print(subnetType, targetSubnetType) 233 | if subnetType != targetSubnetType: continue 234 | 235 | # Store in filtered instances 236 | instance['SubnetType'] = subnetType 237 | filteredInstances.append(instance) 238 | 239 | # Return instances 240 | return filteredInstances 241 | 242 | 243 | def getSubnetType(ec2, subnetId): 244 | 245 | # Get subnet's route table 246 | response = ec2.describe_route_tables(Filters = [{'Name': 'association.subnet-id', 'Values': [subnetId]}]) 247 | RouteTable = response['RouteTables'] 248 | 249 | # Check if subnet is associated with main table 250 | if not RouteTable: 251 | # print('Subnet is associated with main route table') 252 | 253 | # Get main route table 254 | response2 = ec2.describe_route_tables(Filters = [{'Name': 'association.main', 'Values': ['true']}]) 255 | routes = response2['RouteTables'][0]['Routes'] 256 | 257 | # Check if routes include igw 258 | isPublic = any([route['GatewayId'].startswith('igw-') for route in routes]) 259 | 260 | else: 261 | 262 | # Get route table routes 263 | routes = RouteTable[0]['Routes'] 264 | 265 | # Check if routes include igw 266 | isPublic = any([route['GatewayId'].startswith('igw-') for route in routes]) 267 | 268 | 269 | return 'public' if isPublic else 'private' 270 | 271 | def createInstance(intent_request): 272 | logger.info('Received a request to create an EC2 instance') 273 | 274 | # Build config and create ec2 resource 275 | config = buildConfig(intent_request) 276 | ec2Res = boto3.resource('ec2', config = config) 277 | ec2 = boto3.client('ec2', config = config) 278 | 279 | # Extract slot variables 280 | slots = intent_request['sessionState']['intent']['slots'] 281 | instanceAmi = slots['ami']['value']['interpretedValue'] 282 | instanceType = slots['instanceType']['value']['interpretedValue'] 283 | instanceCount = int(slots['count']['value']['interpretedValue']) 284 | 285 | # Get default security group id 286 | securityGroupId = [group['GroupId'] for group in ec2.describe_security_groups()['SecurityGroups'] if group['GroupName'] == 'default'][0] 287 | 288 | # Create the instance 289 | response = ec2Res.create_instances(ImageId = instanceAmi, \ 290 | InstanceType = instanceType, SecurityGroupIds = [securityGroupId], \ 291 | MinCount = instanceCount, MaxCount = instanceCount) 292 | newInstanceIds = [instance.instance_id for instance in response] 293 | time.sleep(0.5) 294 | 295 | # Describe newly created instances & extract subset of attributes 296 | describeResponse = ec2.describe_instances(InstanceIds = [instance.instance_id for instance in response]) 297 | instancesFilteredAttributes = filterInstanceAttributes(describeResponse) 298 | 299 | # Store created instances in session attriubtes 300 | sessionAttributes = updateSessionAttributes(intent_request, 'instances', json.dumps(instancesFilteredAttributes, default=str)) 301 | 302 | # Return response 303 | intentName = intent_request['sessionState']['intent']['name'] 304 | message = '{} instances were launched with the following ids: {}'.format(instanceCount, newInstanceIds) 305 | 306 | logger.info(message) 307 | return prepareResponse(intentName, sessionAttributes, message) 308 | 309 | 310 | 311 | def terminateInstances(intent_request): 312 | logger.info('Received a request to terminate an EC2 instance') 313 | 314 | # Build config and create ec2 resource 315 | config = buildConfig(intent_request) 316 | ec2 = boto3.client('ec2', config = config) 317 | 318 | 319 | # Extract selected instances from session attributes 320 | sessionAttributes = intent_request['sessionState'].get('sessionAttributes') 321 | logger.info(sessionAttributes) 322 | selectedInstances = json.loads(sessionAttributes['instances']) 323 | instanceIds = [instance['InstanceId'] for instance in selectedInstances] 324 | 325 | # Create the instance 326 | response = ec2.terminate_instances(InstanceIds = instanceIds) 327 | 328 | # Create message 329 | message = 'These instances were terminated: {}'.format(instanceIds) 330 | logger.info(message) 331 | 332 | # Return response 333 | intentName = intent_request['sessionState']['intent']['name'] 334 | sessionAttributes = intent_request['sessionState'].get('sessionAttributes') 335 | return prepareResponse(intentName, sessionAttributes, message) 336 | 337 | 338 | 339 | def changeRegion(intent_request): 340 | logger.info('Received a request to change the region') 341 | 342 | # Get region slot 343 | slots = intent_request['sessionState']['intent']['slots'] 344 | region = slots['region']['value']['interpretedValue'] 345 | 346 | # Change region in session attributes 347 | sessionAttributes = updateSessionAttributes(intent_request, 'region', region) 348 | 349 | # Prepare resulting message 350 | message = "Assistant is now operating in the {} region".format(region) 351 | intentName = intent_request['sessionState']['intent']['name'] 352 | 353 | return prepareResponse(intentName, sessionAttributes, message) 354 | 355 | 356 | 357 | def isOpenRule(rule): 358 | 359 | # Get ip ranges 360 | ipRanges = rule['IpRanges'] 361 | if not ipRanges: return False 362 | 363 | # Check ip 364 | if ipRanges[0]['CidrIp'] == '0.0.0.0/0': return True 365 | return False 366 | 367 | def listRules(intent_request): 368 | logger.info('Received a request to list security group rules') 369 | 370 | # Build config and create ec2 resource 371 | config = buildConfig(intent_request) 372 | ec2Res = boto3.resource('ec2', config = config) 373 | ec2 = boto3.client('ec2', config = config) 374 | 375 | # Get default security group id 376 | securityGroupId = [group['GroupId'] for group in ec2.describe_security_groups()['SecurityGroups'] if group['GroupName'] == 'default'][0] 377 | 378 | # Find security group resource & get inbound rules 379 | sg = ec2Res.SecurityGroup(securityGroupId) 380 | inboundRules = sg.ip_permissions 381 | logger.info(inboundRules) 382 | 383 | # Identify open rules 384 | openRules = [rule for rule in inboundRules if isOpenRule(rule)] 385 | openPorts = [rule['ToPort'] for rule in openRules] 386 | 387 | # Update session attributes 388 | sessionAttributes = updateSessionAttributes(intent_request, 'sg-open-rules', json.dumps(openRules, default=str)) 389 | 390 | # Create message 391 | message = 'There are {} security group rules with unrestricted inbound traffic to the following ports: {}'.format(len(openRules), openPorts) 392 | logger.info(message) 393 | 394 | # Return response 395 | intentName = intent_request['sessionState']['intent']['name'] 396 | return prepareResponse(intentName, sessionAttributes, message) 397 | 398 | 399 | def listS3Buckets(intent_request): 400 | logger.info('Received a request to list all S3 buckets') 401 | 402 | # Build config and create s3 resource dfg 403 | config = buildConfig(intent_request) 404 | s3 = boto3.client('s3') 405 | 406 | # List all buckets 407 | buckets = s3.list_buckets()['Buckets'] 408 | bucketNames = [bucket['Name'] for bucket in buckets] 409 | bucketList = [str(idx+1) + ') ' + bucket['Name'] for idx, bucket in enumerate(buckets)] 410 | bucketList = '\n'.join(bucketList) 411 | 412 | # Store versioning information 413 | for i in range(len(buckets)): 414 | buckets[i]['Versioning'] = True if s3.get_bucket_versioning(Bucket=buckets[i]['Name']).get('Status') == 'Enabled' else False 415 | 416 | # Update session attributes 417 | sessionAttributes = updateSessionAttributes(intent_request, 's3-bucket-list', json.dumps(buckets, default=str)) 418 | 419 | # Create message 420 | # message = 'There are {} S3 buckets. They are listed below: \n'.format(len(bucketNames)) + bucketList 421 | message = 'There are {} S3 buckets. Bucket names and other information is attached.'.format(len(bucketNames)) 422 | logger.info(message) 423 | 424 | # Return response 425 | intentName = intent_request['sessionState']['intent']['name'] 426 | return prepareResponse(intentName, sessionAttributes, message) 427 | 428 | 429 | 430 | def searchS3(intent_request): 431 | logger.info('Received a request to search in S3') 432 | 433 | # Build config and create s3 resource 434 | config = buildConfig(intent_request) 435 | s3 = boto3.client('s3') 436 | 437 | # List all buckets 438 | buckets = s3.list_buckets()['Buckets'] 439 | bucketNames = [bucket['Name'] for bucket in buckets] 440 | 441 | # Get available slots 442 | slots = intent_request['sessionState']['intent']['slots'] 443 | pattern = slots['objName']['value']['originalValue'] 444 | bucketIndex = None 445 | if slots['bucketIndex'] is not None: bucketIndex = slots['bucketIndex']['value']['interpretedValue'] 446 | 447 | # Initialize results 448 | items = [] 449 | maxPerBucket = 10 450 | printableItems = '' 451 | 452 | # Search in specific bucket 453 | if bucketIndex is not None: 454 | 455 | # Get bucket name 456 | logger.info('Search in single bucket') 457 | bucketIndex = int(bucketIndex) - 1 458 | bucketName = bucketNames[bucketIndex] 459 | 460 | # Search bucket 461 | items = searchBucket(s3, bucketName, pattern) 462 | itemKeys = [str(idx+1) + ') ' + item['Key'] for idx, item in enumerate(items)] 463 | 464 | logger.info(items) 465 | if items: printableItems = '\n'.join(itemKeys) 466 | 467 | # Create message 468 | logger.info(items) 469 | # message = '{} objects were found containing the keyword "{}" in bucket {}. Items are listed below: {}'.format(len(items), pattern, bucketName, printableItems) 470 | message = '{} objects were found containing the keyword "{}" in bucket {}. Search results are attached.'.format(len(items), pattern, bucketName) 471 | 472 | 473 | # Search across all buckets (powerful) 474 | else: 475 | 476 | # Loop through buckets 477 | logger.info('Search in all buckets') 478 | for bucketName in bucketNames: 479 | 480 | # Skip admin buckets 481 | if 'isengard' in bucketName.lower(): continue 482 | 483 | # Search in bucket 484 | logger.info('Searching in bucket {}'.format(bucketName)) 485 | bucketItems = searchBucket(s3, bucketName, pattern) 486 | if not bucketItems: continue 487 | 488 | # Append items 489 | items += bucketItems[:maxPerBucket] 490 | 491 | 492 | # Create message 493 | itemKeys = [str(idx+1) + ') ' + item['Key'] for idx, item in enumerate(items)] 494 | if items: printableItems = '\n'.join(itemKeys) 495 | # message = '{} objects were found containing the keyword "{}" across all buckets. Items are listed below: {}'.format(len(items), pattern, printableItems) 496 | message = '{} objects were found containing the keyword "{}" across all buckets. Search results are attached.'.format(len(items), pattern) 497 | 498 | #Update session attributes 499 | sessionAttributes = updateSessionAttributes(intent_request, 's3-found-objects', json.dumps(items, default=str)) 500 | 501 | # Log message 502 | logger.info(message) 503 | 504 | # Return response 505 | intentName = intent_request['sessionState']['intent']['name'] 506 | return prepareResponse(intentName, sessionAttributes, message) 507 | 508 | 509 | def searchBucket(client, bucketName, pattern): 510 | 511 | # Get paginator 512 | paginator = client.get_paginator('list_objects_v2') 513 | page_iterator = paginator.paginate(Bucket=bucketName) 514 | 515 | # Search for pattern 516 | items = [] 517 | objects = page_iterator.search("Contents[?contains(Key, `{}`) || contains(Key, `{}`)][]".format(pattern, pattern.capitalize())) 518 | for item in objects: 519 | if item is None: continue # here 520 | item['Bucket'] = bucketName 521 | items.append(item) 522 | 523 | # Return items 524 | return items 525 | 526 | 527 | def createS3Bucket(intent_request): 528 | logger.info('Received a request to create an S3 bucket') 529 | 530 | # Build config and create s3 resource 531 | config = buildConfig(intent_request) 532 | s3Res = boto3.resource('s3') 533 | 534 | # Define parameters 535 | acl = 'private' 536 | 537 | # Read bucket name from slots 538 | slots = intent_request['sessionState']['intent']['slots'] 539 | bucketName = slots['bucketName']['value']['originalValue'] 540 | bucketName = bucketName.lower() 541 | 542 | # Create bucket 543 | try: 544 | bucket = s3Res.create_bucket(ACL=acl, Bucket=bucketName) #CreateBucketConfiguration= {'LocationConstraint': config.region_name} 545 | except ClientError as err: 546 | logger.info(err.response) 547 | # if err.response['Error']['Code'] == 'BucketAlreadyExists': 548 | try: 549 | logger.info('Retrying bucket creation with a random bucket suffix...') 550 | timeSuffix = datetime.datetime.now().strftime('-%m-%d-%Y-%H-%M-%S') 551 | bucket = s3Res.create_bucket(ACL=acl, Bucket=bucketName + timeSuffix) 552 | except Exception as ex: 553 | logger.info(ex) 554 | logger.info('Some other error happened...exiting') 555 | return 556 | 557 | # Update session attributes 558 | sessionAttributes = updateSessionAttributes(intent_request, 's3-new-bucket', bucket.name) 559 | 560 | # Create message 561 | message = 'A new S3 bucket was created with the following name: {}'.format(bucket.name) 562 | logger.info(message) 563 | 564 | # Return response 565 | intentName = intent_request['sessionState']['intent']['name'] 566 | return prepareResponse(intentName, sessionAttributes, message) 567 | 568 | 569 | def copyToNewBucket(intent_request): 570 | logger.info('Received a request to copy files to a new S3 bucket') 571 | 572 | # Build config and create s3 resource 573 | config = buildConfig(intent_request) 574 | s3Res = boto3.resource('s3') 575 | 576 | # Retrive new bucket and search results from session attributes 577 | sessionAttributes = intent_request['sessionState'].get('sessionAttributes') 578 | logger.info(sessionAttributes) 579 | newBucketName = sessionAttributes['s3-new-bucket'] 580 | s3Objects = json.loads(sessionAttributes['s3-found-objects']) 581 | 582 | # Get new bucket resource 583 | newbucket = s3Res.Bucket(newBucketName) 584 | 585 | 586 | # Copy files to new bucket 587 | for obj in s3Objects: 588 | 589 | # create source copy 590 | copy_source = { 591 | 'Bucket': obj['Bucket'], 592 | 'Key': obj['Key'] 593 | } 594 | 595 | # Copy to bucket 596 | newbucket.copy(copy_source, obj['Key']) 597 | 598 | 599 | # Create message 600 | message = '{} target files/objects were successfully copied to new bucket {}'.format(len(s3Objects), newBucketName) 601 | logger.info(message) 602 | 603 | # Return response 604 | intentName = intent_request['sessionState']['intent']['name'] 605 | return prepareResponse(intentName, sessionAttributes, message) 606 | 607 | 608 | 609 | def replaceRules(intent_request): 610 | logger.info('Received a request to modify security group rules') 611 | myIpAddress = '76.243.176.78/32' 612 | 613 | # Build config and create ec2 resource 614 | config = buildConfig(intent_request) 615 | ec2Res = boto3.resource('ec2', config = config) 616 | ec2 = boto3.client('ec2', config = config) 617 | 618 | # Get default security group id 619 | securityGroupId = [group['GroupId'] for group in ec2.describe_security_groups()['SecurityGroups'] if group['GroupName'] == 'default'][0] 620 | 621 | # Extract slot values 622 | slots = intent_request['sessionState']['intent']['slots'] 623 | allowedIpAddress = myIpAddress if slots['ipAddress'] is None else slots['ipAddress']['value']['originalValue'] + '/32' 624 | 625 | 626 | # Extract selected SG rules from session attributes 627 | sessionAttributes = intent_request['sessionState'].get('sessionAttributes') 628 | logger.info(sessionAttributes) 629 | selectedRules = json.loads(sessionAttributes['sg-open-rules']) 630 | logger.info(selectedRules) 631 | 632 | # Modify rules 633 | modifiedRules = [] 634 | for rule in selectedRules: 635 | modifiedRule = copy.deepcopy(rule) 636 | modifiedRule['IpRanges'][0]['CidrIp'] = allowedIpAddress 637 | modifiedRules.append(modifiedRule) 638 | 639 | # Revoke previous rules, and authorize modified rules 640 | sg = ec2Res.SecurityGroup(securityGroupId) 641 | sg.revoke_ingress(IpPermissions = selectedRules) 642 | sg.authorize_ingress(IpPermissions = modifiedRules) 643 | 644 | 645 | # Create message 646 | message = 'Selected security group rules have been modified to allow traffic from: {}'.format(allowedIpAddress) 647 | logger.info(message) 648 | 649 | # Return response 650 | intentName = intent_request['sessionState']['intent']['name'] 651 | return prepareResponse(intentName, sessionAttributes, message) 652 | 653 | 654 | 655 | def updateSessionAttributes(intent_request, paramName, paramValue): 656 | 657 | sessionAttributes = intent_request['sessionState'].get('sessionAttributes') 658 | if not sessionAttributes: sessionAttributes = {} 659 | sessionAttributes[paramName] = paramValue 660 | return sessionAttributes 661 | 662 | 663 | 664 | 665 | def prepareResponse(intentName, sessionAttributes, message, contexts = []): 666 | 667 | return { 668 | 'sessionState': { 669 | 'activeContexts': contexts, 670 | 'dialogAction': {'type': 'Close'}, 671 | 'intent': { 672 | 'name': intentName, 673 | 'state': 'Fulfilled' 674 | }, 675 | 'sessionAttributes': sessionAttributes, 676 | }, 677 | 678 | 'messages': [ 679 | { 680 | 'contentType': 'PlainText', 681 | 'content': message 682 | }, 683 | # { 684 | # 'contentType': 'PlainText', 685 | # 'content': "A secondary message" 686 | # } 687 | ] 688 | } 689 | 690 | 691 | def dispatch(intent_request): 692 | 693 | # Log request 694 | # logger.debug('dispatch userId={}, intentName={}'.format(intent_request['userId'], intent_request['currentIntent']['name'])) 695 | 696 | # Get intent name 697 | # intent_name = intent_request['currentIntent']['name'] 698 | intent_name = intent_request['sessionState']['intent']['name'] 699 | 700 | # Dispatch ec2-list intent 701 | if intent_name == 'ec2-list': 702 | return listInstances(intent_request) 703 | 704 | # Dispatch ec2-create intent 705 | if intent_name == 'ec2-create': 706 | return createInstance(intent_request) 707 | 708 | # Dispatch ec2-terminate intent 709 | if intent_name == 'ec2-terminate': 710 | return terminateInstances(intent_request) 711 | 712 | # Dispatch set-region intent 713 | if intent_name == 'set-region': 714 | return changeRegion(intent_request) 715 | 716 | # Dispatch sg-rule-list intent 717 | if intent_name == 'sg-rule-list': 718 | return listRules(intent_request) 719 | 720 | # Dispatch sg-rule-list intent 721 | if intent_name == 'sg-rule-replace': 722 | return replaceRules(intent_request) 723 | 724 | # Dispatch s3-list-buckets intent 725 | if intent_name == 's3-list-buckets': 726 | return listS3Buckets(intent_request) 727 | 728 | # Dispatch s3-search intent 729 | if intent_name == 's3-search': 730 | return searchS3(intent_request) 731 | 732 | # Dispatch s3-create bucket intent 733 | if intent_name == 's3-create-bucket': 734 | return createS3Bucket(intent_request) 735 | 736 | # Dispatch s3-copy-to-new-bucket bucket intent 737 | if intent_name == 's3-copy-to-new-bucket': 738 | return copyToNewBucket(intent_request) 739 | 740 | # Raise exception if intent is not recognized 741 | raise Exception('Intent with name ' + intent_name + ' not supported') 742 | 743 | 744 | """ --- Main handler --- """ 745 | def handler(event, context): 746 | 747 | # Log event and context 748 | logger.info(event) 749 | logger.info(context) 750 | 751 | # By default, treat the user request as coming from the America/New_York time zone. 752 | os.environ['TZ'] = 'America/New_York' 753 | time.tzset() 754 | logger.debug('event.bot.name={}'.format(event['bot']['name'])) 755 | 756 | # dispatch event and return 757 | return dispatch(event) 758 | --------------------------------------------------------------------------------