Skip to content

Commit 4dc44c4

Browse files
author
Archana Venkitaramanan
committed
New serverless pattern - apigw-lambda-bedrock-novacanvas
1 parent ae11f3e commit 4dc44c4

File tree

6 files changed

+327
-0
lines changed

6 files changed

+327
-0
lines changed
23 KB
Loading
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Serverless Text-to-Image Generation with Amazon Bedrock Nova Canvas
2+
3+
This pattern implements a serverless text-to-image generation service using Amazon API Gateway, AWS Lambda and Amazon Bedrock's Nova Canvas model. It provides a REST API endpoint where users can submit text prompts.
4+
5+
This invokes a Lambda function containing the request and the function makes a call to Amazon Bedrock's Nova Canvas model to generate an image based on the text description. Once the image is generated, the Lambda function saves it to an S3 bucket and returns this filename to the user through the API Gateway API.
6+
7+
Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/apigw-lambda-bedrock-novacanvas
8+
9+
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
10+
11+
## Requirements
12+
13+
* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
14+
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
15+
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
16+
* [Terraform](https://learn.hashicorp.cxom/tutorials/terraform/install-cli?in=terraform/aws-get-started) installed
17+
* [Amazon Bedrock Nova Canvas Foundation Model Access](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html#add-model-access)
18+
19+
## Deployment Instructions
20+
21+
For this pattern, you would need access only to Amazon Nova Canvas foundation model (Model ID: amazon.nova-canvas-v1:0) in us-east-1 region, since the pattern uses us-east-1 region by default.
22+
23+
You must request access to the model before you can use it. If you try to use the model before you have requested access to it, you will receive an error message.
24+
25+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
26+
```
27+
git clone https://github.com/aws-samples/serverless-patterns
28+
```
29+
1. Change directory to the pattern directory:
30+
```
31+
cd apigw-lambda-bedrock-novacanvas
32+
```
33+
1. From the command line, initialize terraform to downloads and installs the providers defined in the configuration:
34+
```
35+
terraform init
36+
```
37+
1. From the command line, apply the configuration in the main.tf file:
38+
```
39+
terraform apply
40+
```
41+
1. During the prompts
42+
#var.prefix
43+
- Enter a value: {enter any prefix to associate with resources}
44+
45+
## Testing
46+
47+
1. Make a POST request to the API using the following cURL command:
48+
49+
curl -X POST 'https://<api-id>.execute-api.us-east-1.amazonaws.com/dev/image_gen' --header "Content-Type: application/json" --data '{"prompt": "<your prompt>"}'
50+
51+
Note: Replace 'api-id' with the generated API ID from Terraform (refer to the Terraform Outputs section), "your prompt" with your desired prompt. For ex,
52+
53+
curl -X POST 'https://1234abcde.execute-api.us-east-1.amazonaws.com/dev/image_gen' --header "Content-Type: application/json" --data '{"prompt": "Kitten playing the piano"}'
54+
55+
1. Once the API Gateway responds with the image ID, you can navigate to the S3 bucket (refer to the Terraform Outputs section for the bucket name) and select the correct image ID to view the generated image.
56+
57+
## Cleanup
58+
59+
1. Change directory to the pattern directory:
60+
```
61+
cd serverless-patterns/apigw-lambda-bedrock-novacanvas
62+
```
63+
64+
1. Delete all created resources
65+
```
66+
terraform destroy
67+
```
68+
69+
1. During the prompts:
70+
```
71+
Enter all details as entered during creation.
72+
```
73+
74+
1. Confirm all created resources has been deleted
75+
```
76+
terraform show
77+
```
78+
----
79+
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
80+
81+
SPDX-License-Identifier: MIT-0
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"title": "Serverless Text-to-Image Generation with Amazon Bedrock Nova Canvas",
3+
"description": "This pattern implements a serverless text-to-image generation service using Amazon API Gateway, AWS Lambda and Amazon Bedrock's Nova Canvas model. It provides a REST API endpoint where users can submit text prompts and receive generated images whic are stored in an S3 bucket.",
4+
"language": "Python",
5+
"level": "200",
6+
"framework": "Terraform",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"The solution works by receiving a text prompt to an API Gateway endpoint, which triggers a Lambda function containing the request. The Lambda function then formats this prompt and makes a call to Amazon Bedrock's Nova Canvas model to generate an image based on the text description and the generated image is saved to the S3 bucket."
11+
]
12+
},
13+
"gitHub": {
14+
"template": {
15+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-lambda-bedrock-novacanvas",
16+
"templateURL": "serverless-patterns/apigw-lambda-bedrock-novacanvas",
17+
"projectFolder": "apigw-lambda-bedrock-novacanvas",
18+
"templateFile": "main.tf"
19+
}
20+
},
21+
"resources": {
22+
"bullets": [
23+
{
24+
"text": "Amazon Nova Canvas",
25+
"link": "https://docs.aws.amazon.com/ai/responsible-ai/nova-canvas/overview.html"
26+
},
27+
{
28+
"text": "Invoke Amazon Nova Canvas on Amazon Bedrock to generate an image",
29+
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/bedrock-runtime_example_bedrock-runtime_InvokeModel_AmazonNovaImageGeneration_section.html"
30+
}
31+
]
32+
},
33+
"deploy": {
34+
"text": [
35+
"terraform init",
36+
"terraform apply"
37+
]
38+
},
39+
"testing": {
40+
"text": [
41+
"See the GitHub repo for detailed testing instructions."
42+
]
43+
},
44+
"cleanup": {
45+
"text": [
46+
"terraform destroy",
47+
"terraform show"
48+
]
49+
},
50+
"authors": [
51+
{
52+
"name": "Archana V",
53+
"image": "https://media.licdn.com/dms/image/v2/D5603AQHfEnMkJSFiGQ/profile-displayphoto-shrink_200_200/profile-displayphoto-shrink_200_200/0/1731306594216?e=1750291200&v=beta&t=LkZ1hyXT40DiX6CnWPb-KslCdZ0pXMRJXOwys_NpLCE",
54+
"bio": "Solutions Architect at AWS",
55+
"linkedin": "archana-venkat-9b80b7184"
56+
}
57+
]
58+
}
1.38 KB
Binary file not shown.
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
provider "aws" {
2+
region = "us-east-1"
3+
}
4+
5+
variable "prefix" {
6+
description = "Prefix to associate with the resources"
7+
type = string
8+
}
9+
10+
resource "random_string" "suffix" {
11+
length = 8
12+
special = false
13+
upper = false
14+
}
15+
16+
# Create Lambda layer for Pillow from provided zip file
17+
resource "aws_lambda_layer_version" "pillow_layer" {
18+
filename = "pillow.zip" # Make sure this zip file exists in your terraform directory
19+
layer_name = "pillow_layer"
20+
compatible_runtimes = ["python3.11"]
21+
description = "Pillow library layer for image processing"
22+
}
23+
24+
# IAM Policy for invoking Bedrock model
25+
resource "aws_iam_policy" "invoke_model_policy" {
26+
name = "${lower(var.prefix)}-InvokeModelPolicy-${random_string.suffix.result}"
27+
path = "/"
28+
description = "Policy to invoke Bedrock model"
29+
30+
policy = jsonencode({
31+
Version = "2012-10-17"
32+
Statement = [
33+
{
34+
Action = [
35+
"bedrock:InvokeModel",
36+
]
37+
Effect = "Allow"
38+
Resource = [
39+
"arn:aws:bedrock:${data.aws_region.current.name}::foundation-model/amazon.nova-canvas-v1:0"
40+
]
41+
},
42+
]
43+
})
44+
}
45+
46+
# S3 bucket for storing images
47+
resource "aws_s3_bucket" "image_bucket" {
48+
bucket = "${lower(var.prefix)}-image-bucket-${random_string.suffix.result}"
49+
force_destroy = true
50+
}
51+
52+
# Create CloudWatch Log Group for Lambda
53+
resource "aws_cloudwatch_log_group" "lambda_log_group" {
54+
name = "/aws/lambda/${lower(var.prefix)}-invoke-bedrock"
55+
retention_in_days = 14
56+
57+
lifecycle {
58+
prevent_destroy = false
59+
}
60+
}
61+
62+
# Lambda function
63+
resource "aws_lambda_function" "invoke_bedrock_function" {
64+
filename = "index.zip" # Replace with your Lambda code zip file
65+
function_name = "${lower(var.prefix)}-invoke-bedrock"
66+
role = aws_iam_role.lambda_role.arn
67+
handler = "index.handler"
68+
runtime = "python3.11"
69+
timeout = 30
70+
71+
layers = [
72+
aws_lambda_layer_version.pillow_layer.arn
73+
]
74+
75+
environment {
76+
variables = {
77+
BUCKET = aws_s3_bucket.image_bucket.id
78+
}
79+
}
80+
81+
depends_on = [aws_cloudwatch_log_group.lambda_log_group]
82+
}
83+
84+
# IAM role for Lambda function
85+
resource "aws_iam_role" "lambda_role" {
86+
name = "${lower(var.prefix)}-lambda_role-${random_string.suffix.result}"
87+
88+
assume_role_policy = jsonencode({
89+
Version = "2012-10-17"
90+
Statement = [
91+
{
92+
Action = "sts:AssumeRole"
93+
Effect = "Allow"
94+
Principal = {
95+
Service = "lambda.amazonaws.com"
96+
}
97+
}
98+
]
99+
})
100+
}
101+
102+
# Attach policies to Lambda role
103+
resource "aws_iam_role_policy_attachment" "lambda_invoke_model_policy" {
104+
policy_arn = aws_iam_policy.invoke_model_policy.arn
105+
role = aws_iam_role.lambda_role.name
106+
}
107+
108+
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
109+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
110+
role = aws_iam_role.lambda_role.name
111+
}
112+
113+
resource "aws_iam_role_policy_attachment" "lambda_s3_access" {
114+
policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
115+
role = aws_iam_role.lambda_role.name
116+
}
117+
118+
# API Gateway
119+
resource "aws_api_gateway_rest_api" "bedrock_api" {
120+
name = "${lower(var.prefix)}-BedrockImageAPI-${random_string.suffix.result}"
121+
}
122+
123+
resource "aws_api_gateway_resource" "image_gen" {
124+
rest_api_id = aws_api_gateway_rest_api.bedrock_api.id
125+
parent_id = aws_api_gateway_rest_api.bedrock_api.root_resource_id
126+
path_part = "image_gen"
127+
}
128+
129+
resource "aws_api_gateway_method" "image_gen_post" {
130+
rest_api_id = aws_api_gateway_rest_api.bedrock_api.id
131+
resource_id = aws_api_gateway_resource.image_gen.id
132+
http_method = "POST"
133+
authorization = "NONE"
134+
}
135+
136+
resource "aws_api_gateway_integration" "lambda_integration" {
137+
rest_api_id = aws_api_gateway_rest_api.bedrock_api.id
138+
resource_id = aws_api_gateway_resource.image_gen.id
139+
http_method = aws_api_gateway_method.image_gen_post.http_method
140+
141+
integration_http_method = "POST"
142+
type = "AWS_PROXY"
143+
uri = aws_lambda_function.invoke_bedrock_function.invoke_arn
144+
}
145+
146+
# API Gateway Deployment
147+
resource "aws_api_gateway_deployment" "api_deployment" {
148+
rest_api_id = aws_api_gateway_rest_api.bedrock_api.id
149+
150+
depends_on = [
151+
aws_api_gateway_integration.lambda_integration
152+
]
153+
}
154+
155+
# API Gateway Stage
156+
resource "aws_api_gateway_stage" "api_stage" {
157+
deployment_id = aws_api_gateway_deployment.api_deployment.id
158+
rest_api_id = aws_api_gateway_rest_api.bedrock_api.id
159+
stage_name = "dev"
160+
}
161+
162+
# Lambda permission for API Gateway
163+
resource "aws_lambda_permission" "api_gateway_lambda" {
164+
statement_id = "AllowAPIGatewayInvoke"
165+
action = "lambda:InvokeFunction"
166+
function_name = aws_lambda_function.invoke_bedrock_function.function_name
167+
principal = "apigateway.amazonaws.com"
168+
source_arn = "${aws_api_gateway_rest_api.bedrock_api.execution_arn}/*/*"
169+
}
170+
171+
# Outputs
172+
output "lambda_function" {
173+
description = "The ARN of the Lambda function"
174+
value = aws_lambda_function.invoke_bedrock_function.arn
175+
}
176+
177+
output "api_endpoint" {
178+
description = "The API Gateway endpoint URL "
179+
value = "${aws_api_gateway_stage.api_stage.invoke_url}/image_gen"
180+
}
181+
182+
output "s3_image_bucket" {
183+
description = "The Output S3 bucket is "
184+
value = aws_s3_bucket.image_bucket.id
185+
}
186+
187+
# Data source for current region
188+
data "aws_region" "current" {}
4.6 MB
Binary file not shown.

0 commit comments

Comments
 (0)