Front-End Web & Mobile

Add Amazon Bedrock Chat Capabilities to a React Native App

This post will teach you to create a React Native chat application using Amazon Bedrock to build AI-powered chat features.

The sample application includes the following:

  1. A mobile application using custom JSX components for the user interface.
  2. Seamless end-user chat interactions integrated with Amazon Bedrock foundational models.
  3. Backend development powered by AWS Amplify Gen2.
  4. Implementation of RESTful APIs using Amazon API Gateway for communication.
  5. Serverless backend processing using AWS Lambda.
  6. Use Amazon CloudWatch Logs to monitor AWS Lambda functions and view their logs.

Architecture

Figure 1 illustrates the architecture and process flow for running a React Native mobile application backend in the AWS Cloud.

Figure 1: Flow of a mobile chat application using AWS services.

Figure 1: Flow of a mobile chat application using AWS services.

  1. Users access the application from their mobile devices.
  2. The mobile client React chat application interfaces with Amazon API Gateway.
  3. Amazon API Gateway interacts with AWS Lambda to post and fetch the data.
  4. AWS Lambda interacts with one of the Amazon Bedrock models and returns the generated response in a JSON format.
  5. The processed data is then returned to the frontend for display, facilitating content or chat presentation.

Note: This tutorial was built on a Macintosh and uses the macOS terminal for command execution. If you are using either Windows or Linux operating system, use the equivalent commands.

Prerequisites

Before you get started, make sure you have the following installed:

Create your application

Run the below command to create an app (Uses Expo‘s TypeScript template).

npx create-expo-app amazon_bedrock_expo_chat_app -t expo-template-blank-typescript

Start your application

Navigate to the root folder of your application and execute the following command to start the application.

cd amazon_bedrock_expo_chat_app
npm run ios

When prompted, enter i to open the App in iOS simulator.

Press i │ open iOS simulator

Upon successful execution, you will see your new application running in the iOS Simulator, as shown in Figure 2.

New application running in the iOS Simulator

Figure 2: New application running in the iOS Simulator

Set up the backend environment

Open a new terminal window from the root project directory. Initialize Amplify by executing the following command.

npm add --save-dev @aws-amplify/backend@latest @aws-amplify/backend-cli@latest typescript

Note: TypeScript is not a requirement but is recommended for an optimal experience.

Install packages/libraries

npm install aws-amplify @aws-amplify/react-native @react-native-async-storage/async-storage @react-native-community/netinfo

Keep the code snippets handy

The complete code snippets are available at amazon-bedrock-react-native-chat-app, keep them ready for easy copying and pasting.

Open the project root with the IDE of your choice.

Create backend entry point for your backend

To create the backend.ts file and include the provided code, follow these steps.

  1. Inside the amplify folder, create a new file named backend.ts.
  2. Copy the entire code snippet from the demo repository for the backend.ts component and paste it into your newly created backend.ts file.
…

const backend = defineBackend({
    myApiFunction,
});

const apiStack = backend.createStack("api-stack");

const myRestApi = new RestApi(apiStack, "RestApi", {
    restApiName: "myRestApi",
    …
});

…

This code implements the following.

  1. Defines a backend environment with a Lambda function.
  2. Creates an API stack and a REST API with logging and CORS settings.
  3. Integrates the Lambda function with a POST method at the /chat endpoint.
  4. Sets up an IAM policy to allow API invocation and access to a Bedrock model.
  5. Adds API endpoint details to the backend output for configuration.

Note: For this tutorial, the API is open to unauthenticated access. Consider implementing authentication and authorization if needed.

Set up Amplify REST API with Lambda Function

Create a new directory and a resource file amplify/functions/api-function/resource.ts. Then, define the function with defineFunction:

import { defineFunction } from "@aws-amplify/backend";
export const myApiFunction = defineFunction({
  name: "api-function",
});

Create the corresponding handler file, amplify/functions/api-function/handler.ts. Copy the entire code snippet from the demo repository for the handler.ts file and paste it into your newly created handler.ts file.

…

    const command = new InvokeModelCommand({
      body: JSON.stringify(newBody),
      modelId: modelId,
      accept: accept,
      contentType: contentType,
    });

    …

    return {
      statusCode: 200,
      body: JSON.stringify(responseBody),
    }
…

This code implements the following.

  1. Imports the necessary libraries.
  2. Configures the Amazon Bedrock Runtime.
  3. Utilizes the AI21 model for this demo application.
  4. Extracts the message input from body if provided, else uses the default message.
  5. Invokes the Amazon Bedrock model with set of parameters.
  6. Processes and returns the response.

Now you can run npx ampx sandbox to create your first backend!

npx ampx sandbox

Amplify Gen 2 requires your backend to be configured for use with ECMAScript modules (ESM). Create a local file in the Amplify backend directory, amplify/package.json

{
  "type": "module"
}

Frontend development

Make the following changes in the frontend code.

Create header component

To create the Header.jsx file and include the provided code, follow these steps.

  1. Inside the src/components/ folder, create a new file named Header.jsx.
  2. Copy the entire code snippet from the demo repository for the Header.jsx component and paste it into your newly created Header.jsx file.
...
const AppHeader = ({title}) => {
  return (
    <View style={styles.wrapper}>
      <Text style={styles.appTitle}>{title}</Text>
    </View>
  );
};
...

Now, you have successfully created the Header.jsx component that displays a header with a customizable title.

Create avatar component

  1. Inside the src/components/ folder, create a new file named Avatar.jsx.
  2. Copy the entire code snippet from the demo repository for the Avatar.jsx component and paste it into your newly created Avatar.jsx file.
...
const Avatar = ({isUser}) => {
  ...
  return <View style={[avatarStyle]}>{icon}</View>;
};
export const UserAvatar = () => {
  return <Avatar isUser={true} />;
};
export const ChatBotAvatar = () => {
  return <Avatar isUser={false} />;
};

The Avatar component dynamically renders avatars for the user and chat bot.

Create ChatInput component

  1. Inside the src/components/ folder, create a new file named ChatInput.jsx.
  2. Copy the entire code snippet from the demo repository for the ChatInput.jsx component and paste it into your newly created ChatInput.jsx file.
...

const ChatInput = ({ value, onChangeText, onSend, placeholder }) => (
  <View style={styles.container}>
    <TextInput
      style={styles.input}
      placeholder={placeholder}
      value={value}
      onChangeText={onChangeText}
    />
    <Button title="Send" onPress={onSend} />
  </View>
);

...

The ChatInput component provides a user interface for entering and sending messages in a chat application. It consists of a text input field for typing messages, accompanied by a Send button to trigger the message sending action.

Create message bubble component

  1. Inside the src/components/ folder, create a new file named MessageBubble.jsx.
  2. Copy the entire code snippet from the demo repository for the MessageBubble.jsx component and paste it into your newly created MessageBubble.jsx file.
...

const MessageBubble = ({ item }) => {
...
  return (
    <View style={...>
      {item.sender === 'bot' && avatarComponent}
      <View style={messageContainerStyle}>
        <Text style={messageTextStyle}>{item.message}</Text>
      </View>
      {item.sender === 'user' && avatarComponent}
    </View>
  );
};

...

The MessageBubble component renders chat message bubbles in a chat application, dynamically styling them based on the sender (user or bot). It integrates user and chat bot avatars alongside the message text, offering a visually distinct and organized representation of chat interactions.

Create chat component

  1. Inside the src/components/ folder, create a new file named Chat.jsx.
  2. Copy the entire code snippet from the demo repository for the Chat.jsx component and paste it into your newly created Chat.jsx file.
...
const ChatComponent = () => {
  ...
  const fetchAPI = async (message) => {
    ...
  };
  const handleSend = () => {
    ...
  };

  return (
    <View style={styles.container}>
      <FlatList
        data={messages}
        ...
        renderItem={renderMessage}
      />
      <ChatInput ... />
    </View>
  );
};
...

The chat component functionality:

  1. Manages chat messages and user input.
  2. Uses state to store messages and the current input.
  3. Handles sending messages, fetches bot responses from an API, and renders messages using MessageBubble.
  4. The user interacts through the integrated ChatInput.

Create API service

  1. Inside the src/services/ folder, create a new file named api.js.
  2. Copy the entire code snippet from the demo repository for the api.js component and paste it into your newly created api.js file.
  3. Replace the apiUrl with Amazon API Gateway provided URL.
…

const fetchChatAPI = async message => {
  try {
    const restOperation = post({
      apiName: 'myRestApi',
      path: 'chat',
      options: {
        body: {
          message: message
        }
      }
    });

    const { body } = await restOperation.response;
     …
    return cleanedText
  } catch (error) {
    console.log('POST call failed :', JSON.parse(error.response.body));
  }
}

…

The above code defines an async function, fetchChatAPI, that sends a POST request to a REST API endpoint using AWS Amplify. It processes the response to extract and clean a specific text field, handling errors by logging the details.

Update the App component

To update the App.tsx component and incorporate the provided code, follow these steps.

  1. Navigate to the src folder and locate the App.tsx file.
  2. Copy the entire code snippet from the demo repository for the App.tsx component and paste it into your existing App.tsx file.
import React from 'react';
import Header from './src/components/Header';
import {ChatComponent} from './src/components/Chat';
const App = () => {
  return (
    <>
      <Header title='Amazon Bedrock Chat App' />
      <ChatComponent />
    </>
  );
};
export default App;

Run your React Native application in the simulator, if is not running already.

npm run ios

The App.tsx component is updated with the provided code. You can open the app in the simulator, enter text, select the Send button, and receive responses from the Amazon Bedrock model. Make sure to check the provided screenshot (Figure 3) as a reference for the expected output.

Amazon Bedrock chat application user interface

Amazon Bedrock chat application user interface

Conclusion

In this blog post, we have guided you through the development of a simple chat application for the mobile platform using Amazon Bedrock, which leverages generative AI models. By integrating We’ve also used multiple AWS services including AWS Amplify, Amazon API Gateway, and AWS Lambda. To learn more, go to the AWS Amplify Documentation.

 


About the Author

Author: Deekshitulu Pentakota

Deekshitulu Pentakota

Deekshitulu Pentakota is a Lead Consultant at Amazon Web Services in India, where he helps global customers build secure, scalable, and cost-effective cloud applications. As a Certified Usability Analyst from Human Factors International (HFI) with expertise in User Experience Design and Full Stack Application Development, he delivers innovative cloud solutions for clients across various industries.