Skip to content

Commit 5ea72ba

Browse files
authored
Merge pull request #2858 from asmovian/fix-lambda-bedrock-streaming
Fix lambda bedrock streaming
2 parents 7841f6a + a79471a commit 5ea72ba

File tree

2 files changed

+39
-23
lines changed

2 files changed

+39
-23
lines changed

lambda-streaming-ttfb-write-sam-with-bedrock-streaming/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Lambda Response streaming: time-to-first-byte using write() method
1+
# AWS Lambda Response streaming: time-to-first-byte using write() method
22

3-
This pattern shows how to use Lambda response streaming ability and bedrock LLM streaming inference api to improve time-to-first byte using the write() method and `InvokeModelWithResponseStreamCommand`. For more information on the feature, see the [launch blog post](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/).
3+
This pattern shows how to use AWS Lambda response streaming ability and Amazon Bedrock LLM streaming inference api to improve time-to-first byte using the write() method and `InvokeModelWithResponseStreamCommand`. For more information on the feature, see the [launch blog post](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/).
44

55
Learn more about this pattern at Serverless Land Patterns: [lambda-streaming-ttfb-write-sam](https://github.com/aws-samples/serverless-patterns/tree/main/lambda-streaming-ttfb-write-sam)
66

@@ -69,4 +69,4 @@ You can see the gradual display of the streamed response.
6969
----
7070
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
7171
72-
SPDX-License-Identifier: MIT-0
72+
SPDX-License-Identifier: MIT-0

lambda-streaming-ttfb-write-sam-with-bedrock-streaming/src/index.js

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ const {
66
exports.handler = awslambda.streamifyResponse(
77
async (event, responseStream, context) => {
88
const lambdaRequestBody = JSON.parse(event.body);
9+
try {
10+
// Handle base64 encoded body from AWS SigV4 requests
11+
const body = event.isBase64Encoded ?
12+
Buffer.from(event.body, 'base64').toString('utf-8') :
13+
event.body;
14+
lambdaRequestBody = JSON.parse(body);
15+
} catch (error) {
16+
console.error('Error parsing request body:', error);
17+
responseStream.write("Invalid JSON in request body.");
18+
responseStream.end();
19+
return;
20+
}
21+
922
const prompt = lambdaRequestBody.prompt || '';
1023
if (prompt == '') {
1124
responseStream.write("No prompt provided.");
@@ -20,18 +33,15 @@ exports.handler = awslambda.streamifyResponse(
2033
}
2134
};
2235

23-
const
36+
const
2437
maxTokens = 2500,
2538
temperature = .7,
2639
topP = 1,
27-
stopSequences = ["\n\nHuman:"],
28-
anthropicVersion = "bedrock-2023-05-31",
29-
modelId = 'anthropic.claude-v2',
40+
anthropicVersion = "bedrock-2023-05-31"
41+
modelId = 'anthropic.claude-3-haiku-20240307-v1:0',
3042
contentType = 'application/json',
3143
accept = '*/*';
3244

33-
const formattedPrompt = `Human: ${prompt}\n\nAssistant:`
34-
3545
try {
3646
responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
3747

@@ -45,12 +55,16 @@ exports.handler = awslambda.streamifyResponse(
4555
});
4656

4757
const llmRequestBody = {
48-
prompt: formattedPrompt,
49-
max_tokens_to_sample: maxTokens,
58+
max_tokens: maxTokens,
59+
messages: [
60+
{
61+
role: "user",
62+
content: prompt
63+
}
64+
],
5065
temperature,
51-
top_p: topP,
52-
stop_sequences: stopSequences,
53-
anthropic_version: anthropicVersion
66+
top_p: topP
67+
anthropic_version: anthropicVersion,
5468
};
5569

5670
const params = {
@@ -68,19 +82,21 @@ exports.handler = awslambda.streamifyResponse(
6882
responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
6983
const chunks = []
7084
for await (const value of actualStream) {
71-
const jsonString = new TextDecoder().decode(value.body); // body is a Uint8Array. jsonString->'{"bytes":"eyJjb21wbGV0aW9uIjoiIEkiLCJzdG9wX3JlYXNvbiI6bnVsbH0="}'
72-
const base64encoded = JSON.parse(jsonString).bytes; // base64 encoded string.
73-
const decodedString = Buffer.from(base64encoded, "base64").toString(
74-
"utf-8"
75-
);
85+
const jsonString = new TextDecoder().decode(value.body);
86+
const base64encoded = JSON.parse(jsonString).bytes;
87+
const decodedString = Buffer.from(base64encoded, "base64").toString("utf-8");
88+
7689
try {
77-
const streamingCompletion = JSON.parse(decodedString).completion;
78-
chunks.push(streamingCompletion)
79-
responseStream.write(streamingCompletion)
90+
const chunk = JSON.parse(decodedString);
91+
if (chunk.type === 'content_block_delta' && chunk.delta?.text) {
92+
const text = chunk.delta.text;
93+
chunks.push(text);
94+
responseStream.write(text);
95+
}
8096
} catch (error) {
8197
console.error(error);
8298
responseStream.write(null);
83-
responseStream.end()
99+
responseStream.end();
84100
}
85101
}
86102
console.log("stream ended: ", chunks.join(''))

0 commit comments

Comments
 (0)