Using Amazon Bedrock to generate images with Stability AI models and AWS Lambda
The goal of this article is to document how one can test the Stability.ai models in Amazon Bedrock using AWS Lambda. This article will be a quick start guide that can be adapted to suit your needs in the future. For developing the AWS Lambda, the AWS SAM framework will be used.
- Create a skeleton SAM project
Using the sam init command, create a new skeleton project. This sample will use a Python lambda that is exposed via an API Gateway. The Hello World Example sam template has been followed to create the skeleton project.
sam init
Once the sam init command is finished running, tweak the generated code to suit theuse case you are working on.
Below is the template.yaml that has been generated for this article.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
amazon-bedrock-images-stability-ai
Sample SAM Template for amazon-bedrock-images-stability-ai
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 60
MemorySize: 128
# You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
LoggingConfig:
LogFormat: JSON
Resources:
AmazonBedrockFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: bedrock/
Handler: app.lambda_handler
Runtime: python3.12
Architectures:
- x86_64
Events:
AmazonBedrock:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /bedrock
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
AmazonBedrockApi:
Description: API Gateway endpoint URL for Prod stage for the Amazon Bedrock function
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/bedrock/"
AmazonBedrockFunction:
Description: Amazon Bedrock Lambda Function ARN
Value: !GetAtt AmazonBedrockFunction.Arn
AmazonBedrockFunctionIamRole:
Description: Implicit IAM Role created for Amazon Bedrock function
Value: !GetAtt AmazonBedrockFunctionRole.Arn
2. Deploy initial sam stack
Deploy the initial sam stack using the sam deploy command.
sam deploy --guided --profile <aws profile name>
In the output section of the sam deploy command will be an AmazonBedrockApi endpoint as per the image below.
Click onto the AmazonBedrockApi link to validate it is running as expected.
3. Enable the Stability AI models.
At the time of writing (14th December 2023), the Stability AI models are only available in certain regions. For this demo, we will configure resources in the us-east-1 (North Virginia) region as the required models are available in that region.
Navigate to the Amazon Bedrock service in the North Virginia region and select model access on the left hand menu.
Select the Stability AI models and click Request model access
Wait some time before the access request moves from In Progress to Access Granted
4. Update the lambda code to call Amazon Bedrock
In this section, the lambda code will be updated to call the Stability AI model in Amazon Bedrock.
Note: For python boto3 examples — see the following AWS Link
The boto3 library currently configured for python on AWS Lambda does not support the bedrock-runtime client. If you are to load bedrock-runtime from boto3 — you get the following error
"ERROR", "errorMessage": "Unknown service: 'bedrock-runtime'. Valid service names are: accessanalyzer, account, acm, acm-pca
To get around this, we can update the boto3 dependency in requirements.txt to specify which version of boto3 should be used
boto3=1.34.0
Or we can use a lambda layer — which is what we are going to do in this example.
Note: All code will be shared at the end of this article which also shows
The updated template.yml looks like the following
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
amazon-bedrock-images-stability-ai
Sample SAM Template for amazon-bedrock-images-stability-ai
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 60
MemorySize: 512
# You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
LoggingConfig:
LogFormat: JSON
Resources:
Boto3Layer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: boto3-layer
Description: Boto3 Layer
ContentUri: ./dependencies/boto3/
CompatibleRuntimes:
- python3.12
CompatibleArchitectures:
- x86_64
Metadata:
BuildMethod: python3.12
BuildArchitecture: x86_64
AmazonBedrockFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: bedrock/
Handler: app.lambda_handler
Runtime: python3.12
Architectures:
- x86_64
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "bedrock:InvokeModel"
Resource: "*"
Layers:
- !Ref Boto3Layer
Events:
AmazonBedrock:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /bedrock
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
AmazonBedrockApi:
Description: API Gateway endpoint URL for Prod stage for the Amazon Bedrock function
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/bedrock/"
AmazonBedrockFunction:
Description: Amazon Bedrock Lambda Function ARN
Value: !GetAtt AmazonBedrockFunction.Arn
AmazonBedrockFunctionIamRole:
Description: Implicit IAM Role created for Amazon Bedrock function
Value: !GetAtt AmazonBedrockFunctionRole.Arn
5. Update Code
The final lambda code to call a Stability AI model in Amazon Bedrock is as follows.
import json
import logging
import boto3
from botocore.exceptions import ClientError
import botocore.session
import base64
logger = logging.getLogger(__name__)
bedrock_runtime_client = boto3.client('bedrock-runtime', region_name='us-east-1' )
def lambda_handler(event, context):
if "queryStringParameters" not in event:
return {
'statusCode': 400,
'body': 'No query string parameters passed in'
}
if "prompt" not in event["queryStringParameters"]:
return {
'statusCode': 400,
'body': 'Prompt needs to be passed in the query string parameters'
}
query_string_parameters = event["queryStringParameters"]
prompt = query_string_parameters["prompt"]
seed = 0
if "seed" in query_string_parameters:
seed = query_string_parameters["seed"]
image_data = invoke_stable_diffusion(prompt, seed)
print(f"image_data: {image_data}")
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>Amazon Bedrock - Stability AI</title>
</head>
<body>
<img src="{}" alt="Base64 Image">
</body>
</html>
""".format(f"data:image/png;base64,{image_data}")
# Return HTML content as the response
return {
'statusCode': 200,
'body': html_content,
'headers': {
'Content-Type': 'text/html',
},
}
def invoke_stable_diffusion(prompt, seed, style_preset=None):
"""
Invokes the Stability.ai Stable Diffusion XL model to create an image using
the input provided in the request body.
:param prompt: The prompt that you want Stable Diffusion to use for image generation.
:param seed: Random noise seed (omit this option or use 0 for a random seed)
:param style_preset: Pass in a style preset to guide the image model towards a particular style.
:return: Base64-encoded inference response from the model.
"""
try:
# The different model providers have individual request and response formats.
# For the format, ranges, and available style_presets of Stable Diffusion models refer to:
# https://platform.stability.ai/docs/api-reference#tag/v1generation
body = {
"text_prompts": [{"text": prompt}],
"seed": seed,
"cfg_scale": 10,
"steps": 30,
}
if style_preset:
body["style_preset"] = style_preset
response = bedrock_runtime_client.invoke_model(
modelId="stability.stable-diffusion-xl", body=json.dumps(body)
)
response_body = json.loads(response["body"].read())
base64_image_data = response_body["artifacts"][0]["base64"]
return base64_image_data
except ClientError:
logger.error("Couldn't invoke Stable Diffusion XL")
raise
6. Build code and deploy
Then we can perform a build using the following command to download the required dependencies and finally deploy the code using the following commands
sam build
sam deploy
7. Test the code
By calling the API Gateway endpoint with a query string parameter of prompt — we can now test the solution.
E.g. https://<api gateway endpoint>/Prod/bedrock?prompt=a dog playing with a dinosaur should yield a result similar to the following
The above sample could be improved by using a HTTP Post request instead of a GET request but the purpose of this article was to get a working solution as quickly as possible.
8. Code
If you wish to view the code for this sample project — it can be viewed on GitHub.