Skip to content

Commit

Permalink
Merge pull request #508 from aws-samples/dev
Browse files Browse the repository at this point in the history
chore: merge from dev
  • Loading branch information
NingLu authored Jan 8, 2025
2 parents f45dff8 + 39d6418 commit dd27544
Show file tree
Hide file tree
Showing 133 changed files with 3,382 additions and 12,739 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ Sample config.json:
},
"chat": {
"enabled": true,
"bedrockRegion": "us-east-1",
"useOpenSourceLLM": true,
"amazonConnect": {
"enabled": true
}
Expand Down
2 changes: 2 additions & 0 deletions README_zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ cd Intelli-Agent/source/infrastructure
},
"chat": {
"enabled": true,
"bedrockRegion": "us-east-1",
"useOpenSourceLLM": true,
"amazonConnect": {
"enabled": true
}
Expand Down
1 change: 1 addition & 0 deletions source/infrastructure/bin/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function getConfig(): SystemConfig {
bedrockRegion: "us-east-1",
bedrockAk: "",
bedrockSk: "",
useOpenSourceLLM: true,
amazonConnect: {
enabled: true
}
Expand Down
13 changes: 12 additions & 1 deletion source/infrastructure/cli/magic-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ async function getAwsAccountAndRegion() {
options.enableChat = config.chat.enabled;
options.bedrockRegion = config.chat.bedrockRegion;
options.enableConnect = config.chat.amazonConnect.enabled;
options.useOpenSourceLLM = config.chat.useOpenSourceLLM;
options.defaultEmbedding = config.model.embeddingsModels && config.model.embeddingsModels.length > 0
? config.model.embeddingsModels[0].name
: embeddingModels[0].name;
Expand Down Expand Up @@ -192,7 +193,7 @@ async function processCreateOptions(options: any): Promise<void> {
type: "confirm",
name: "enableKnowledgeBase",
message: "Do you want to use knowledge base in this solution?",
initial: options.enableKnowledgeBase ?? false,
initial: options.enableKnowledgeBase ?? true,
},
{
type: "select",
Expand Down Expand Up @@ -335,6 +336,15 @@ async function processCreateOptions(options: any): Promise<void> {
return (!(this as any).state.answers.enableChat);
},
},
{
type: "confirm",
name: "useOpenSourceLLM",
message: "Do you want to use open source LLM(eg. Qwen, ChatGLM, IntermLM)?",
initial: options.useOpenSourceLLM ?? true,
skip(): boolean {
return (!(this as any).state.answers.enableChat);
},
},
{
type: "confirm",
name: "enableConnect",
Expand Down Expand Up @@ -474,6 +484,7 @@ async function processCreateOptions(options: any): Promise<void> {
chat: {
enabled: answers.enableChat,
bedrockRegion: answers.bedrockRegion,
useOpenSourceLLM: answers.useOpenSourceLLM,
amazonConnect: {
enabled: answers.enableConnect,
},
Expand Down
405 changes: 63 additions & 342 deletions source/infrastructure/lib/api/api-stack.ts

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions source/infrastructure/lib/api/chat-history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**********************************************************************************************************************
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. *
* *
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance *
* with the License. A copy of the License is located at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES *
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
* and limitations under the License. *
*********************************************************************************************************************/

import { Code } from "aws-cdk-lib/aws-lambda";
import * as apigw from "aws-cdk-lib/aws-apigateway";
import { Construct } from "constructs";
import { join } from "path";
import { IAMHelper } from "../shared/iam-helper";
import { LambdaFunction } from "../shared/lambda-helper";


export interface ChatHistoryApiProps {
api: apigw.RestApi;
auth: apigw.RequestAuthorizer;
iamHelper: IAMHelper;
messagesTableName: string;
sessionsTableName: string;
genMethodOption: any;
}

export class ChatHistoryApi extends Construct {
private readonly api: apigw.RestApi;
private readonly auth: apigw.RequestAuthorizer;
private readonly messagesTableName: string;
private readonly sessionsTableName: string;
private readonly iamHelper: IAMHelper;
private readonly genMethodOption: any;

constructor(scope: Construct, id: string, props: ChatHistoryApiProps) {
super(scope, id);

this.api = props.api;
this.auth = props.auth;
this.messagesTableName = props.messagesTableName;
this.sessionsTableName = props.sessionsTableName;
this.iamHelper = props.iamHelper;
this.genMethodOption = props.genMethodOption;

const chatHistoryManagementLambda = new LambdaFunction(this, "ChatHistoryManagementLambda", {
code: Code.fromAsset(join(__dirname, "../../../lambda/chat_history")),
handler: "chat_history_management.lambda_handler",
environment: {
SESSIONS_TABLE_NAME: this.sessionsTableName,
MESSAGES_TABLE_NAME: this.messagesTableName,
SESSIONS_BY_TIMESTAMP_INDEX_NAME: "byTimestamp",
MESSAGES_BY_SESSION_ID_INDEX_NAME: "bySessionId",
},
statements: [this.iamHelper.dynamodbStatement],
});

const apiResourceSessions = this.api.root.addResource("sessions");
apiResourceSessions.addMethod("GET", new apigw.LambdaIntegration(chatHistoryManagementLambda.function), this.genMethodOption(this.api, this.auth, null),);
const apiResourceMessages = apiResourceSessions.addResource('{sessionId}').addResource("messages");
apiResourceMessages.addMethod("GET", new apigw.LambdaIntegration(chatHistoryManagementLambda.function), this.genMethodOption(this.api, this.auth, null),);
const apiResourceMessageFeedback = apiResourceMessages.addResource("{messageId}").addResource("feedback");
apiResourceMessageFeedback.addMethod("POST", new apigw.LambdaIntegration(chatHistoryManagementLambda.function), this.genMethodOption(this.api, this.auth, null),);
}
}
245 changes: 245 additions & 0 deletions source/infrastructure/lib/api/intention-management.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
/**********************************************************************************************************************
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. *
* *
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance *
* with the License. A copy of the License is located at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES *
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
* and limitations under the License. *
*********************************************************************************************************************/

import { Duration } from "aws-cdk-lib";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { JsonSchemaType } from "aws-cdk-lib/aws-apigateway";
import * as apigw from "aws-cdk-lib/aws-apigateway";
import { Construct } from "constructs";
import { join } from "path";
import { PythonFunction } from "@aws-cdk/aws-lambda-python-alpha";
import * as pyLambda from "@aws-cdk/aws-lambda-python-alpha";
import { IAMHelper } from "../shared/iam-helper";
import { Vpc, SecurityGroup } from 'aws-cdk-lib/aws-ec2';
import { SystemConfig } from "../shared/types";


export interface IntentionApiProps {
api: apigw.RestApi;
auth: apigw.RequestAuthorizer;
vpc: Vpc;
securityGroups: [SecurityGroup];
intentionTableName: string;
indexTable: string;
chatbotTable: string;
modelTable: string;
s3Bucket: string;
defaultEmbeddingModelName: string;
domainEndpoint: string;
config: SystemConfig;
sharedLayer: pyLambda.PythonLayerVersion;
iamHelper: IAMHelper;
genMethodOption: any;
genRequestModel: any;
}

export class IntentionApi extends Construct {
private readonly api: apigw.RestApi;
private readonly auth: apigw.RequestAuthorizer;
private readonly vpc: Vpc;
private readonly securityGroups: [SecurityGroup];
private readonly sharedLayer: pyLambda.PythonLayerVersion;
private readonly iamHelper: IAMHelper;
private readonly intentionTableName: string;
private readonly indexTable: string;
private readonly chatbotTable: string;
private readonly modelTable: string;
private readonly s3Bucket: string;
private readonly defaultEmbeddingModelName: string;
private readonly domainEndpoint: string;
private readonly config: SystemConfig;
private readonly genMethodOption: any;
private readonly genRequestModel: any;

constructor(scope: Construct, id: string, props: IntentionApiProps) {
super(scope, id);

this.api = props.api;
this.auth = props.auth;
this.vpc = props.vpc;
this.securityGroups = props.securityGroups;
this.intentionTableName = props.intentionTableName;
this.indexTable = props.indexTable;
this.chatbotTable = props.chatbotTable;
this.modelTable = props.modelTable;
this.s3Bucket = props.s3Bucket;
this.defaultEmbeddingModelName = props.defaultEmbeddingModelName;
this.domainEndpoint = props.domainEndpoint;
this.config = props.config;
this.sharedLayer = props.sharedLayer;
this.iamHelper = props.iamHelper;
this.genMethodOption = props.genMethodOption;
this.genRequestModel = props.genRequestModel;

const intentionLambda = new PythonFunction(scope, "IntentionLambda", {
runtime: Runtime.PYTHON_3_12,
entry: join(__dirname, "../../../lambda/intention"),
index: "intention.py",
handler: "lambda_handler",
timeout: Duration.minutes(15),
vpc: this.vpc,
securityGroups: this.securityGroups,
environment: {
INTENTION_TABLE_NAME: this.intentionTableName,
INDEX_TABLE_NAME: this.indexTable,
CHATBOT_TABLE_NAME: this.chatbotTable,
MODEL_TABLE_NAME: this.modelTable,
S3_BUCKET: this.s3Bucket,
EMBEDDING_MODEL_ENDPOINT: this.defaultEmbeddingModelName,
AOS_ENDPOINT: this.domainEndpoint,
KNOWLEDGE_BASE_ENABLED: this.config.knowledgeBase.enabled.toString(),
KNOWLEDGE_BASE_TYPE: JSON.stringify(this.config.knowledgeBase.knowledgeBaseType || {}),
BEDROCK_REGION: this.config.chat.bedrockRegion,
},
layers: [this.sharedLayer],
});
intentionLambda.addToRolePolicy(this.iamHelper.dynamodbStatement);
intentionLambda.addToRolePolicy(this.iamHelper.logStatement);
intentionLambda.addToRolePolicy(this.iamHelper.secretStatement);
intentionLambda.addToRolePolicy(this.iamHelper.esStatement);
intentionLambda.addToRolePolicy(this.iamHelper.s3Statement);
intentionLambda.addToRolePolicy(this.iamHelper.bedrockStatement);
intentionLambda.addToRolePolicy(this.iamHelper.endpointStatement);

// API Gateway Lambda Integration to manage intention
const lambdaIntentionIntegration = new apigw.LambdaIntegration(intentionLambda, {
proxy: true,
});
const apiResourceIntentionManagement = this.api.root.addResource("intention");
const indexScan = apiResourceIntentionManagement.addResource("index-used-scan")
indexScan.addMethod("POST", lambdaIntentionIntegration, this.genMethodOption(this.api, this.auth, null));
const presignedUrl = apiResourceIntentionManagement.addResource("execution-presigned-url");
presignedUrl.addMethod("POST", lambdaIntentionIntegration, {
...this.genMethodOption(this.api, this.auth, {
data: { type: JsonSchemaType.STRING },
message: { type: JsonSchemaType.STRING },
s3Bucket: { type: JsonSchemaType.STRING },
s3Prefix: { type: JsonSchemaType.STRING }
}),
requestModels: this.genRequestModel(this.api, {
"content_type": { "type": JsonSchemaType.STRING },
"file_name": { "type": JsonSchemaType.STRING },
})
})
const apiResourceDownload = apiResourceIntentionManagement.addResource("download-template");
apiResourceDownload.addMethod("GET", lambdaIntentionIntegration, this.genMethodOption(this.api, this.auth, null));

const apiResourceIntentionExecution = apiResourceIntentionManagement.addResource("executions");
apiResourceIntentionExecution.addMethod("DELETE", lambdaIntentionIntegration, this.genMethodOption(this.api, this.auth, null))
apiResourceIntentionExecution.addMethod("POST", lambdaIntentionIntegration, {
...this.genMethodOption(this.api, this.auth, {
execution_id: { type: JsonSchemaType.STRING },
input_payload: {
type: JsonSchemaType.OBJECT,
properties: {
tableItemId: { type: JsonSchemaType.STRING },
chatbotId: { type: JsonSchemaType.STRING },
groupName: { type: JsonSchemaType.STRING },
index: { type: JsonSchemaType.STRING },
model: { type: JsonSchemaType.STRING },
fieldName: { type: JsonSchemaType.STRING }
}
},
result: { type: JsonSchemaType.STRING }
}),
requestModels: this.genRequestModel(this.api, {
"chatbotId": { "type": JsonSchemaType.STRING },
"index": { "type": JsonSchemaType.STRING },
"model": { "type": JsonSchemaType.STRING },
"s3Bucket": { "type": JsonSchemaType.STRING },
"s3Prefix": { "type": JsonSchemaType.STRING }
})
});
apiResourceIntentionExecution.addMethod("GET", lambdaIntentionIntegration, {
...this.genMethodOption(this.api, this.auth, {
Items: {
type: JsonSchemaType.ARRAY, items: {
type: JsonSchemaType.OBJECT,
properties: {
model: { type: JsonSchemaType.STRING },
executionStatus: { type: JsonSchemaType.STRING },
index: { type: JsonSchemaType.STRING },
fileName: { type: JsonSchemaType.STRING },
createTime: { type: JsonSchemaType.STRING },
createBy: { type: JsonSchemaType.STRING },
executionId: { type: JsonSchemaType.STRING },
chatbotId: { type: JsonSchemaType.STRING },
details: { type: JsonSchemaType.STRING },
tag: { type: JsonSchemaType.STRING },
},
required: ['model',
'executionStatus',
'index',
'fileName',
'createTime',
'createBy',
'executionId',
'chatbotId',
'details',
'tag'],
}
},
Count: { type: JsonSchemaType.INTEGER },
Config: {
type: JsonSchemaType.OBJECT,
properties: {
MaxItems: { type: JsonSchemaType.INTEGER },
PageSize: { type: JsonSchemaType.INTEGER },
StartingToken: { type: JsonSchemaType.NULL }
}
}
}),
requestParameters: {
'method.request.querystring.max_items': false,
'method.request.querystring.page_size': false
}
});
const apiGetIntentionById = apiResourceIntentionExecution.addResource("{executionId}");
apiGetIntentionById.addMethod(
"GET",
lambdaIntentionIntegration,
{
...this.genMethodOption(this.api, this.auth, {
Items: {
type: JsonSchemaType.ARRAY,
items: {
type: JsonSchemaType.OBJECT,
properties: {
s3Path: { type: JsonSchemaType.STRING },
s3Prefix: { type: JsonSchemaType.STRING },
createTime: { type: JsonSchemaType.STRING }, // Consider using format: 'date-time'
status: { type: JsonSchemaType.STRING },
QAList: {
type: JsonSchemaType.ARRAY,
items: {
type: JsonSchemaType.OBJECT,
properties: {
question: { type: JsonSchemaType.STRING },
intention: { type: JsonSchemaType.STRING },
kwargs: { type: JsonSchemaType.STRING },
}
}
}
},
required: ['s3Path', 's3Prefix', 'createTime', 'status', 'executionId'],
}
},
Count: { type: JsonSchemaType.INTEGER }
}),
requestParameters: {
'method.request.path.intentionId': true
},
}
);
}
}
Loading

0 comments on commit dd27544

Please sign in to comment.