Skip to content

Commit 3344397

Browse files
author
Austin Johnson
committed
Initial checkin of q business integration
1 parent f337b00 commit 3344397

File tree

7 files changed

+307
-0
lines changed

7 files changed

+307
-0
lines changed

README-qbusiness.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Amazon Q Business Integration
2+
3+
Amazon Q is a new generative AI-powered application that helps users get work done. Amazon Q can become your tailored business expert and let you discover content, brainstorm ideas, or create summaries using your company’s data safely and securely. For more information see: [Introducing Amazon Q, a new generative AI-powered assistant](https://aws.amazon.com/blogs/aws/introducing-amazon-q-a-new-generative-ai-powered-assistant-preview)
4+
5+
In this repo we share a project which lets you use Amazon Q's generative AI to enable QnABot users to access your organization's data and knowledge sources via conversational question-answering. You can connect to your organization data via data source connectors and integrate it with the QnABot LambdaHook plugin for Amazon Q to enable access to your QnABot users. It allows your users to converse with Amazon Q using QnABot to ask questions and get answers based on company data, get help creating new content such as emails, and performing tasks.
6+
7+
This feature supports integration with file attachments, enable both to allow QBusiness to read files uploaded via Lex Web UI. There's more information on this feature in the [File Upload README](https://github.com/aws-samples/aws-lex-web-ui/blob/master/README-file-upload.md).
8+
9+
### Prerequisites
10+
11+
1. A deployment of the Lex Web UI with login enabled is required for this stack. To learn more about deploying the Web UI see the [Github repo for the solution](https://github.com/aws-samples/aws-lex-web-ui). This Cognito should be integrated with the same identity provider as your Identity Center (in the below example we will use IAM Identity Center as the IDP).
12+
2. The Cognito user pool created by the Web UI will need to be added as **Trusted token issuer** to Identity Center by doing the following steps
13+
1. Go to Identity Center and click on `Settings`, then `Create trusted token issuer`
14+
2. The issuer URL will be `https://cognito-idp.[region].amazonaws.com/[cognito-pool-id]` and you will need to provide which attributes should map between the two.
15+
![Issuer](./img//token-issuer.PNG)
16+
3. A custom application will need to be created in Identity Center to handle the connection between your Q Business application and your Cognito pool. Follow these steps to create the application.
17+
1. Go to Identity Center and click on `Applications` then `Add application`
18+
2. Select `I have an application I want to set up` and `OAuth 2.0` on the next page for Selecting Application type, then hit `Next`
19+
3. For `Application URL`, provide the **Web experience URL** of your Q Business application. You can either opt to assign specific users/groups to this application or allow any Identity Center users/groups to access the application. Your Q Business subscriptions will still apply however so only users with a subscription can successfully chat with the application. Then hit `Next`
20+
4. Select the Trusted token issuer that was created in Step 2 of this guide, you will now need an aud claim so that the token issuer can identify the application. This aud claim is created when you deploy the Lex Web UI and can be found within the Coginto User pool. To find this value go to your Cognito user pool and select the `App integration` tab and scroll to the bottom. The aud claim is the **Client ID** value found under the App client list. Take this value and paste it into the aud claim field, then select `Next`
21+
![Claim](./img//aud-claim.PNG)
22+
5. You will need to wait until after you deploy the CloudFormation stack to provide the role on the Specify application credentials page. For now, provide any existing IAM role in your environment and hit `Next`.
23+
24+
### Deploy a new Amazon Q (Business) Plugin stack
25+
26+
Use AWS CloudFormation to deploy one or more of the sample plugin Lambdas in your own AWS account (if you do not have an AWS account, please see [How do I create and activate a new Amazon Web Services account?](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/)):
27+
28+
1. Log into the [AWS console](https://console.aws.amazon.com/) if you are not already.
29+
2. Choose one of the **Launch Stack** buttons below for your desired AWS region to open the AWS CloudFormation console and create a new stack.
30+
3. On the CloudFormation `Create Stack` page, click `Next`
31+
4. Enter the following parameters:
32+
1. `Stack Name`: Name your stack, e.g. QNABOTPLUGIN-QNA-BOT-QBUSINESS-LAMBDAHOOK.
33+
2. `AmazonQAppId`: Existing Amazon Q Application ID (copy from AWS console)
34+
3. `AmazonQRegion`: Amazon Q Region (us-east-1, or us-west-2)
35+
4. `DynamoDBTableName`: DynamoDB table that will be used to cache user credential for question answering with QBusiness.
36+
5. `IDCApplicationARN`: ARN of the Identity Center customer managed application created for QBusiness (see prerequisites for steps to create)
37+
5. Launch the stack.
38+
6. When your QNABOTPLUGIN-QNA-BOT-QBUSINESS-LAMBDAHOOK Plugin CloudFormation stack status is CREATE_COMPLETE, choose the **Outputs** tab. Look for the output `QnAItemLambdaFunctionRoleArn` and modify your existing Identity Center application with this value by following these steps.
39+
1. Go to Identity Center and click on `Applications` and find the application created for the QBusiness plugin. Click on the application to view more details.
40+
2. Select `Actions->Edit configuration` to modify the settings of the application
41+
3. Expand the Application credentials and paste the ARN obtained from the Outputs section.
42+
4. Hit `Save changes`
43+
44+
## After your Amazon Q Plugin stack is deployed
45+
The default behavior is to relay the user's query to Amazon Q Business as the user input. If LLM_QUERY_GENERATION is enabled, the generated (disambiguated) query will be used, otherwise the user's utterance is used.
46+
Alternatively, you can supply an explicit `"Prompt"` key in the `QnAItemLambdaHookArgs` value. For example setting `QnAItemLambdaHookArgs` to `{"Prefix":"Amazon Q Answer:", "ShowContextText":true, "ShowSourceLinks":true, "Prompt":"Why is the sky blue?"}` will ignore the user's input and simply use the configured prompt instead. You may find this useful if you use the function as a Lambda Hook for QnA items that match explicit lists of utterances/questions, and you want to normalise these into a single static question to ask Amazon Q. Prompts supplied in this manner do not (yet) support variable substitution (eg to substitute user attributes, session attributes, etc. into the prompt). If you feel that would be a useful feature, please create a feature request issue in the repo, or, better yet, implement it, and submit a Pull Request!
47+
48+
### Say hello
49+
> Time to say Hi!
50+
51+
1. Go to QnAbot
52+
2. Launch the Web client
53+
4. Say *Hello*. And start asking questions!
54+
5. Enjoy.
55+
56+
### Using file attachments
57+
58+
This plugin now supports attachments! Use the newest version of the [Lex Web UI](http://amazon.com/chatbotui) - version 0.20.4 or later - to add local file attachments to your conversation. There's more information on this feature in the Lex Web UI [File Upload README](https://github.com/aws-samples/aws-lex-web-ui/blob/master/README-file-upload.md).
59+
When deploying or updating your Lex Web UI, you can reuse QnABot's existing **ImportBucket** name as the **UploadBucket** parameter - it already has a CORS policy that will work, and the Q Business plugin lambda role already grants read access to uploads in this bucket. To find your QnaBot's ImportBucket, use the `Resources` tab in the QnABot stack to search for the bucket reasorce with the logical name **ImportBucket**.
60+
61+
Here's an example of what you can do with attachments - it is a beautiful thing!
62+
63+
![Amazon Q Demo](../../images/FileAttach.png)
64+

build/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,20 @@ upload-streaming-lambda:
9999
"$(OUT)/$(STREAMING_LAMBDA_ZIP)" "s3://$(BOOTSTRAP_BUCKET_PATH)/$(STREAMING_LAMBDA_ZIP)" \
100100
| tee -a "$(OUT)/$(@)"
101101

102+
QBUSINESS_LAMBDA_DIR := $(SOURCE_DIR)/qbusiness-lambda
103+
QBUSINESS_LAMBDA_ZIP := qbusiness-lambda-$(VERSION).zip
104+
QBUSINESS_LAMBDA_RESOURCES_FILES := $(wildcard $(QBUSINESS_LAMBDA_DIR)/*.js)
105+
106+
$(QBUSINESS_LAMBDA_ZIP): $(QBUSINESS_LAMBDA_DIR)/index.js
107+
@echo "[INFO] Creating qbusiness Lambda zip file"
108+
zip -r -j "$(OUT)/$(QBUSINESS_LAMBDA_ZIP)" $(QBUSINESS_LAMBDA_DIR) ;
109+
110+
upload-qbusiness-lambda:
111+
@echo "[INFO] uploading qbusiness lambda"
112+
aws s3 cp --acl public-read \
113+
"$(OUT)/$(QBUSINESS_LAMBDA_ZIP)" "s3://$(BOOTSTRAP_BUCKET_PATH)/$(QBUSINESS_LAMBDA_ZIP)" \
114+
| tee -a "$(OUT)/$(@)"
115+
102116
# files in this repo are bundled in a zip file to boostrap the codecommit repo
103117
SRC_ZIP := src-$(VERSION).zip
104118
SRC_FILES := $(shell git ls-files ..)

build/upload-bootstrap.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ aws s3 cp out/initiate-chat-lambda-$version.zip \
3535
aws s3 cp out/streaming-lambda-$version.zip \
3636
"s3://${BOOTSTRAP_BUCKET_PATH}/streaming-lambda-$version.zip"
3737

38+
aws s3 cp out/streaming-lambda-$version.zip \
39+
"s3://${BOOTSTRAP_BUCKET_PATH}/qbusiness-lambda-$version.zip"
40+
3841
aws s3 sync --exclude "*" --include "*.yaml" \
3942
../templates "s3://${BOOTSTRAP_BUCKET_PATH}/templates/"
4043

img/aud-claim.PNG

68.1 KB
Loading

img/token-issuer.PNG

127 KB
Loading

src/qbusiness-lambda/index.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import base64
2+
import json
3+
import os
4+
import random
5+
import string
6+
import uuid
7+
import boto3
8+

templates/qbusiness.yml

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
AWSTemplateFormatVersion: "2010-09-09"
2+
Description: >
3+
Deploys lambda function and resources to integrate with QBusiness
4+
5+
Parameters:
6+
7+
AmazonQAppId:
8+
Type: String
9+
AllowedPattern: '^[a-zA-Z0-9][a-zA-Z0-9-]{35}$'
10+
Description: Amazon Q Application ID
11+
12+
IDCApplicationARN:
13+
Type: String
14+
Description: ARN of the Identity Center customer managed application created for QBusiness
15+
16+
DynamoDBTableName:
17+
Type: String
18+
Description: DynamoDB Table Name used for caching QBusiness credentials
19+
20+
AmazonQRegion:
21+
Type: String
22+
Default: "us-east-1"
23+
AllowedPattern: '^[a-z]{2}-[a-z]+-[0-9]+$'
24+
Description: Amazon Q Region
25+
26+
AmazonQEndpointUrl:
27+
Type: String
28+
Default: ""
29+
Description: (Optional) Amazon Q Endpoint (leave empty for default endpoint)
30+
31+
QBusinessLambdaCodeObject:
32+
Type: String
33+
Description: >
34+
S3 object zip file containing Lambda for QBusiness integration
35+
Default: artifacts/aws-lex-web-ui/artifacts/streaming-lambda.zip
36+
37+
Resources:
38+
39+
QManagedPolicy:
40+
Type: AWS::IAM::ManagedPolicy
41+
Properties:
42+
PolicyDocument:
43+
Version: '2012-10-17'
44+
Statement:
45+
- Sid: AllowQChat
46+
Effect: Allow
47+
Action:
48+
- "qbusiness:ChatSync"
49+
Resource: !Sub "arn:${AWS::Partition}:qbusiness:${AWS::Region}:${AWS::AccountId}:application/${AmazonQAppId}"
50+
51+
QServiceRole:
52+
Type: AWS::IAM::Role
53+
Properties:
54+
AssumeRolePolicyDocument:
55+
Version: 2012-10-17
56+
Statement:
57+
- Effect: Allow
58+
Principal:
59+
AWS:
60+
- !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root
61+
Action:
62+
- sts:AssumeRole
63+
- sts:SetContext
64+
Path: /
65+
ManagedPolicyArns:
66+
- !Ref QManagedPolicy
67+
68+
QBusinessModelLayer:
69+
Type: "AWS::Lambda::LayerVersion"
70+
Properties:
71+
Content: ../../layers/qbusiness_boto3_model
72+
CompatibleRuntimes:
73+
- python3.12
74+
75+
KMSKey:
76+
Type: 'AWS::KMS::Key'
77+
Properties:
78+
KeySpec: 'SYMMETRIC_DEFAULT'
79+
KeyUsage: 'ENCRYPT_DECRYPT'
80+
KeyPolicy:
81+
Version: '2012-10-17'
82+
Statement:
83+
- Effect: Allow
84+
Principal:
85+
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
86+
Action: 'kms:*'
87+
Resource: '*'
88+
89+
CredentialsTable:
90+
Type: AWS::DynamoDB::Table
91+
Properties:
92+
AttributeDefinitions:
93+
- AttributeName: "jti"
94+
AttributeType: "S"
95+
KeySchema:
96+
- AttributeName: "jti"
97+
KeyType: "HASH"
98+
BillingMode: PAY_PER_REQUEST
99+
SSESpecification:
100+
SSEEnabled: True
101+
TableName: !Ref DynamoDBTableName
102+
TimeToLiveSpecification:
103+
AttributeName: ExpiresAt
104+
Enabled: true
105+
106+
LambdaFunctionRole:
107+
Type: AWS::IAM::Role
108+
Properties:
109+
AssumeRolePolicyDocument:
110+
Version: '2012-10-17'
111+
Statement:
112+
- Effect: Allow
113+
Principal:
114+
Service: lambda.amazonaws.com
115+
Action: sts:AssumeRole
116+
ManagedPolicyArns:
117+
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
118+
Policies:
119+
- PolicyDocument:
120+
Version: 2012-10-17
121+
Statement:
122+
- Effect: Allow
123+
Action:
124+
- "qbusiness:ChatSync"
125+
Resource: !Sub "arn:aws:qbusiness:${AWS::Region}:${AWS::AccountId}:application/${AmazonQAppId}"
126+
PolicyName: QBusinessPolicy
127+
- PolicyDocument:
128+
Version: 2012-10-17
129+
Statement:
130+
- Effect: Allow
131+
Action:
132+
- "s3:GetObject"
133+
Resource: "arn:aws:s3:::*/*"
134+
PolicyName: S3ImportBucketPolicy
135+
- PolicyDocument:
136+
Version: 2012-10-17
137+
Statement:
138+
- Effect: Allow
139+
Action:
140+
- "dynamodb:PutItem"
141+
- "dynamodb:GetItem"
142+
Resource:
143+
- !Sub "arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${DynamoDBTableName}"
144+
PolicyName: DynamoDbPolicy
145+
- PolicyDocument:
146+
Version: 2012-10-17
147+
Statement:
148+
- Effect: Allow
149+
Action:
150+
- "kms:Decrypt"
151+
- "kms:Encrypt"
152+
Resource:
153+
- !Sub "arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${KMSKey}"
154+
PolicyName: KmsPolicy
155+
- PolicyDocument:
156+
Version: 2012-10-17
157+
Statement:
158+
- Effect: Allow
159+
Action:
160+
- "sso-oauth:CreateTokenWithIAM"
161+
Resource: "*"
162+
PolicyName: OICDPolicy
163+
- PolicyDocument:
164+
Version: 2012-10-17
165+
Statement:
166+
- Effect: Allow
167+
Action:
168+
- "sts:AssumeRole"
169+
- "sts:SetContext"
170+
Resource:
171+
- !GetAtt QServiceRole.Arn
172+
PolicyName: AllowAssumeQRole
173+
174+
QnaItemLambdaHookFunction:
175+
Type: AWS::Lambda::Function
176+
Properties:
177+
# LambdaHook name must start with 'QNA-' to match QnAbot invoke policy
178+
FunctionName: !Sub "QNA-LAMBDAHOOK-${AWS::StackName}"
179+
Handler: lambdahook.lambda_handler
180+
Role: !GetAtt 'LambdaFunctionRole.Arn'
181+
Runtime: python3.12
182+
Layers:
183+
- !Ref QBusinessModelLayer
184+
Timeout: 60
185+
MemorySize: 128
186+
Environment:
187+
Variables:
188+
AWS_DATA_PATH: /opt/model
189+
AMAZONQ_APP_ID: !Ref AmazonQAppId
190+
AMAZONQ_ROLE_ARN: !GetAtt QServiceRole.Arn
191+
DYNAMODB_CACHE_TABLE_NAME: !Ref CredentialsTable
192+
KMS_KEY_ID: !Ref KMSKey
193+
IDC_CLIENT_ID: !Ref IDCApplicationARN
194+
AMAZONQ_ENDPOINT_URL: !Ref AmazonQEndpointUrl
195+
Code: ./src
196+
Metadata:
197+
cfn_nag:
198+
rules_to_suppress:
199+
- id: W89
200+
reason: No VPC resources.
201+
- id: W92
202+
reason: No requirements to set reserved concurrencies.
203+
204+
205+
Outputs:
206+
207+
QnAItemLambdaHookFunctionName:
208+
Description: QnA Item Lambda Hook Function Name (use with no_hits item for optional ask-Amazon-Q-Business fallback)
209+
Value: !Ref 'QnaItemLambdaHookFunction'
210+
211+
QnAItemLambdaHookArgs:
212+
Description: QnA Item Lambda Hook Args (use with no_hits item for optional ask-the-LLM fallback)
213+
Value: '{"Prefix":"Amazon Q Answer:", "ShowContextText":true, "ShowSourceLinks":true}'
214+
215+
QnAItemLambdaFunctionRoleArn:
216+
Description: ARN of the Role created for executing the Lambda function
217+
Value: !GetAtt LambdaFunctionRole.Arn
218+

0 commit comments

Comments
 (0)