diff --git a/.changeset/curvy-needles-punch.md b/.changeset/curvy-needles-punch.md new file mode 100644 index 00000000000..2e41930d90b --- /dev/null +++ b/.changeset/curvy-needles-punch.md @@ -0,0 +1,5 @@ +--- +'@ai-sdk/amazon-bedrock': patch +--- + +feat (provider/bedrock): add file content part support diff --git a/content/providers/01-ai-sdk-providers/08-amazon-bedrock.mdx b/content/providers/01-ai-sdk-providers/08-amazon-bedrock.mdx index 8e7c1726f85..51d97a712ca 100644 --- a/content/providers/01-ai-sdk-providers/08-amazon-bedrock.mdx +++ b/content/providers/01-ai-sdk-providers/08-amazon-bedrock.mdx @@ -157,8 +157,6 @@ const model = bedrock('anthropic.claude-3-sonnet-20240229-v1:0', { Documentation for additional settings based on the selected model can be found within the [Amazon Bedrock Inference Parameter Documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters.html). -### Example - You can use Amazon Bedrock language models to generate text with the `generateText` function: ```ts @@ -174,6 +172,37 @@ const { text } = await generateText({ Amazon Bedrock language models can also be used in the `streamText` function (see [AI SDK Core](/docs/ai-sdk-core)). +### File Inputs + + + Amazon Bedrock supports file inputs on in combination with specific models, + e.g. `anthropic.claude-3-haiku-20240307-v1:0`. + + +The Amazon Bedrock provider supports file inputs, e.g. PDF files. + +```ts +import { bedrock } from '@ai-sdk/amazon-bedrock'; +import { generateText } from 'ai'; + +const result = await generateText({ + model: bedrock('anthropic.claude-3-haiku-20240307-v1:0'), + messages: [ + { + role: 'user', + content: [ + { type: 'text', text: 'Describe the pdf in detail.' }, + { + type: 'file', + data: fs.readFileSync('./data/ai.pdf'), + mimeType: 'application/pdf', + }, + ], + }, + ], +}); +``` + ### Guardrails You can use the `bedrock` provider metadata to utilize [Amazon Bedrock Guardrails](https://aws.amazon.com/bedrock/guardrails/): diff --git a/examples/ai-core/src/stream-text/amazon-bedrock-pdf.ts b/examples/ai-core/src/stream-text/amazon-bedrock-pdf.ts new file mode 100644 index 00000000000..19041530294 --- /dev/null +++ b/examples/ai-core/src/stream-text/amazon-bedrock-pdf.ts @@ -0,0 +1,29 @@ +import { bedrock } from '@ai-sdk/amazon-bedrock'; +import { streamText } from 'ai'; +import 'dotenv/config'; +import fs from 'node:fs'; + +async function main() { + const result = await streamText({ + model: bedrock('anthropic.claude-3-haiku-20240307-v1:0'), + messages: [ + { + role: 'user', + content: [ + { type: 'text', text: 'Describe the pdf in detail.' }, + { + type: 'file', + data: fs.readFileSync('./data/ai.pdf'), + mimeType: 'application/pdf', + }, + ], + }, + ], + }); + + for await (const textPart of result.textStream) { + process.stdout.write(textPart); + } +} + +main().catch(console.error); diff --git a/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.test.ts b/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.test.ts index 58ddb7d5f6e..b4732d48ded 100644 --- a/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.test.ts +++ b/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.test.ts @@ -21,7 +21,9 @@ describe('system messages', () => { }); describe('user messages', () => { - it('should convert messages with image and text parts to multiple parts', async () => { + it('should convert messages with file, image, and text parts to multiple parts', async () => { + const fileData = new Uint8Array([0, 1, 2, 3]); + const { messages } = convertToBedrockChatMessages([ { role: 'user', @@ -32,6 +34,11 @@ describe('user messages', () => { image: new Uint8Array([0, 1, 2, 3]), mimeType: 'image/png', }, + { + type: 'file', + data: Buffer.from(fileData).toString('base64'), + mimeType: 'application/pdf', + }, ], }, ]); @@ -47,6 +54,13 @@ describe('user messages', () => { source: { bytes: new Uint8Array([0, 1, 2, 3]) }, }, }, + { + document: { + format: 'pdf', + name: expect.any(String), + source: { bytes: Buffer.from(fileData) }, + }, + }, ], }, ]); diff --git a/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.ts b/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.ts index 965be0e005a..9747b9f38b7 100644 --- a/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.ts +++ b/packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.ts @@ -3,13 +3,16 @@ import { LanguageModelV1Prompt, UnsupportedFunctionalityError, } from '@ai-sdk/provider'; -import { ImageFormat } from '@aws-sdk/client-bedrock-runtime'; +import { createIdGenerator } from '@ai-sdk/provider-utils'; +import { DocumentFormat, ImageFormat } from '@aws-sdk/client-bedrock-runtime'; import { BedrockAssistantMessage, BedrockMessagesPrompt, BedrockUserMessage, } from './bedrock-chat-prompt'; +const generateFileId = createIdGenerator({ prefix: 'file', size: 16 }); + export function convertToBedrockChatMessages( prompt: LanguageModelV1Prompt, ): BedrockMessagesPrompt { @@ -70,6 +73,28 @@ export function convertToBedrockChatMessages( }, }); + break; + } + case 'file': { + if (part.data instanceof URL) { + // The AI SDK automatically downloads files for user file parts with URLs + throw new UnsupportedFunctionalityError({ + functionality: 'File URLs in user messages', + }); + } + + bedrockContent.push({ + document: { + format: part.mimeType?.split( + '/', + )?.[1] as DocumentFormat, + name: generateFileId(), + source: { + bytes: Buffer.from(part.data, 'base64'), + }, + }, + }); + break; } }